From a3c723ee30db61e4c2c5375fa3c8c677336ca113 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 2 Apr 2013 23:48:55 +0100 Subject: Fix minor race condition where SOP.GetGeometricCenter() and GetCenterOfMass() could return results which were never the case if these values were changed whilst the method was running No need to create new Vector3s since these are structs. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ec9e87e..2fcb199 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2136,9 +2136,9 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor pa = PhysActor; if (pa != null) - return new Vector3(pa.GeometricCenter.X, pa.GeometricCenter.Y, pa.GeometricCenter.Z); + return pa.GeometricCenter; else - return new Vector3(0, 0, 0); + return Vector3.Zero; } public Vector3 GetCenterOfMass() @@ -2146,9 +2146,9 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor pa = PhysActor; if (pa != null) - return new Vector3(pa.CenterOfMass.X, pa.CenterOfMass.Y, pa.CenterOfMass.Z); + return pa.CenterOfMass; else - return new Vector3(0, 0, 0); + return Vector3.Zero; } public float GetMass() -- cgit v1.1 From 3332af4060960a4b649d3d5237988e0f410b54e3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 3 Apr 2013 00:01:06 +0100 Subject: minor: Make SOP.UpdateOffset() more consistent by checking against the same old OffsetPosition rather than one which may vary if it simultaneously changes. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 2fcb199..d412702 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -3915,17 +3915,17 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// + /// Update this part's offset position. /// /// - public void UpdateOffSet(Vector3 pos) + public void UpdateOffSet(Vector3 newPos) { - if ((pos.X != OffsetPosition.X) || - (pos.Y != OffsetPosition.Y) || - (pos.Z != OffsetPosition.Z)) - { - Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); + Vector3 oldPos = OffsetPosition; + if ((newPos.X != oldPos.X) || + (newPos.Y != oldPos.Y) || + (newPos.Z != oldPos.Z)) + { if (ParentGroup.RootPart.GetStatusSandbox()) { if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10) -- cgit v1.1 From c0319daa403f68427bb80b4845a92eb37f21a7b7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 3 Apr 2013 00:09:28 +0100 Subject: fix minor race condition in SOP.SitTargetPositionLL where inconsistency could occur if the sit target position changed whilst the property was fetched --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index d412702..3e816fc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1146,7 +1146,7 @@ namespace OpenSim.Region.Framework.Scenes // the mappings more consistant. public Vector3 SitTargetPositionLL { - get { return new Vector3(m_sitTargetPosition.X, m_sitTargetPosition.Y,m_sitTargetPosition.Z); } + get { return m_sitTargetPosition; } set { m_sitTargetPosition = value; } } -- cgit v1.1 From 97f0c9da84f9a3a73a63c209012260fa2c59c0de Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 3 Apr 2013 00:23:20 +0100 Subject: Use consistent GroupPosition value Make SOP.UpdateGroupPosition() rather than one that could change whilst the method is being executed. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 3e816fc..7697411 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -3902,13 +3902,14 @@ namespace OpenSim.Region.Framework.Scenes } } - public void UpdateGroupPosition(Vector3 pos) + public void UpdateGroupPosition(Vector3 newPos) { - if ((pos.X != GroupPosition.X) || - (pos.Y != GroupPosition.Y) || - (pos.Z != GroupPosition.Z)) + Vector3 oldPos = GroupPosition; + + if ((newPos.X != oldPos.X) || + (newPos.Y != oldPos.Y) || + (newPos.Z != oldPos.Z)) { - Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); GroupPosition = newPos; ScheduleTerseUpdate(); } -- cgit v1.1 From 7bf1986e9138df4629aa9323d3ba9fab5c884400 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 3 Apr 2013 00:24:33 +0100 Subject: Fix minor race condition in SOP.SitTargetOrientationLL where inconsistent values could be returned if the sit orientation was changed whilst the property was being fetched. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 7697411..93d4da0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1152,17 +1152,8 @@ namespace OpenSim.Region.Framework.Scenes public Quaternion SitTargetOrientationLL { - get - { - return new Quaternion( - m_sitTargetOrientation.X, - m_sitTargetOrientation.Y, - m_sitTargetOrientation.Z, - m_sitTargetOrientation.W - ); - } - - set { m_sitTargetOrientation = new Quaternion(value.X, value.Y, value.Z, value.W); } + get { return m_sitTargetOrientation; } + set { m_sitTargetOrientation = value; } } public bool Stopped -- cgit v1.1 From 94d44142e37a9191162a426f28dd23f40b0cf4aa Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 3 Apr 2013 00:48:36 +0100 Subject: minor: Stop falsely logging that a teleport was being aborted on client logout even when no teleport was active. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 3e69bf2..ca0cef1 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -280,10 +280,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private void OnConnectionClosed(IClientAPI client) { - if (client.IsLoggingOut) + if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) { - m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting); - m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", client.Name, Scene.Name); -- cgit v1.1 From 831e4c38506140e9ece2db4b96b4f0960a0276a8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 4 Apr 2013 00:36:15 +0100 Subject: Fix bug where outstanding llHTTPRequests for scripts were not being aborted when they were deleted. This was because AsyncCommandManager was handing an item ID to IHttpRequestModule.StopHttpRequest() rather than the expected request ID. This commit also makes the http request asynchronous using BeginGetResponse() rather than doing this by launching a new thread so that we can more safely abort it via HttpWebRequest.Abort() rather than aborting the thread itself. This also renames StopHttpRequest() to StopHttpRequestsForScript() since any outstanding requests are now aborted and/or removed. --- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 92 +++++++++++++++------- .../Region/Framework/Interfaces/IHttpRequests.cs | 8 +- .../Api/Implementation/AsyncCommandManager.cs | 8 +- 3 files changed, 76 insertions(+), 32 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index c2e37c4..1c251b8 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -28,12 +28,15 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Mail; using System.Net.Security; +using System.Reflection; using System.Text; using System.Threading; using System.Security.Cryptography.X509Certificates; +using log4net; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; @@ -250,18 +253,29 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest return reqID; } - public void StopHttpRequest(uint m_localID, UUID m_itemID) + public void StopHttpRequestsForScript(UUID id) { if (m_pendingRequests != null) { + List keysToRemove = null; + lock (HttpListLock) { - HttpRequestClass tmpReq; - if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) + foreach (HttpRequestClass req in m_pendingRequests.Values) { - tmpReq.Stop(); - m_pendingRequests.Remove(m_itemID); + if (req.ItemID == id) + { + req.Stop(); + + if (keysToRemove == null) + keysToRemove = new List(); + + keysToRemove.Add(req.ReqID); + } } + + if (keysToRemove != null) + keysToRemove.ForEach(keyToRemove => m_pendingRequests.Remove(keyToRemove)); } } } @@ -362,6 +376,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public class HttpRequestClass: IServiceRequest { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // Constants for parameters // public const int HTTP_BODY_MAXLENGTH = 2; // public const int HTTP_METHOD = 0; @@ -419,12 +435,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void Process() { - httpThread = new Thread(SendRequest); - httpThread.Name = "HttpRequestThread"; - httpThread.Priority = ThreadPriority.BelowNormal; - httpThread.IsBackground = true; - _finished = false; - httpThread.Start(); + SendRequest(); } /* @@ -435,10 +446,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest public void SendRequest() { HttpWebResponse response = null; - StringBuilder sb = new StringBuilder(); - byte[] buf = new byte[8192]; - string tempString = null; - int count = 0; try { @@ -497,11 +504,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest bstream.Close(); } - Request.Timeout = HttpTimeout; try { - // execute the request - response = (HttpWebResponse) Request.GetResponse(); + IAsyncResult result = (IAsyncResult)Request.BeginGetResponse(ResponseCallback, null); + + ThreadPool.RegisterWaitForSingleObject( + result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), null, HttpTimeout, true); } catch (WebException e) { @@ -510,11 +518,31 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest throw; } response = (HttpWebResponse)e.Response; + _finished = true; } + } + catch (Exception e) + { + Status = (int)OSHttpStatusCode.ClientErrorJoker; + ResponseBody = e.Message; + _finished = true; + } + } + private void ResponseCallback(IAsyncResult ar) + { + HttpWebResponse response = null; + + try + { + response = (HttpWebResponse)Request.EndGetResponse(ar); Status = (int)response.StatusCode; Stream resStream = response.GetResponseStream(); + StringBuilder sb = new StringBuilder(); + byte[] buf = new byte[8192]; + string tempString = null; + int count = 0; do { @@ -530,36 +558,40 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest // continue building the string sb.Append(tempString); } - } while (count > 0); // any more data to read? + } + while (count > 0); // any more data to read? - ResponseBody = sb.ToString(); + ResponseBody = sb.ToString(); } catch (Exception e) { Status = (int)OSHttpStatusCode.ClientErrorJoker; ResponseBody = e.Message; - _finished = true; - return; +// m_log.Debug( +// string.Format("[SCRIPTS HTTP REQUESTS]: Exception on response to {0} for {1} ", Url, ItemID), e); } finally { if (response != null) response.Close(); + + _finished = true; } + } - _finished = true; + private void TimeoutCallback(object state, bool timedOut) + { + if (timedOut) + Request.Abort(); } public void Stop() { - try - { - httpThread.Abort(); - } - catch (Exception) - { - } +// m_log.DebugFormat("[SCRIPTS HTTP REQUESTS]: Stopping request to {0} for {1} ", Url, ItemID); + + if (Request != null) + Request.Abort(); } } } diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs index eb6c5ac..113dcd7 100644 --- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs +++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs @@ -45,7 +45,13 @@ namespace OpenSim.Region.Framework.Interfaces { UUID MakeHttpRequest(string url, string parameters, string body); UUID StartHttpRequest(uint localID, UUID itemID, string url, List parameters, Dictionary headers, string body); - void StopHttpRequest(uint m_localID, UUID m_itemID); + + /// + /// Stop and remove all http requests for the given script. + /// + /// + void StopHttpRequestsForScript(UUID id); + IServiceRequest GetNextCompletedRequest(); void RemoveCompletedRequest(UUID id); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 47a9cdc..1c59624 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -28,7 +28,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Reflection; using System.Threading; +using log4net; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Monitoring; @@ -45,6 +47,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public class AsyncCommandManager { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static Thread cmdHandlerThread; private static int cmdHandlerThreadCycleSleepms; @@ -225,6 +229,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) { +// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); + // Remove a specific script // Remove dataserver events @@ -236,7 +242,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Remove from: HttpRequest IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); if (iHttpReq != null) - iHttpReq.StopHttpRequest(localID, itemID); + iHttpReq.StopHttpRequestsForScript(itemID); IWorldComm comms = engine.World.RequestModuleInterface(); if (comms != null) -- cgit v1.1 From f281a994e8544d95961ef669a0fe14c0cba7f175 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 4 Apr 2013 00:49:07 +0100 Subject: refactor: Simplify ScriptsHttpRequests.GetNextCompletedRequest to more simply iterate through pending requests without unnecessary checks. --- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 1c251b8..ebf56cd 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -293,19 +293,13 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { lock (HttpListLock) { - foreach (UUID luid in m_pendingRequests.Keys) + foreach (HttpRequestClass req in m_pendingRequests.Values) { - HttpRequestClass tmpReq; - - if (m_pendingRequests.TryGetValue(luid, out tmpReq)) - { - if (tmpReq.Finished) - { - return tmpReq; - } - } + if (req.Finished) + return req; } } + return null; } -- cgit v1.1 From f064075a85962039f4737ec9ca631c377a6197c9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 4 Apr 2013 01:06:57 +0100 Subject: Fix XmlRpcAdmin admin_exists_user call so that it actually returns the last user login time rather than serializing the DateTime directly which generates a set of unexpected fields. lastlogin return is in unix timestamp format. --- OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 5d44b2a..d19b8b6 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -1094,7 +1094,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController { GridUserInfo userInfo = m_application.SceneManager.CurrentOrFirstScene.GridUserService.GetGridUserInfo(account.PrincipalID.ToString()); if (userInfo != null) - responseData["lastlogin"] = userInfo.Login; + responseData["lastlogin"] = Util.ToUnixTime(userInfo.Login); else responseData["lastlogin"] = 0; -- cgit v1.1 From d2367968e4227f8a6e37d22ed5904c4f1d87a15e Mon Sep 17 00:00:00 2001 From: teravus Date: Thu, 4 Apr 2013 19:10:23 -0400 Subject: * In between the fog, a moment of clarity. This fixes mantis 6570 --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index dfdd566..96a030b 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -453,7 +453,7 @@ namespace OpenSim.Framework.Servers.HttpServer } OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); - + resp.ReuseContext = true; HandleRequest(req, resp); -- cgit v1.1 From 0f008d5f7d4a34d4f7529036f5dd83742423c42f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Apr 2013 01:44:06 +0100 Subject: When rezzing a coalesced object, check adjust position of all components. --- .../InventoryAccess/InventoryAccessModule.cs | 47 +++++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index eaf4ce2..ebada5a 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -807,7 +807,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) + if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment)) return null; for (int i = 0; i < objlist.Count; i++) @@ -905,10 +905,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// /// + /// + /// List of vector position adjustments for a coalesced objects. For ordinary objects + /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist + /// /// /// true if we can processed with rezzing, false if we need to abort private bool DoPreRezWhenFromItem( - IClientAPI remoteClient, InventoryItemBase item, List objlist, Vector3 pos, bool isAttachment) + IClientAPI remoteClient, InventoryItemBase item, List objlist, + Vector3 pos, List veclist, bool isAttachment) { UUID fromUserInventoryItemId = UUID.Zero; @@ -932,27 +937,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } int primcount = 0; - foreach (SceneObjectGroup g in objlist) - primcount += g.PrimCount; - - if (!m_Scene.Permissions.CanRezObject( - primcount, remoteClient.AgentId, pos) - && !isAttachment) + for(int i = 0; i < objlist.Count; i++) { - // The client operates in no fail mode. It will - // have already removed the item from the folder - // if it's no copy. - // Put it back if it's not an attachment - // - if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) - remoteClient.SendBulkUpdateInventory(item); + SceneObjectGroup g = objlist[i]; + + if (!m_Scene.Permissions.CanRezObject( + g.PrimCount, remoteClient.AgentId, pos + veclist[i]) + && !isAttachment) + { + // The client operates in no fail mode. It will + // have already removed the item from the folder + // if it's no copy. + // Put it back if it's not an attachment + // + if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) + remoteClient.SendBulkUpdateInventory(item); - ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); - remoteClient.SendAlertMessage(string.Format( - "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", - item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); + ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); + remoteClient.SendAlertMessage(string.Format( + "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", + item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name)); - return false; + return false; + } } for (int i = 0; i < objlist.Count; i++) -- cgit v1.1 From 7f070236f72058ba22d017048b978adea380f0a1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Apr 2013 02:34:51 +0100 Subject: Fix taking (and rezzing) of coalesced objects in the non-root subregions of megaregions. This fixes the combined bounding box location for regions bigger than 256x256. It also fixes the position on taking coalesced objects in the non-root regions, where position checks are properly done on rez instead. It also fixes the megaregion land channel to return null if the land does not exist, which should probably also be done for the ordinary land channels rather than returning a dummy region. Inspiration from Garmin's commit in http://opensimulator.org/mantis/view.php?id=6595. Thanks! --- .../InventoryAccess/InventoryAccessModule.cs | 32 ++++----- .../World/Permissions/PermissionsModule.cs | 2 + OpenSim/Region/Framework/Scenes/Scene.cs | 12 ++-- .../RegionCombinerLargeLandChannel.cs | 83 ++++++++++++++-------- 4 files changed, 76 insertions(+), 53 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index ebada5a..f796ec9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -357,19 +357,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (SceneObjectGroup objectGroup in objlist) { - Vector3 inventoryStoredPosition = new Vector3 - (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) - ? 250 - : objectGroup.AbsolutePosition.X) - , - (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) - ? 250 - : objectGroup.AbsolutePosition.Y, - objectGroup.AbsolutePosition.Z); - - originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; - - objectGroup.AbsolutePosition = inventoryStoredPosition; +// Vector3 inventoryStoredPosition = new Vector3 +// (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) +// ? 250 +// : objectGroup.AbsolutePosition.X) +// , +// (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) +// ? 250 +// : objectGroup.AbsolutePosition.Y, +// objectGroup.AbsolutePosition.Z); +// +// originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; +// +// objectGroup.AbsolutePosition = inventoryStoredPosition; // Make sure all bits but the ones we want are clear // on take. @@ -397,9 +397,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); - // Restore the position of each group now that it has been stored to inventory. - foreach (SceneObjectGroup objectGroup in objlist) - objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; +// // Restore the position of each group now that it has been stored to inventory. +// foreach (SceneObjectGroup objectGroup in objlist) +// objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 79dd4a0..77299be 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -1453,6 +1453,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions bool permission = false; + m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); + ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); if (land == null) return false; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 911a3e4..f50d3cd 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5361,12 +5361,12 @@ namespace OpenSim.Region.Framework.Scenes List objects, out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) { - minX = 256; - maxX = -256; - minY = 256; - maxY = -256; - minZ = 8192; - maxZ = -256; + minX = float.MaxValue; + maxX = float.MinValue; + minY = float.MaxValue; + maxY = float.MinValue; + minZ = float.MaxValue; + maxZ = float.MinValue; List offsets = new List(); diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs index b4abc1d..4bf2a82 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs @@ -27,6 +27,8 @@ using System; using System.Collections.Generic; +using System.Reflection; +using log4net; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; @@ -34,10 +36,10 @@ using OpenSim.Region.CoreModules.World.Land; namespace OpenSim.Region.RegionCombinerModule { -public class RegionCombinerLargeLandChannel : ILandChannel + public class RegionCombinerLargeLandChannel : ILandChannel { - // private static readonly ILog m_log = - // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private RegionData RegData; private ILandChannel RootRegionLandChannel; private readonly List RegionConnections; @@ -75,40 +77,51 @@ public class RegionCombinerLargeLandChannel : ILandChannel public ILandObject GetLandObject(int x, int y) { - //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); - - if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) - { - return RootRegionLandChannel.GetLandObject(x, y); - } - else - { - int offsetX = (x / (int)Constants.RegionSize); - int offsetY = (y / (int)Constants.RegionSize); - offsetX *= (int)Constants.RegionSize; - offsetY *= (int)Constants.RegionSize; - - foreach (RegionData regionData in RegionConnections) - { - if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) - { - return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); - } - } - ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); - obj.LandData.Name = "NO LAND"; - return obj; - } + return GetLandObject((float)x, (float)y); + +// m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); +// +// if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) +// { +// return RootRegionLandChannel.GetLandObject(x, y); +// } +// else +// { +// int offsetX = (x / (int)Constants.RegionSize); +// int offsetY = (y / (int)Constants.RegionSize); +// offsetX *= (int)Constants.RegionSize; +// offsetY *= (int)Constants.RegionSize; +// +// foreach (RegionData regionData in RegionConnections) +// { +// if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) +// { +// m_log.DebugFormat( +// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}", +// regionData.RegionScene.Name, offsetX, offsetY); +// +// return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); +// } +// } +// //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); +// //obj.LandData.Name = "NO LAND"; +// //return obj; +// } +// +// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y); +// +// return null; } public ILandObject GetLandObject(int localID) { + // XXX: Possibly should be looking in every land channel, not just the root. return RootRegionLandChannel.GetLandObject(localID); } public ILandObject GetLandObject(float x, float y) { - //m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); +// m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) { @@ -125,14 +138,22 @@ public class RegionCombinerLargeLandChannel : ILandChannel { if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) { +// m_log.DebugFormat( +// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}", +// regionData.RegionScene.Name, offsetX, offsetY); + return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); } } - ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); - obj.LandData.Name = "NO LAND"; - return obj; +// ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); +// obj.LandData.Name = "NO LAND"; +// return obj; } + +// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y); + + return null; } public bool IsForcefulBansAllowed() -- cgit v1.1 From c7cd077e55c2e889f61bb2e28cd3254b15e07567 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Sun, 7 Apr 2013 17:31:44 -0700 Subject: Optimize the number of Simian calls to get the initial presence information for the friends list. This is a pretty big performance improvement on login. Note that you must upgrade simian to incorporate the corresponding GetSessions call. --- .../SimianGrid/SimianPresenceServiceConnector.cs | 193 +++++++++------------ 1 file changed, 83 insertions(+), 110 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 854bea4..7bb06fb 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -137,10 +137,11 @@ namespace OpenSim.Services.Connectors.SimianGrid userID, sessionID, secureSessionID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "AddSession" }, - { "UserID", userID.ToString() } - }; + { + { "RequestMethod", "AddSession" }, + { "UserID", userID.ToString() } + }; + if (sessionID != UUID.Zero) { requestArgs["SessionID"] = sessionID.ToString(); @@ -158,13 +159,13 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool LogoutAgent(UUID sessionID) { -// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); + // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "RemoveSession" }, - { "SessionID", sessionID.ToString() } - }; + { + { "RequestMethod", "RemoveSession" }, + { "SessionID", sessionID.ToString() } + }; OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); @@ -177,13 +178,13 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool LogoutRegionAgents(UUID regionID) { -// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); + // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "RemoveSessions" }, - { "SceneID", regionID.ToString() } - }; + { + { "RequestMethod", "RemoveSessions" }, + { "SceneID", regionID.ToString() } + }; OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); @@ -202,49 +203,46 @@ namespace OpenSim.Services.Connectors.SimianGrid public PresenceInfo GetAgent(UUID sessionID) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); - - NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "GetSession" }, - { "SessionID", sessionID.ToString() } - }; - - OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs); - if (sessionResponse["Success"].AsBoolean()) + OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID); + if (sessionResponse == null) { - UUID userID = sessionResponse["UserID"].AsUUID(); - m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); - - requestArgs = new NameValueCollection - { - { "RequestMethod", "GetUser" }, - { "UserID", userID.ToString() } - }; - - OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); - if (userResponse["Success"].AsBoolean()) - return ResponseToPresenceInfo(sessionResponse, userResponse); - else - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString()); + return null; } - else + + UUID userID = sessionResponse["UserID"].AsUUID(); + OSDMap userResponse = GetUserData(userID); + if (userResponse == null) { - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString()); + return null; } - return null; + return ResponseToPresenceInfo(sessionResponse); } public PresenceInfo[] GetAgents(string[] userIDs) { - List presences = new List(userIDs.Length); + List presences = new List(); - for (int i = 0; i < userIDs.Length; i++) + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "GetSessions" }, + { "UserIDList", String.Join(",",userIDs) } + }; + + OSDMap sessionListResponse = WebUtil.PostToService(m_serverUrl, requestArgs); + if (! sessionListResponse["Success"].AsBoolean()) { - UUID userID; - if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) - presences.AddRange(GetSessions(userID)); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString()); + return null; + } + + OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray; + for (int i = 0; i < sessionList.Count; i++) + { + OSDMap sessionInfo = sessionList[i] as OSDMap; + presences.Add(ResponseToPresenceInfo(sessionInfo)); } return presences.ToArray(); @@ -262,7 +260,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); // Remove the session to mark this user offline if (!LogoutAgent(sessionID)) @@ -270,11 +268,11 @@ namespace OpenSim.Services.Connectors.SimianGrid // Save our last position as user data NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "AddUserData" }, - { "UserID", userID.ToString() }, - { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } - }; + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } + }; OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); @@ -287,14 +285,14 @@ namespace OpenSim.Services.Connectors.SimianGrid public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "AddUserData" }, - { "UserID", userID.ToString() }, - { "HomeLocation", SerializeLocation(regionID, position, lookAt) } - }; + { + { "RequestMethod", "AddUserData" }, + { "UserID", userID.ToString() }, + { "HomeLocation", SerializeLocation(regionID, position, lookAt) } + }; OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); @@ -312,23 +310,14 @@ namespace OpenSim.Services.Connectors.SimianGrid public GridUserInfo GetGridUserInfo(string user) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); UUID userID = new UUID(user); -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); - - NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "GetUser" }, - { "UserID", userID.ToString() } - }; - - OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); - if (userResponse["Success"].AsBoolean()) + OSDMap userResponse = GetUserData(userID); + if (userResponse != null) return ResponseToGridUserInfo(userResponse); - else - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID,userResponse["Message"].AsString()); return null; } @@ -338,65 +327,49 @@ namespace OpenSim.Services.Connectors.SimianGrid private OSDMap GetUserData(UUID userID) { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); + // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "GetUser" }, - { "UserID", userID.ToString() } - }; + { + { "RequestMethod", "GetUser" }, + { "UserID", userID.ToString() } + }; OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) return response; - else - m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString()); + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString()); return null; } - private List GetSessions(UUID userID) + private OSDMap GetSessionDataFromSessionID(UUID sessionID) { - List presences = new List(1); - - OSDMap userResponse = GetUserData(userID); - if (userResponse != null) - { -// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting sessions for " + userID); - - NameValueCollection requestArgs = new NameValueCollection + NameValueCollection requestArgs = new NameValueCollection { - { "RequestMethod", "GetSession" }, - { "UserID", userID.ToString() } + { "RequestMethod", "GetSession" }, + { "SessionID", sessionID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); - if (response["Success"].AsBoolean()) - { - PresenceInfo presence = ResponseToPresenceInfo(response, userResponse); - if (presence != null) - presences.Add(presence); - } -// else -// { -// m_log.Debug("[SIMIAN PRESENCE CONNECTOR]: No session returned for " + userID + ": " + response["Message"].AsString()); -// } - } + OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + if (response["Success"].AsBoolean()) + return response; - return presences; + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString()); + return null; } private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { // Save our current location as session data NameValueCollection requestArgs = new NameValueCollection - { - { "RequestMethod", "UpdateSession" }, - { "SessionID", sessionID.ToString() }, - { "SceneID", regionID.ToString() }, - { "ScenePosition", lastPosition.ToString() }, - { "SceneLookAt", lastLookAt.ToString() } - }; + { + { "RequestMethod", "UpdateSession" }, + { "SessionID", sessionID.ToString() }, + { "SceneID", regionID.ToString() }, + { "ScenePosition", lastPosition.ToString() }, + { "SceneLookAt", lastLookAt.ToString() } + }; OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); @@ -407,7 +380,7 @@ namespace OpenSim.Services.Connectors.SimianGrid return success; } - private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) + private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse) { if (sessionResponse == null) return null; -- cgit v1.1 From fe16dc09da3f2736fad5a9e792f5f81098b5f9a1 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 7 Apr 2013 08:27:49 -0700 Subject: BulletSim: complete movement of physical object action code out of the physical object and into actors for setForce, setTorque, hover, lock axis and avatar move. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 287 +++++++++++++++++++ .../Region/Physics/BulletSPlugin/BSActorHover.cs | 176 ++++++++++++ .../Physics/BulletSPlugin/BSActorLockAxis.cs | 4 +- .../Physics/BulletSPlugin/BSActorMoveToTarget.cs | 156 +++++++++++ .../Physics/BulletSPlugin/BSActorSetForce.cs | 137 +++++++++ .../Physics/BulletSPlugin/BSActorSetTorque.cs | 138 +++++++++ OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 12 +- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 268 +++--------------- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 226 ++++++--------- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 307 ++++----------------- .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 3 +- 11 files changed, 1078 insertions(+), 636 deletions(-) create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs new file mode 100755 index 0000000..634a898 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -0,0 +1,287 @@ +/* + * 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 copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.Physics.Manager; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public class BSActorAvatarMove : BSActor +{ + BSVMotor m_velocityMotor; + + public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_velocityMotor = null; + m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawForce == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh,notAvatarMove,removing={1}", m_controllingPrim.LocalID, ActorName); + m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateAvatarMove(); + } + else + { + DeactivateAvatarMove(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveBodyDependencies() + public override void RemoveBodyDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) + { + m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() + { + m_velocityMotor.Reset(); + m_velocityMotor.SetTarget(targ); + m_velocityMotor.SetCurrent(vel); + m_velocityMotor.Enabled = true; + }); + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateAvatarMove() + { + if (m_velocityMotor == null) + { + // Infinite decay and timescale values so motor only changes current to target values. + m_velocityMotor = new BSVMotor("BSCharacter.Velocity", + 0.2f, // time scale + BSMotor.Infinite, // decay time scale + BSMotor.InfiniteVector, // friction timescale + 1f // efficiency + ); + // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateAvatarMove() + { + if (m_velocityMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_velocityMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do movement while the object is selected. + if (!isActive) + return; + + // TODO: Decide if the step parameters should be changed depending on the avatar's + // state (flying, colliding, ...). There is code in ODE to do this. + + // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity + // specified for the avatar is the one that should be used. For falling, if the avatar + // is not flying and is not colliding then it is presumed to be falling and the Z + // component is not fooled with (thus allowing gravity to do its thing). + // When the avatar is standing, though, the user has specified a velocity of zero and + // the avatar should be standing. But if the avatar is pushed by something in the world + // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to + // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity + // errors can creap in and the avatar will slowly float off in some direction. + // So, the problem is that, when an avatar is standing, we cannot tell creaping error + // from real pushing. + // The code below uses whether the collider is static or moving to decide whether to zero motion. + + m_velocityMotor.Step(timeStep); + m_controllingPrim.IsStationary = false; + + // If we're not supposed to be moving, make sure things are zero. + if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) + { + // The avatar shouldn't be moving + m_velocityMotor.Zero(); + + if (m_controllingPrim.IsColliding) + { + // If we are colliding with a stationary object, presume we're standing and don't move around + if (!m_controllingPrim.ColliderIsMoving) + { + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); + m_controllingPrim.IsStationary = true; + m_controllingPrim.ZeroMotion(true /* inTaintTime */); + } + + // Standing has more friction on the ground + if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) + { + m_controllingPrim.Friction = BSParam.AvatarStandingFriction; + m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); + } + } + else + { + if (m_controllingPrim.Flying) + { + // Flying and not collising and velocity nearly zero. + m_controllingPrim.ZeroMotion(true /* inTaintTime */); + } + } + + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", + m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); + } + else + { + // Supposed to be moving. + OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; + + if (m_controllingPrim.Friction != BSParam.AvatarFriction) + { + // Probably starting up walking. Set friction to moving friction. + m_controllingPrim.Friction = BSParam.AvatarFriction; + m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); + } + + // If falling, we keep the world's downward vector no matter what the other axis specify. + // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). + if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) + { + if (m_controllingPrim.RawVelocity.Z < 0) + stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); + } + + // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. + OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; + + // Should we check for move force being small and forcing velocity to zero? + + // Add special movement force to allow avatars to walk up stepped surfaces. + moveForce += WalkUpStairs(); + + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", + m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); + } + } + + // Decide if the character is colliding with a low object and compute a force to pop the + // avatar up so it can walk up and over the low objects. + private OMV.Vector3 WalkUpStairs() + { + OMV.Vector3 ret = OMV.Vector3.Zero; + + // This test is done if moving forward, not flying and is colliding with something. + // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", + // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); + if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) + { + // The range near the character's feet where we will consider stairs + float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; + float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; + + // Look for a collision point that is near the character's feet and is oriented the same as the charactor is + foreach (KeyValuePair kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) + { + // Don't care about collisions with the terrain + if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) + { + OMV.Vector3 touchPosition = kvp.Value.Position; + // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", + // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); + if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) + { + // This contact is within the 'near the feet' range. + // The normal should be our contact point to the object so it is pointing away + // thus the difference between our facing orientation and the normal should be small. + OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; + OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); + float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); + if (diff < BSParam.AvatarStepApproachFactor) + { + // Found the stairs contact point. Push up a little to raise the character. + float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; + ret = new OMV.Vector3(0f, 0f, upForce); + + // Also move the avatar up for the new height + OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", + m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); + } + } + } + } + + return ret; + } + +} +} + + diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs new file mode 100755 index 0000000..8dd3700 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs @@ -0,0 +1,176 @@ +/* + * 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 copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.Physics.Manager; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public class BSActorHover : BSActor +{ + private BSFMotor m_hoverMotor; + + public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_hoverMotor = null; + m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (!m_controllingPrim.HoverActive) + { + m_physicsScene.DetailLog("{0},BSActorHover,refresh,notHovering,removing={1}", m_controllingPrim.LocalID, ActorName); + m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateHover(); + } + else + { + DeactivateHover(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveBodyDependencies() + public override void RemoveBodyDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateHover() + { + if (m_hoverMotor == null) + { + // Turning the target on + m_hoverMotor = new BSFMotor("BSActorHover", + m_controllingPrim.HoverTau, // timeScale + BSMotor.Infinite, // decay time scale + BSMotor.Infinite, // friction timescale + 1f // efficiency + ); + m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); + m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. + + m_physicsScene.BeforeStep += Hoverer; + } + } + + private void DeactivateHover() + { + if (m_hoverMotor != null) + { + m_physicsScene.BeforeStep -= Hoverer; + m_hoverMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Hoverer(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + + m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); + m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + float targetHeight = m_hoverMotor.Step(timeStep); + + // 'targetHeight' is where we'd like the Z of the prim to be at this moment. + // Compute the amount of force to push us there. + float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; + // Undo anything the object thinks it's doing at the moment + moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; + + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); + m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", + m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); + } + + // Based on current position, determine what we should be hovering at now. + // Must recompute often. What if we walked offa cliff> + private float ComputeCurrentHoverHeight() + { + float ret = m_controllingPrim.HoverHeight; + float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); + + switch (m_controllingPrim.HoverType) + { + case PIDHoverType.Ground: + ret = groundHeight + m_controllingPrim.HoverHeight; + break; + case PIDHoverType.GroundAndWater: + float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); + if (groundHeight > waterHeight) + { + ret = groundHeight + m_controllingPrim.HoverHeight; + } + else + { + ret = waterHeight + m_controllingPrim.HoverHeight; + } + break; + } + return ret; + } +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index 7219617..c40a499 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs @@ -40,7 +40,7 @@ public class BSActorLockAxis : BSActor BSConstraint LockAxisConstraint = null; public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj,actorName) + : base(physicsScene, pObj, actorName) { m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); LockAxisConstraint = null; @@ -99,7 +99,7 @@ public class BSActorLockAxis : BSActor // If a constraint is set up, remove it from the physical scene RemoveAxisLockConstraint(); // Schedule a call before the next simulation step to restore the constraint. - m_physicsScene.PostTaintObject(m_controllingPrim.LockedAxisActorName, m_controllingPrim.LocalID, delegate() + m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate() { Refresh(); }); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs new file mode 100755 index 0000000..3517ef2 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs @@ -0,0 +1,156 @@ +/* + * 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 copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.Physics.Manager; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public class BSActorMoveToTarget : BSActor +{ + private BSVMotor m_targetMotor; + + public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_targetMotor = null; + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh", m_controllingPrim.LocalID); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (!m_controllingPrim.HoverActive) + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,notMoveToTarget,removing={1}", m_controllingPrim.LocalID, ActorName); + m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateMoveToTarget(); + } + else + { + DeactivateMoveToTarget(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveBodyDependencies() + public override void RemoveBodyDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateMoveToTarget() + { + if (m_targetMotor == null) + { + // We're taking over after this. + m_controllingPrim.ZeroMotion(true); + + m_targetMotor = new BSVMotor("BSPrim.PIDTarget", + m_controllingPrim.MoveToTargetTau, // timeScale + BSMotor.Infinite, // decay time scale + BSMotor.InfiniteVector, // friction timescale + 1f // efficiency + ); + m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. + m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); + m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateMoveToTarget() + { + if (m_targetMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_targetMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + + OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) + + // 'movePosition' is where we'd like the prim to be at this moment. + OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); + + // If we are very close to our target, turn off the movement motor. + if (m_targetMotor.ErrorIsZero()) + { + m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", + m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); + m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_targetMotor.Enabled = false; + } + else + { + m_controllingPrim.ForcePosition = movePosition; + } + m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); + } +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs new file mode 100755 index 0000000..d942490 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs @@ -0,0 +1,137 @@ +/* + * 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 copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.Physics.Manager; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public class BSActorSetForce : BSActor +{ + BSFMotor m_forceMotor; + + public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_forceMotor = null; + m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawForce == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); + m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateSetForce(); + } + else + { + DeactivateSetForce(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveBodyDependencies() + public override void RemoveBodyDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateSetForce() + { + if (m_forceMotor == null) + { + // A fake motor that might be used someday + m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f, 1f); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateSetForce() + { + if (m_forceMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_forceMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do force while the object is selected. + if (!isActive) + return; + + m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); + if (m_controllingPrim.PhysBody.HasPhysicalBody) + { + m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); + m_controllingPrim.ActivateIfPhysical(false); + } + + // TODO: + } +} +} + diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs new file mode 100755 index 0000000..e0f719f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs @@ -0,0 +1,138 @@ +/* + * 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 copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenSim.Region.Physics.Manager; + +using OMV = OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public class BSActorSetTorque : BSActor +{ + BSFMotor m_torqueMotor; + + public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_torqueMotor = null; + m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + Enabled = false; + } + + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh", m_controllingPrim.LocalID); + + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,removing={1}", m_controllingPrim.LocalID, ActorName); + m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + return; + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateSetTorque(); + } + else + { + DeactivateSetTorque(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveBodyDependencies() + public override void RemoveBodyDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateSetTorque() + { + if (m_torqueMotor == null) + { + // A fake motor that might be used someday + m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f, 1f); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateSetTorque() + { + if (m_torqueMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_torqueMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do force while the object is selected. + if (!isActive) + return; + + m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); + if (m_controllingPrim.PhysBody.HasPhysicalBody) + { + m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true); + m_controllingPrim.ActivateIfPhysical(false); + } + + // TODO: + } +} +} + + diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index 5a19ba4..fb4d452 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -32,12 +32,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public class BSActorCollection { - private BSScene PhysicsScene { get; set; } + private BSScene m_physicsScene { get; set; } private Dictionary m_actors; public BSActorCollection(BSScene physicsScene) { - PhysicsScene = physicsScene; + m_physicsScene = physicsScene; m_actors = new Dictionary(); } public void Add(string name, BSActor actor) @@ -61,6 +61,10 @@ public class BSActorCollection Release(); m_actors.Clear(); } + public void Dispose() + { + Clear(); + } public bool HasActor(string name) { return m_actors.ContainsKey(name); @@ -71,6 +75,10 @@ public class BSActorCollection act(kvp.Value); } + public void Enable(bool enabl) + { + ForEachActor(a => a.Enable(enabl)); + } public void Release() { ForEachActor(a => a.Dispose()); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 25be416..09c9b16 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject private OMV.Vector3 _position; private float _mass; private float _avatarVolume; - private OMV.Vector3 _force; - private OMV.Vector3 _velocity; - private OMV.Vector3 _torque; private float _collisionScore; private OMV.Vector3 _acceleration; private OMV.Quaternion _orientation; @@ -61,17 +58,13 @@ public sealed class BSCharacter : BSPhysObject private OMV.Vector3 _rotationalVelocity; private bool _kinematic; private float _buoyancy; - private bool _isStationaryStanding; // true is standing on a stationary object - private BSVMotor _velocityMotor; + private BSActorAvatarMove m_moveActor; + private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; private OMV.Vector3 _PIDTarget; private bool _usePID; private float _PIDTau; - private bool _useHoverPID; - private float _PIDHoverHeight; - private PIDHoverType _PIDHoverType; - private float _PIDHoverTao; public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) : base(parent_scene, localID, avName, "BSCharacter") @@ -81,11 +74,10 @@ public sealed class BSCharacter : BSPhysObject _flying = isFlying; _orientation = OMV.Quaternion.Identity; - _velocity = OMV.Vector3.Zero; + RawVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); Friction = BSParam.AvatarStandingFriction; Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; - _isStationaryStanding = false; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. @@ -99,7 +91,12 @@ public sealed class BSCharacter : BSPhysObject // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); - SetupMovementMotor(); + // The avatar's movement is controlled by this motor that speeds up and slows down + // the avatar seeking to reach the motor's target speed. + // This motor runs as a prestep action for the avatar so it will keep the avatar + // standing as well as moving. Destruction of the avatar will destroy the pre-step action. + m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName); + PhysicalActors.Add(AvatarMoveActorName, m_moveActor); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, Density, _avatarVolume, RawMass); @@ -139,10 +136,10 @@ public sealed class BSCharacter : BSPhysObject ForcePosition = _position; // Set the velocity - _velocityMotor.Reset(); - _velocityMotor.SetTarget(_velocity); - _velocityMotor.SetCurrent(_velocity); - ForceVelocity = _velocity; + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); + + ForceVelocity = RawVelocity; // This will enable or disable the flying buoyancy of the avatar. // Needs to be reset especially when an avatar is recreated after crossing a region boundry. @@ -176,162 +173,6 @@ public sealed class BSCharacter : BSPhysObject PhysBody.ApplyCollisionMask(PhysicsScene); } - // The avatar's movement is controlled by this motor that speeds up and slows down - // the avatar seeking to reach the motor's target speed. - // This motor runs as a prestep action for the avatar so it will keep the avatar - // standing as well as moving. Destruction of the avatar will destroy the pre-step action. - private void SetupMovementMotor() - { - // Infinite decay and timescale values so motor only changes current to target values. - _velocityMotor = new BSVMotor("BSCharacter.Velocity", - 0.2f, // time scale - BSMotor.Infinite, // decay time scale - BSMotor.InfiniteVector, // friction timescale - 1f // efficiency - ); - // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. - - RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) - { - // TODO: Decide if the step parameters should be changed depending on the avatar's - // state (flying, colliding, ...). There is code in ODE to do this. - - // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity - // specified for the avatar is the one that should be used. For falling, if the avatar - // is not flying and is not colliding then it is presumed to be falling and the Z - // component is not fooled with (thus allowing gravity to do its thing). - // When the avatar is standing, though, the user has specified a velocity of zero and - // the avatar should be standing. But if the avatar is pushed by something in the world - // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to - // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity - // errors can creap in and the avatar will slowly float off in some direction. - // So, the problem is that, when an avatar is standing, we cannot tell creaping error - // from real pushing. - // The code below uses whether the collider is static or moving to decide whether to zero motion. - - _velocityMotor.Step(timeStep); - _isStationaryStanding = false; - - // If we're not supposed to be moving, make sure things are zero. - if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero) - { - // The avatar shouldn't be moving - _velocityMotor.Zero(); - - if (IsColliding) - { - // If we are colliding with a stationary object, presume we're standing and don't move around - if (!ColliderIsMoving) - { - DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID); - _isStationaryStanding = true; - ZeroMotion(true /* inTaintTime */); - } - - // Standing has more friction on the ground - if (Friction != BSParam.AvatarStandingFriction) - { - Friction = BSParam.AvatarStandingFriction; - PhysicsScene.PE.SetFriction(PhysBody, Friction); - } - } - else - { - if (Flying) - { - // Flying and not collising and velocity nearly zero. - ZeroMotion(true /* inTaintTime */); - } - } - - DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); - } - else - { - // Supposed to be moving. - OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; - - if (Friction != BSParam.AvatarFriction) - { - // Probably starting up walking. Set friction to moving friction. - Friction = BSParam.AvatarFriction; - PhysicsScene.PE.SetFriction(PhysBody, Friction); - } - - // If falling, we keep the world's downward vector no matter what the other axis specify. - // The check for _velocity.Z < 0 makes jumping work (temporary upward force). - if (!Flying && !IsColliding) - { - if (_velocity.Z < 0) - stepVelocity.Z = _velocity.Z; - // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); - } - - // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. - OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; - - // Should we check for move force being small and forcing velocity to zero? - - // Add special movement force to allow avatars to walk up stepped surfaces. - moveForce += WalkUpStairs(); - - DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); - PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); - } - }); - } - - // Decide if the character is colliding with a low object and compute a force to pop the - // avatar up so it can walk up and over the low objects. - private OMV.Vector3 WalkUpStairs() - { - OMV.Vector3 ret = OMV.Vector3.Zero; - - // This test is done if moving forward, not flying and is colliding with something. - // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", - // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); - if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) - { - // The range near the character's feet where we will consider stairs - float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; - float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; - - // Look for a collision point that is near the character's feet and is oriented the same as the charactor is - foreach (KeyValuePair kvp in CollisionsLastTick.m_objCollisionList) - { - // Don't care about collisions with the terrain - if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID) - { - OMV.Vector3 touchPosition = kvp.Value.Position; - // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", - // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); - if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) - { - // This contact is within the 'near the feet' range. - // The normal should be our contact point to the object so it is pointing away - // thus the difference between our facing orientation and the normal should be small. - OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation; - OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); - float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); - if (diff < BSParam.AvatarStepApproachFactor) - { - // Found the stairs contact point. Push up a little to raise the character. - float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor; - ret = new OMV.Vector3(0f, 0f, upForce); - - // Also move the avatar up for the new height - OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); - ForcePosition = RawPosition + displacement; - } - DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", - LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); - } - } - } - } - - return ret; - } public override void RequestPhysicsterseUpdate() { @@ -403,7 +244,7 @@ public sealed class BSCharacter : BSPhysObject // Called at taint time! public override void ZeroMotion(bool inTaintTime) { - _velocity = OMV.Vector3.Zero; + RawVelocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; @@ -542,15 +383,15 @@ public sealed class BSCharacter : BSPhysObject } public override OMV.Vector3 Force { - get { return _force; } + get { return RawForce; } set { - _force = value; + RawForce = value; // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() { - DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); + DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetObjectForce(PhysBody, _force); + PhysicsScene.PE.SetObjectForce(PhysBody, RawForce); }); } } @@ -573,7 +414,7 @@ public sealed class BSCharacter : BSPhysObject { get { - return m_targetVelocity; + return base.m_targetVelocity; } set { @@ -583,51 +424,39 @@ public sealed class BSCharacter : BSPhysObject if (_setAlwaysRun) targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); - PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() - { - _velocityMotor.Reset(); - _velocityMotor.SetTarget(targetVel); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.Enabled = true; - }); + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); } } - public override OMV.Vector3 RawVelocity - { - get { return _velocity; } - set { _velocity = value; } - } // Directly setting velocity means this is what the user really wants now. public override OMV.Vector3 Velocity { - get { return _velocity; } + get { return RawVelocity; } set { - _velocity = value; - // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); + RawVelocity = value; + // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() { - _velocityMotor.Reset(); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.SetTarget(_velocity); - _velocityMotor.Enabled = false; + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); - DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); - ForceVelocity = _velocity; + DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity); + ForceVelocity = RawVelocity; }); } } public override OMV.Vector3 ForceVelocity { - get { return _velocity; } + get { return RawVelocity; } set { PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); - _velocity = value; - PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); + RawVelocity = value; + PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); PhysicsScene.PE.Activate(PhysBody, true); } } public override OMV.Vector3 Torque { - get { return _torque; } - set { _torque = value; + get { return RawTorque; } + set { RawTorque = value; } } public override float CollisionScore { @@ -783,27 +612,6 @@ public sealed class BSCharacter : BSPhysObject set { _PIDTau = value; } } - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public override bool PIDHoverActive { - set { _useHoverPID = value; } - } - public override float PIDHoverHeight { - set { _PIDHoverHeight = value; } - } - public override PIDHoverType PIDHoverType { - set { _PIDHoverType = value; } - } - public override float PIDHoverTau { - set { _PIDHoverTao = value; } - } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - public override void AddForce(OMV.Vector3 force, bool pushforce) { // Since this force is being applied in only one step, make this a force per second. @@ -833,7 +641,7 @@ public sealed class BSCharacter : BSPhysObject } } - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { + public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { } public override void SetMomentum(OMV.Vector3 momentum) { } @@ -887,7 +695,7 @@ public sealed class BSCharacter : BSPhysObject public override void UpdateProperties(EntityProperties entprop) { // Don't change position if standing on a stationary object. - if (!_isStationaryStanding) + if (!IsStationary) _position = entprop.Position; _orientation = entprop.Rotation; @@ -896,8 +704,8 @@ public sealed class BSCharacter : BSPhysObject // and will send agent updates to the clients if velocity changes by more than // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many // extra updates. - if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) - _velocity = entprop.Velocity; + if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) + RawVelocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; @@ -920,7 +728,7 @@ public sealed class BSCharacter : BSPhysObject // base.RequestPhysicsterseUpdate(); DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); + LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 98ea833..644bc7e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -43,7 +43,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin * VariableName: used by the simulator and performs taint operations, etc * RawVariableName: direct reference to the BulletSim storage for the variable value * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. - * The last two (and certainly the last one) should be referenced only in taint-time. + * The last one should only be referenced in taint-time. */ /* @@ -84,6 +84,7 @@ public abstract class BSPhysObject : PhysicsActor // Initialize variables kept in base. GravModifier = 1.0f; Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); + HoverActive = false; // We don't have any physical representation yet. PhysBody = new BulletBody(localID); @@ -110,11 +111,10 @@ public abstract class BSPhysObject : PhysicsActor // Tell the object to clean up. public virtual void Destroy() { - UnRegisterAllPreStepActions(); - UnRegisterAllPostStepActions(); + PhysicalActors.Enable(false); PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() { - PhysicalActors.Release(); + PhysicalActors.Dispose(); }); } @@ -203,15 +203,48 @@ public abstract class BSPhysObject : PhysicsActor public abstract OMV.Quaternion RawOrientation { get; set; } public abstract OMV.Quaternion ForceOrientation { get; set; } - public abstract OMV.Vector3 RawVelocity { get; set; } + public OMV.Vector3 RawVelocity { get; set; } public abstract OMV.Vector3 ForceVelocity { get; set; } + public OMV.Vector3 RawForce { get; set; } + public OMV.Vector3 RawTorque { get; set; } + public override void AddAngularForce(OMV.Vector3 force, bool pushforce) + { + AddAngularForce(force, pushforce, false); + } + public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); + public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } public abstract float ForceBuoyancy { get; set; } public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } + public override bool PIDActive { set { MoveToTargetActive = value; } } + public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } + public override float PIDTau { set { MoveToTargetTau = value; } } + + public bool MoveToTargetActive { get; set; } + public OMV.Vector3 MoveToTargetTarget { get; set; } + public float MoveToTargetTau { get; set; } + + // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z + public override bool PIDHoverActive { set { HoverActive = value; } } + public override float PIDHoverHeight { set { HoverHeight = value; } } + public override PIDHoverType PIDHoverType { set { HoverType = value; } } + public override float PIDHoverTau { set { HoverTau = value; } } + + public bool HoverActive { get; set; } + public float HoverHeight { get; set; } + public PIDHoverType HoverType { get; set; } + public float HoverTau { get; set; } + + // For RotLookAt + public override OMV.Quaternion APIDTarget { set { return; } } + public override bool APIDActive { set { return; } } + public override float APIDStrength { set { return; } } + public override float APIDDamping { set { return; } } + // The current velocity forward public virtual float ForwardSpeed { @@ -237,7 +270,44 @@ public abstract class BSPhysObject : PhysicsActor public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free - public readonly String LockedAxisActorName = "BSPrim.LockedAxis"; + + // Enable physical actions. Bullet will keep sleeping non-moving physical objects so + // they need waking up when parameters are changed. + // Called in taint-time!! + public void ActivateIfPhysical(bool forceIt) + { + if (IsPhysical && PhysBody.HasPhysicalBody) + PhysicsScene.PE.Activate(PhysBody, forceIt); + } + + // 'actors' act on the physical object to change or constrain its motion. These can range from + // hovering to complex vehicle motion. + public delegate BSActor CreateActor(); + public void CreateRemoveActor(bool createRemove, string actorName, bool inTaintTime, CreateActor creator) + { + if (createRemove) + { + PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CreateRemoveActor:" + actorName, delegate() + { + if (!PhysicalActors.HasActor(actorName)) + { + DetailLog("{0},BSPrim.CreateRemoveActor,taint,registerActor,a={1}", LocalID, actorName); + PhysicalActors.Add(actorName, creator()); + } + }); + } + else + { + PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CreateRemoveActor:" + actorName, delegate() + { + if (PhysicalActors.HasActor(actorName)) + { + DetailLog("{0},BSPrim.CreateRemoveActor,taint,unregisterActor,a={1}", LocalID, actorName); + PhysicalActors.RemoveAndRelease(actorName); + } + }); + } + } #region Collisions @@ -255,7 +325,9 @@ public abstract class BSPhysObject : PhysicsActor protected CollisionFlags CurrentCollisionFlags { get; set; } // On a collision, check the collider and remember if the last collider was moving // Used to modify the standing of avatars (avatars on stationary things stand still) - protected bool ColliderIsMoving; + public bool ColliderIsMoving; + // Used by BSCharacter to manage standing (and not slipping) + public bool IsStationary; // Count of collisions for this object protected long CollisionAccumulation { get; set; } @@ -293,7 +365,7 @@ public abstract class BSPhysObject : PhysicsActor protected CollisionEventUpdate CollisionCollection; // Remember collisions from last tick for fancy collision based actions // (like a BSCharacter walking up stairs). - protected CollisionEventUpdate CollisionsLastTick; + public CollisionEventUpdate CollisionsLastTick; // The simulation step is telling this object about a collision. // Return 'true' if a collision was processed and should be sent up. @@ -424,104 +496,6 @@ public abstract class BSPhysObject : PhysicsActor public BSActorCollection PhysicalActors; - // There are some actions that must be performed for a physical object before each simulation step. - // These actions are optional so, rather than scanning all the physical objects and asking them - // if they have anything to do, a physical object registers for an event call before the step is performed. - // This bookkeeping makes it easy to add, remove and clean up after all these registrations. - private Dictionary RegisteredPrestepActions = new Dictionary(); - private Dictionary RegisteredPoststepActions = new Dictionary(); - protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) - { - string identifier = op + "-" + id.ToString(); - - lock (RegisteredPrestepActions) - { - // Clean out any existing action - UnRegisterPreStepAction(op, id); - RegisteredPrestepActions[identifier] = actn; - PhysicsScene.BeforeStep += actn; - } - DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); - } - - // Unregister a pre step action. Safe to call if the action has not been registered. - // Returns 'true' if an action was actually removed - protected bool UnRegisterPreStepAction(string op, uint id) - { - string identifier = op + "-" + id.ToString(); - bool removed = false; - lock (RegisteredPrestepActions) - { - if (RegisteredPrestepActions.ContainsKey(identifier)) - { - PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier]; - RegisteredPrestepActions.Remove(identifier); - removed = true; - } - } - DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); - return removed; - } - - protected void UnRegisterAllPreStepActions() - { - lock (RegisteredPrestepActions) - { - foreach (KeyValuePair kvp in RegisteredPrestepActions) - { - PhysicsScene.BeforeStep -= kvp.Value; - } - RegisteredPrestepActions.Clear(); - } - DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); - } - - protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn) - { - string identifier = op + "-" + id.ToString(); - - lock (RegisteredPoststepActions) - { - // Clean out any existing action - UnRegisterPostStepAction(op, id); - RegisteredPoststepActions[identifier] = actn; - PhysicsScene.AfterStep += actn; - } - DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); - } - - // Unregister a pre step action. Safe to call if the action has not been registered. - // Returns 'true' if an action was actually removed. - protected bool UnRegisterPostStepAction(string op, uint id) - { - string identifier = op + "-" + id.ToString(); - bool removed = false; - lock (RegisteredPoststepActions) - { - if (RegisteredPoststepActions.ContainsKey(identifier)) - { - PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier]; - RegisteredPoststepActions.Remove(identifier); - removed = true; - } - } - DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed); - return removed; - } - - protected void UnRegisterAllPostStepActions() - { - lock (RegisteredPoststepActions) - { - foreach (KeyValuePair kvp in RegisteredPoststepActions) - { - PhysicsScene.AfterStep -= kvp.Value; - } - RegisteredPoststepActions.Clear(); - } - DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); - } - // When an update to the physical properties happens, this event is fired to let // different actors to modify the update before it is passed around public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); @@ -533,46 +507,6 @@ public abstract class BSPhysObject : PhysicsActor actions(ref entprop); } - private Dictionary RegisteredPreUpdatePropertyActions = new Dictionary(); - public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn) - { - lock (RegisteredPreUpdatePropertyActions) - { - // Clean out any existing action - UnRegisterPreUpdatePropertyAction(identifier); - RegisteredPreUpdatePropertyActions[identifier] = actn; - OnPreUpdateProperty += actn; - } - DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier); - } - public bool UnRegisterPreUpdatePropertyAction(string identifier) - { - bool removed = false; - lock (RegisteredPreUpdatePropertyActions) - { - if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier)) - { - OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier]; - RegisteredPreUpdatePropertyActions.Remove(identifier); - removed = true; - } - } - DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed); - return removed; - } - public void UnRegisterAllPreUpdatePropertyActions() - { - lock (RegisteredPreUpdatePropertyActions) - { - foreach (KeyValuePair kvp in RegisteredPreUpdatePropertyActions) - { - OnPreUpdateProperty -= kvp.Value; - } - RegisteredPreUpdatePropertyActions.Clear(); - } - DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID); - } - #endregion // Per Simulation Step actions // High performance detailed logging routine used by the physical objects. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e56276a..71fea59 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject private OMV.Vector3 _position; private float _mass; // the mass of this object - private OMV.Vector3 _force; - private OMV.Vector3 _velocity; - private OMV.Vector3 _torque; private OMV.Vector3 _acceleration; private OMV.Quaternion _orientation; private int _physicsActorType; @@ -73,16 +70,13 @@ public class BSPrim : BSPhysObject private int CrossingFailures { get; set; } public BSDynamics VehicleActor; - public string VehicleActorName = "BasicVehicle"; + public const string VehicleActorName = "BasicVehicle"; - private BSVMotor _targetMotor; - private OMV.Vector3 _PIDTarget; - private float _PIDTau; - - private BSFMotor _hoverMotor; - private float _PIDHoverHeight; - private PIDHoverType _PIDHoverType; - private float _PIDHoverTau; + public const string HoverActorName = "HoverActor"; + public const String LockedAxisActorName = "BSPrim.LockedAxis"; + public const string MoveToTargetActorName = "MoveToTargetActor"; + public const string SetForceActorName = "SetForceActor"; + public const string SetTorqueActorName = "SetTorqueActor"; public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) @@ -95,7 +89,7 @@ public class BSPrim : BSPhysObject Scale = size; // prims are the size the user wants them to be (different for BSCharactes). _orientation = rotation; _buoyancy = 0f; - _velocity = OMV.Vector3.Zero; + RawVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; BaseShape = pbs; _isPhysical = pisPhysical; @@ -233,7 +227,7 @@ public class BSPrim : BSPhysObject // Called at taint time! public override void ZeroMotion(bool inTaintTime) { - _velocity = OMV.Vector3.Zero; + RawVelocity = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; @@ -270,19 +264,17 @@ public class BSPrim : BSPhysObject if (axis.Z != 1) locking.Z = 0f; LockedAxis = locking; - if (LockedAxis != LockedAxisFree) + CreateRemoveActor(LockedAxis != LockedAxisFree /* creatActor */, LockedAxisActorName, false /* inTaintTime */, delegate() { - PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() - { - // If there is not already an axis locker, make one - if (!PhysicalActors.HasActor(LockedAxisActorName)) - { - DetailLog("{0},BSPrim.LockAngularMotion,taint,registeringLockAxisActor", LocalID); - PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName)); - } - UpdatePhysicalParameters(); - }); - } + return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName); + }); + + // Update parameters so the new actor's Refresh() action is called at the right time. + PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() + { + UpdatePhysicalParameters(); + }); + return; } @@ -407,9 +399,9 @@ public class BSPrim : BSPhysObject ZeroMotion(inTaintTime); ret = true; } - if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) + if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity) { - _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); + RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); ret = true; } if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) @@ -506,35 +498,13 @@ public class BSPrim : BSPhysObject } public override OMV.Vector3 Force { - get { return _force; } + get { return RawForce; } set { - _force = value; - if (_force != OMV.Vector3.Zero) - { - // If the force is non-zero, it must be reapplied each tick because - // Bullet clears the forces applied last frame. - RegisterPreStepAction("BSPrim.setForce", LocalID, - delegate(float timeStep) - { - if (!IsPhysicallyActive || _force == OMV.Vector3.Zero) - { - UnRegisterPreStepAction("BSPrim.setForce", LocalID); - return; - } - - DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - { - PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); - ActivateIfPhysical(false); - } - } - ); - } - else + RawForce = value; + CreateRemoveActor(RawForce == OMV.Vector3.Zero, SetForceActorName, false /* inTaintTime */, delegate() { - UnRegisterPreStepAction("BSPrim.setForce", LocalID); - } + return new BSActorSetForce(PhysicsScene, this, SetForceActorName); + }); } } @@ -670,62 +640,39 @@ public class BSPrim : BSPhysObject } } } - public override OMV.Vector3 RawVelocity - { - get { return _velocity; } - set { _velocity = value; } - } public override OMV.Vector3 Velocity { - get { return _velocity; } + get { return RawVelocity; } set { - _velocity = value; + RawVelocity = value; PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() { - // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); - ForceVelocity = _velocity; + // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); + ForceVelocity = RawVelocity; }); } } public override OMV.Vector3 ForceVelocity { - get { return _velocity; } + get { return RawVelocity; } set { PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); - _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); + RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); if (PhysBody.HasPhysicalBody) { - DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); - PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); + DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); + PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); ActivateIfPhysical(false); } } } public override OMV.Vector3 Torque { - get { return _torque; } + get { return RawTorque; } set { - _torque = value; - if (_torque != OMV.Vector3.Zero) + RawTorque = value; + CreateRemoveActor(RawTorque == OMV.Vector3.Zero, SetTorqueActorName, false /* inTaintTime */, delegate() { - // If the torque is non-zero, it must be reapplied each tick because - // Bullet clears the forces applied last frame. - RegisterPreStepAction("BSPrim.setTorque", LocalID, - delegate(float timeStep) - { - if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero) - { - UnRegisterPreStepAction("BSPrim.setTorque", LocalID); - return; - } - - if (PhysBody.HasPhysicalBody) - AddAngularForce(_torque, false, true); - } - ); - } - else - { - UnRegisterPreStepAction("BSPrim.setTorque", LocalID); - } + return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName); + }); // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); } } @@ -909,7 +856,7 @@ public class BSPrim : BSPhysObject // For good measure, make sure the transform is set through to the motion state ForcePosition = _position; - ForceVelocity = _velocity; + ForceVelocity = RawVelocity; ForceRotationalVelocity = _rotationalVelocity; // A dynamic object has mass @@ -966,15 +913,6 @@ public class BSPrim : BSPhysObject } } - // Enable physical actions. Bullet will keep sleeping non-moving physical objects so - // they need waking up when parameters are changed. - // Called in taint-time!! - private void ActivateIfPhysical(bool forceIt) - { - if (IsPhysical && PhysBody.HasPhysicalBody) - PhysicsScene.PE.Activate(PhysBody, forceIt); - } - // Turn on or off the flag controlling whether collision events are returned to the simulator. private void EnableCollisions(bool wantsCollisionEvents) { @@ -1096,78 +1034,13 @@ public class BSPrim : BSPhysObject } } - // Used for MoveTo - public override OMV.Vector3 PIDTarget { - set - { - // TODO: add a sanity check -- don't move more than a region or something like that. - _PIDTarget = value; - } - } - public override float PIDTau { - set { _PIDTau = value; } - } public override bool PIDActive { set { - if (value) - { - // We're taking over after this. - ZeroMotion(true); - - _targetMotor = new BSVMotor("BSPrim.PIDTarget", - _PIDTau, // timeScale - BSMotor.Infinite, // decay time scale - BSMotor.InfiniteVector, // friction timescale - 1f // efficiency - ); - _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. - _targetMotor.SetTarget(_PIDTarget); - _targetMotor.SetCurrent(RawPosition); - /* - _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget"); - _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. - - _targetMotor.SetTarget(_PIDTarget); - _targetMotor.SetCurrent(RawPosition); - _targetMotor.TimeScale = _PIDTau; - _targetMotor.Efficiency = 1f; - */ - - RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep) - { - if (!IsPhysicallyActive) - { - UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); - return; - } - - OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) - - // 'movePosition' is where we'd like the prim to be at this moment. - OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep); - - // If we are very close to our target, turn off the movement motor. - if (_targetMotor.ErrorIsZero()) - { - DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", - LocalID, movePosition, RawPosition, Mass); - ForcePosition = _targetMotor.TargetValue; - _targetMotor.Enabled = false; - } - else - { - _position = movePosition; - PositionSanityCheck(true /* intaintTime */); - ForcePosition = _position; - } - DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition); - }); - } - else + base.MoveToTargetActive = value; + CreateRemoveActor(MoveToTargetActive, MoveToTargetActorName, false /* inTaintTime */, delegate() { - // Stop any targetting - UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); - } + return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName); + }); } } @@ -1175,88 +1048,14 @@ public class BSPrim : BSPhysObject // Hover Height will override MoveTo target's Z public override bool PIDHoverActive { set { - if (value) - { - // Turning the target on - _hoverMotor = new BSFMotor("BSPrim.Hover", - _PIDHoverTau, // timeScale - BSMotor.Infinite, // decay time scale - BSMotor.Infinite, // friction timescale - 1f // efficiency - ); - _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); - _hoverMotor.SetCurrent(RawPosition.Z); - _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. - - RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep) - { - // Don't do hovering while the object is selected. - if (!IsPhysicallyActive) - return; - - _hoverMotor.SetCurrent(RawPosition.Z); - _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); - float targetHeight = _hoverMotor.Step(timeStep); - - // 'targetHeight' is where we'd like the Z of the prim to be at this moment. - // Compute the amount of force to push us there. - float moveForce = (targetHeight - RawPosition.Z) * Mass; - // Undo anything the object thinks it's doing at the moment - moveForce = -RawVelocity.Z * Mass; - - PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce)); - DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass); - }); - } - else + base.HoverActive = value; + CreateRemoveActor(HoverActive /* creatActor */, HoverActorName, false /* inTaintTime */, delegate() { - UnRegisterPreStepAction("BSPrim.Hover", LocalID); - } - } - } - public override float PIDHoverHeight { - set { _PIDHoverHeight = value; } - } - public override PIDHoverType PIDHoverType { - set { _PIDHoverType = value; } - } - public override float PIDHoverTau { - set { _PIDHoverTau = value; } - } - // Based on current position, determine what we should be hovering at now. - // Must recompute often. What if we walked offa cliff> - private float ComputeCurrentPIDHoverHeight() - { - float ret = _PIDHoverHeight; - float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); - - switch (_PIDHoverType) - { - case PIDHoverType.Ground: - ret = groundHeight + _PIDHoverHeight; - break; - case PIDHoverType.GroundAndWater: - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); - if (groundHeight > waterHeight) - { - ret = groundHeight + _PIDHoverHeight; - } - else - { - ret = waterHeight + _PIDHoverHeight; - } - break; + return new BSActorHover(PhysicsScene, this, HoverActorName); + }); } - return ret; } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - public override void AddForce(OMV.Vector3 force, bool pushforce) { // Per documentation, max force is limited. OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); @@ -1324,10 +1123,8 @@ public class BSPrim : BSPhysObject } } - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { - AddAngularForce(force, pushforce, false); - } - public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) + // BSPhysObject.AddAngularForce() + public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { if (force.IsFinite()) { @@ -1694,8 +1491,8 @@ public class BSPrim : BSPhysObject _orientation = entprop.Rotation; // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be // very sensitive to velocity changes. - if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) - _velocity = entprop.Velocity; + if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) + RawVelocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; @@ -1705,7 +1502,7 @@ public class BSPrim : BSPhysObject if (PositionSanityCheck(true /* inTaintTime */ )) { entprop.Position = _position; - entprop.Velocity = _velocity; + entprop.Velocity = RawVelocity; entprop.RotationalVelocity = _rotationalVelocity; entprop.Acceleration = _acceleration; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 8a15abe..a0131c7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -6,7 +6,6 @@ Enable vehicle border crossings (at least as poorly as ODE) Terrain skirts Avatar created in previous region and not new region when crossing border Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) -Lock axis Deleting a linkset while standing on the root will leave the physical shape of the root behind. Not sure if it is because standing on it. Done with large prim linksets. Linkset child rotations. @@ -344,3 +343,5 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. Verify that angular motion specified around Z moves in the vehicle coordinates. DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. Nebadon vehicles turning funny in arena (DONE) +Lock axis (DONE 20130401) + -- cgit v1.1 From a7a1b8b7e9269b446e3396a35153b00942c1e35b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 7 Apr 2013 14:05:35 -0700 Subject: BulletSim: clean up actor code so routines use the same coding pattern. Fix a few enabling problems. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 22 ++--- .../Region/Physics/BulletSPlugin/BSActorHover.cs | 6 +- .../Physics/BulletSPlugin/BSActorLockAxis.cs | 105 ++++++++++----------- .../Physics/BulletSPlugin/BSActorMoveToTarget.cs | 12 +-- .../Physics/BulletSPlugin/BSActorSetForce.cs | 2 +- .../Physics/BulletSPlugin/BSActorSetTorque.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 49 +++++++--- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 3 + .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 35 +++---- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 22 ++--- 10 files changed, 137 insertions(+), 123 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 634a898..8416740 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -67,14 +67,6 @@ public class BSActorAvatarMove : BSActor { m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); - // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) - if (m_controllingPrim.RawForce == OMV.Vector3.Zero) - { - m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh,notAvatarMove,removing={1}", m_controllingPrim.LocalID, ActorName); - m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); - return; - } - // If the object is physically active, add the hoverer prestep action if (isActive) { @@ -95,14 +87,19 @@ public class BSActorAvatarMove : BSActor // Nothing to do for the hoverer since it is all software at pre-step action time. } + // Usually called when target velocity changes to set the current velocity and the target + // into the movement motor. public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) { m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() { - m_velocityMotor.Reset(); - m_velocityMotor.SetTarget(targ); - m_velocityMotor.SetCurrent(vel); - m_velocityMotor.Enabled = true; + if (m_velocityMotor != null) + { + m_velocityMotor.Reset(); + m_velocityMotor.SetTarget(targ); + m_velocityMotor.SetCurrent(vel); + m_velocityMotor.Enabled = true; + } }); } @@ -119,6 +116,7 @@ public class BSActorAvatarMove : BSActor 1f // efficiency ); // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. + SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); m_physicsScene.BeforeStep += Mover; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs index 8dd3700..e8310df 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs @@ -67,12 +67,10 @@ public class BSActorHover : BSActor { m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); - // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + // If not active any more, turn me off if (!m_controllingPrim.HoverActive) { - m_physicsScene.DetailLog("{0},BSActorHover,refresh,notHovering,removing={1}", m_controllingPrim.LocalID, ActorName); - m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); - return; + SetEnabled(false); } // If the object is physically active, add the hoverer prestep action diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index c40a499..09ee32b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs @@ -36,7 +36,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public class BSActorLockAxis : BSActor { - bool TryExperimentalLockAxisCode = true; BSConstraint LockAxisConstraint = null; public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) @@ -69,18 +68,13 @@ public class BSActorLockAxis : BSActor // If all the axis are free, we don't need to exist if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) { - m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,allAxisFree,removing={1}", m_controllingPrim.LocalID, ActorName); - m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); - return; + Enabled = false; } + // If the object is physically active, add the axis locking constraint - if (Enabled - && m_controllingPrim.IsPhysicallyActive - && TryExperimentalLockAxisCode - && m_controllingPrim.LockedAxis != m_controllingPrim.LockedAxisFree) + if (isActive) { - if (LockAxisConstraint == null) - AddAxisLockConstraint(); + AddAxisLockConstraint(); } else { @@ -108,58 +102,61 @@ public class BSActorLockAxis : BSActor private void AddAxisLockConstraint() { - // Lock that axis by creating a 6DOF constraint that has one end in the world and - // the other in the object. - // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 - // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 + if (LockAxisConstraint == null) + { + // Lock that axis by creating a 6DOF constraint that has one end in the world and + // the other in the object. + // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 + // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 - // Remove any existing axis constraint (just to be sure) - RemoveAxisLockConstraint(); + // Remove any existing axis constraint (just to be sure) + RemoveAxisLockConstraint(); - BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, - OMV.Vector3.Zero, OMV.Quaternion.Identity, - false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); - LockAxisConstraint = axisConstrainer; - m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); + BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, + OMV.Vector3.Zero, OMV.Quaternion.Identity, + false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); + LockAxisConstraint = axisConstrainer; + m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); - // The constraint is tied to the world and oriented to the prim. + // The constraint is tied to the world and oriented to the prim. - // Free to move linearly in the region - OMV.Vector3 linearLow = OMV.Vector3.Zero; - OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; - axisConstrainer.SetLinearLimits(linearLow, linearHigh); + // Free to move linearly in the region + OMV.Vector3 linearLow = OMV.Vector3.Zero; + OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; + axisConstrainer.SetLinearLimits(linearLow, linearHigh); - // Angular with some axis locked - float fPI = (float)Math.PI; - OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); - OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); - if (m_controllingPrim.LockedAxis.X != 1f) - { - angularLow.X = 0f; - angularHigh.X = 0f; - } - if (m_controllingPrim.LockedAxis.Y != 1f) - { - angularLow.Y = 0f; - angularHigh.Y = 0f; - } - if (m_controllingPrim.LockedAxis.Z != 1f) - { - angularLow.Z = 0f; - angularHigh.Z = 0f; - } - if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) - { - m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); - } + // Angular with some axis locked + float fPI = (float)Math.PI; + OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); + OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); + if (m_controllingPrim.LockedAxis.X != 1f) + { + angularLow.X = 0f; + angularHigh.X = 0f; + } + if (m_controllingPrim.LockedAxis.Y != 1f) + { + angularLow.Y = 0f; + angularHigh.Y = 0f; + } + if (m_controllingPrim.LockedAxis.Z != 1f) + { + angularLow.Z = 0f; + angularHigh.Z = 0f; + } + if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) + { + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); + } - m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", - m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", + m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); - // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. - axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); + // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. + axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); - axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); + axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); + } } private void RemoveAxisLockConstraint() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs index 3517ef2..16c2b14 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs @@ -67,15 +67,12 @@ public class BSActorMoveToTarget : BSActor { m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh", m_controllingPrim.LocalID); - // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) - if (!m_controllingPrim.HoverActive) + // If not active any more... + if (!m_controllingPrim.MoveToTargetActive) { - m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,notMoveToTarget,removing={1}", m_controllingPrim.LocalID, ActorName); - m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); - return; + Enabled = false; } - // If the object is physically active, add the hoverer prestep action if (isActive) { ActivateMoveToTarget(); @@ -92,7 +89,7 @@ public class BSActorMoveToTarget : BSActor // BSActor.RemoveBodyDependencies() public override void RemoveBodyDependencies() { - // Nothing to do for the hoverer since it is all software at pre-step action time. + // Nothing to do for the moveToTarget since it is all software at pre-step action time. } // If a hover motor has not been created, create one and start the hovering. @@ -144,7 +141,6 @@ public class BSActorMoveToTarget : BSActor m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; - m_targetMotor.Enabled = false; } else { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs index d942490..3ad138d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs @@ -71,7 +71,7 @@ public class BSActorSetForce : BSActor if (m_controllingPrim.RawForce == OMV.Vector3.Zero) { m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); - m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + Enabled = false; return; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs index e0f719f..159a3a8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs @@ -70,8 +70,8 @@ public class BSActorSetTorque : BSActor // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) { - m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,removing={1}", m_controllingPrim.LocalID, ActorName); - m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName); + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); + Enabled = false; return; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index fb4d452..12a8817 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -42,24 +42,36 @@ public class BSActorCollection } public void Add(string name, BSActor actor) { - m_actors[name] = actor; + lock (m_actors) + { + if (!m_actors.ContainsKey(name)) + { + m_actors[name] = actor; + } + } } public bool RemoveAndRelease(string name) { bool ret = false; - if (m_actors.ContainsKey(name)) + lock (m_actors) { - BSActor beingRemoved = m_actors[name]; - beingRemoved.Dispose(); - m_actors.Remove(name); - ret = true; + if (m_actors.ContainsKey(name)) + { + BSActor beingRemoved = m_actors[name]; + m_actors.Remove(name); + beingRemoved.Dispose(); + ret = true; + } } return ret; } public void Clear() { - Release(); - m_actors.Clear(); + lock (m_actors) + { + Release(); + m_actors.Clear(); + } } public void Dispose() { @@ -69,15 +81,22 @@ public class BSActorCollection { return m_actors.ContainsKey(name); } + public bool TryGetActor(string actorName, out BSActor theActor) + { + return m_actors.TryGetValue(actorName, out theActor); + } public void ForEachActor(Action act) { - foreach (KeyValuePair kvp in m_actors) - act(kvp.Value); + lock (m_actors) + { + foreach (KeyValuePair kvp in m_actors) + act(kvp.Value); + } } public void Enable(bool enabl) { - ForEachActor(a => a.Enable(enabl)); + ForEachActor(a => a.SetEnabled(enabl)); } public void Release() { @@ -106,7 +125,7 @@ public abstract class BSActor { protected BSScene m_physicsScene { get; private set; } protected BSPhysObject m_controllingPrim { get; private set; } - protected bool Enabled { get; set; } + public virtual bool Enabled { get; set; } public string ActorName { get; private set; } public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) @@ -122,8 +141,10 @@ public abstract class BSActor { get { return Enabled; } } - // Turn the actor on an off. - public virtual void Enable(bool setEnabled) + + // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. + // Anyone else should assign true/false to 'Enabled'. + public void SetEnabled(bool setEnabled) { Enabled = setEnabled; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 09c9b16..a0d58d3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -160,6 +160,9 @@ public sealed class BSCharacter : BSPhysObject // Make so capsule does not fall over PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); + // The avatar mover sets some parameters. + PhysicalActors.Refresh(); + PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 644bc7e..64bf395 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -282,30 +282,31 @@ public abstract class BSPhysObject : PhysicsActor // 'actors' act on the physical object to change or constrain its motion. These can range from // hovering to complex vehicle motion. + // May be called at non-taint time as this just adds the actor to the action list and the real + // work is done during the simulation step. + // Note that, if the actor is already in the list and we are disabling same, the actor is just left + // in the list disabled. public delegate BSActor CreateActor(); - public void CreateRemoveActor(bool createRemove, string actorName, bool inTaintTime, CreateActor creator) + public void EnableActor(bool enableActor, string actorName, CreateActor creator) { - if (createRemove) + lock (PhysicalActors) { - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CreateRemoveActor:" + actorName, delegate() + BSActor theActor; + if (PhysicalActors.TryGetActor(actorName, out theActor)) { - if (!PhysicalActors.HasActor(actorName)) - { - DetailLog("{0},BSPrim.CreateRemoveActor,taint,registerActor,a={1}", LocalID, actorName); - PhysicalActors.Add(actorName, creator()); - } - }); - } - else - { - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CreateRemoveActor:" + actorName, delegate() + // The actor already exists so just turn it on or off + theActor.Enabled = enableActor; + } + else { - if (PhysicalActors.HasActor(actorName)) + // The actor does not exist. If it should, create it. + if (enableActor) { - DetailLog("{0},BSPrim.CreateRemoveActor,taint,unregisterActor,a={1}", LocalID, actorName); - PhysicalActors.RemoveAndRelease(actorName); + theActor = creator(); + PhysicalActors.Add(actorName, theActor); + theActor.Enabled = true; } - }); + } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 71fea59..16c7a90 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -95,6 +95,7 @@ public class BSPrim : BSPhysObject _isPhysical = pisPhysical; _isVolumeDetect = false; + // We keep a handle to the vehicle actor so we can set vehicle parameters later. VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); PhysicalActors.Add(VehicleActorName, VehicleActor); @@ -264,7 +265,7 @@ public class BSPrim : BSPhysObject if (axis.Z != 1) locking.Z = 0f; LockedAxis = locking; - CreateRemoveActor(LockedAxis != LockedAxisFree /* creatActor */, LockedAxisActorName, false /* inTaintTime */, delegate() + EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate() { return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName); }); @@ -501,7 +502,7 @@ public class BSPrim : BSPhysObject get { return RawForce; } set { RawForce = value; - CreateRemoveActor(RawForce == OMV.Vector3.Zero, SetForceActorName, false /* inTaintTime */, delegate() + EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() { return new BSActorSetForce(PhysicsScene, this, SetForceActorName); }); @@ -510,14 +511,13 @@ public class BSPrim : BSPhysObject public override int VehicleType { get { - return (int)VehicleActor.Type; // if we are a vehicle, return that type + return (int)VehicleActor.Type; } set { Vehicle type = (Vehicle)value; PhysicsScene.TaintedObject("setVehicleType", delegate() { - // Done at taint time so we're sure the physics engine is not using the variables // Vehicle code changes the parameters for this vehicle type. VehicleActor.ProcessTypeChange(type); ActivateIfPhysical(false); @@ -669,11 +669,11 @@ public class BSPrim : BSPhysObject get { return RawTorque; } set { RawTorque = value; - CreateRemoveActor(RawTorque == OMV.Vector3.Zero, SetTorqueActorName, false /* inTaintTime */, delegate() + EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() { return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName); }); - // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); + DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); } } public override OMV.Vector3 Acceleration { @@ -786,7 +786,6 @@ public class BSPrim : BSPhysObject MakeDynamic(IsStatic); // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) - VehicleActor.Refresh(); PhysicalActors.Refresh(); // Arrange for collision events if the simulator wants them @@ -1037,7 +1036,7 @@ public class BSPrim : BSPhysObject public override bool PIDActive { set { base.MoveToTargetActive = value; - CreateRemoveActor(MoveToTargetActive, MoveToTargetActorName, false /* inTaintTime */, delegate() + EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() { return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName); }); @@ -1049,7 +1048,7 @@ public class BSPrim : BSPhysObject public override bool PIDHoverActive { set { base.HoverActive = value; - CreateRemoveActor(HoverActive /* creatActor */, HoverActorName, false /* inTaintTime */, delegate() + EnableActor(HoverActive, HoverActorName, delegate() { return new BSActorHover(PhysicsScene, this, HoverActorName); }); @@ -1458,7 +1457,7 @@ public class BSPrim : BSPhysObject { // Create the correct physical representation for this type of object. // Updates base.PhysBody and base.PhysShape with the new information. - // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. + // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) { // Called if the current prim body is about to be destroyed. @@ -1472,9 +1471,9 @@ public class BSPrim : BSPhysObject return; } + // Called at taint-time protected virtual void RemoveBodyDependencies() { - VehicleActor.RemoveBodyDependencies(); PhysicalActors.RemoveBodyDependencies(); } @@ -1482,6 +1481,7 @@ public class BSPrim : BSPhysObject // the world that things have changed. public override void UpdateProperties(EntityProperties entprop) { + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. TriggerPreUpdatePropertyAction(ref entprop); // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG -- cgit v1.1 From 99f39836a1879a807bb7d6bf5bf793c3a99584c4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 8 Apr 2013 06:27:01 -0700 Subject: BulletSim: moving comments around. No functional change. --- OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 10 +--------- OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 9 +++++++++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs index 159a3a8..7a791ec 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs @@ -65,7 +65,7 @@ public class BSActorSetTorque : BSActor // BSActor.Refresh() public override void Refresh() { - m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh", m_controllingPrim.LocalID); + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 16c7a90..3423d2e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -1514,16 +1514,8 @@ public class BSPrim : BSPhysObject LastEntityProperties = CurrentEntityProperties; CurrentEntityProperties = entprop; + // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. base.RequestPhysicsterseUpdate(); - /* - else - { - // For debugging, report the movement of children - DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, - entprop.Acceleration, entprop.RotationalVelocity); - } - */ } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index d65d407..28242d4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -163,6 +163,15 @@ public class BSPrimLinkable : BSPrimDisplaced // TODO: this will have to change when linksets are articulated. base.UpdateProperties(entprop); } + /* + else + { + // For debugging, report the movement of children + DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, + entprop.Acceleration, entprop.RotationalVelocity); + } + */ // The linkset might like to know about changing locations Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); } -- cgit v1.1 From f68b963596e7df2c28761af4584b4dcb17d550eb Mon Sep 17 00:00:00 2001 From: Jon Cundill Date: Sun, 7 Apr 2013 12:31:49 +0100 Subject: fixed bullet config for osx Signed-off-by: Robert Adams --- bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config b/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config index 1bc7e41..2763525 100755 --- a/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config +++ b/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config @@ -1,6 +1,8 @@ + + -- cgit v1.1 From 4d2203ff5298ffe40902ce018c1be1b4096c936d Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 8 Apr 2013 09:15:20 -0700 Subject: BulletSim: Add dylib for BulletSim and add he who figured out building BulletSim on a Mac to the CONTRIBUTORS file. --- CONTRIBUTORS.txt | 1 + bin/lib32/libBulletSim.dylib | Bin 0 -> 1181656 bytes 2 files changed, 1 insertion(+) create mode 100755 bin/lib32/libBulletSim.dylib diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 8ff55df..36b17be 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -101,6 +101,7 @@ what it is today. * jhurliman * John R Sohn (XenReborn) * jonc +* Jon Cundill * Junta Kohime * Kayne * Kevin Cozens diff --git a/bin/lib32/libBulletSim.dylib b/bin/lib32/libBulletSim.dylib new file mode 100755 index 0000000..02f8a7f Binary files /dev/null and b/bin/lib32/libBulletSim.dylib differ -- cgit v1.1 From 8e04c752fc2bc1f27fce224d2aec3ea72edbc2cc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Apr 2013 22:38:47 +0100 Subject: If OpenSimulator is writing a PID file and finds the file already present on startup, logging an error since this is commonly due to an unclean shutdown. Unclean shutdown can cause constantly moving objects to disappear if an OAR has just been loaded and they have not reached persistence time threshold, among other problems. --- OpenSim/Framework/Servers/ServerBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 657444c..2c4a687 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -76,6 +76,11 @@ namespace OpenSim.Framework.Servers protected void CreatePIDFile(string path) { + if (File.Exists(path)) + m_log.ErrorFormat( + "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", + path); + try { string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); -- cgit v1.1 From 8690a08881d41c285dd830b4b1646eb116ad098d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Apr 2013 23:02:11 +0100 Subject: minor: Log an exception if we aren't able to delete a script state file rather than simply ignoring it. This should never normally happen but if it does then it can be valuable diagonstic information. --- OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index bf19a42..1e6db43 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -520,8 +520,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { File.Delete(savedState); } - catch(Exception) + catch (Exception e) { + m_log.Warn( + string.Format( + "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ", + ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name), + e); } } -- cgit v1.1 From 659c741ff5a3d13b4462d3ce906c6785bb296322 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Apr 2013 23:15:01 +0100 Subject: Add more notes to async_call_method relating to UnsafeQueueUserWorkItem UnsafeQueueUserWorkItem is so called because it allows the calling code to escalate its security privileges. However, since we must already trust this code anyway in OpenSimulator this is not an issue. --- bin/OpenSimDefaults.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 1d2c0cf..28c1db2 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -43,9 +43,14 @@ ; Sets the method that OpenSim will use to fire asynchronous ; events. Valid values are UnsafeQueueUserWorkItem, ; QueueUserWorkItem, BeginInvoke, SmartThreadPool, and Thread. + ; ; SmartThreadPool is reported to work well on Mono/Linux, but ; UnsafeQueueUserWorkItem has been benchmarked with better ; performance on .NET/Windows + ; + ; UnsafeQueueUserWorkItem refers to the fact that the code creating the event could elevate its security + ; privileges. However, as calling code is trusted anyway this is safe (if you set + ; TrustedBinaries = true in the [XEngine] section then you already have to trust that incoming code for other reasons). async_call_method = SmartThreadPool ; Max threads to allocate on the FireAndForget thread pool -- cgit v1.1 From 06068444e2486cb761d266c6831c54fc27d7d5c2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Apr 2013 23:21:13 +0100 Subject: Comment out rez perms logging I accidentally left in at 7f07023 (Sat Apr 6 02:34:51 2013) --- OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 77299be..f8e93e1 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -1453,7 +1453,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions bool permission = false; - m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); +// m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); if (land == null) return false; -- cgit v1.1 From e20b0d5695dc583d161b39fa26bfd56e63c7b30e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 10 Apr 2013 00:03:37 +0100 Subject: minor: Make exceptions thrown by MySQLAssetData more consistent. --- OpenSim/Data/MySQL/MySQLAssetData.cs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs index cf80b3d..21362b9 100644 --- a/OpenSim/Data/MySQL/MySQLAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLAssetData.cs @@ -142,7 +142,8 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.Error("[ASSETS DB]: MySql failure fetching asset " + assetID + ": " + e.Message); + m_log.Error( + string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", assetID), e); } } } @@ -209,8 +210,11 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}", - asset.FullID, asset.Name, e.Message); + m_log.Error( + string.Format( + "[ASSET DB]: MySQL failure creating asset {0} with name {1}. Exception ", + asset.FullID, asset.Name) + , e); } } } @@ -241,10 +245,11 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.ErrorFormat( - "[ASSETS DB]: " + - "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() - + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); + m_log.Error( + string.Format( + "[ASSETS DB]: Failure updating access_time for asset {0} with name {1}. Exception ", + asset.FullID, asset.Name), + e); } } } @@ -284,8 +289,8 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.ErrorFormat( - "[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid); + m_log.Error( + string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", uuid), e); } } } @@ -344,7 +349,11 @@ namespace OpenSim.Data.MySQL } catch (Exception e) { - m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); + m_log.Error( + string.Format( + "[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ", + start, count), + e); } } } -- cgit v1.1 From 29e28f4b84677fa1e1b138d0ede610c55add12f2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 10 Apr 2013 00:05:03 +0100 Subject: minor: remove mono compiler warnings in InventoryAccessModule --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index f796ec9..e0009bb 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -353,7 +353,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess bool asAttachment) { CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); - Dictionary originalPositions = new Dictionary(); +// Dictionary originalPositions = new Dictionary(); foreach (SceneObjectGroup objectGroup in objlist) { @@ -936,8 +936,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - int primcount = 0; - for(int i = 0; i < objlist.Count; i++) + for (int i = 0; i < objlist.Count; i++) { SceneObjectGroup g = objlist[i]; -- cgit v1.1 From 148e46563f9f95e43a460780592deceed3dd5d14 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 10 Apr 2013 00:07:58 +0100 Subject: minor: fix mono compiler warning in ScriptsHttpRequests.cs --- OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index ebf56cd..6793fc8 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -395,7 +395,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest //public bool HttpVerboseThrottle = true; // not implemented public List HttpCustomHeaders = null; public bool HttpPragmaNoCache = true; - private Thread httpThread; // Request info private UUID _itemID; -- cgit v1.1 From 17fd075f39df71d628db08b7c280150f231f8a26 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Apr 2013 11:55:29 -0700 Subject: BulletSim: fix problem where large sets of mega-regions weren't registering all the terrain with the base region. --- OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index cd15850..5240ad8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -213,13 +213,13 @@ public sealed class BSTerrainManager : IDisposable }); } - // Another region is calling this region passing a terrain. + // Another region is calling this region and passing a terrain. // A region that is not the mega-region root will pass its terrain to the root region so the root region // physics engine will have all the terrains. private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) { // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. - PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + m_worldOffset.ToString(), 0, delegate() + PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() { UpdateTerrain(id, heightMap, minCoords, maxCoords); }); @@ -306,7 +306,7 @@ public sealed class BSTerrainManager : IDisposable newTerrainID = ++m_terrainCount; DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", - BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); + BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); m_terrains.Add(terrainRegionBase, newTerrainPhys); -- cgit v1.1 From 59135c9a31875dc514b3ea2fe14021571807701d Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Apr 2013 16:32:54 -0700 Subject: BulletSim: add Bullet HACD library invocation. Turned off by default as not totally debugged. Updated DLLs and SOs with more debugged HACD library code. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 53 ++++- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 1 + .../Physics/BulletSPlugin/BSShapeCollection.cs | 223 ++++++++++++--------- bin/lib32/BulletSim.dll | Bin 570880 -> 1008640 bytes bin/lib32/libBulletSim.so | Bin 1762207 -> 2093987 bytes bin/lib64/BulletSim.dll | Bin 721920 -> 1140224 bytes bin/lib64/libBulletSim.so | Bin 1920169 -> 2258808 bytes 7 files changed, 183 insertions(+), 94 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 385ed9e..06df85e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -86,6 +86,7 @@ public static class BSParam public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects public static bool ShouldRemoveZeroWidthTriangles { get; private set; } + public static bool ShouldUseBulletHACD { get; set; } public static float TerrainImplementation { get; private set; } public static int TerrainMeshMagnification { get; private set; } @@ -149,6 +150,15 @@ public static class BSParam public static float CSHullVolumeConservationThresholdPercent { get; private set; } public static int CSHullMaxVertices { get; private set; } public static float CSHullMaxSkinWidth { get; private set; } + public static float BHullMaxVerticesPerHull { get; private set; } // 100 + public static float BHullMinClusters { get; private set; } // 2 + public static float BHullCompacityWeight { get; private set; } // 0.1 + public static float BHullVolumeWeight { get; private set; } // 0.0 + public static float BHullConcavity { get; private set; } // 100 + public static bool BHullAddExtraDistPoints { get; private set; } // false + public static bool BHullAddNeighboursDistPoints { get; private set; } // false + public static bool BHullAddFacesPoints { get; private set; } // false + public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false // Linkset implementation parameters public static float LinksetImplementation { get; private set; } @@ -325,6 +335,10 @@ public static class BSParam true, (s) => { return ShouldRemoveZeroWidthTriangles; }, (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), + new ParameterDefn("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", + false, + (s) => { return ShouldUseBulletHACD; }, + (s,v) => { ShouldUseBulletHACD = v; } ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5, @@ -663,10 +677,47 @@ public static class BSParam (s) => { return CSHullMaxVertices; }, (s,v) => { CSHullMaxVertices = v; } ), new ParameterDefn("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", - 0, + 0f, (s) => { return CSHullMaxSkinWidth; }, (s,v) => { CSHullMaxSkinWidth = v; } ), + new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", + 100f, + (s) => { return BHullMaxVerticesPerHull; }, + (s,v) => { BHullMaxVerticesPerHull = v; } ), + new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", + 2f, + (s) => { return BHullMinClusters; }, + (s,v) => { BHullMinClusters = v; } ), + new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", + 2f, + (s) => { return BHullCompacityWeight; }, + (s,v) => { BHullCompacityWeight = v; } ), + new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", + 0.1f, + (s) => { return BHullVolumeWeight; }, + (s,v) => { BHullVolumeWeight = v; } ), + new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", + 100f, + (s) => { return BHullConcavity; }, + (s,v) => { BHullConcavity = v; } ), + new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", + false, + (s) => { return BHullAddExtraDistPoints; }, + (s,v) => { BHullAddExtraDistPoints = v; } ), + new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", + false, + (s) => { return BHullAddNeighboursDistPoints; }, + (s,v) => { BHullAddNeighboursDistPoints = v; } ), + new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", + false, + (s) => { return BHullAddFacesPoints; }, + (s,v) => { BHullAddFacesPoints = v; } ), + new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", + false, + (s) => { return BHullShouldAdjustCollisionMargin; }, + (s,v) => { BHullShouldAdjustCollisionMargin = v; } ), + new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", (float)BSLinkset.LinksetImplementation.Compound, (s) => { return LinksetImplementation; }, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 9818b05..8e05b58 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -316,6 +316,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters break; case "bulletxna": ret = new BSAPIXNA(engineName, this); + BSParam.ShouldUseBulletHACD = false; break; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index b6ac23d..bfa69b2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -720,7 +720,7 @@ public sealed class BSShapeCollection : IDisposable // Remove usage of the previous shape. DereferenceShape(prim.PhysShape, shapeCallback); - newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); + newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod); // It might not have been created if we're waiting for an asset. newShape = VerifyMeshCreated(newShape, prim); @@ -731,7 +731,7 @@ public sealed class BSShapeCollection : IDisposable } List m_hulls; - private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + private BulletShape CreatePhysicalHull(BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = new BulletShape(); @@ -745,116 +745,153 @@ public sealed class BSShapeCollection : IDisposable } else { - // Build a new hull in the physical world. - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); - if (meshData != null) + if (BSParam.ShouldUseBulletHACD) { - - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) + DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); + MeshDesc meshDesc; + if (!Meshes.TryGetValue(newHullKey, out meshDesc)) { - convIndices.Add(indices[ii]); + // That's odd because the mesh should have been created before the hull + // but, since it doesn't exist, create it. + newShape = CreatePhysicalMesh(prim, newHullKey, prim.BaseShape, prim.Size, lod); + DetailLog("{0},BSShapeCollection.CreatePhysicalHull,noMeshBuiltNew,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + + if (newShape.HasPhysicalShape) + { + ReferenceShape(newShape); + Meshes.TryGetValue(newHullKey, out meshDesc); + } } - foreach (OMV.Vector3 vv in vertices) + if (meshDesc.shape.HasPhysicalShape) { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + HACDParams parms; + parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; + parms.minClusters = BSParam.BHullMinClusters; + parms.compacityWeight = BSParam.BHullCompacityWeight; + parms.volumeWeight = BSParam.BHullVolumeWeight; + parms.concavity = BSParam.BHullConcavity; + parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); + parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); + parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); + parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); + + DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); + newShape = PhysicsScene.PE.BuildHullShapeFromMesh(PhysicsScene.World, meshDesc.shape, parms); + DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } - - uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; - if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + } + if (!newShape.HasPhysicalShape) + { + // Build a new hull in the physical world. + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); + if (meshData != null) { - // Simple primitive shapes we know are convex so they are better implemented with - // fewer hulls. - // Check for simple shape (prim without cuts) and reduce split parameter if so. - if (PrimHasNoCuts(pbs)) + int[] indices = meshData.getIndexListAsInt(); + List vertices = meshData.getVertexList(); + + //format conversion from IMesh format to DecompDesc format + List convIndices = new List(); + List convVertices = new List(); + for (int ii = 0; ii < indices.GetLength(0); ii++) { - maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; + convIndices.Add(indices[ii]); + } + foreach (OMV.Vector3 vv in vertices) + { + convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); } - } - // setup and do convex hull conversion - m_hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - dcomp.mDepth = maxDepthSplit; - dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; - dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; - dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; - dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", - BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); - - // Convert the vertices and indices for passing to unmanaged. - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = m_hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in m_hulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles - } - float[] convHulls = new float[totalVertices]; + uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; + if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + { + // Simple primitive shapes we know are convex so they are better implemented with + // fewer hulls. + // Check for simple shape (prim without cuts) and reduce split parameter if so. + if (PrimHasNoCuts(pbs)) + { + maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; + } + } - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in m_hulls) - { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) + // setup and do convex hull conversion + m_hulls = new List(); + DecompDesc dcomp = new DecompDesc(); + dcomp.mIndices = convIndices; + dcomp.mVertices = convVertices; + dcomp.mDepth = maxDepthSplit; + dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; + dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; + dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; + dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; + ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); + // create the hull into the _hulls variable + convexBuilder.process(dcomp); + + DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", + BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); + + // Convert the vertices and indices for passing to unmanaged. + // The hull information is passed as a large floating point array. + // The format is: + // convHulls[0] = number of hulls + // convHulls[1] = number of vertices in first hull + // convHulls[2] = hull centroid X coordinate + // convHulls[3] = hull centroid Y coordinate + // convHulls[4] = hull centroid Z coordinate + // convHulls[5] = first hull vertex X + // convHulls[6] = first hull vertex Y + // convHulls[7] = first hull vertex Z + // convHulls[8] = second hull vertex X + // ... + // convHulls[n] = number of vertices in second hull + // convHulls[n+1] = second hull centroid X coordinate + // ... + // + // TODO: is is very inefficient. Someday change the convex hull generator to return + // data structures that do not need to be converted in order to pass to Bullet. + // And maybe put the values directly into pinned memory rather than marshaling. + int hullCount = m_hulls.Count; + int totalVertices = 1; // include one for the count of the hulls + foreach (ConvexResult cr in m_hulls) { - verts[kk++] = ff; + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += cr.HullIndices.Count * 3; // we pass just triangles } + float[] convHulls = new float[totalVertices]; - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (ConvexResult cr in m_hulls) { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; + // copy vertices for index access + float3[] verts = new float3[cr.HullVertices.Count]; + int kk = 0; + foreach (float3 ff in cr.HullVertices) + { + verts[kk++] = ff; + } + + // add to the array one hull's worth of data + convHulls[jj++] = cr.HullIndices.Count; + convHulls[jj++] = 0f; // centroid x,y,z + convHulls[jj++] = 0f; + convHulls[jj++] = 0f; + foreach (int ind in cr.HullIndices) + { + convHulls[jj++] = verts[ind].x; + convHulls[jj++] = verts[ind].y; + convHulls[jj++] = verts[ind].z; + } } + // create the hull data structure in Bullet + newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); } - // create the hull data structure in Bullet - newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); } + newShape.shapeKey = newHullKey; } - newShape.shapeKey = newHullKey; - return newShape; } diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 5432813..618d4bd 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 286d930..e3b40fb 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index dca7116..491ac22 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index b63feb3..a8ad533 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From 9cc41d511872fcd74a074ab484db2b981f3f5676 Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Tue, 9 Apr 2013 17:23:50 -0400 Subject: Another algorithm for AngularVerticalAttraction. This one Takes into account all rotations before it and makes the corrections more close to the time that sl does. Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 0fd1f73..723be0b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1358,6 +1358,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin // If vertical attaction timescale is reasonable if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) { + //Another formula to try got from : + //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html + Vector3 VehicleUpAxis = Vector3.UnitZ *VehicleOrientation; + //Flipping what was originally a timescale into a speed variable and then multiplying it by 2 since only computing half + //the distance between the angles. + float VerticalAttractionSpeed=(1/m_verticalAttractionTimescale)*2.0f; + //making a prediction of where the up axis will be when this is applied rather then where it is now this makes for a smoother + //adjustment and less fighting between the various forces + Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); + //this is only half the distance to the target so it will take 2 seconds to complete the turn. + Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); + //Scaling vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared + Vector3 vertContributionV=torqueVector * VerticalAttractionSpeed *VerticalAttractionSpeed; + VehicleRotationalVelocity += vertContributionV; + VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", + ControllingPrim.LocalID, + VehicleUpAxis, + predictedUp, + torqueVector, + vertContributionV); + //===================================================================== + /* // Possible solution derived from a discussion at: // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no @@ -1392,6 +1414,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin differenceAngle, correctionRotation, vertContributionV); + */ // =================================================================== /* -- cgit v1.1 From b53713cdda3c4e49913a6a82239da35d62f74e68 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Apr 2013 17:14:15 -0700 Subject: BulletSim: some formatting changes. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 723be0b..612c68b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1360,19 +1360,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin { //Another formula to try got from : //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html - Vector3 VehicleUpAxis = Vector3.UnitZ *VehicleOrientation; - //Flipping what was originally a timescale into a speed variable and then multiplying it by 2 since only computing half - //the distance between the angles. - float VerticalAttractionSpeed=(1/m_verticalAttractionTimescale)*2.0f; - //making a prediction of where the up axis will be when this is applied rather then where it is now this makes for a smoother - //adjustment and less fighting between the various forces + + Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation; + + // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 + // since only computing half the distance between the angles. + float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; + + // Make a prediction of where the up axis will be when this is applied rather then where it is now as + // this makes for a smoother adjustment and less fighting between the various forces. Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); - //this is only half the distance to the target so it will take 2 seconds to complete the turn. + + // This is only half the distance to the target so it will take 2 seconds to complete the turn. Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); - //Scaling vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared - Vector3 vertContributionV=torqueVector * VerticalAttractionSpeed *VerticalAttractionSpeed; + + // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared + Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; + VehicleRotationalVelocity += vertContributionV; - VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", + + VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", ControllingPrim.LocalID, VehicleUpAxis, predictedUp, -- cgit v1.1 From 5f2cbfc0fd27198f8f05f4a9a4e2908d8b11752e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Apr 2013 17:53:18 -0700 Subject: BulletSim: fixing problems with llMoveToTarget. Not all fixed yet. --- OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs | 2 +- .../Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs | 16 +++++++++++----- OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 6 ++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs index e8310df..92ace66 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs @@ -50,7 +50,7 @@ public class BSActorHover : BSActor // BSActor.isActive public override bool isActive { - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + get { return Enabled; } } // Release any connections and resources used by the actor. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs index 16c2b14..56aacc5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs @@ -50,7 +50,7 @@ public class BSActorMoveToTarget : BSActor // BSActor.isActive public override bool isActive { - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + get { return Enabled; } } // Release any connections and resources used by the actor. @@ -65,7 +65,9 @@ public class BSActorMoveToTarget : BSActor // BSActor.Refresh() public override void Refresh() { - m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh", m_controllingPrim.LocalID); + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", + m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, + m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); // If not active any more... if (!m_controllingPrim.MoveToTargetActive) @@ -100,7 +102,7 @@ public class BSActorMoveToTarget : BSActor // We're taking over after this. m_controllingPrim.ZeroMotion(true); - m_targetMotor = new BSVMotor("BSPrim.PIDTarget", + m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate", m_controllingPrim.MoveToTargetTau, // timeScale BSMotor.Infinite, // decay time scale BSMotor.InfiniteVector, // friction timescale @@ -138,15 +140,19 @@ public class BSActorMoveToTarget : BSActor // If we are very close to our target, turn off the movement motor. if (m_targetMotor.ErrorIsZero()) { - m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); } else { m_controllingPrim.ForcePosition = movePosition; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); } - m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 64bf395..98eb4ca 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -295,6 +295,7 @@ public abstract class BSPhysObject : PhysicsActor if (PhysicalActors.TryGetActor(actorName, out theActor)) { // The actor already exists so just turn it on or off + DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); theActor.Enabled = enableActor; } else @@ -302,10 +303,15 @@ public abstract class BSPhysObject : PhysicsActor // The actor does not exist. If it should, create it. if (enableActor) { + DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); theActor = creator(); PhysicalActors.Add(actorName, theActor); theActor.Enabled = true; } + else + { + DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); + } } } } -- cgit v1.1 From c5de9840b05514eb659696239593e51e636398b8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 16 Apr 2013 21:58:24 +0100 Subject: refactor: Remove IClientNetworkServer.NetworkStop() in favour of existing Stop(). This was an undocumented interface which I think was for long defunct region load balancing experiments. Also adds method doc for some IClientNetworkServer methods. --- OpenSim/Region/Application/OpenSimBase.cs | 2 +- OpenSim/Region/ClientStack/IClientNetworkServer.cs | 15 +++++++++++++-- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 5 ----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index c555915..d86eefe 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -737,7 +737,7 @@ namespace OpenSim if (foundClientServer) { - m_clientServers[clientServerElement].NetworkStop(); + m_clientServers[clientServerElement].Stop(); m_clientServers.RemoveAt(clientServerElement); } } diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs index 54a441b..bb7e6d0 100644 --- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs +++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs @@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager authenticateClass); - void NetworkStop(); bool HandlesRegion(Location x); - void AddScene(IScene x); + /// + /// Add the given scene to be handled by this IClientNetworkServer. + /// + /// + void AddScene(IScene scene); + + /// + /// Start sending and receiving data. + /// void Start(); + + /// + /// Stop sending and receiving data. + /// void Stop(); } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 72516cd..985aa4d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -62,11 +62,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); } - public void NetworkStop() - { - m_udpServer.Stop(); - } - public void AddScene(IScene scene) { m_udpServer.AddScene(scene); -- cgit v1.1 From d4fa2c69ed2895dcab76e0df1b26252246883c07 Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 17 Apr 2013 21:31:18 -0700 Subject: update libomv to git master which adds support for MaterialID in TextureEntry --- bin/CSJ2K.dll | Bin 502784 -> 495616 bytes bin/OpenMetaverse.StructuredData.XML | 28 +- bin/OpenMetaverse.StructuredData.dll | Bin 114688 -> 102400 bytes bin/OpenMetaverse.XML | 36629 ++++++++++---------- bin/OpenMetaverse.dll | Bin 1925120 -> 1785856 bytes bin/OpenMetaverse.dll.config | 8 +- bin/OpenMetaverseTypes.XML | 1462 +- bin/OpenMetaverseTypes.dll | Bin 122880 -> 114688 bytes bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so | Bin 0 -> 140028 bytes bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so | Bin 0 -> 149368 bytes bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib | Bin 0 -> 130560 bytes 11 files changed, 19633 insertions(+), 18494 deletions(-) create mode 100644 bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so create mode 100644 bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so create mode 100644 bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib diff --git a/bin/CSJ2K.dll b/bin/CSJ2K.dll index 238291f..581e410 100755 Binary files a/bin/CSJ2K.dll and b/bin/CSJ2K.dll differ diff --git a/bin/OpenMetaverse.StructuredData.XML b/bin/OpenMetaverse.StructuredData.XML index 897a330..3999d99 100644 --- a/bin/OpenMetaverse.StructuredData.XML +++ b/bin/OpenMetaverse.StructuredData.XML @@ -31,17 +31,33 @@ - + Serializes OSD to binary format. It does no prepend header - - + OSD to serialize + Serialized data + + + + Serializes OSD to binary format + + OSD to serialize + + Serialized data - + Serializes OSD to binary format. It does no prepend header - - + OSD to serialize + Serialized data + + + + Serializes OSD to binary format + + OSD to serialize + + Serialized data diff --git a/bin/OpenMetaverse.StructuredData.dll b/bin/OpenMetaverse.StructuredData.dll index c7216ce..4df771a 100755 Binary files a/bin/OpenMetaverse.StructuredData.dll and b/bin/OpenMetaverse.StructuredData.dll differ diff --git a/bin/OpenMetaverse.XML b/bin/OpenMetaverse.XML index 6e57fed..abd4cd5 100644 --- a/bin/OpenMetaverse.XML +++ b/bin/OpenMetaverse.XML @@ -4,9695 +4,8916 @@ OpenMetaverse - - = - - - Number of times we've received an unknown CAPS exception in series. + + + Starts a thread that keeps the daemon running + + + - - For exponential backoff on error. + + + Stops the daemon and the thread keeping it running + - + - Add a custom decoder callback + - The key of the field to decode - The custom decode handler + + + - + - Remove a custom decoder callback + Create a Session + Sessions typically represent a connection to a media session with one or more + participants. This is used to generate an ‘outbound’ call to another user or + channel. The specifics depend on the media types involved. A session handle is + required to control the local user functions within the session (or remote + users if the current account has rights to do so). Currently creating a + session automatically connects to the audio media, there is no need to call + Session.Connect at this time, this is reserved for future use. - The key of the field to decode - The custom decode handler + Handle returned from successful Connector ‘create’ request + This is the URI of the terminating point of the session (ie who/what is being called) + This is the display name of the entity being called (user or channel) + Only needs to be supplied when the target URI is password protected + This indicates the format of the password as passed in. This can either be + “ClearText” or “SHA1UserName”. If this element does not exist, it is assumed to be “ClearText”. If it is + “SHA1UserName”, the password as passed in is the SHA1 hash of the password and username concatenated together, + then base64 encoded, with the final “=” character stripped off. + + + - + - Creates a formatted string containing the values of a Packet + Used to accept a call - The Packet - A formatted string of values of the nested items in the Packet object + SessionHandle such as received from SessionNewEvent + "default" + - + - Decode an IMessage object into a beautifully formatted string + This command is used to start the audio render process, which will then play + the passed in file through the selected audio render device. This command + should not be issued if the user is on a call. - The IMessage object - Recursion level (used for indenting) - A formatted string containing the names and values of the source object + The fully qualified path to the sound file. + True if the file is to be played continuously and false if it is should be played once. + - + - A custom decoder callback + This command is used to stop the audio render process. - The key of the object - the data to decode - A string represending the fieldData + The fully qualified path to the sound file issued in the start render command. + - + - Access to the data server which allows searching for land, events, people, etc + This is used to ‘end’ an established session (i.e. hang-up or disconnect). + Handle returned from successful Session ‘create’ request or a SessionNewEvent + - - The event subscribers. null if no subcribers + + + Set the combined speaking and listening position in 3D space. + + Handle returned from successful Session ‘create’ request or a SessionNewEvent + Speaking position + Listening position + - - Raises the EventInfoReply event - An EventInfoReplyEventArgs object containing the - data returned from the data server + + + Set User Volume for a particular user. Does not affect how other users hear that user. + + Handle returned from successful Session ‘create’ request or a SessionNewEvent + + The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume + - - Thread sync lock object + + + This is used to get a list of audio devices that can be used for capture (input) of voice. + + - - The event subscribers. null if no subcribers + + + This is used to get a list of audio devices that can be used for render (playback) of voice. + - - Raises the DirEventsReply event - An DirEventsReplyEventArgs object containing the - data returned from the data server + + + This command is used to select the render device. + + The name of the device as returned by the Aux.GetRenderDevices command. - - Thread sync lock object + + + This command is used to select the capture device. + + The name of the device as returned by the Aux.GetCaptureDevices command. - - The event subscribers. null if no subcribers + + + This command is used to start the audio capture process which will cause + AuxAudioProperty Events to be raised. These events can be used to display a + microphone VU meter for the currently selected capture device. This command + should not be issued if the user is on a call. + + (unused but required) + - - Raises the PlacesReply event - A PlacesReplyEventArgs object containing the - data returned from the data server + + + This command is used to stop the audio capture process. + + - - Thread sync lock object + + + This command is used to set the mic volume while in the audio tuning process. + Once an acceptable mic level is attained, the application must issue a + connector set mic volume command to have that level be used while on voice + calls. + + the microphone volume (-100 to 100 inclusive) + - - The event subscribers. null if no subcribers + + + This command is used to set the speaker volume while in the audio tuning + process. Once an acceptable speaker level is attained, the application must + issue a connector set speaker volume command to have that level be used while + on voice calls. + + the speaker volume (-100 to 100 inclusive) + - - Raises the DirPlacesReply event - A DirPlacesReplyEventArgs object containing the - data returned from the data server + + + Start up the Voice service. + - - Thread sync lock object + + + Handle miscellaneous request status + + + + ///If something goes wrong, we log it. - - The event subscribers. null if no subcribers + + + Cleanup oject resources + - - Raises the DirClassifiedsReply event - A DirClassifiedsReplyEventArgs object containing the - data returned from the data server + + + Request voice cap when changing regions + - - Thread sync lock object + + + Handle a change in session state + - - The event subscribers. null if no subcribers + + + Close a voice session + + - - Raises the DirGroupsReply event - A DirGroupsReplyEventArgs object containing the - data returned from the data server + + + Locate a Session context from its handle + + Creates the session context if it does not exist. - - Thread sync lock object + + + Handle completion of main voice cap request. + + + + - - The event subscribers. null if no subcribers + + + Daemon has started so connect to it. + - - Raises the DirPeopleReply event - A DirPeopleReplyEventArgs object containing the - data returned from the data server + + + The daemon TCP connection is open. + - - 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 + Handle creation of the Connector. - 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 + Handle response to audio output device query - 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 + Handle response to audio input device query - 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) + + + Set voice channel for new parcel + - The event is raised when a response is received from the simulator + + + + Request info from a parcel capability Uri. - 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 + Receive parcel voice cap - 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 + Tell Vivox where we are standing - 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. + This has to be called when we move or turn. - + - Starts a search for land sales using the directory - - The event is raised when a response is received from the simulator + Start and stop updating out position. - 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 + This is used to initialize and stop the Connector as a whole. The Connector + Create call must be completed successfully before any other requests are made + (typically during application initialization). The shutdown should be called + when the application is shutting down to gracefully release resources - - 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); - + A string value indicting the Application name + URL for the management server + LoggingSettings + + - + - Search for Groups + Shutdown Connector -- Should be called when the application is shutting down + to gracefully release resources - The name or portion of the name of the group you wish to search for - Start from the match number - + Handle returned from successful Connector ‘create’ request - + - Search for Groups + Mute or unmute the microphone - The name or portion of the name of the group you wish to search for - Start from the match number - Search flags - + Handle returned from successful Connector ‘create’ request + true (mute) or false (unmute) - + - Search the People directory for other avatars + Mute or unmute the speaker - The name or portion of the name of the avatar you wish to search for - - + Handle returned from successful Connector ‘create’ request + true (mute) or false (unmute) - + - Search Places for parcels of land you personally own + Set microphone volume + Handle returned from successful Connector ‘create’ request + The level of the audio, a number between -100 and 100 where + 0 represents ‘normal’ speaking volume - + - Searches Places for land owned by the specified group + Set local speaker volume - 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. + Handle returned from successful Connector ‘create’ request + The level of the audio, a number between -100 and 100 where + 0 represents ‘normal’ speaking volume - + - Search the Places directory for parcels that are listed in search and contain the specified keywords + This is used to login a specific user account(s). It may only be called after + Connector initialization has completed successfully - A string containing the keywords to search for - Transaction (Query) ID which can be associated with results from your request. + Handle returned from successful Connector ‘create’ request + User's account name + User's account password + Values may be “AutoAnswer” or “VerifyAnswer” + "" + This is an integer that specifies how often + the daemon will send participant property events while in a channel. If this is not set + the default will be “on state change”, which means that the events will be sent when + the participant starts talking, stops talking, is muted, is unmuted. + The valid values are: + 0 – Never + 5 – 10 times per second + 10 – 5 times per second + 50 – 1 time per second + 100 – on participant state change (this is the default) + false + - + - Search Places - All Options + This is used to logout a user session. It should only be called with a valid AccountHandle. - 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. + Handle returned from successful Connector ‘login’ request + - + - Search All Events with specifid searchText in all categories, includes PG, Mature and Adult + Event for most mundane request reposnses. - 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. + + Response to Connector.Create request - - Requests Event Details - ID of Event returned from the method + + Response to Aux.GetCaptureDevices request - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Response to Aux.GetRenderDevices request - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Audio Properties Events are sent after audio capture is started. + These events are used to display a microphone VU meter - - Process an incoming event message - The Unique Capabilities Key - The event message containing the data - The simulator the message originated from + + Response to Account.Login request - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + This event message is sent whenever the login state of the + particular Account has transitioned from one value to another - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + List of audio input devices + - - Process an incoming event message - The Unique Capabilities Key - The event message containing the data - The simulator the message originated from + + + List of audio output devices + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Set audio test mode + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Enable logging - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + The folder where any logs will be created - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + This will be prepended to beginning of each log file - - Raised when the data server responds to a request. + + The suffix or extension to be appended to each log file - - Raised when the data server responds to a request. + + + 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 + - - Raised when the data server responds to a request. + + + Constructor for default logging settings + - - Raised when the data server responds to a request. + + Audio Properties Events are sent after audio capture is started. These events are used to display a microphone VU meter - - Raised when the data server responds to a request. + + Positional vector of the users position - - Raised when the data server responds to a request. + + Velocity vector of the position - - Raised when the data server responds to a request. + + At Orientation (X axis) of the position - - Raised when the data server responds to a request. + + Up Orientation (Y axis) of the position - - Classified Ad categories + + Left Orientation (Z axis) of the position - - Classified is listed in the Any category + + + Represents a string of characters encoded with specific formatting properties + - - Classified is shopping related + + + Base class for all Asset types + - - Classified is + + A byte array containing the raw asset data - - + + True if the asset it only stored on the server temporarily - - + + A unique ID - - + + + Construct a new Asset object + - - + + + Construct a new Asset object + + A unique specific to this asset + A byte array containing the raw asset data - - + + + Regenerates the AssetData byte array from the properties + of the derived class. + - - + + + Decodes the AssetData, placing it in appropriate properties of the derived + class. + + True if the asset decoding succeeded, otherwise false - - + + The assets unique ID - - Event Categories + + + The "type" of asset, Notecard, Animation, etc + - - + + 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 - - - - - - - - - - - - - - - - + - 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 + + 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 - - Query the Groups database + + The event subscribers, null of no subscribers - - Query the Events database + + Raises the AttachedSoundGainChange Event + A AttachedSoundGainChangeEventArgs object containing + the data sent from the simulator - - Query the land holdings database for land owned by the currently connected agent + + Thread sync lock object - - + + The event subscribers, null of no subscribers - - Query the land holdings database for land which is owned by a Group + + Raises the SoundTrigger Event + A SoundTriggerEventArgs object containing + the data sent from the simulator - - Specifies the query should pre sort the results based upon traffic - when searching the Places database + + 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 - - 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 + + + Plays a sound in the current region at full volume from avatar position + + UUID of the sound to be played - - 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 + + + 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. - - 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 + + + 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 - - 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 + + + 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 - - 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 + + + 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 - - 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 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - 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 + + 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 - - Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases + + Raised when the simulator sends us data containing + sound - - Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases + + Raised when the simulator sends us data containing + ... - - Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases + + 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 ... + } + + + + - Land types to search dataserver for + 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 - - Search Auction, Mainland and Estate - - - Land which is currently up for auction + + Simulator where the event originated - - Parcels which are on the mainland (Linden owned) continents + + Get the sound asset id - - Parcels which are on privately owned simulators + + Get the ID of the owner - - - The content rating of the event - + + Get the ID of the Object - - Event is PG + + Get the volume level - - Event is Mature + + Get the - - Event is Adult + + Provides data for the event + The event occurs when an attached sound + changes its volume level - + - Classified Ad Options + Construct a new instance of the AttachedSoundGainChangedEventArgs class - There appear to be two formats the flags are packed in. - This set of flags is for the newer style + 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); + } + + - + - Classified ad query options + 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 - - Include all ads in results - - - Include PG ads in results + + Simulator where the event originated - - Include Mature ads in results + + Get the sound asset id - - Include Adult ads in results + + Get the ID of the owner - - - The For Sale flag in PlacesReplyData - + + Get the ID of the Object - - Parcel is not listed for sale + + Get the ID of the objects parent - - Parcel is For Sale + + Get the volume level - - - A classified ad on the grid - + + Get the regionhandle - - UUID for this ad, useful for looking up detailed - information about it + + Get the source position - - The title of this classified ad + + 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") + } + + - - Flags that show certain options applied to the classified + + + 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 - - Creation date of the ad + + Simulator where the event originated - - Expiration date of the ad + + Get the sound asset id - - Price that was paid for this ad + + Get the ID of the owner - - Print the struct data as a string - A string containing the field name, and field value + + Get the ID of the Object - + - A parcel retrieved from the dataserver such as results from the - "For-Sale" listings or "Places" Search + Capabilities is the name of the bi-directional HTTP REST protocol + used to communicate non real-time transactions such as teleporting or + group messaging - - 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 + + Reference to the simulator this system is connected to - - The size of the parcel - This field is not returned for Places searches + + + Default constructor + + + - - The price of the parcel - This field is not returned for Places searches + + + Request the URI of a named capability + + Name of the capability to request + The URI of the requested capability, or String.Empty if + the capability does not exist - - If True, this parcel is flagged to be auctioned + + + Process any incoming events, check to see if we have a message created for the event, + + + - - If true, this parcel is currently set for sale + + Capabilities URI this system was initialized with - - Parcel traffic + + Whether the capabilities event queue is connected and + listening for incoming events - - Print the struct data as a string - A string containing the field name, and field value + + + Triggered when an event is received via the EventQueueGet + capability + + Event name + Decoded event data + The simulator that generated the event - + - An Avatar returned from the dataserver + Manager class for our own avatar - - Online status of agent - This field appears to be obsolete and always returns false + + The event subscribers. null if no subcribers - - The agents first name + + Raises the ChatFromSimulator event + A ChatEventArgs object containing the + data returned from the data server - - The agents last name + + Thread sync lock object - - The agents + + The event subscribers. null if no subcribers - - Print the struct data as a string - A string containing the field name, and field value + + Raises the ScriptDialog event + A SctriptDialogEventArgs object containing the + data returned from the data server - - - Response to a "Groups" Search - + + Thread sync lock object - - The Group ID + + The event subscribers. null if no subcribers - - The name of the group + + Raises the ScriptQuestion event + A ScriptQuestionEventArgs object containing the + data returned from the data server - - The current number of members + + Thread sync lock object - - Print the struct data as a string - A string containing the field name, and field value + + The event subscribers. null if no subcribers - - - 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 + + Raises the LoadURL event + A LoadUrlEventArgs object containing the + data returned from the data server - - The name + + Thread sync lock object - - The description + + The event subscribers. null if no subcribers - - The Size of the parcel + + Raises the MoneyBalance event + A BalanceEventArgs object containing the + data returned from the data server - - 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 + + Thread sync lock object - - Indicates the ForSale status of the parcel + + The event subscribers. null if no subcribers - - The Gridwide X position + + Raises the MoneyBalanceReply event + A MoneyBalanceReplyEventArgs object containing the + data returned from the data server - - The Gridwide Y position + + Thread sync lock object - - The Z position of the parcel, or 0 if no landing point set + + The event subscribers. null if no subcribers - - The name of the Region the parcel is located in + + Raises the IM event + A InstantMessageEventArgs object containing the + data returned from the data server - - The Asset ID of the parcels Snapshot texture + + Thread sync lock object - - The calculated visitor traffic + + The event subscribers. null if no subcribers - - The billing product SKU - Known values are: - - 023Mainland / Full Region - 024Estate / Full Region - 027Estate / Openspace - 029Estate / Homestead - 129Mainland / Homestead (Linden Owned) - - + + Raises the TeleportProgress event + A TeleportEventArgs object containing the + data returned from the data server - - No longer used, will always be 0 + + Thread sync lock object - - Get a SL URL for the parcel - A string, containing a standard SLURL + + The event subscribers. null if no subcribers - - Print the struct data as a string - A string containing the field name, and field value + + Raises the AgentDataReply event + A AgentDataReplyEventArgs object containing the + data returned from the data server - - - An "Event" Listing summary - + + Thread sync lock object - - The ID of the event creator + + The event subscribers. null if no subcribers - - The name of the event + + Raises the AnimationsChanged event + A AnimationsChangedEventArgs object containing the + data returned from the data server - - The events ID + + Thread sync lock object - - A string containing the short date/time the event will begin + + The event subscribers. null if no subcribers - - The event start time in Unixtime (seconds since epoch) + + Raises the MeanCollision event + A MeanCollisionEventArgs object containing the + data returned from the data server - - The events maturity rating + + Thread sync lock object - - Print the struct data as a string - A string containing the field name, and field value + + The event subscribers. null if no subcribers - - - The details of an "Event" - + + Raises the RegionCrossed event + A RegionCrossedEventArgs object containing the + data returned from the data server - - The events ID + + Thread sync lock object - - The ID of the event creator + + The event subscribers. null if no subcribers - - The name of the event + + Raises the GroupChatJoined event + A GroupChatJoinedEventArgs object containing the + data returned from the data server - - The category + + Thread sync lock object - - The events description + + The event subscribers. null if no subcribers - - The short date/time the event will begin + + Raises the AlertMessage event + A AlertMessageEventArgs object containing the + data returned from the data server - - The event start time in Unixtime (seconds since epoch) UTC adjusted + + Thread sync lock object - - The length of the event in minutes + + The event subscribers. null if no subcribers - - 0 if no cover charge applies + + Raises the ScriptControlChange event + A ScriptControlEventArgs object containing the + data returned from the data server - - The cover charge amount in L$ if applicable + + Thread sync lock object - - The name of the region where the event is being held + + The event subscribers. null if no subcribers - - The gridwide location of the event + + Raises the CameraConstraint event + A CameraConstraintEventArgs object containing the + data returned from the data server - - The maturity rating + + Thread sync lock object - - Get a SL URL for the parcel where the event is hosted - A string, containing a standard SLURL + + The event subscribers. null if no subcribers - - Print the struct data as a string - A string containing the field name, and field value + + Raises the ScriptSensorReply event + A ScriptSensorReplyEventArgs object containing the + data returned from the data server - - Contains the Event data returned from the data server from an EventInfoRequest + + Thread sync lock object - - Construct a new instance of the EventInfoReplyEventArgs class - A single EventInfo object containing the details of an event + + The event subscribers. null if no subcribers - - - A single EventInfo object containing the details of an event - + + Raises the AvatarSitResponse event + A AvatarSitResponseEventArgs object containing the + data returned from the data server - - Contains the "Event" detail data returned from the data server + + Thread sync lock object - - 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 event subscribers. null if no subcribers - - The ID returned by + + Raises the ChatSessionMemberAdded event + A ChatSessionMemberAddedEventArgs object containing the + data returned from the data server - - 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 + + Thread sync lock object - - A list containing Places data returned by the data server + + The event subscribers. null if no subcribers - - Contains the classified data returned from the data server + + Raises the ChatSessionMemberLeft event + A ChatSessionMemberLeftEventArgs object containing the + 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 + + Thread sync lock object - - A list containing Classified Ads returned by the data server + + The event subscribers, null of no subscribers - - Contains the group data returned from the data server + + Raises the SetDisplayNameReply Event + A SetDisplayNameReplyEventArgs object containing + the data sent from the simulator - - 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 + + Thread sync lock object - - The ID returned by + + The event subscribers. null if no subcribers - - A list containing Groups data returned by the data server + + Raises the MuteListUpdated event + A EventArgs object containing the + data returned from the data server - - Contains the people data returned from the data server + + Thread sync lock object - - 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 + + Reference to the GridClient instance - - The ID returned by + + Used for movement and camera tracking - - A list containing People data returned by the data server + + Currently playing animations for the agent. Can be used to + check the current movement status such as walking, hovering, aiming, + etc. by checking against system animations found in the Animations class - - Contains the land sales data returned from the data server + + Dictionary containing current Group Chat sessions and members - - Construct a new instance of the DirLandReplyEventArgs class - A list of parcels for sale returned by the data server + + Dictionary containing mute list keyead on mute name and key - - A list containing land forsale data returned by the data server + + Various abilities and preferences sent by the grid - + - Sent to the client to indicate a teleport request has completed + Constructor, setup callbacks for packets related to our avatar + A reference to the Class - + - Interface requirements for Messaging system + Send a text message from the Agent to the Simulator + A containing the message + The channel to send the message on, 0 is the public channel. Channels above 0 + can be used however only scripts listening on the specified channel will see the message + Denotes the type of message being sent, shout, whisper, etc. - - The of the agent - - - - - - The simulators handle the agent teleported to - - - A Uri which contains a list of Capabilities the simulator supports - - - Indicates the level of access required - to access the simulator, or the content rating, or the simulators - map status - - - The IP Address of the simulator - - - The UDP Port the simulator will listen for UDP traffic on - - - Status flags indicating the state of the Agent upon arrival, Flying, etc. - - + - Serialize the object + Request any instant messages sent while the client was offline to be resent. - An containing the objects data - + - Deserialize the message + Send an Instant Message to another Avatar - An containing the data + The recipients + A containing the message to send - + - Sent to the viewer when a neighboring simulator is requesting the agent make a connection to it. + Send an Instant Message to an existing group chat or conference chat + The recipients + A containing the message to send + IM session ID (to differentiate between IM windows) - + - Serialize the object + Send an Instant Message - An containing the objects data + The name this IM will show up as being from + Key of Avatar + Text message being sent + IM session ID (to differentiate between IM windows) + IDs of sessions for a conference - + - Deserialize the message + Send an Instant Message - An containing the data + The name this IM will show up as being from + Key of Avatar + Text message being sent + IM session ID (to differentiate between IM windows) + Type of instant message to send + Whether to IM offline avatars as well + Senders Position + RegionID Sender is In + Packed binary data that is specific to + the dialog type - + - Serialize the object + Send an Instant Message to a group - An containing the objects data + of the group to send message to + Text Message being sent. - + - Deserialize the message + Send an Instant Message to a group the agent is a member of - An containing the data + The name this IM will show up as being from + of the group to send message to + Text message being sent - + - Serialize the object + Send a request to join a group chat session - An containing the objects data + of Group to leave - + - Deserialize the message + Exit a group chat session. This will stop further Group chat messages + from being sent until session is rejoined. - An containing the data + of Group chat session to leave - + - A message sent to the client which indicates a teleport request has failed - and contains some information on why it failed + Reply to script dialog questions. + Channel initial request came on + Index of button you're "clicking" + Label of button you're "clicking" + of Object that sent the dialog request + - - - - - A string key of the reason the teleport failed e.g. CouldntTPCloser - Which could be used to look up a value in a dictionary or enum - - - The of the Agent - - - A string human readable message containing the reason - An example: Could not teleport closer to destination - - + - Serialize the object + Accept invite for to a chatterbox session - An containing the objects data + of session to accept invite to - + - Deserialize the message + Start a friends conference - An containing the data + List of UUIDs to start a conference with + the temportary session ID returned in the callback> - + - Serialize the object + Start a particle stream between an agent and an object - An containing the objects data + Key of the source agent + Key of the target object + + The type from the enum + A unique for this effect - + - Deserialize the message + Start a particle stream between an agent and an object - An containing the data + Key of the source agent + Key of the target object + A representing the beams offset from the source + A which sets the avatars lookat animation + of the Effect - + - Contains a list of prim owner information for a specific parcel in a simulator + Create a particle beam between an avatar and an primitive - - A Simulator will always return at least 1 entry - If agent does not have proper permission the OwnerID will be UUID.Zero - If agent does not have proper permission OR there are no primitives on parcel - the DataBlocksExtended map will not be sent from the simulator - - - - An Array of objects + The ID of source avatar + The ID of the target primitive + global offset + A object containing the combined red, green, blue and alpha + color values of particle beam + a float representing the duration the parcicle beam will last + A Unique ID for the beam + - + - Serialize the object + Create a particle swirl around a target position using a packet - An containing the objects data + global offset + A object containing the combined red, green, blue and alpha + color values of particle beam + a float representing the duration the parcicle beam will last + A Unique ID for the beam - + - Deserialize the message + Sends a request to sit on the specified object - An containing the data + of the object to sit on + Sit at offset - + - Prim ownership information for a specified owner on a single parcel + Follows a call to to actually sit on the object - - The of the prim owner, - UUID.Zero if agent has no permission to view prim owner information + + Stands up from sitting on a prim or the ground + true of AgentUpdate was sent - - The total number of prims + + + Does a "ground sit" at the avatar's current position + - - True if the OwnerID is a + + + Starts or stops flying + + True to start flying, false to stop flying - - True if the owner is online - This is no longer used by the LL Simulators + + + Starts or stops crouching + + True to start crouching, false to stop crouching - - The date the most recent prim was rezzed + + + Starts a jump (begin holding the jump key) + - + - The details of a single parcel in a region, also contains some regionwide globals + Use the autopilot sim function to move the avatar to a new + position. Uses double precision to get precise movements + The z value is currently not handled properly by the simulator + Global X coordinate to move to + Global Y coordinate to move to + Z coordinate to move to - - Simulator-local ID of this parcel + + + Use the autopilot sim function to move the avatar to a new position + + The z value is currently not handled properly by the simulator + Integer value for the global X coordinate to move to + Integer value for the global Y coordinate to move to + Floating-point value for the Z coordinate to move to - - Maximum corner of the axis-aligned bounding box for this - parcel + + + Use the autopilot sim function to move the avatar to a new position + + The z value is currently not handled properly by the simulator + Integer value for the local X coordinate to move to + Integer value for the local Y coordinate to move to + Floating-point value for the Z coordinate to move to - - Minimum corner of the axis-aligned bounding box for this - parcel + + Macro to cancel autopilot sim function + Not certain if this is how it is really done + true if control flags were set and AgentUpdate was sent to the simulator - - Total parcel land area + + + Grabs an object + + an unsigned integer of the objects ID within the simulator + - - + + + Overload: Grab a simulated object + + an unsigned integer of the objects ID within the simulator + + The texture coordinates to grab + The surface coordinates to grab + The face of the position to grab + The region coordinates of the position to grab + The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + The surface binormal of the position to grab (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space - - Key of authorized buyer + + + Drag an object + + of the object to drag + Drag target in region coordinates - - Bitmap describing land layout in 4x4m squares across the - entire region + + + Overload: Drag an object + + of the object to drag + Drag target in region coordinates + + The texture coordinates to grab + The surface coordinates to grab + The face of the position to grab + The region coordinates of the position to grab + The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + The surface binormal of the position to grab (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space - - + + + Release a grabbed object + + The Objects Simulator Local ID + + + - - Date land was claimed + + + Release a grabbed object + + The Objects Simulator Local ID + The texture coordinates to grab + The surface coordinates to grab + The face of the position to grab + The region coordinates of the position to grab + The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + The surface binormal of the position to grab (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space - - Appears to always be zero + + + Touches an object + + an unsigned integer of the objects ID within the simulator + - - Parcel Description + + + Request the current L$ balance + - - + + + Give Money to destination Avatar + + UUID of the Target Avatar + Amount in L$ - - + + + Give Money to destination Avatar + + UUID of the Target Avatar + Amount in L$ + Description that will show up in the + recipients transaction history - - Total number of primitives owned by the parcel group on - this parcel + + + Give L$ to an object + + object to give money to + amount of L$ to give + name of object - - Whether the land is deeded to a group or not + + + Give L$ to a group + + group to give money to + amount of L$ to give - - + + + Give L$ to a group + + group to give money to + amount of L$ to give + description of transaction - - Maximum number of primitives this parcel supports + + + Pay texture/animation upload fee + - - The Asset UUID of the Texture which when applied to a - primitive will display the media + + + Pay texture/animation upload fee + + description of the transaction - - A URL which points to any Quicktime supported media type + + + Give Money to destination Object or Avatar + + UUID of the Target Object/Avatar + Amount in L$ + Reason (Optional normally) + The type of transaction + Transaction flags, mostly for identifying group + transactions - - A byte, if 0x1 viewer should auto scale media to fit object + + + Plays a gesture + + Asset of the gesture - - URL For Music Stream + + + Mark gesture active + + Inventory of the gesture + Asset of the gesture - - Parcel Name + + + Mark gesture inactive + + Inventory of the gesture - - Autoreturn value in minutes for others' objects + + + Send an AgentAnimation packet that toggles a single animation on + + The of the animation to start playing + Whether to ensure delivery of this packet or not - - + + + Send an AgentAnimation packet that toggles a single animation off + + The of a + currently playing animation to stop playing + Whether to ensure delivery of this packet or not - - Total number of other primitives on this parcel + + + Send an AgentAnimation packet that will toggle animations on or off + + A list of animation s, and whether to + turn that animation on or off + Whether to ensure delivery of this packet or not - - UUID of the owner of this parcel + + + Teleports agent to their stored home location + + true on successful teleport to home location - - Total number of primitives owned by the parcel owner on - this parcel + + + Teleport agent to a landmark + + of the landmark to teleport agent to + true on success, false on failure - - + + + Attempt to look up a simulator name and teleport to the discovered + destination + + Region name to look up + Position to teleport to + True if the lookup and teleport were successful, otherwise + false - - How long is pass valid for + + + Attempt to look up a simulator name and teleport to the discovered + destination + + Region name to look up + Position to teleport to + Target to look at + True if the lookup and teleport were successful, otherwise + false - - Price for a temporary pass + + + Teleport agent to another region + + handle of region to teleport agent to + position in destination sim to teleport to + true on success, false on failure + This call is blocking - - + + + Teleport agent to another region + + handle of region to teleport agent to + position in destination sim to teleport to + direction in destination sim agent will look at + true on success, false on failure + This call is blocking - - + + + Request teleport to a another simulator + + handle of region to teleport agent to + position in destination sim to teleport to - - + + + Request teleport to a another simulator + + handle of region to teleport agent to + position in destination sim to teleport to + direction in destination sim agent will look at - - + + + Teleport agent to a landmark + + of the landmark to teleport agent to - - True if the region denies access to age unverified users + + + Send a teleport lure to another avatar with default "Join me in ..." invitation message + + target avatars to lure - - + + + Send a teleport lure to another avatar with custom invitation message + + target avatars to lure + custom message to send with invitation - - This field is no longer used + + + Respond to a teleport lure by either accepting it and initiating + the teleport, or denying it + + of the avatar sending the lure + IM session of the incoming lure request + true to accept the lure, false to decline it - - The result of a request for parcel properties + + + Update agent profile + + struct containing updated + profile information - - 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 + + + Update agents profile interests + + selection of interests from struct - + - Number of primitives your avatar is currently - selecting and sitting on in this parcel + Set the height and the width of the client window. This is used + by the server to build a virtual camera frustum for our avatar + New height of the viewer window + New width of the viewer window - - + + + Request the list of muted objects and avatars for this agent + - + - A number which increments by 1, starting at 0 for each ParcelProperties request. - Can be overriden by specifying the sequenceID with the ParcelPropertiesRequest being sent. - a Negative number indicates the action in has occurred. + Mute an object, resident, etc. + Mute type + Mute UUID + Mute name - - Maximum primitives across the entire simulator + + + Mute an object, resident, etc. + + Mute type + Mute UUID + Mute name + Mute flags - - Total primitives across the entire simulator + + + Unmute an object, resident, etc. + + Mute UUID + Mute name - - + + + Sets home location to agents current position + + will fire an AlertMessage () with + success or failure message - - Key of parcel snapshot + + + Move an agent in to a simulator. This packet is the last packet + needed to complete the transition in to a new simulator + + Object - - Parcel ownership status + + + Reply to script permissions request + + Object + of the itemID requesting permissions + of the taskID requesting permissions + list of permissions to allow - - Total number of primitives on this parcel + + + Respond to a group invitation by either accepting or denying it + + UUID of the group (sent in the AgentID field of the invite message) + IM Session ID from the group invitation message + Accept the group invitation or deny it - - - - - - - - A description of the media - - - An Integer which represents the height of the media - - - An integer which represents the width of the media - - - A boolean, if true the viewer should loop the media - - - A string which contains the mime type of the media - - - true to obscure (hide) media url - - - true to obscure (hide) music url - - + - Serialize the object + Requests script detection of objects and avatars - An containing the objects data + name of the object/avatar to search for + UUID of the object or avatar to search for + Type of search from ScriptSensorTypeFlags + range of scan (96 max?) + the arc in radians to search within + an user generated ID to correlate replies with + Simulator to perform search in - + - Deserialize the message + Create or update profile pick - An containing the data - - - A message sent from the viewer to the simulator to updated a specific parcels settings - - - The of the agent authorized to purchase this - parcel of land or a NULL if the sale is authorized to anyone - - - true to enable auto scaling of the parcel media - - - The category of this parcel used when search is enabled to restrict - search results - - - A string containing the description to set - - - The of the which allows for additional - powers and restrictions. - - - The which specifies how avatars which teleport - to this parcel are handled - - - The LocalID of the parcel to update settings on - - - A string containing the description of the media which can be played - to visitors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + UUID of the pick to update, or random UUID to create a new pick + Is this a top pick? (typically false) + UUID of the parcel (UUID.Zero for the current parcel) + Name of the pick + Global position of the pick landmark + UUID of the image displayed with the pick + Long description of the pick - + - Deserialize the message + Delete profile pick - An containing the data + UUID of the pick to delete - + - Serialize the object + Create or update profile Classified - An containing the objects data - - - Base class used for the RemoteParcelRequest message + UUID of the classified to update, or random UUID to create a new classified + Defines what catagory the classified is in + UUID of the image displayed with the classified + Price that the classified will cost to place for a week + Global position of the classified landmark + Name of the classified + Long description of the classified + if true, auto renew classified after expiration - + - A message sent from the viewer to the simulator to request information - on a remote parcel + Create or update profile Classified + UUID of the classified to update, or random UUID to create a new classified + Defines what catagory the classified is in + UUID of the image displayed with the classified + Price that the classified will cost to place for a week + Name of the classified + Long description of the classified + if true, auto renew classified after expiration - - Local sim position of the parcel we are looking up - - - Region handle of the parcel we are looking up - - - Region of the parcel we are looking up - - + - Serialize the object + Delete a classified ad - An containing the objects data + The classified ads ID - + - Deserialize the message + Fetches resource usage by agents attachmetns - An containing the data + Called when the requested information is collected - + - A message sent from the simulator to the viewer in response to a - which will contain parcel information + Initates request to set a new display name + Previous display name + Desired new display name - - The grid-wide unique parcel ID - - + - Serialize the object + Tells the sim what UI language is used, and if it's ok to share that with scripts - An containing the objects data + Two letter language code + Share language info with scripts - + - Deserialize the message + Take an incoming ImprovedInstantMessage packet, auto-parse, and if + OnInstantMessage is defined call that with the appropriate arguments - An containing the data + The sender + The EventArgs object containing the packet data - + - A message containing a request for a remote parcel from a viewer, or a response - from the simulator to that request + Take an incoming Chat packet, auto-parse, and if OnChat is defined call + that with the appropriate arguments. + The sender + The EventArgs object containing the packet data - - The request or response details block - - + - Serialize the object + Used for parsing llDialogs - An containing the objects data + The sender + The EventArgs object containing the packet data - + - Deserialize the message + Used for parsing llRequestPermissions dialogs - An containing the data + The sender + The EventArgs object containing the packet data - + - Serialize the object + Handles Script Control changes when Script with permissions releases or takes a control - An containing the objects data + The sender + The EventArgs object containing the packet data - + - Deserialize the message + Used for parsing llLoadURL Dialogs - An containing the data + The sender + The EventArgs object containing the packet data - + - Serialize the object + Update client's Position, LookAt and region handle from incoming packet - An containing the objects data + The sender + The EventArgs object containing the packet data + This occurs when after an avatar moves into a new sim - - - Deserialize the message - - An containing the data - - - - A message sent from the simulator to an agent which contains - the groups the agent is in - - - - The Agent receiving the message + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - An array containing information - for each the agent is a member of + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - An array containing information - for each the agent is a member of + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Serialize the object + EQ Message fired with the result of SetDisplayName request - An containing the objects data + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - + - Deserialize the message + Process TeleportFailed message sent via EventQueue, informs agent its last teleport has failed and why. - An containing the data - - - Group Details specific to the agent - - - true of the agent accepts group notices - - - The agents tier contribution to the group - - - The Groups - - - The of the groups insignia + The Message Key + An IMessage object Deserialized from the recieved message event + The simulator originating the event message - - The name of the group + + + Process TeleportFinish from Event Queue and pass it onto our TeleportHandler + + The message system key for this event + IMessage object containing decoded data from OSD + The simulator originating the event message - - The aggregate permissions the agent has in the group for all roles the agent - is assigned + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - An optional block containing additional agent specific information + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - true of the agent allows this group to be - listed in their profile + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - A message sent from the viewer to the simulator which - specifies the language and permissions for others to detect - the language specified + Crossed region handler for message that comes across the EventQueue. Sent to an agent + when the agent crosses a sim border into a new region. + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - - A string containng the default language - to use for the agent - - - true of others are allowed to - know the language setting + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + This packet is now being sent via the EventQueue - + - Serialize the object + Group Chat event handler - An containing the objects data + The capability Key + IMessage object containing decoded data from OSD + - + - Deserialize the message + Response from request to join a group chat - An containing the data + + IMessage object containing decoded data from OSD + - + - An EventQueue message sent from the simulator to an agent when the agent - leaves a group + Someone joined or left group chat + + IMessage object containing decoded data from OSD + - + - An Array containing the AgentID and GroupID + Handle a group chat Invitation + Caps Key + IMessage object containing decoded data from OSD + Originating Simulator - + - Serialize the object + Moderate a chat session - An containing the objects data + the of the session to moderate, for group chats this will be the groups UUID + the of the avatar to moderate + Either "voice" to moderate users voice, or "text" to moderate users text session + true to moderate (silence user), false to allow avatar to speak - - - Deserialize the message - - An containing the data + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - An object containing the Agents UUID, and the Groups UUID + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The ID of the Agent leaving the group + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The GroupID the Agent is leaving + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Base class for Asset uploads/results via Capabilities + + Raised when a scripted object or agent within range sends a public message - - - The request state - + + Raised when a scripted object sends a dialog box containing possible + options an agent can respond to - - - Serialize the object - - An containing the objects data + + Raised when an object requests a change in the permissions an agent has permitted - - - Deserialize the message - - An containing the data + + Raised when a script requests an agent open the specified URL - - - A message sent from the viewer to the simulator to request a temporary upload capability - which allows an asset to be uploaded - + + Raised when an agents currency balance is updated - - The Capability URL sent by the simulator to upload the baked texture to + + Raised when a transaction occurs involving currency such as a land purchase - - - A message sent from the simulator that will inform the agent the upload is complete, - and the UUID of the uploaded asset - + + 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 uploaded texture asset ID + + 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 - - - A message sent from the viewer to the simulator to request a temporary - capability URI which is used to upload an agents baked appearance textures - + + Raised when a simulator sends agent specific information for our avatar. - - Object containing request or response + + Raised when our agents animation playlist changes - - - Serialize the object - - An containing the objects data + + Raised when an object or avatar forcefully collides with our agent - - - Deserialize the message - - An containing the data + + Raised when our agent crosses a region border into another region - - - A message sent from the simulator which indicates the minimum version required for - using voice chat - + + Raised when our agent succeeds or fails to join a group chat session - - Major Version Required - - - Minor version required + + 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 name of the region sending the version requrements + + Raised when a script attempts to take or release specified controls for our agent - - - Serialize the object - - An containing the objects data + + Raised when the simulator detects our agent is trying to view something + beyond its limits - - - Deserialize the message - - An containing the data + + Raised when a script sensor reply is received from a simulator - - - A message sent from the simulator to the viewer containing the - voice server URI - + + Raised in response to a request - - The Parcel ID which the voice server URI applies + + Raised when an avatar enters a group chat session we are participating in - - The name of the region + + Raised when an agent exits a group chat session we are participating in - - A uri containing the server/channel information - which the viewer can utilize to participate in voice conversations + + Raised when the simulator sends us data containing + the details of display name change - - - Serialize the object - - An containing the objects data + + Raised when a scripted object or agent within range sends a public message - - - Deserialize the message - - An containing the data + + 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 - - - Serialize the object - - An containing the objects data + + Where the avatar started at login. Can be "last", "home" + or a login - - - Deserialize the message - - An containing the data + + The access level of this agent, usually M or PG - - - A message sent by the viewer to the simulator to request a temporary - capability for a script contained with in a Tasks inventory to be updated - + + The CollisionPlane of Agent - - Object containing request or response + + An representing the velocity of our agent - - - Serialize the object - - An containing the objects data + + An representing the acceleration of our agent - - - Deserialize the message - - An containing the data + + A which specifies the angular speed, and axis about which an Avatar is rotating. - - - A message sent from the simulator to the viewer to indicate - a Tasks scripts status. - + + Position avatar client will goto when login to 'home' or during + teleport request to 'home' region. - - The Asset ID of the script + + LookAt point saved/restored with HomePosition - - True of the script is compiled/ran using the mono interpreter, false indicates it - uses the older less efficient lsl2 interprter + + Avatar First Name (i.e. Philip) - - The Task containing the scripts + + Avatar Last Name (i.e. Linden) - - true of the script is in a running state + + Avatar Full Name (i.e. Philip Linden) - - - Serialize the object - - An containing the objects data + + Gets the health of the agent - - - Deserialize the message - - An containing the data + + Gets the current balance of the agent - - - A message containing the request/response used for updating a gesture - contained with an agents inventory - + + Gets the local ID of the prim the agent is sitting on, + zero if the avatar is not currently sitting - - Object containing request or response + + Gets the of the agents active group. - - - Serialize the object - - An containing the objects data + + Gets the Agents powers in the currently active group - - - Deserialize the message - - An containing the data + + Current status message for teleporting - - - A message request/response which is used to update a notecard contained within - a tasks inventory - + + Current position of the agent as a relative offset from + the simulator, or the parent object if we are sitting on something - - The of the Task containing the notecard asset to update + + Current rotation of the agent as a relative rotation from + the simulator, or the parent object if we are sitting on something - - The notecard assets contained in the tasks inventory + + Current position of the agent in the simulator - + - Serialize the object + A representing the agents current rotation - An containing the objects data - - - Deserialize the message - - An containing the data + + Returns the global grid position of the avatar - + - A reusable class containing a message sent from the viewer to the simulator to request a temporary uploader capability - which is used to update an asset in an agents inventory + Used to specify movement actions for your agent - - - The Notecard AssetID to replace - + + Empty flag - - - Serialize the object - - An containing the objects data + + Move Forward (SL Keybinding: W/Up Arrow) - - - Deserialize the message - - An containing the data + + Move Backward (SL Keybinding: S/Down Arrow) - - - A message containing the request/response used for updating a notecard - contained with an agents inventory - + + Move Left (SL Keybinding: Shift-(A/Left Arrow)) - - Object containing request or response + + Move Right (SL Keybinding: Shift-(D/Right Arrow)) - - - Serialize the object - - An containing the objects data + + Not Flying: Jump/Flying: Move Up (SL Keybinding: E) - - - Deserialize the message - - An containing the data + + Not Flying: Croutch/Flying: Move Down (SL Keybinding: C) - - - Serialize the object - - An containing the objects data + + Unused - - - Deserialize the message - - An containing the data + + Unused - - - A message sent from the simulator to the viewer which indicates - an error occurred while attempting to update a script in an agents or tasks - inventory - + + Unused - - true of the script was successfully compiled by the simulator + + Unused - - A string containing the error which occured while trying - to update the script + + ORed with AGENT_CONTROL_AT_* if the keyboard is being used - - A new AssetID assigned to the script + + ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used - - - A message sent from the viewer to the simulator - requesting the update of an existing script contained - within a tasks inventory - + + ORed with AGENT_CONTROL_UP_* if the keyboard is being used - - if true, set the script mode to running + + Fly - - The scripts InventoryItem ItemID to update + + - - A lowercase string containing either "mono" or "lsl2" which - specifies the script is compiled and ran on the mono runtime, or the older - lsl runtime + + Finish our current animation - - The tasks which contains the script to update + + Stand up from the ground or a prim seat - - - Serialize the object - - An containing the objects data + + Sit on the ground at our current location - - - Deserialize the message - - An containing the data + + Whether mouselook is currently enabled - - - A message containing either the request or response used in updating a script inside - a tasks inventory - + + Legacy, used if a key was pressed for less than a certain amount of time - - Object containing request or response + + Legacy, used if a key was pressed for less than a certain amount of time - - - Serialize the object - - An containing the objects data + + Legacy, used if a key was pressed for less than a certain amount of time - - - Deserialize the message - - An containing the data + + Legacy, used if a key was pressed for less than a certain amount of time - - - Response from the simulator to notify the viewer the upload is completed, and - the UUID of the script asset and its compiled status - + + Legacy, used if a key was pressed for less than a certain amount of time - - The uploaded texture asset ID + + Legacy, used if a key was pressed for less than a certain amount of time - - true of the script was compiled successfully + + - - - A message sent from a viewer to the simulator requesting a temporary uploader capability - used to update a script contained in an agents inventory - + + - - The existing asset if of the script in the agents inventory to replace + + Set when the avatar is idled or set to away. Note that the away animation is + activated separately from setting this flag - - The language of the script - Defaults to lsl version 2, "mono" might be another possible option + + - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - - A message containing either the request or response used in updating a script inside - an agents inventory - + + - - Object containing request or response + + + Agent movement and camera control + + Agent movement is controlled by setting specific + After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags + This is most easily accomplished by setting one or more of the AgentMovement properties + + Movement of an avatar is always based on a compass direction, for example AtPos will move the + agent from West to East or forward on the X Axis, AtNeg will of course move agent from + East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis + The Z axis is Up, finer grained control of movements can be done using the Nudge properties + - - - Serialize the object - - An containing the objects data + + Agent camera controls - - - Deserialize the message - - An containing the data + + Currently only used for hiding your group title - - - Serialize the object - - An containing the objects data + + Action state of the avatar, which can currently be + typing and editing - - - Deserialize the message - - An containing the data + + - - Base class for Map Layers via Capabilities + + - + - + + + + + + + + + + + + + + + + + + + + Timer for sending AgentUpdate packets + + + Default constructor + + - Serialize the object + Send an AgentUpdate with the camera set at the current agent + position and pointing towards the heading specified - An containing the objects data + Camera rotation in radians + Whether to send the AgentUpdate reliable + or not - + - Deserialize the message + Rotates the avatar body and camera toward a target position. + This will also anchor the camera position on the avatar - An containing the data + Region coordinates to turn toward - + - Sent by an agent to the capabilities server to request map layers + 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 - + - A message sent from the simulator to the viewer which contains an array of map images and their grid coordinates + Send new AgentUpdate packet to update our current camera + position and rotation - - An array containing LayerData items + + + Send new AgentUpdate packet to update our current camera + position and rotation + + Whether to require server acknowledgement + of this packet - + - Serialize the object + Send new AgentUpdate packet to update our current camera + position and rotation - An containing the objects data + Whether to require server acknowledgement + of this packet + Simulator to send the update to - + - Deserialize the message + Builds an AgentUpdate packet entirely from parameters. This + will not touch the state of Self.Movement or + Self.Movement.Camera in any way - An containing the data + + + + + + + + + + + - + - An object containing map location details + Sends update of Field of Vision vertical angle to the simulator + Angle in radians - - The Asset ID of the regions tile overlay + + Move agent positive along the X axis - - The grid location of the southern border of the map tile + + Move agent negative along the X axis - - The grid location of the western border of the map tile + + Move agent positive along the Y axis - - The grid location of the eastern border of the map tile + + Move agent negative along the Y axis - - The grid location of the northern border of the map tile + + Move agent positive along the Z axis - - Object containing request or response + + Move agent negative along the Z axis - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - - New as of 1.23 RC1, no details yet. - + + - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - A string containing the method used + + Causes simulator to make agent fly - - - A request sent from an agent to the Simulator to begin a new conference. - Contains a list of Agents which will be included in the conference - + + Stop movement - - An array containing the of the agents invited to this conference + + Finish animation - - The conferences Session ID + + Stand up from a sit - - - Serialize the object - - An containing the objects data + + Tells simulator to sit agent on ground - - - Deserialize the message - - An containing the data + + Place agent into mouselook mode - - - A moderation request sent from a conference moderator - Contains an agent and an optional action to take - + + Nudge agent positive along the X axis - - The Session ID + + Nudge agent negative along the X axis - + + Nudge agent positive along the Y axis + + + Nudge agent negative along the Y axis + + + Nudge agent positive along the Z axis + + + Nudge agent negative along the Z axis + + - - A list containing Key/Value pairs, known valid values: - key: text value: true/false - allow/disallow specified agents ability to use text in session - key: voice value: true/false - allow/disallow specified agents ability to use voice in session - - "text" or "voice" + + - + + Tell simulator to mark agent as away + + - + + + + + + + + + + - Serialize the object + Returns "always run" value, or changes it by sending a SetAlwaysRunPacket - An containing the objects data - + + The current value of the agent control flags + + + Gets or sets the interval in milliseconds at which + AgentUpdate packets are sent to the current simulator. Setting + this to a non-zero value will also enable the packet sending if + it was previously off, and setting it to zero will disable + + + Gets or sets whether AgentUpdate packets are sent to + the current simulator + + + Reset movement controls every time we send an update + + - Deserialize the message + 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 - An containing the data - + + + + + The camera is a local frame of reference inside of + the larger grid space. This is where the math happens + + - A message sent from the agent to the simulator which tells the - simulator we've accepted a conference invitation + Default constructor - - The conference SessionID + + - + + + + + + + + + + - Serialize the object + Called once attachment resource usage information has been collected - An containing the objects data + Indicates if operation was successfull + Attachment resource usage information - + - Deserialize the message + Contains all mesh faces that belong to a prim - An containing the data - + + List of primitive faces + + - Serialize the object + Decodes mesh asset into FacetedMesh - An containing the objects data + Mesh primitive + Asset retrieved from the asset server + Level of detail + Resulting decoded FacetedMesh + True if mesh asset decoding was successful - + - Deserialize the message + A set of textures that are layered on texture of each other and "baked" + in to a single texture, for avatar appearances - An containing the data - + + Final baked texture + + + Component layers + + + Width of the final baked image and scratchpad + + + Height of the final baked image and scratchpad + + + Bake type + + - Serialize the object + Default constructor - An containing the objects data + Bake type - + - Deserialize the message + Adds layer for baking - An containing the data + TexturaData struct that contains texture and its params - + - Serialize the object + Converts avatar texture index (face) to Bake type - An containing the objects data + Face number (AvatarTextureIndex) + BakeType, layer to which this texture belongs to - + - Deserialize the message + Make sure images exist, resize source if needed to match the destination - An containing the data + Destination image + Source image + Sanitization was succefull - - Key of sender + + + Fills a baked layer as a solid *appearing* color. The colors are + subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from + compressing it too far since it seems to cause upload failures if + the image is a pure solid color + + Color of the base of this layer - - Name of sender + + + Fills a baked layer as a solid *appearing* color. The colors are + subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from + compressing it too far since it seems to cause upload failures if + the image is a pure solid color + + Red value + Green value + Blue value - - Key of destination avatar + + Final baked texture - - ID of originating estate + + Component layers - - Key of originating region + + Width of the final baked image and scratchpad - - Coordinates in originating region + + Height of the final baked image and scratchpad - - Instant message type + + Bake type - - Group IM session toggle + + Is this one of the 3 skin bakes - - Key of IM session, for Group Messages, the groups UUID + + + Represents a Wearable Asset, Clothing, Hair, Skin, Etc + - - Timestamp of the instant message + + A string containing the name of the asset - - Instant message text + + A string containing a short description of the asset - - Whether this message is held for offline avatars + + The Assets WearableType - - Context specific packed data + + The For-Sale status of the object - - Is this invitation for voice group/conference chat + + An Integer representing the purchase price of the asset - - - Serialize the object - - An containing the objects data + + The of the assets creator - - - Deserialize the message - - An containing the data + + The of the assets current owner - - - Sent from the simulator to the viewer. - - When an agent initially joins a session the AgentUpdatesBlock object will contain a list of session members including - a boolean indicating they can use voice chat in this session, a boolean indicating they are allowed to moderate - this session, and lastly a string which indicates another agent is entering the session with the Transition set to "ENTER" - - During the session lifetime updates on individuals are sent. During the update the booleans sent during the initial join are - excluded with the exception of the Transition field. This indicates a new user entering or exiting the session with - the string "ENTER" or "LEAVE" respectively. - + + The of the assets prior owner - - - Serialize the object - - An containing the objects data + + The of the Group this asset is set to - - - Deserialize the message - - An containing the data + + True if the asset is owned by a - - - An EventQueue message sent when the agent is forcibly removed from a chatterbox session - + + The Permissions mask of the asset - - - A string containing the reason the agent was removed - + + A Dictionary containing Key/Value pairs of the objects parameters - - - The ChatterBoxSession's SessionID - + + A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures - - - Serialize the object - - An containing the objects data + + Initializes a new instance of an AssetWearable object - - - Deserialize the message - - An containing the data + + Initializes a new instance of an AssetWearable object with parameters + A unique specific to this asset + A byte array containing the raw asset data - + - Serialize the object + Decode an assets byte encoded data to a string - An containing the objects data + true if the asset data was decoded successfully - + - Deserialize the message + Encode the assets string represantion into a format consumable by the asset server - An containing the data - - - Serialize the object - - An containing the objects data + + Information about agents display name - - - Deserialize the message - - An containing the data + + Agent UUID - - - Serialize the object - - An containing the objects data + + Username - - - Deserialize the message - - An containing the data + + Display name - - - Serialize the object - - An containing the objects data + + First name (legacy) - - - Deserialize the message - - An containing the data + + Last name (legacy) - - - - + + Is display name default display name - + + Cache display name until + + + Last updated timestamp + + - Serialize the object + Creates AgentDisplayName object from OSD - An containing the objects data + Incoming OSD data + AgentDisplayName object - + - Deserialize the message + Return object as OSD map - An containing the data + OSD containing agent's display name data - + + Full name (legacy) + + - Serialize the object + Holds group information for Avatars such as those you might find in a profile - An containing the objects data - - - Deserialize the message - - An containing the data - - - - Serialize the object - - An containing the objects data + + true of Avatar accepts group notices - - - Deserialize the message - - An containing the data + + Groups Key - - - A message sent from the viewer to the simulator which - specifies that the user has changed current URL - of the specific media on a prim face - + + Texture Key for groups insignia - - - New URL - + + Name of the group - - - Prim UUID where navigation occured - + + Powers avatar has in the group - - - Face index - + + Avatars Currently selected title - - - Serialize the object - - An containing the objects data + + true of Avatar has chosen to list this in their profile - + - Deserialize the message + Contains an animation currently being played by an agent - An containing the data - - Base class used for the ObjectMedia message + + The ID of the animation asset - - - Message used to retrive prim media data - + + A number to indicate start order of currently playing animations + On Linden Grids this number is unique per region, with OpenSim it is per client - - - Prim UUID - + + - + - Requested operation, either GET or UPDATE + Holds group information on an individual profile pick - + - Serialize object + Retrieve friend status notifications, and retrieve avatar names and + profiles - Serialized object as OSDMap - - - Deserialize the message - - An containing the data + + The event subscribers, null of no subscribers - - - Message used to update prim media data - + + Raises the AvatarAnimation Event + An AvatarAnimationEventArgs object containing + the data sent from the simulator - - - Prim UUID - + + Thread sync lock object - - - Array of media entries indexed by face number - + + The event subscribers, null of no subscribers - - - Media version string - + + Raises the AvatarAppearance Event + A AvatarAppearanceEventArgs object containing + the data sent from the simulator - - - Serialize object - - Serialized object as OSDMap + + Thread sync lock object - - - Deserialize the message - - An containing the data + + The event subscribers, null of no subscribers - - - Message used to update prim media data - + + Raises the UUIDNameReply Event + A UUIDNameReplyEventArgs object containing + the data sent from the simulator - - - Prim UUID - + + Thread sync lock object - - - Array of media entries indexed by face number - + + The event subscribers, null of no subscribers - - - Requested operation, either GET or UPDATE - + + Raises the AvatarInterestsReply Event + A AvatarInterestsReplyEventArgs object containing + the data sent from the simulator - - - Serialize object - - Serialized object as OSDMap + + Thread sync lock object - - - Deserialize the message - - An containing the data + + The event subscribers, null of no subscribers - - - Message for setting or getting per face MediaEntry - + + Raises the AvatarPropertiesReply Event + A AvatarPropertiesReplyEventArgs object containing + the data sent from the simulator - - The request or response details block + + Thread sync lock object - - - Serialize the object - - An containing the objects data + + The event subscribers, null of no subscribers - - - Deserialize the message - - An containing the data + + Raises the AvatarGroupsReply Event + A AvatarGroupsReplyEventArgs object containing + the data sent from the simulator - - Details about object resource usage + + Thread sync lock object - - Object UUID + + The event subscribers, null of no subscribers - - Object name + + Raises the AvatarPickerReply Event + A AvatarPickerReplyEventArgs object containing + the data sent from the simulator - - Indicates if object is group owned + + Thread sync lock object - - Locatio of the object + + The event subscribers, null of no subscribers - - Object owner + + Raises the ViewerEffectPointAt Event + A ViewerEffectPointAtEventArgs object containing + the data sent from the simulator - - Resource usage, keys are resource names, values are resource usage for that specific resource + + Thread sync lock object - - - Deserializes object from OSD - - An containing the data + + The event subscribers, null of no subscribers - - - Makes an instance based on deserialized data - - serialized data - Instance containg deserialized data + + Raises the ViewerEffectLookAt Event + A ViewerEffectLookAtEventArgs object containing + the data sent from the simulator - - Details about parcel resource usage + + Thread sync lock object - - Parcel UUID - - - Parcel local ID - - - Parcel name - - - Indicates if parcel is group owned + + The event subscribers, null of no subscribers - - Parcel owner + + Raises the ViewerEffect Event + A ViewerEffectEventArgs object containing + the data sent from the simulator - - Array of containing per object resource usage + + Thread sync lock object - - - Deserializes object from OSD - - An containing the data + + The event subscribers, null of no subscribers - - - Makes an instance based on deserialized data - - serialized data - Instance containg deserialized data + + Raises the AvatarPicksReply Event + A AvatarPicksReplyEventArgs object containing + the data sent from the simulator - - Resource usage base class, both agent and parcel resource - usage contains summary information + + Thread sync lock object - - Summary of available resources, keys are resource names, - values are resource usage for that specific resource + + The event subscribers, null of no subscribers - - Summary resource usage, keys are resource names, - values are resource usage for that specific resource + + Raises the PickInfoReply Event + A PickInfoReplyEventArgs object containing + the data sent from the simulator - - - Serializes object - - serialized data + + Thread sync lock object - - - Deserializes object from OSD - - An containing the data + + The event subscribers, null of no subscribers - - Agent resource usage + + Raises the AvatarClassifiedReply Event + A AvatarClassifiedReplyEventArgs object containing + the data sent from the simulator - - Per attachment point object resource usage + + Thread sync lock object - - - Deserializes object from OSD - - An containing the data + + The event subscribers, null of no subscribers - - - Makes an instance based on deserialized data - - serialized data - Instance containg deserialized data + + Raises the ClassifiedInfoReply Event + A ClassifiedInfoReplyEventArgs object containing + the data sent from the simulator - - - Detects which class handles deserialization of this message - - An containing the data - Object capable of decoding this message + + Thread sync lock object - - Request message for parcel resource usage + + The event subscribers, null of no subscribers - - UUID of the parel to request resource usage info + + Raises the DisplayNameUpdate Event + A DisplayNameUpdateEventArgs object containing + the data sent from the simulator - - - Serializes object - - serialized data + + Thread sync lock object - + - Deserializes object from OSD + Represents other avatars - An containing the data - - - Response message for parcel resource usage - - - URL where parcel resource usage details can be retrieved + - - URL where parcel resource usage summary can be retrieved + + Tracks the specified avatar on your map + Avatar ID to track - + - Serializes object + Request a single avatar name - serialized data + The avatar key to retrieve a name for - + - Deserializes object from OSD + Request a list of avatar names - An containing the data + The avatar keys to retrieve names for - + - Detects which class handles deserialization of this message + Check if Display Names functionality is available - An containing the data - Object capable of decoding this message - - - Parcel resource usage - - - Array of containing per percal resource usage + True if Display name functionality is available - + - Deserializes object from OSD + Request retrieval of display names (max 90 names per request) - An containing the data + List of UUIDs to lookup + Callback to report result of the operation - + - Type of gesture step + Start a request for Avatar Properties + - + - Base class for gesture steps + Search for an avatar (first name, last name) + The name to search for + An ID to associate with this query - + - Retururns what kind of gesture step this is + Start a request for Avatar Picks + UUID of the avatar - + - Describes animation step of a gesture + Start a request for Avatar Classifieds + UUID of the avatar - + - If true, this step represents start of animation, otherwise animation stop + Start a request for details of a specific profile pick + UUID of the avatar + UUID of the profile pick - + - Animation asset + Start a request for details of a specific profile classified + UUID of the avatar + UUID of the profile classified - - - Animation inventory name - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Returns what kind of gesture step this is - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Describes sound step of a gesture - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Sound asset - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Sound inventory name - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Returns what kind of gesture step this is + EQ Message fired when someone nearby changes their display name + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - + - Describes sound step of a gesture + Crossed region handler for message that comes across the EventQueue. Sent to an agent + when the agent crosses a sim border into a new region. + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - - - Text to output in chat - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Returns what kind of gesture step this is - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Describes sound step of a gesture - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - If true in this step we wait for all animations to finish - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - If true gesture player should wait for the specified amount of time - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Time in seconds to wait if WaitForAnimation is false - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Returns what kind of gesture step this is - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Describes the final step of a gesture - + + Raised when the simulator sends us data containing + an agents animation playlist - - - Returns what kind of gesture step this is - + + Raised when the simulator sends us data containing + the appearance information for an agent - - - Represents a sequence of animations, sounds, and chat actions - + + Raised when the simulator sends us data containing + agent names/id values - - - Base class for all Asset types - + + Raised when the simulator sends us data containing + the interests listed in an agents profile - - A byte array containing the raw asset data + + Raised when the simulator sends us data containing + profile property information for an agent - - True if the asset it only stored on the server temporarily + + Raised when the simulator sends us data containing + the group membership an agent is a member of - - A unique ID + + Raised when the simulator sends us data containing + name/id pair - - - Construct a new Asset object - + + Raised when the simulator sends us data containing + the objects and effect when an agent is pointing at - - - Construct a new Asset object - - A unique specific to this asset - A byte array containing the raw asset data + + Raised when the simulator sends us data containing + the objects and effect when an agent is looking at - - - Regenerates the AssetData byte array from the properties - of the derived class. - + + Raised when the simulator sends us data containing + an agents viewer effect information - - - Decodes the AssetData, placing it in appropriate properties of the derived - class. - - True if the asset decoding succeeded, otherwise false + + Raised when the simulator sends us data containing + the top picks from an agents profile - - The assets unique ID + + Raised when the simulator sends us data containing + the Pick details - - - The "type" of asset, Notecard, Animation, etc - + + Raised when the simulator sends us data containing + the classified ads an agent has placed - - - Keyboard key that triggers the gestyre - + + Raised when the simulator sends us data containing + the details of a classified ad - - - Modifier to the trigger key - + + Raised when the simulator sends us data containing + the details of display name change - + - String that triggers playing of the gesture sequence + Callback giving results when fetching display names + If the request was successful + Array of display names + Array of UUIDs that could not be fetched - - - Text that replaces trigger in chat once gesture is triggered - + + Provides data for the event + The event occurs when the simulator sends + the animation playlist for an agent + + The following code example uses the and + properties to display the animation playlist of an avatar on the window. + + // subscribe to the event + Client.Avatars.AvatarAnimation += Avatars_AvatarAnimation; + + private void Avatars_AvatarAnimation(object sender, AvatarAnimationEventArgs e) + { + // create a dictionary of "known" animations from the Animations class using System.Reflection + Dictionary<UUID, string> systemAnimations = new Dictionary<UUID, string>(); + Type type = typeof(Animations); + System.Reflection.FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + foreach (System.Reflection.FieldInfo field in fields) + { + systemAnimations.Add((UUID)field.GetValue(type), field.Name); + } + + // find out which animations being played are known animations and which are assets + foreach (Animation animation in e.Animations) + { + if (systemAnimations.ContainsKey(animation.AnimationID)) + { + Console.WriteLine("{0} is playing {1} ({2}) sequence {3}", e.AvatarID, + systemAnimations[animation.AnimationID], animation.AnimationSequence); + } + else + { + Console.WriteLine("{0} is playing {1} (Asset) sequence {2}", e.AvatarID, + animation.AnimationID, animation.AnimationSequence); + } + } + } + + - + - Sequence of gesture steps + Construct a new instance of the AvatarAnimationEventArgs class + The ID of the agent + The list of animations to start - - - Constructs guesture asset - + + Get the ID of the agent - - - Constructs guesture asset - - A unique specific to this asset - A byte array containing the raw asset data + + Get the list of animations to start - - - Encodes gesture asset suitable for uplaod - + + 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") + } + + - + - Decodes gesture assset into play sequence + Construct a new instance of the AvatarAppearanceEventArgs class - true if the asset data was decoded successfully + 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 - - - Returns asset type - + + Get the Simulator this request is from of the agent - - - Archives assets - + + Get the ID of the agent - - - Archive assets - + + true if the agent is a trial account - + + Get the default agent texture + + + Get the agents appearance layer textures + + + Get the for the agent + + + Version of the appearance system used. + Value greater than 0 indicates that server side baking is used + + + Version of the Current Outfit Folder the appearance is based on + + + Appearance flags, introduced with server side baking, currently unused + + + Represents the interests from the profile of an agent + + + Get the ID of the agent + + + The properties of an agent + + + Get the ID of the agent + + + Get the ID of the agent + + + Get the ID of the agent + + + Get the ID of the avatar + + - Archive the assets given to this archiver to the given archive. + Event args class for display name notification messages - - + - Write an assets metadata file to the given archive + Index of TextureEntry slots for avatar appearances - - + - Write asset data files to the given archive + Bake layers for avatar appearance - - + - Constants for the archiving module + Appearance Flags, introdued with server side baking, currently unused - + + Maximum number of concurrent downloads for wearable assets and textures + + + Maximum number of concurrent uploads for baked textures + + + Timeout for fetching inventory listings + + + Timeout for fetching a single wearable, or receiving a single packet response + + + Timeout for fetching a single texture + + + Timeout for uploading a single baked texture + + + Number of times to retry bake upload + + + When changing outfit, kick off rebake after + 20 seconds has passed since the last change + + + Total number of wearables for each avatar + + + Total number of baked textures on each avatar + + + 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 + + + Magic values to finalize the cache check hashes for each + bake + + + Default avatar texture, used to detect when a custom + texture is not set for a face + + + The event subscribers. null if no subcribers + + + Raises the AgentWearablesReply event + An AgentWearablesReplyEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + The event subscribers. null if no subcribers + + + Raises the CachedBakesReply event + An AgentCachedBakesReplyEventArgs object containing the + data returned from the data server AgentCachedTextureResponse + + + Thread sync lock object + + + The event subscribers. null if no subcribers + + + Raises the AppearanceSet event + An AppearanceSetEventArgs object indicating if the operatin was successfull + + + Thread sync lock object + + + The event subscribers. null if no subcribers + + + Raises the RebakeAvatarRequested event + An RebakeAvatarTexturesEventArgs object containing the + data returned from the data server + + + Thread sync lock object + + + Visual parameters last sent to the sim + + + Textures about this client sent to the sim + + + A cache of wearables currently being worn + + + A cache of textures currently being worn + + + Incrementing serial number for AgentCachedTexture packets + + + Incrementing serial number for AgentSetAppearance packets + + + Indicates if WearablesRequest succeeded + + + Indicates whether or not the appearance thread is currently + running, to prevent multiple appearance threads from running + simultaneously + + + Reference to our agent + + - The location of the archive control file + Timer used for delaying rebake on changing outfit - + - Path for the assets held in an archive + Main appearance thread - + - Path for the prims file + Is server baking complete. It needs doing only once - + - Path for terrains. Technically these may be assets, but I think it's quite nice to split them out. + Default constructor + A reference to our agent - + - Path for region settings. + Obsolete method for setting appearance. This function no longer does anything. + Use RequestSetAppearance() to manually start the appearance thread - + - The character the separates the uuid from extension information in an archived asset filename + Obsolete method for setting appearance. This function no longer does anything. + Use RequestSetAppearance() to manually start the appearance thread + Unused parameter - + - Extensions used for asset types in the archive + Starts the appearance setting thread - + - Capabilities is the name of the bi-directional HTTP REST protocol - used to communicate non real-time transactions such as teleporting or - group messaging + Starts the appearance setting thread + True to force rebaking, otherwise false - - Reference to the simulator this system is connected to - - + - Default constructor + Check if current region supports server side baking - - + True if server side baking support is detected - + - Request the URI of a named capability + Ask the server what textures our agent is currently wearing - Name of the capability to request - The URI of the requested capability, or String.Empty if - the capability does not exist - + - Process any incoming events, check to see if we have a message created for the event, + Build hashes out of the texture assetIDs for each baking layer to + ask the simulator whether it has cached copies of each baked texture - - - - - 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 + Returns the AssetID of the asset that is currently being worn in a + given WearableType slot - Event name - Decoded event data - The simulator that generated the event + WearableType slot to get the AssetID for + The UUID of the asset being worn in the given slot, or + UUID.Zero if no wearable is attached to the given slot or wearables + have not been downloaded yet - + - Throttles the network traffic for various different traffic types. - Access this class through GridClient.Throttle + Add a wearable to the current outfit and set appearance + Wearable to be added to the outfit - + - Default constructor, uses a default high total of 1500 KBps (1536000) + Add a wearable to the current outfit and set appearance + Wearable to be added to the outfit + Should existing item on the same point or of the same type be replaced - + - Constructor that decodes an existing AgentThrottle packet in to - individual values + Add a list of wearables to the current outfit and set appearance - Reference to the throttle data in an AgentThrottle - packet - Offset position to start reading at in the - throttle data - This is generally not needed in clients as the server will - never send a throttle packet to the client + List of wearable inventory items to + be added to the outfit + Should existing item on the same point or of the same type be replaced - + - Send an AgentThrottle packet to the current server using the - current values + Add a list of wearables to the current outfit and set appearance + List of wearable inventory items to + be added to the outfit + Should existing item on the same point or of the same type be replaced - + - Send an AgentThrottle packet to the specified server using the - current values + Remove a wearable from the current outfit and set appearance + Wearable to be removed from the outfit - + - Convert the current throttle values to a byte array that can be put - in an AgentThrottle packet + Removes a list of wearables from the current outfit and set appearance - Byte array containing all the throttle values - - - Maximum bits per second for resending unacknowledged packets - - - Maximum bits per second for LayerData terrain + List of wearable inventory items to + be removed from the outfit - - Maximum bits per second for LayerData wind data + + + Replace the current outfit with a list of wearables and set appearance + + List of wearable inventory items that + define a new outfit - - Maximum bits per second for LayerData clouds + + + Replace the current outfit with a list of wearables and set appearance + + List of wearable inventory items that + define a new outfit + Check if we have all body parts, set this to false only + if you know what you're doing - - Unknown, includes object data + + + Checks if an inventory item is currently being worn + + The inventory item to check against the agent + wearables + The WearableType slot that the item is being worn in, + or WearbleType.Invalid if it is not currently being worn - - Maximum bits per second for textures + + + Returns a copy of the agents currently worn wearables + + A copy of the agents currently worn wearables + Avoid calling this function multiple times as it will make + a copy of all of the wearable data each time - - Maximum bits per second for downloaded assets + + + Calls either or + depending on the value of + replaceItems + + List of wearable inventory items to add + to the outfit or become a new outfit + True to replace existing items with the + new list of items, false to add these items to the existing outfit - - Maximum bits per second the entire connection, divided up - between invidiual streams using default multipliers + + + Adds a list of attachments to our agent + + A List containing the attachments to add + If true, tells simulator to remove existing attachment + first - + - Particle system specific enumerators, flags and methods. + Adds a list of attachments to our agent + A List containing the attachments to add + If true, tells simulator to remove existing attachment + If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + first - - + + + Attach an item to our agent at a specific attach point + + A to attach + the on the avatar + to attach the item to - - + + + Attach an item to our agent at a specific attach point + + A to attach + the on the avatar + If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + to attach the item to - - + + + Attach an item to our agent specifying attachment details + + The of the item to attach + The attachments owner + The name of the attachment + The description of the attahment + The to apply when attached + The of the attachment + The on the agent + to attach the item to - - + + + Attach an item to our agent specifying attachment details + + The of the item to attach + The attachments owner + The name of the attachment + The description of the attahment + The to apply when attached + The of the attachment + The on the agent + If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + to attach the item to - - + + + Detach an item from our agent using an object + + An object - - + + + Detach an item from our agent + + The inventory itemID of the item to detach - - Foliage type for this primitive. Only applicable if this - primitive is foliage + + + Inform the sim which wearables are part of our current outfit + - - Unknown + + + Replaces the Wearables collection with a list of new wearable items + + Wearable items to replace the Wearables collection with - - + + + Calculates base color/tint for a specific wearable + based on its params + + All the color info gathered from wearable's VisualParams + passed as list of ColorParamInfo tuples + Base color/tint for the wearable - - + + + Blocking method to populate the Wearables dictionary + + True on success, otherwise false - - + + + Blocking method to populate the Textures array with cached bakes + + True on success, otherwise false - - + + + Populates textures and visual params from a decoded asset + + Wearable to decode - - + + + Blocking method to download and parse currently worn wearable assets + + True on success, otherwise false - - + + + Get a list of all of the textures that need to be downloaded for a + single bake layer + + Bake layer to get texture AssetIDs for + A list of texture AssetIDs to download - - + + + Helper method to lookup the TextureID for a single layer and add it + to a list if it is not already present + + + - - + + + Blocking method to download all of the textures needed for baking + the given bake layers + + A list of layers that need baking + No return value is given because the baking will happen + whether or not all textures are successfully downloaded - - + + + Blocking method to create and upload baked textures for all of the + missing bakes + + True on success, otherwise false - - + + + Blocking method to create and upload a baked texture for a single + bake layer + + Layer to bake + True on success, otherwise false - - - - - - - - Identifies the owner if audio or a particle system is - active - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Blocking method to upload a baked texture + + Five channel JPEG2000 texture data to upload + UUID of the newly created asset on success, otherwise UUID.Zero - - + + + Creates a dictionary of visual param values from the downloaded wearables + + A dictionary of visual param indices mapping to visual param + values for our agent that can be fed to the Baker class - + - Default constructor + Initate server baking process + True if the server baking was successful - + - Packs PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew - parameters in to signed eight bit values + Get the latest version of COF - Floating point parameter to pack - Signed eight bit value containing the packed parameter + Current Outfit Folder (or null if getting the data failed) - + - Unpacks PathTwist, PathTwistBegin, PathRadiusOffset, and PathSkew - parameters from signed eight bit integers to floating point values + Create an AgentSetAppearance packet from Wearables data and the + Textures array and send it - Signed eight bit value to unpack - Unpacked floating point value - - + + + Converts a WearableType to a bodypart or clothing WearableType + + A WearableType + AssetType.Bodypart or AssetType.Clothing or AssetType.Unknown - + - Current version of the media data for the prim + Converts a BakeType to the corresponding baked texture slot in AvatarTextureIndex + A BakeType + The AvatarTextureIndex slot that holds the given BakeType - + - Array of media entries indexed by face number + Gives the layer number that is used for morph mask + >A BakeType + Which layer number as defined in BakeTypeToTextures is used for morph mask - - + + + Converts a BakeType to a list of the texture slots that make up that bake + + 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. - - Uses basic heuristics to estimate the primitive shape + + Raised when an AgentCachedTextureResponse packet is + received, giving a list of cached bakes that were found on the + simulator + request. - + - Parameters used to construct a visual representation of a primitive + 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 - - + + Construct a new instance of the AgentWearablesReplyEventArgs class - - + + Contains the Event data returned from the data server from an AgentCachedTextureResponse - - + + Construct a new instance of the AgentCachedBakesReplyEventArgs class - - + + Contains the Event data returned from an AppearanceSetRequest - - + + + Triggered when appearance data is sent to the sim and + the main appearance thread is done. + Indicates whether appearance setting was successful - - Attachment point to an avatar + + Indicates whether appearance setting was successful - - + + Contains the Event data returned from the data server from an RebakeAvatarTextures - - + + + Triggered when the simulator sends a request for this agent to rebake + its appearance + + The ID of the Texture Layer to bake - - + + The ID of the Texture Layer to bake - - + + + Image width + - + - Information on the flexible properties of a primitive + Image height - - + + + Image channel flags + - - + + + Red channel data + - - + + + Green channel data + - - + + + Blue channel data + - - + + + Alpha channel data + - - + + + Bump channel data + - + - Default constructor + Create a new blank image + width + height + channel flags - + - - + - + - + Convert the channels in the image. Channels are created or destroyed as required. - + new channel flags - + - + Resize or stretch the image using nearest neighbor (ugly) resampling - + new width + new height - + - Information on the light properties of a primitive + Create a byte array containing 32-bit RGBA data with a bottom-left + origin, suitable for feeding directly into OpenGL + A byte array containing raw texture data - - + + + 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 + + + + + + + - + - + - + - Default constructor + Thrown when a packet could not be successfully deserialized - + - + Default constructor - - - + - + Constructor that takes an additional error message - + An error message to attach to this exception - + - + The header of a message template packet. Holds packet flags, sequence + number, packet ID, and any ACKs that will be appended at the end of + the packet - - + - Information on the sculpt properties of a sculpted primitive + Convert the AckList to a byte array, used for packet serializing + Reference to the target byte array + Beginning position to start writing to in the byte + array, will be updated with the ending position of the ACK list - + - Default constructor + + + + + - + - - + + + - + - Render inside out (inverts the normals). + A block of data in a packet. Packets are composed of one or more blocks, + each block containing one or more fields - + - Render an X axis mirror of the sculpty. + Create a block from a byte array + Byte array containing the serialized block + Starting position of the block in the byte array. + This will point to the data after the end of the block when the + call returns - + - Extended properties to describe an object + Serialize this block into a byte array + Byte array to serialize this block into + Starting position in the byte array to serialize to. + 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 - - + + + Attempts to convert an LLSD structure to a known Packet type + + Event name, this must match an actual + packet name for a Packet to be successfully built + LLSD to convert to a Packet + A Packet on success, otherwise null - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - Default constructor - + + - - - Set the properties that are set in an ObjectPropertiesFamily packet - - that has - been partially filled by an ObjectPropertiesFamily packet + + - - - 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 + + - - - 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 + + - - - Particle Flags Enum - + + - - None + + - - Acceleration and velocity for particles are - relative to the object rotation + + - - Particles use new 'correct' angle parameters + + - - - 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 - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - + + - - - - - + + - - - A Wrapper around openjpeg to encode and decode images to and from byte arrays - + + - - TGA Header size + + - - OpenJPEG is not threadsafe, so this object is used to lock - during calls into unmanaged code + + - - - Encode a object into a byte array - - The object to encode - true to enable lossless conversion, only useful for small images ie: sculptmaps - A byte array containing the encoded Image object + + - - - Encode a object into a byte array - - The object to encode - a byte array of the encoded image + + - - - Decode JPEG2000 data to an and - - - JPEG2000 encoded data - ManagedImage object to decode to - Image object to decode to - True if the decode succeeds, otherwise false - - - - - - - - + + - - - - - - - - + + - - - Encode a object into a byte array - - The source object to encode - 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 + + - - - Represents an that represents an avatars body ie: Hair, Etc. - + + - - - Represents a Wearable Asset, Clothing, Hair, Skin, Etc - + + - - A string containing the name of the asset + + - - A string containing a short description of the asset + + - - The Assets WearableType + + - - The For-Sale status of the object + + - - An Integer representing the purchase price of the asset + + - - The of the assets creator + + - - The of the assets current owner + + - - The of the assets prior owner + + - - The of the Group this asset is set to + + - - True if the asset is owned by a + + - - The Permissions mask of the asset + + - - A Dictionary containing Key/Value pairs of the objects parameters + + - - A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures + + - - Initializes a new instance of an AssetWearable object + + - - Initializes a new instance of an AssetWearable object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + - - - Decode an assets byte encoded data to a string - - true if the asset data was decoded successfully + + - - - 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 + + - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - + + - - + + - - + + - - + + - - + + - - - - - - + + - - - - + + - - + + - - + + - - + + - - + + - - - - - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - + + - - - - - - + + - - - - - - + + - - - - - - - + + - - - - + + - - - - - - + + - - - - - - + + - - - - - + + - - - Permission request flags, asked when a script wants to control an Avatar - + + - - Placeholder for empty values, shouldn't ever see this + + - - Script wants ability to take money from you + + - - Script wants to take camera controls for you + + - - Script wants to remap avatars controls + + - - Script wants to trigger avatar animations - This function is not implemented on the grid + + - - Script wants to attach or detach the prim or primset to your avatar + + - - Script wants permission to release ownership - This function is not implemented on the grid - The concept of "public" objects does not exist anymore. + + - - Script wants ability to link/delink with other prims + + - - Script wants permission to change joints - This function is not implemented on the grid + + - - Script wants permissions to change permissions - This function is not implemented on the grid + + - - Script wants to track avatars camera position and rotation + + - - Script wants to control your camera + + - - - Special commands used in Instant Messages - + + - - Indicates a regular IM from another agent + + - - Simple notification box with an OK button + + - - You've been invited to join a group. - - - Inventory offer + + - - Accepted inventory offer + + - - Declined inventory offer + + - - Group vote + + - - An object is offering its inventory + + - - Accept an inventory offer from an object + + - - Decline an inventory offer from an object + + - - Unknown + + - - Start a session, or add users to a session + + - - Start a session, but don't prune offline users + + - - Start a session with your group + + - - Start a session without a calling card (finder or objects) + + - - Send a message to a session + + - - Leave a session + + - - Indicates that the IM is from an object + + - - Sent an IM to a busy user, this is the auto response + + - - Shows the message in the console and chat history + + - - Send a teleport lure + + - - Response sent to the agent which inititiated a teleport invitation + + - - Response sent to the agent which inititiated a teleport invitation + + - - Only useful if you have Linden permissions + + - - A placeholder type for future expansion, currently not - used + + - - IM to tell the user to go to an URL + + - - IM for help + + - - IM sent automatically on call for help, sends a lure - to each Helper reached + + - - Like an IM but won't go to email + + - - IM from a group officer to all group members + + - - Unknown + + - - Unknown + + - - Accept a group invitation + + - - Decline a group invitation + + - - Unknown + + - - An avatar is offering you friendship + + - - An avatar has accepted your friendship offer + + - - An avatar has declined your friendship offer + + - - Indicates that a user has started typing + + - - Indicates that a user has stopped typing + + - - - Flag in Instant Messages, whether the IM should be delivered to - offline avatars as well - + + - - Only deliver to online avatars + + - - If the avatar is offline the message will be held until - they login next, and possibly forwarded to their e-mail account + + - - - Conversion type to denote Chat Packet types in an easier-to-understand format - + + - - Whisper (5m radius) + + - - Normal chat (10/20m radius), what the official viewer typically sends + + - - Shouting! (100m radius) + + - - Event message when an Avatar has begun to type + + - - Event message when an Avatar has stopped typing + + - - Send the message to the debug channel + + - - Event message when an object uses llOwnerSay + + - - Special value to support llRegionSay, never sent to the client + + - - - Identifies the source of a chat message - + + - - Chat from the grid or simulator + + - - Chat from another avatar + + - - Chat from an object + + - - - - + + - - + + - - + + - - + + - - - Effect type used in ViewerEffect packets - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - Project a beam from a source to a destination, such as - the one used when editing an object + + - - + + - - + + - - + + - - Create a swirl of particles around an object + + - - + + - - + + - - Cause an avatar to look at an object + + - - Cause an avatar to point at an object + + - - - The action an avatar is doing when looking at something, used in - ViewerEffect packets for the LookAt effect - + + - - + + - - + + - - + + - - + + - - + + - - + + - - Deprecated + + - - + + - - + + - - + + - - + + - - - The action an avatar is doing when pointing at something, used in - ViewerEffect packets for the PointAt effect - + + - - + + - - + + - - + + - - + + - - - Money transaction types - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - Flags sent when a script takes or releases a control - - NOTE: (need to verify) These might be a subset of the ControlFlags enum in Movement, + + - - No Flags set + + - - Forward (W or up Arrow) + + - - Back (S or down arrow) + + - - Move left (shift+A or left arrow) + + - - Move right (shift+D or right arrow) + + - - Up (E or PgUp) + + - - Down (C or PgDown) + + - - Rotate left (A or left arrow) + + - - Rotate right (D or right arrow) + + - - Left Mouse Button + + - - Left Mouse button in MouseLook + + - - - Currently only used to hide your group title - + + - - No flags set + + - - Hide your group title + + - - - Action state of the avatar, which can currently be typing and - editing - + + - - + + - - + + - - + + - - - Current teleport status - + + - - Unknown status + + - - Teleport initialized + + - - Teleport in progress + + - - Teleport failed + + - - Teleport completed + + - - Teleport cancelled + + - - - - + + - - No flags set, or teleport failed + + - - Set when newbie leaves help island for first time + + - - + + - - Via Lure + + - - Via Landmark + + - - Via Location + + - - Via Home + + - - Via Telehub + + - - Via Login + + - - Linden Summoned + + - - Linden Forced me + + - - + + - - Agent Teleported Home via Script + + - - + + - - + + - - + + - - forced to new location for example when avatar is banned or ejected + + - - Teleport Finished via a Lure + + - - Finished, Sim Changed + + - - Finished, Same Sim + + - - - - + + - - + + - - + + - - + + - - - - + + - - + + - - + + - - + + - - + + - - - Instant Message - + + - - Key of sender + + - - Name of sender + + - - Key of destination avatar + + - - ID of originating estate + + - - Key of originating region + + - - Coordinates in originating region + + - - Instant message type + + - - Group IM session toggle + + - - Key of IM session, for Group Messages, the groups UUID + + - - Timestamp of the instant message + + - - Instant message text + + - - Whether this message is held for offline avatars + + - - Context specific packed data + + - - Print the struct data as a string - A string containing the field name, and field value + + - - - Manager class for our own avatar - + + - - The event subscribers. null if no subcribers + + - - Raises the ChatFromSimulator event - A ChatEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the ScriptDialog event - A SctriptDialogEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the ScriptQuestion event - A ScriptQuestionEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the LoadURL event - A LoadUrlEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the MoneyBalance event - A BalanceEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers - - - Raises the MoneyBalanceReply event - A MoneyBalanceReplyEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the IM event - A InstantMessageEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the TeleportProgress event - A TeleportEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the AgentDataReply event - A AgentDataReplyEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the AnimationsChanged event - A AnimationsChangedEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the MeanCollision event - A MeanCollisionEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the RegionCrossed event - A RegionCrossedEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the GroupChatJoined event - A GroupChatJoinedEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the AlertMessage event - A AlertMessageEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the ScriptControlChange event - A ScriptControlEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the CameraConstraint event - A CameraConstraintEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the ScriptSensorReply event - A ScriptSensorReplyEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the AvatarSitResponse event - A AvatarSitResponseEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the ChatSessionMemberAdded event - A ChatSessionMemberAddedEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the ChatSessionMemberLeft event - A ChatSessionMemberLeftEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - Reference to the GridClient instance + + - - Used for movement and camera tracking + + - - Currently playing animations for the agent. Can be used to - check the current movement status such as walking, hovering, aiming, - etc. by checking against system animations found in the Animations class + + - - Dictionary containing current Group Chat sessions and members + + - - - Constructor, setup callbacks for packets related to our avatar - - A reference to the Class + + - - - Send a text message from the Agent to the Simulator - - A containing the message - The channel to send the message on, 0 is the public channel. Channels above 0 - can be used however only scripts listening on the specified channel will see the message - Denotes the type of message being sent, shout, whisper, etc. + + - - - Request any instant messages sent while the client was offline to be resent. - + + - - - Send an Instant Message to another Avatar - - The recipients - A containing the message to send + + - - - Send an Instant Message to an existing group chat or conference chat - - The recipients - A containing the message to send - IM session ID (to differentiate between IM windows) + + - - - Send an Instant Message - - The name this IM will show up as being from - Key of Avatar - Text message being sent - IM session ID (to differentiate between IM windows) - IDs of sessions for a conference + + - - - Send an Instant Message - - The name this IM will show up as being from - Key of Avatar - Text message being sent - IM session ID (to differentiate between IM windows) - Type of instant message to send - Whether to IM offline avatars as well - Senders Position - RegionID Sender is In - Packed binary data that is specific to - the dialog type + + - - - Send an Instant Message to a group - - of the group to send message to - Text Message being sent. + + - - - Send an Instant Message to a group the agent is a member of - - The name this IM will show up as being from - of the group to send message to - Text message being sent + + - - - Send a request to join a group chat session - - of Group to leave + + - - - Exit a group chat session. This will stop further Group chat messages - from being sent until session is rejoined. - - of Group chat session to leave + + - - - Reply to script dialog questions. - - Channel initial request came on - Index of button you're "clicking" - Label of button you're "clicking" - of Object that sent the dialog request - + + - - - Accept invite for to a chatterbox session - - of session to accept invite to + + - - - Start a friends conference - - List of UUIDs to start a conference with - the temportary session ID returned in the callback> + + - - - Start a particle stream between an agent and an object - - Key of the source agent - Key of the target object - - The type from the enum - A unique for this effect + + - - - Start a particle stream between an agent and an object - - Key of the source agent - Key of the target object - A representing the beams offset from the source - A which sets the avatars lookat animation - of the Effect + + - - - Create a particle beam between an avatar and an primitive - - The ID of source avatar - The ID of the target primitive - global offset - A object containing the combined red, green, blue and alpha - color values of particle beam - a float representing the duration the parcicle beam will last - A Unique ID for the beam - + + - - - Create a particle swirl around a target position using a packet - - global offset - A object containing the combined red, green, blue and alpha - color values of particle beam - a float representing the duration the parcicle beam will last - A Unique ID for the beam + + - - - Sends a request to sit on the specified object - - of the object to sit on - Sit at offset + + - - - Follows a call to to actually sit on the object - + + - - Stands up from sitting on a prim or the ground - true of AgentUpdate was sent + + - - - Does a "ground sit" at the avatar's current position - + + - - - Starts or stops flying - - True to start flying, false to stop flying + + - - - Starts or stops crouching - - True to start crouching, false to stop crouching + + - - - Starts a jump (begin holding the jump key) - + + - - - Use the autopilot sim function to move the avatar to a new - position. Uses double precision to get precise movements - - The z value is currently not handled properly by the simulator - Global X coordinate to move to - Global Y coordinate to move to - Z coordinate to move to + + - - - Use the autopilot sim function to move the avatar to a new position - - The z value is currently not handled properly by the simulator - Integer value for the global X coordinate to move to - Integer value for the global Y coordinate to move to - Floating-point value for the Z coordinate to move to + + - - - Use the autopilot sim function to move the avatar to a new position - - The z value is currently not handled properly by the simulator - Integer value for the local X coordinate to move to - Integer value for the local Y coordinate to move to - Floating-point value for the Z coordinate to move to + + - - Macro to cancel autopilot sim function - Not certain if this is how it is really done - true if control flags were set and AgentUpdate was sent to the simulator + + - - - Grabs an object - - an unsigned integer of the objects ID within the simulator - + + - - - Overload: Grab a simulated object - - an unsigned integer of the objects ID within the simulator - - The texture coordinates to grab - The surface coordinates to grab - The face of the position to grab - The region coordinates of the position to grab - The surface normal of the position to grab (A normal is a vector perpindicular to the surface) - The surface binormal of the position to grab (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space + + - - - Drag an object - - of the object to drag - Drag target in region coordinates + + - - - Overload: Drag an object - - of the object to drag - Drag target in region coordinates - - The texture coordinates to grab - The surface coordinates to grab - The face of the position to grab - The region coordinates of the position to grab - The surface normal of the position to grab (A normal is a vector perpindicular to the surface) - The surface binormal of the position to grab (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space + + - - - Release a grabbed object - - The Objects Simulator Local ID - - - + + - - - Release a grabbed object - - The Objects Simulator Local ID - The texture coordinates to grab - The surface coordinates to grab - The face of the position to grab - The region coordinates of the position to grab - The surface normal of the position to grab (A normal is a vector perpindicular to the surface) - The surface binormal of the position to grab (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space + + - - - Touches an object - - an unsigned integer of the objects ID within the simulator - + + - - - Request the current L$ balance - + + - - - Give Money to destination Avatar - - UUID of the Target Avatar - Amount in L$ + + - - - Give Money to destination Avatar - - UUID of the Target Avatar - Amount in L$ - Description that will show up in the - recipients transaction history + + - - - Give L$ to an object - - object to give money to - amount of L$ to give - name of object + + - - - Give L$ to a group - - group to give money to - amount of L$ to give + + - - - Give L$ to a group - - group to give money to - amount of L$ to give - description of transaction + + - - - Pay texture/animation upload fee - + + - - - Pay texture/animation upload fee - - description of the transaction + + - - - Give Money to destination Object or Avatar - - UUID of the Target Object/Avatar - Amount in L$ - Reason (Optional normally) - The type of transaction - Transaction flags, mostly for identifying group - transactions + + - - - Plays a gesture - - Asset of the gesture + + - - - Mark gesture active - - Inventory of the gesture - Asset of the gesture + + - - - Mark gesture inactive - - Inventory of the gesture + + - - - Send an AgentAnimation packet that toggles a single animation on - - The of the animation to start playing - Whether to ensure delivery of this packet or not + + - - - Send an AgentAnimation packet that toggles a single animation off - - The of a - currently playing animation to stop playing - Whether to ensure delivery of this packet or not + + - - - Send an AgentAnimation packet that will toggle animations on or off - - A list of animation s, and whether to - turn that animation on or off - Whether to ensure delivery of this packet or not + + - - - Teleports agent to their stored home location - - true on successful teleport to home location + + - - - Teleport agent to a landmark - - of the landmark to teleport agent to - true on success, false on failure + + - - - Attempt to look up a simulator name and teleport to the discovered - destination - - Region name to look up - Position to teleport to - True if the lookup and teleport were successful, otherwise - false + + - - - Attempt to look up a simulator name and teleport to the discovered - destination - - Region name to look up - Position to teleport to - Target to look at - True if the lookup and teleport were successful, otherwise - false + + - - - Teleport agent to another region - - handle of region to teleport agent to - position in destination sim to teleport to - true on success, false on failure - This call is blocking + + - - - Teleport agent to another region - - handle of region to teleport agent to - position in destination sim to teleport to - direction in destination sim agent will look at - true on success, false on failure - This call is blocking + + - - - Request teleport to a another simulator - - handle of region to teleport agent to - position in destination sim to teleport to + + - - - Request teleport to a another simulator - - handle of region to teleport agent to - position in destination sim to teleport to - direction in destination sim agent will look at + + - - - Teleport agent to a landmark - - of the landmark to teleport agent to + + - - - Send a teleport lure to another avatar with default "Join me in ..." invitation message - - target avatars to lure + + - - - Send a teleport lure to another avatar with custom invitation message - - target avatars to lure - custom message to send with invitation + + - - - Respond to a teleport lure by either accepting it and initiating - the teleport, or denying it - - of the avatar sending the lure - IM session of the incoming lure request - true to accept the lure, false to decline it + + - - - Update agent profile - - struct containing updated - profile information + + - - - Update agents profile interests - - selection of interests from struct + + - - - Set the height and the width of the client window. This is used - by the server to build a virtual camera frustum for our avatar - - New height of the viewer window - New width of the viewer window + + - - - Request the list of muted objects and avatars for this agent - + + - - - Sets home location to agents current position - - will fire an AlertMessage () with - success or failure message + + - - - Move an agent in to a simulator. This packet is the last packet - needed to complete the transition in to a new simulator - - Object + + - - - Reply to script permissions request - - Object - of the itemID requesting permissions - of the taskID requesting permissions - list of permissions to allow + + - - - Respond to a group invitation by either accepting or denying it - - UUID of the group (sent in the AgentID field of the invite message) - IM Session ID from the group invitation message - Accept the group invitation or deny it + + - - - Requests script detection of objects and avatars - - name of the object/avatar to search for - UUID of the object or avatar to search for - Type of search from ScriptSensorTypeFlags - range of scan (96 max?) - the arc in radians to search within - an user generated ID to correlate replies with - Simulator to perform search in + + - - - Create or update profile pick - - UUID of the pick to update, or random UUID to create a new pick - Is this a top pick? (typically false) - UUID of the parcel (UUID.Zero for the current parcel) - Name of the pick - Global position of the pick landmark - UUID of the image displayed with the pick - Long description of the pick + + - - - Delete profile pick - - UUID of the pick to delete + + - - - Create or update profile Classified - - UUID of the classified to update, or random UUID to create a new classified - Defines what catagory the classified is in - UUID of the image displayed with the classified - Price that the classified will cost to place for a week - Global position of the classified landmark - Name of the classified - Long description of the classified - if true, auto renew classified after expiration + + - - - Create or update profile Classified - - UUID of the classified to update, or random UUID to create a new classified - Defines what catagory the classified is in - UUID of the image displayed with the classified - Price that the classified will cost to place for a week - Name of the classified - Long description of the classified - if true, auto renew classified after expiration + + - - - Delete a classified ad - - The classified ads ID + + - - - Fetches resource usage by agents attachmetns - - Called when the requested information is collected + + - - - Take an incoming ImprovedInstantMessage packet, auto-parse, and if - OnInstantMessage is defined call that with the appropriate arguments - - The sender - The EventArgs object containing the packet data + + - - - Take an incoming Chat packet, auto-parse, and if OnChat is defined call - that with the appropriate arguments. - - The sender - The EventArgs object containing the packet data + + - - - Used for parsing llDialogs - - The sender - The EventArgs object containing the packet data + + - - - Used for parsing llRequestPermissions dialogs - - The sender - The EventArgs object containing the packet data + + - - - Handles Script Control changes when Script with permissions releases or takes a control - - The sender - The EventArgs object containing the packet data + + - - - Used for parsing llLoadURL Dialogs - - The sender - The EventArgs object containing the packet data + + - - - Update client's Position, LookAt and region handle from incoming packet - - The sender - The EventArgs object containing the packet data - This occurs when after an avatar moves into a new sim + + - - 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 TeleportFailed message sent via EventQueue, informs agent its last teleport has failed and why. - - The Message Key - An IMessage object Deserialized from the recieved message event - The simulator originating the event message + + - - - Process TeleportFinish from Event Queue and pass it onto our TeleportHandler - - The message system key for this event - IMessage object containing decoded data from OSD - The simulator originating the event message + + - - 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 + + - - - Crossed region handler for message that comes across the EventQueue. Sent to an agent - when the agent crosses a sim border into a new region. - - The message key - the IMessage object containing the deserialized data sent from the simulator - The which originated the packet + + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data - This packet is now being sent via the EventQueue + + - - - Group Chat event handler - - The capability Key - IMessage object containing decoded data from OSD - + + - - - Response from request to join a group chat - - - IMessage object containing decoded data from OSD - + + - - - Someone joined or left group chat - - - IMessage object containing decoded data from OSD - + + - - - Handle a group chat Invitation - - Caps Key - IMessage object containing decoded data from OSD - Originating Simulator + + - - - Moderate a chat session - - the of the session to moderate, for group chats this will be the groups UUID - the of the avatar to moderate - Either "voice" to moderate users voice, or "text" to moderate users text session - true to moderate (silence user), false to allow avatar to speak + + - - 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 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 + + - - 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 or PG + + - - 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) + + - - 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 + + - - - Used to specify movement actions for your agent - + + - - Empty flag + + - - Move Forward (SL Keybinding: W/Up Arrow) + + - - Move Backward (SL Keybinding: S/Down Arrow) + + - - Move Left (SL Keybinding: Shift-(A/Left Arrow)) + + - - Move Right (SL Keybinding: Shift-(D/Right Arrow)) + + - - Not Flying: Jump/Flying: Move Up (SL Keybinding: E) + + - - Not Flying: Croutch/Flying: Move Down (SL Keybinding: C) + + - - Unused + + - - Unused + + - - Unused + + - - Unused + + - - ORed with AGENT_CONTROL_AT_* if the keyboard is being used + + - - ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used + + - - ORed with AGENT_CONTROL_UP_* if the keyboard is being used + + - - Fly + + - - + + - - Finish our current animation + + - - Stand up from the ground or a prim seat + + - - Sit on the ground at our current location + + - - Whether mouselook is currently enabled + + - - Legacy, used if a key was pressed for less than a certain amount of time + + - - Legacy, used if a key was pressed for less than a certain amount of time + + - - Legacy, used if a key was pressed for less than a certain amount of time + + - - Legacy, used if a key was pressed for less than a certain amount of time + + - - Legacy, used if a key was pressed for less than a certain amount of time + + - - Legacy, used if a key was pressed for less than a certain amount of time + + - - + + - - + + - - Set when the avatar is idled or set to away. Note that the away animation is - activated separately from setting this flag + + - - + + - - + + - - + + - - + + - - - Agent movement and camera control - - Agent movement is controlled by setting specific - After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags - This is most easily accomplished by setting one or more of the AgentMovement properties - - Movement of an avatar is always based on a compass direction, for example AtPos will move the - agent from West to East or forward on the X Axis, AtNeg will of course move agent from - East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis - 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 + + - - - Send new AgentUpdate packet to update our current camera - position and rotation - + + - - - 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 - - - - - - - - - - - - + + - - Move agent positive along the X axis + + - - Move agent negative along the X axis + + - - Move agent positive along the Y axis + + - - Move agent negative along the Y axis + + - - Move agent positive along the Z axis + + - - Move agent negative along the Z axis + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - Causes simulator to make agent fly + + - - Stop movement + + - - Finish animation + + - - Stand up from a sit + + - - Tells simulator to sit agent on ground + + - - Place agent into mouselook mode + + - - Nudge agent positive along the X axis + + - - Nudge agent negative along the X axis + + - - Nudge agent positive along the Y axis + + - - Nudge agent negative along the Y axis + + - - Nudge agent positive along the Z axis + + - - Nudge agent negative along the Z axis + + - - + + - - + + - - Tell simulator to mark agent as away + + - - + + - - + + - - + + - - + + - - - Returns "always run" value, or changes it by sending a SetAlwaysRunPacket - + + - - The current value of the agent control flags + + - - Gets or sets the interval in milliseconds at which - AgentUpdate packets are sent to the current simulator. Setting - this to a non-zero value will also enable the packet sending if - it was previously off, and setting it to zero will disable + + - - Gets or sets whether AgentUpdate packets are sent to - the current simulator + + - - Reset movement controls every time we send an update + + - - - 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 - + + - - + + - - The camera is a local frame of reference inside of - the larger grid space. This is where the math happens + + - - - Default constructor - + + - - + + - - + + - - + + - - + + - - - - + + - - - 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 + + - - Get the message sent + + - - Get the audible level of the message + + - - Get the type of message sent: whisper, shout, etc + + - - Get the source type of the message sender + + - - Get the name of the agent or object sending the message + + - - Get the ID of the agent or object sending the message + + - - Get the ID of the object owner, or the agent ID sending the message + + - - Get 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 + + - - Get the dialog message + + - - Get the name of the object that sent the dialog request + + - - Get the ID of the image to be displayed + + - - Get the ID of the primitive sending the dialog + + - - Get the first name of the senders owner + + - - Get the last name of the senders owner + + - - Get the communication channel the dialog was sent on, responses - should also send responses on this same channel + + - - Get the string labels containing the options presented in this dialog + + - - 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 + + - - Get the ID of the script making the request + + - - Get the ID of the primitive containing the script making the request + + - - Get the name of the primitive making the request + + - - Get the name of the owner of the object making the request + + - - Get 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 + + - - Get the ID of the object sending the request + + - - Get the ID of the owner of the object sending the request + + - - True if the object is owned by a group + + - - Get the message sent with the request + + - - Get the URL the object sent + + - - The date received from an ImprovedInstantMessage + + - - - Construct a new instance of the InstantMessageEventArgs object - - the InstantMessage object - the simulator where the InstantMessage origniated + + - - Get the InstantMessage object + + - - Get the simulator where the InstantMessage origniated + + - - Contains the currency 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 + + - - Get the ID of the transaction + + - - True of the transaction was successful + + - - Get the remaining currency balance + + - - Get the meters credited + + - - Get the meters comitted + + - - Get the description of the transaction + + - - 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 + + - - Get the agents last name + + - - Get the active group ID of your agent + + - - Get the active groups title of your agent + + - - Get the combined group powers of your agent + + - - Get the active group name of your agent + + - - Data sent by the simulator to indicate the active/changed animations - applied to your agent + + - - - 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 + + - - Get the ID of the agent or object that collided with your agent + + - - Get the ID of the agent that was attacked + + - - A value indicating the strength of the collision + + - - Get the time the collision occurred + + - - Data sent to your agent when it crosses region boundaries + + - - - Construct a new instance of the RegionCrossedEventArgs class - - 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 + + - - Get the name of the session + + - - Get the temporary session ID used for establishing new sessions + + - - True if your agent successfully joined the session + + - - Data sent by the simulator containing urgent messages + + - - - 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 + + - - 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 - + + - - - 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 + + - - Get the ID of the group associated with the primitive + + - - Get the name of the primitive sending the sensor + + - - Get the ID of the primitive sending the sensor + + - - Get the ID of the owner of the primitive sending the sensor + + - - Get the position of the primitive sending the sensor + + - - Get the range the primitive specified to scan + + - - Get the rotation of the primitive sending the sensor + + - - Get the type of sensor the primitive sent + + - - Get 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 + + - - True if the simulator Autopilot functions were involved + + - - Get the camera offset of the agent when seated + + - - Get the camera eye offset of the agent when seated + + - - True of the agent will be in mouselook mode when seated + + - - Get the position of the agent when seated + + - - Get the rotation of the agent when seated + + - - Data sent when an agent joins a chat session your agent is currently participating in + + - - - Construct a new instance of the ChatSessionMemberAddedEventArgs object - - 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 + + - - - Construct a new instance of the ChatSessionMemberLeftEventArgs object - - 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 + + - - - Return a decoded capabilities message as a strongly typed object - - A string containing the name of the capabilities message key - An to decode - A strongly typed object containing the decoded information from the capabilities message, or null - if no existing Message object exists for the specified event + + - - - 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 + + - - - 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 maximum size of the sequence number archive, used to - check for resent and/or duplicate packets + + - - 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 + + - - 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 + + - - Maximum number of queued ACKs to be sent before SendAcks() - is forced + + - - Network stats queue length (seconds) + + - - 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 + + - - 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 + + - - - 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. - - - Login Routines - + + - - 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 + + - - 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 + + - - 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 - Client application 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 - Client application 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 - Starting location URI that can be built with - StartLocation() - Client application 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 + + - - - Handles response from XML-RPC login replies - + + - - - 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 + + - - 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 + + - - 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 + + - - - 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 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 + + - - 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 + + + The current status of a texture request as it moves through the pipeline or final result of a texture request. + - - Use Estate Voice channel for Voice on this parcel + + The initial state given to a request. Requests in this state + are waiting for an available slot in the pipeline - - Deny Age Unverified Users + + A request that has been added to the pipeline and the request packet + has been sent to the simulator - - - Parcel ownership status - + + A request that has received one or more packets back from the simulator - - Placeholder + + A request that has received all packets back from the simulator - - Parcel is leased (owned) by an avatar or group + + A request that has taken longer than + to download OR the initial packet containing the packet information was never received - - Parcel is in process of being leased (purchased) by an avatar or group + + The texture request was aborted by request of the agent - - Parcel has been abandoned back to Governor Linden + + The simulator replied to the request that it was not able to find the requested texture - + - Category parcel is listed in under search + 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. - - No assigned category - - - Linden Infohub or public area - - - Adult themed area + + + 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. - - Arts and Culture + + 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 - - Business + + Holds the reference to the client object - - Educational + + Maximum concurrent texture requests allowed at a time - - Gaming + + An array of objects used to manage worker request threads - - Hangout or Club + + An array of worker slots which shows the availablity status of the slot - - Newcomer friendly + + The primary thread which manages the requests. - - Parks and Nature + + true if the TexturePipeline is currently running - - Residential + + A synchronization object used by the primary thread - - Shopping + + A refresh timer used to increase the priority of stalled requests - - Not Used? + + + Default constructor, Instantiates a new copy of the TexturePipeline class + + Reference to the instantiated object - - Other + + + Initialize callbacks required for the TexturePipeline to operate + - - Not an actual category, only used for queries + + + Shutdown the TexturePipeline and cleanup any callbacks or transfers + - + - Type of teleport landing for a parcel + 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 - - Unset, simulator default + + + 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 - - Specific landing point set for this parcel + + + Cancel a pending or in process texture request + + The texture assets unique ID - - No landing point set, direct teleports enabled for - this parcel + + + Master Download Thread, Queues up downloads in the threadpool + - + - Parcel Media Command used in ParcelMediaCommandMessage + The worker thread that sends the request and handles timeouts + A object containing the request details - - Stop the media stream and go back to the first frame + + + 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 - - Pause the media stream (stop playing but stay on current frame) + + + Handles the remaining Image data that did not fit in the initial ImageData packet + + The sender + The EventArgs object containing the packet data - - Start the current media stream playing and stop when the end is reached + + + Handle the initial ImageDataPacket sent from the simulator + + The sender + The EventArgs object containing the packet data - - Start the current media stream playing, - loop to the beginning when the end is reached and continue to play + + Current number of pending and in-process transfers - - 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. + + + A request task containing information and status of a request as it is processed through the + - - Specifies the movie URL (254 characters max) + + The current which identifies the current status of the request - - Specifies the time index at which to begin playing + + The Unique Request ID, This is also the Asset ID of the texture being requested - - Specifies a single agent to apply the media command to + + The slot this request is occupying in the threadpoolSlots array - - 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. + + The ImageType of the request. - - 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. + + The callback to fire when the request is complete, will include + the and the + object containing the result data - - Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). - Use "text/html" for HTML. + + 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. - - Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). - This might still not be working + + An object that maintains the data of an request thats in-process. - - Sets a description for the media being displayed (1.19.1 RC0 and later only). + + + Add a custom decoder callback + + The key of the field to decode + The custom decode handler - + - Some information about a parcel of land returned from a DirectoryManager search + Remove a custom decoder callback + The key of the field to decode + The custom decode handler - - Global Key of record + + + Creates a formatted string containing the values of a Packet + + The Packet + A formatted string of values of the nested items in the Packet object - - Parcel Owners + + + Decode an IMessage object into a beautifully formatted string + + The IMessage object + Recursion level (used for indenting) + A formatted string containing the names and values of the source object - - Name field of parcel, limited to 128 characters + + + A custom decoder callback + + The key of the object + the data to decode + A string represending the fieldData - - 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 + Status of the last application run. + Used for error reporting to the grid login service for statistical purposes. - - 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 + + Application exited normally - - A URL which points to any Quicktime supported media type + + Application froze - - A description of the media + + Application detected error and exited abnormally - - An Integer which represents the height of the media + + Other crash - - An integer which represents the width of the media + + Application froze during logout - - A string which contains the mime type of the media + + Application crashed during logout - + - Parcel of land, a portion of virtual real estate in a simulator + Login Request Parameters - - The total number of contiguous 4x4 meter blocks your agent owns within this parcel + + The URL of the Login Server - - The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own + + The number of milliseconds to wait before a login is considered + failed due to timeout - - Deprecated, Value appears to always be 0 + + The request method + login_to_simulator is currently the only supported method - - Simulator-local ID of this parcel + + The Agents First name - - UUID of the owner of this parcel + + The Agents Last name - - Whether the land is deeded to a group or not + + 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 - - Date land was claimed + + A string containing the client software channel information + Second Life Release - - Appears to always be zero + + 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 - - This field is no longer used + + A string containing the platform information the agent is running on - - Minimum corner of the axis-aligned bounding box for this - parcel + + A string hash of the network cards Mac Address - - Maximum corner of the axis-aligned bounding box for this - parcel + + Unknown or deprecated - - Bitmap describing land layout in 4x4m squares across the - entire region + + A string hash of the first disk drives ID used to identify this clients uniqueness - - Total parcel land area + + 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 - - Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used + + If true, this agent agrees to the Terms of Service of the grid its connecting to - - 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 + + Unknown - - Maximum number of primitives this parcel supports + + Status of the last application run sent to the grid login server for statistical purposes - - Total number of primitives on this parcel + + An array of string sent to the login server to enable various options - - 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 + + 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 - - 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. + + + Default constuctor, initializes sane default values + - - Total number of prims owned by other avatars that are not set to group, or not the parcel owner + + + 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 - - 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 + + + 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 - - Autoreturn value in minutes for others' objects + + + The decoded data returned from the login server after a successful login + - - + + true, false, indeterminate - - 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 + + Login message of the day - - Parcel Name + + M or PG, also agent_region_access and agent_access_max - - Parcel Description + + + 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 - - URL For Music Stream + + + 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 - - Price for a temporary pass + + Raises the LoginProgress Event + A LoginProgressEventArgs object containing + the data sent from the simulator - - How long is pass valid for + + Thread sync lock object - - + + Seed CAPS URL returned from the login server - - Key of authorized buyer + + Maximum number of groups an agent can belong to, -1 for unlimited - - Key of parcel snapshot + + Server side baking service URL - - The landing point location - - - The landing point LookAt - - - The type of landing enforced from the enum - - - - - - - - - + + A list of packets obtained during the login process which + networkmanager will log but not process - - Access list of who is whitelisted on this - parcel + + + 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 - - Access list of who is blacklisted on this - parcel + + + 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 - - TRUE of region denies access to age unverified users + + + 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 - - true to obscure (hide) media url + + + 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 - - true to obscure (hide) music url + + + 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 - - A struct containing media details + + + LoginParams and the initial login XmlRpcRequest were made on a remote machine. + This method now initializes libomv with the results. + - + - Displays a parcel object in string format + Handles response from XML-RPC login replies - string containing key=value pairs of a parcel object - + - Defalt constructor + Handles response from XML-RPC login replies with already parsed LoginResponseData - Local ID of this parcel - + - Update the simulator with any local changes to this Parcel object + Handle response from LLSD login replies - Simulator to send updates to - Whether we want the simulator to confirm - the update with a reply packet or not + + + - + - Set Autoreturn time + Get current OS - Simulator to send the update to + Either "Win" or "Linux" - + - Parcel (subdivided simulator lots) subsystem + Get clients default Mac Address + A string containing the first found Mac Address - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ParcelDwellReply event - A ParcelDwellReplyEventArgs object containing the - data returned from the simulator + + Raises the PacketSent Event + A PacketSentEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ParcelInfoReply event - A ParcelInfoReplyEventArgs object containing the - data returned from the simulator + + Raises the LoggedOut Event + A LoggedOutEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ParcelProperties event - A ParcelPropertiesEventArgs object containing the - data returned from the simulator + + Raises the SimConnecting Event + A SimConnectingEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ParcelAccessListReply event - A ParcelAccessListReplyEventArgs object containing the - data returned from the simulator + + Raises the SimConnected Event + A SimConnectedEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ParcelObjectOwnersReply event - A ParcelObjectOwnersReplyEventArgs object containing the - data returned from the simulator + + Raises the SimDisconnected Event + A SimDisconnectedEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the SimParcelsDownloaded event - A SimParcelsDownloadedEventArgs object containing the - data returned from the simulator + + Raises the Disconnected Event + A DisconnectedEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ForceSelectObjectsReply event - A ForceSelectObjectsReplyEventArgs object containing the - data returned from the simulator + + Raises the SimChanged Event + A SimChangedEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + The event subscribers, null of no subscribers - - Raises the ParcelMediaUpdateReply event - A ParcelMediaUpdateReplyEventArgs object containing the - data returned from the simulator + + Raises the EventQueueRunning Event + A EventQueueRunningEventArgs object containing + the data sent from the simulator - + Thread sync lock object - - The event subscribers. null if no subcribers + + All of the simulators we are currently connected to - - Raises the ParcelMediaCommand event - A ParcelMediaCommandEventArgs object containing the - data returned from the simulator + + Handlers for incoming capability events - - Thread sync lock object + + Handlers for incoming packets - + + Incoming packets that are awaiting handling + + + Outgoing packets that are awaiting handling + + Default constructor - A reference to the GridClient object + Reference to the GridClient object - + - Request basic information for a single parcel - - Simulator-local ID of the parcel - - - - Request properties of a single parcel + 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 - 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 + Packet type to trigger events for + Callback to fire when a packet of this type + is received - + - Request the access list for a single parcel + 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 - 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 - + 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 - + - Request properties of parcels using a bounding box selection + 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 - 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 + Packet type this callback is registered with + Callback to stop firing events for - + - Request all simulator parcel properties (used for populating the Simulator.Parcels - dictionary) + 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 - Simulator to request parcels from (must be connected) + Name of the CAPS event to register a handler for + Callback to fire when a CAPS event is received - + - Request all simulator parcel properties (used for populating the Simulator.Parcels - dictionary) + 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 - Simulator to request parcels from (must be connected) - If TRUE, will force a full refresh - Number of milliseconds to pause in between each request + Name of the CAPS event this callback is + registered with + Callback to stop firing events for - + - Request the dwell value for a parcel + Send a packet to the simulator the avatar is currently occupying - Simulator containing the parcel - Simulator-local ID of the parcel + Packet to send - + - Send a request to Purchase a parcel of land + Send a packet to a specified simulator - 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 - + Packet to send + Simulator to send the packet to - + - Reclaim a parcel of land + Connect to a simulator - The simulator the parcel is in - The parcels region specific local ID + 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 - + - Deed a parcel to a group + Connect to a simulator - The simulator the parcel is in - The parcels region specific local ID - The groups + 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 - + - Request prim owners of a parcel of land. + 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 - Simulator parcel is in - The parcels region specific local ID - + - Return objects from a parcel + 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 - 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 + Close a connection to the given simulator - - - - + - + - Join two parcels of land creating a single parcel + 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 - + - Get a parcels LocalID + 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 - 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. + Type of shutdown + Shutdown message - + - Terraform (raise, lower, etc) an area or whole parcel of land + Searches through the list of currently connected simulators to find + one attached to the given IPEndPoint - 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() + IPEndPoint of the Simulator to search for + A Simulator reference on success, otherwise null - + - Terraform (raise, lower, etc) an area or whole parcel of land + Fire an event when an event queue connects for capabilities - 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() + Simulator the event queue is attached to - - - 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() + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - 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 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - 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 sends us data containing + ... - - Raised when the simulator responds to a request + + Called when a reply is received from the login server, the + login sequence will block until this event returns - - Raised when the simulator responds to a request + + Current state of logging in - - Raised when the simulator responds to a request + + Upon login failure, contains a short string key for the + type of login error that occurred - - Raised when the simulator responds to a request + + The raw XML-RPC reply from the login server, exactly as it + was received (minus the HTTP header) - - Raised when the simulator responds to a request + + 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 responds to a request + + Raised when the simulator sends us data containing + ... - - Raised when the simulator responds to a Parcel Update request + + Raised when the simulator sends us data containing + ... - - Raised when the parcel your agent is located sends a ParcelMediaCommand + + Raised when the simulator sends us data containing + ... - - - Parcel Accesslist - + + Raised when the simulator sends us data containing + ... - - Agents + + Raised when the simulator sends us data containing + ... - - + + Raised when the simulator sends us data containing + ... - - Flags for specific entry in white/black lists + + Raised when the simulator sends us data containing + ... - - - Owners of primitives on parcel - + + Raised when the simulator sends us data containing + ... - - Prim Owners + + Unique identifier associated with our connections to + simulators - - True of owner is group + + The simulator that the logged in avatar is currently + occupying - - Total count of prims owned by OwnerID + + Shows whether the network layer is logged in to the + grid or not - - true of OwnerID is currently online and is not a group + + Number of packets in the incoming queue - - The date of the most recent prim left by OwnerID + + Number of packets in the outgoing queue - + - 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 + Explains why a simulator or the grid disconnected from us - 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 + + The client requested the logout or simulator disconnect - - Get the simulator specific ID of the parcel + + The server notified us that it is disconnecting - - Get the calculated dwell + + Either a socket was closed or network traffic timed out - - Contains basic parcel information data returned from the - simulator in response to an request + + The last active simulator shut down - + - Construct a new instance of the ParcelInfoReplyEventArgs class + Holds a simulator reference and a decoded packet, these structs are put in + the packet inbox for event handling - The object containing basic parcel info - - Get the object containing basic parcel info + + Reference to the simulator that this packet came from - - Contains basic parcel information data returned from the simulator in response to an request + + Packet that needs to be processed - + - Construct a new instance of the ParcelPropertiesEventArgs class + Holds a simulator reference and a serialized packet, these structs are put in + the packet outbox for sending - 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 + + Reference to the simulator this packet is destined for - - Get the object containing the details - If Result is NoData, this object will not contain valid data + + Packet that needs to be sent - - Get the result of the request + + Sequence number of the wrapped packet - - Get the number of primitieves your agent is - currently selecting and or sitting on in this parcel + + Number of times this packet has been resent - - Get the user assigned ID used to correlate a request with - these results + + Environment.TickCount when this packet was last sent over the wire - - TODO: + + Type of the packet - - Contains blacklist and whitelist data returned from the simulator in response to an request - - + - Construct a new instance of the ParcelAccessListReplyEventArgs class + Return a decoded capabilities message as a strongly typed object - 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 + A string containing the name of the capabilities message key + An to decode + A strongly typed object containing the decoded information from the capabilities message, or null + if no existing Message object exists for the specified event - + - Construct a new instance of the ParcelObjectOwnersReplyEventArgs class + Capability to load TGAs to Bitmap - The simulator the parcel is located in - The list containing prim ownership counts - - Get the simulator the parcel is located in + + + 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 - - Get the list containing prim ownership counts + + Main grid login server - - Contains the data returned when all parcel data has been retrieved from a simulator + + Beta grid login server - + - Construct a new instance of the SimParcelsDownloadedEventArgs class + InventoryManager requests inventory information on login, + GridClient initializes an Inventory store for main inventory. - 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 + + + InventoryManager requests library information on login, + GridClient initializes an Inventory store for the library. + - - Get the multidimensional array containing a x,y grid mapped - to each 64x64 parcel's LocalID. + + Number of milliseconds between sending pings to each sim - - Contains the data returned when a request + + Number of milliseconds between sending camera updates - - - 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 + + Number of milliseconds between updating the current + positions of moving, non-accelerating and non-colliding objects - - Get the simulator the parcel data was retrieved from + + Millisecond interval between ticks, where all ACKs are + sent out and the age of unACKed packets is checked - - Get the list of primitive IDs + + The initial size of the packet inbox, where packets are + stored before processing - - true if the list is clean and contains the information - only for a given request + + Maximum size of packet that we want to send over the wire - - Contains data when the media data for a parcel the avatar is on changes + + The maximum value of a packet sequence number before it + rolls over back to one - - - Construct a new instance of the ParcelMediaUpdateReplyEventArgs class - - the simulator the parcel media data was updated in - The updated media information + + The relative directory where external resources are kept - - Get the simulator the parcel media data was updated in + + Login server to connect to - - Get the updated media information + + IP Address the client will bind to - - Contains the media command for a parcel the agent is currently on + + Use XML-RPC Login or LLSD Login, default is XML-RPC Login - + - Construct a new instance of the ParcelMediaCommandEventArgs class + Use Caps for fetching inventory where available - 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 + + 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 - - Get the media command that was sent + + 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 - - - 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 + + Network stats queue length (seconds) - + - A dictionary of callbacks to fire when specified action occurs + 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 - + - Register a callback to be fired when an action occurs + Pool parcel data between clients (saves on requesting multiple times when all clients may need it) - The action - The callback to fire - + - Unregister a callback + 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 - The action - The callback to fire - - - - - - + + Enable/disable storing terrain heightmaps in the + TerrainManager - - Internal dictionary that this class wraps around. Do not - modify or enumerate the contents of this dictionary without locking + + Enable/disable sending periodic camera updates - - - 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>(); - - + + Enable/disable automatically setting agent appearance at + login and after sim crossing - - - Initializes a new instance of the Class + + 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 + + + + 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 ObservableDictionary named testDict with a string as the key and an int as the value, + // 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 ObservableDictionary<string, int> testDict = new ObservableDictionary<string, int>(10); + public InternalDictionary<string, int> testDict = new InternalDictionary<string, int>(10); - + - Try to get entry from the with specified key + 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 ObservableDictionary: + // 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); @@ -9700,7 +8921,7 @@ - + Finds the specified match. @@ -9708,7 +8929,7 @@ Matched value - // use a delegate to find a prim in the ObjectsPrimitives ObservableDictionary + // use a delegate to find a prim in the ObjectsPrimitives InternalDictionary // with the ID 95683496 uint findID = 95683496; Primitive findPrim = sim.ObjectsPrimitives.Find( @@ -9716,8 +8937,8 @@ - - Find All items in an + + Find All items in an return matching items. a containing found items. @@ -9733,8 +8954,8 @@ - - Find All items in an + + Find All items in an return matching keys. a containing found keys. @@ -9748,6957 +8969,5955 @@ - - 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, - - + + 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 - + - Clear the contents of the dictionary + Gets the number of Key/Value pairs contained in the - + - Enumerator for iterating dictionary entries + Indexer for the dictionary - + The key + The value - + - Gets the number of Key/Value pairs contained in the + Avatar profile flags - + - Indexer for the dictionary + Represents an avatar (other than your own) - The key - The value - + - Avatar group management + Particle system specific enumerators, flags and methods. - - 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 + + Foliage type for this primitive. Only applicable if this + primitive is foliage - - Group Title associated with Role + + Unknown - - 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 + + Identifies the owner if audio or a particle system is + active - - 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 + + Objects physics engine propertis - - The number of roles this group has configured + + Extra data about primitive - - Show this group in agent's profile + + Indicates if prim is attached to an avatar - - Returns the name of the group - A string containing the name of the group + + Number of clients referencing this prim - + - A group Vote + Default constructor - - Key of Avatar who created Vote + + + 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 - - Text of the Vote proposal + + + 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 - - Total number of votes + + + Current version of the media data for the prim + - + - A group proposal + Array of media entries indexed by face number - - 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 + + Uses basic heuristics to estimate the primitive shape - + - + 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 + + - + - + - Struct representing a group notice + 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 + + + - + - Struct representing a group notice list entry + + - - Notice ID + + + + + - - Creation timestamp of notice + + + + + - - Agent name who created notice + + + Controls the texture animation of a particular prim + - - 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 + Parameters used to construct a visual representation of a primitive - + - + - + - + - + - + - + - - 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 + + + Calculdates hash code for prim construction data + + The has - - Can subdivide and join parcels + + Attachment point to an avatar - - 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 + + + Information on the flexible properties of a primitive + - - 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 + + + Default constructor + - - 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 + + + Information on the light properties of a primitive + - - 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 + + + Default constructor + - - Can deed objects to group + + + + + + - - Can move group owned objects + + + + + - - Can set group owned objects for-sale + + + + + - - Pay group liabilities and receive group dividends + + + Information on the light properties of a primitive as texture map + - - Can send group notices + + - - Can receive group notices + + - - Can create group proposals + + + Default constructor + - - Can vote on group proposals + + + + + + - + - 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 + + + Information on the sculpt properties of a sculpted primitive + - - Thread sync lock object + + + Default constructor + - - The event subscribers. null if no subcribers + + + + + + - - Raises the GroupNamesReply event - A GroupNamesEventArgs object containing the - data response from the simulator + + + Render inside out (inverts the normals). + - - Thread sync lock object + + + Render an X axis mirror of the sculpty. + - - The event subscribers. null if no subcribers + + + Extended properties to describe an object + - - 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 + + + Default constructor + - - Raises the GroupLeft event - A GroupOperationEventArgs object containing the - result of the operation returned from the simulator + + + Set the properties that are set in an ObjectPropertiesFamily packet + + that has + been partially filled by an ObjectPropertiesFamily packet - - Thread sync lock object + + + Describes physics attributes of the prim + - - The event subscribers. null if no subcribers + + Primitive's local ID - - Raises the GroupDropped event - An GroupDroppedEventArgs object containing the - the group your agent left + + Density (1000 for normal density) - - Thread sync lock object + + Friction - - The event subscribers. null if no subcribers + + Gravity multiplier (1 for normal gravity) - - Raises the GroupMemberEjected event - An GroupMemberEjectedEventArgs object containing the - data returned from the simulator + + Type of physics representation of this primitive in the simulator - - Thread sync lock object + + Restitution - - The event subscribers. null if no subcribers + + + Creates PhysicsProperties from OSD + + OSDMap with incoming data + Deserialized PhysicsProperties object - - Raises the GroupNoticesListReply event - An GroupNoticesListReplyEventArgs object containing the - data returned from the simulator + + + Serializes PhysicsProperties to OSD + + OSDMap with serialized PhysicsProperties data - - Thread sync lock object + + + Complete structure for the particle system + - - The event subscribers. null if no subcribers + + 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 - - Raises the GroupInvitation event - An GroupInvitationEventArgs object containing the - data returned from the simulator + + pattern of particles - - Thread sync lock object + + A representing the maximimum age (in seconds) particle will be displayed + Maximum value is 30 seconds - - A reference to the current instance + + 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 - - Currently-active group members requests + + A in radians that specifies where particles will not be created - - Currently-active group roles requests + + A in radians that specifies where particles will be created - - Currently-active group role-member requests + + A representing the number of seconds between burts. - - Dictionary keeping group members while request is in progress + + A representing the number of meters + around the center of the source where particles will be created. - - Dictionary keeping mebmer/role mapping while request is in progress + + A representing in seconds, the minimum speed between bursts of new particles + being emitted - - Dictionary keeping GroupRole information while request is in progress + + A representing in seconds the maximum speed of new particles being emitted. - - Caches group name lookups + + A representing the maximum number of particles emitted per burst - - - Construct a new instance of the GroupManager class - - A reference to the current instance + + A which represents the velocity (speed) from the source which particles are emitted - - - 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. + + A which represents the Acceleration from the source which particles are emitted - - - Lookup name of group based on groupID - - groupID of group to lookup name for. + + The Key of the texture displayed on the particle - - - Request lookup of multiple group names - - List of group IDs to request. + + The Key of the specified target object or avatar particles will follow - - Lookup group profile data such as name, enrollment, founder, logo, etc - Subscribe to OnGroupProfile event to receive the results. - group ID (UUID) + + Flags of particle from - - 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 + + Max Age particle system will emit particles for - - 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 + + The the particle has at the beginning of its lifecycle - - 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) + + The the particle has at the ending of its lifecycle - - 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 + + A that represents the starting X size of the particle + Minimum value is 0, maximum value is 4 - - Set a group as the current active group - group ID (UUID) + + A that represents the starting Y size of the particle + Minimum value is 0, maximum value is 4 - - Change the role that determines your active title - Group ID to use - Role ID to change to + + A that represents the ending X size of the particle + Minimum value is 0, maximum value is 4 - - Set this avatar's tier contribution - Group ID to change tier in - amount of tier to donate + + A that represents the ending Y size of the particle + Minimum value is 0, maximum value is 4 - + - Save wheather agent wants to accept group notices and list this group in their profile + Decodes a byte[] array into a ParticleSystem Object - Group - Accept notices from this group - List this group in the profile + ParticleSystem object + Start position for BitPacker - - Request to join a group - Subscribe to OnGroupJoined event for confirmation. - group ID (UUID) to join. + + + Generate byte[] array from particle data + + Byte array - + - Request to create a new group. If the group is successfully - created, L$100 will automatically be deducted + Particle source pattern - 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. + + None - - Eject a user from a group - Group ID to eject the user from - Avatar's key to eject + + Drop particles from source position with no force - - Update role information - Modified role to be updated + + "Explode" particles in all directions - - Create a new group role - Group ID to update - Role to create + + Particles shoot across a 2D area - - Delete a group role - Group ID to update - Role to delete + + Particles shoot across a 3D Cone - - Remove an avatar from a role - Group ID to update - Role ID to be removed from - Avatar's Key to remove + + Inverse of AngleCone (shoot particles everywhere except the 3D cone defined - - Assign an avatar to a role - Group ID to update - Role ID to assign to - Avatar's ID to assign to role + + + Particle Data Flags + - - Request the group notices list - Group ID to fetch notices for + + None - - Request a group notice by key - ID of group notice + + Interpolate color and alpha from start to end - - Send out a group notice - Group ID to update - GroupNotice structure containing notice data + + Interpolate scale from start to end - - Start a group proposal (vote) - The Group ID to send proposal to - GroupProposal structure containing the proposal + + Bounce particles off particle sources Z height - - Request to leave a group - Subscribe to OnGroupLeft event to receive confirmation - The group to leave + + velocity of particles is dampened toward the simulators wind - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Particles follow the source - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Particles point towards the direction of source's velocity - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Target of the particles - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Particles are sent in a straight line - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Particles emit a glow - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + used for point/grab/touch - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Particle Flags Enum + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + None - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Acceleration and velocity for particles are + relative to the object rotation - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Particles use new 'correct' angle parameters - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Groups that this avatar is a member of - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Positive and negative ratings - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Avatar properties including about text, profile URL, image IDs and + publishing settings - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Avatar interests including spoken languages, skills, and "want to" + choices - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Movement control flags for avatars. Typically not set or used by + clients. To move your avatar, use Client.Self.Movement instead - - Raised when the simulator sends us data containing - our current group membership + + + Contains the visual parameters describing the deformation of the avatar + - - Raised when the simulator responds to a RequestGroupName - or RequestGroupNames request + + + Appearance version. Value greater than 0 indicates using server side baking + - - 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 + + + Version of the Current Outfit Folder that the appearance is based on + - - Raised when the simulator responds to a request + + + Appearance flags. Introduced with server side baking, currently unused. + - - Raised when a response to a RequestGroupAccountSummary is returned - by the simulator + + + List of current avatar animations + - - Raised when a request to create a group is successful + + + Default constructor + - - Raised when a request to join a group either - fails or succeeds + + First name - - Raised when a request to leave a group either - fails or succeeds + + Last name - - Raised when A group is removed from the group server + + Full name - - Raised when a request to eject a member from a group either - fails or succeeds + + Active group - - Raised when the simulator sends us group notices - + + + Positive and negative ratings + - - Raised when another agent invites our avatar to join a group + + Positive ratings for Behavior - - Contains the current groups your agent is a member of + + Negative ratings for Behavior - - Construct a new instance of the CurrentGroupsEventArgs class - The current groups your agent is a member of + + Positive ratings for Appearance - - Get the current groups your agent is a member of + + Negative ratings for Appearance - - A Dictionary of group names, where the Key is the groups ID and the value is the groups name + + Positive ratings for Building - - Construct a new instance of the GroupNamesEventArgs class - The Group names dictionary + + Negative ratings for Building - - Get the Group Names dictionary + + Positive ratings given by this avatar - - Represents the members of a group + + Negative ratings given by this avatar - + - Construct a new instance of the GroupMembersReplyEventArgs class + Avatar properties including about text, profile URL, image IDs and + publishing settings - 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 + + First Life about text - - Get the ID of the group + + First Life image ID - - 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 + + Profile image ID - - Get the dictionary containing the roles + + Flags of the profile - - Represents the Role to Member mappings for a group + + Web URL for this profile - - 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 + + Should this profile be published on the web - - Get the ID as returned by the request to correlate - this result set and the request + + Avatar Online Status - - Get the ID of the group + + Is this a mature profile - - 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 + + + Avatar interests including spoken languages, skills, and "want to" + choices + - - Get the ID as returned by the request to correlate - this result set and the request + + Languages profile field - - 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 + + + Throttles the network traffic for various different traffic types. + Access this class through GridClient.Throttle + - - Get the summary data + + + Default constructor, uses a default high total of 1500 KBps (1536000) + - - A response to a group create request + + + Constructor that decodes an existing AgentThrottle packet in to + individual values + + Reference to the throttle data in an AgentThrottle + packet + Offset position to start reading at in the + throttle data + This is generally not needed in clients as the server will + never send a throttle packet to the client - - 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 + + + Send an AgentThrottle packet to the current server using the + current values + - - Get the ID of the group + + + Send an AgentThrottle packet to the specified server using the + current values + - - true of the group was created successfully + + + Convert the current throttle values to a byte array that can be put + in an AgentThrottle packet + + Byte array containing all the throttle values - - A string containing the message + + Maximum bits per second for resending unacknowledged packets - - Represents a response to a request + + Maximum bits per second for LayerData terrain - - Construct a new instance of the GroupOperationEventArgs class - The ID of the group - true of the request was successful + + Maximum bits per second for LayerData wind data - - Get the ID of the group + + Maximum bits per second for LayerData clouds - - true of the request was successful + + Unknown, includes object data - - Represents your agent leaving a group + + Maximum bits per second for textures - - Construct a new instance of the GroupDroppedEventArgs class - The ID of the group + + Maximum bits per second for downloaded assets - - Get the ID of the group + + Maximum bits per second the entire connection, divided up + between invidiual streams using default multipliers - - 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 + + Number of times we've received an unknown CAPS exception in series. - - Get the ID of the group + + For exponential backoff on error. - - Get the notices list + + + Represents Mesh asset + - - Represents the profile of a group + + + Decoded mesh data + - - Construct a new instance of the GroupProfileEventArgs class - The group profile + + Initializes a new instance of an AssetMesh object - - Get the group profile + + Initializes a new instance of an AssetMesh object with parameters + A unique specific to this asset + A byte array containing the raw asset data - + - Provides notification of a group invitation request sent by another Avatar + TODO: Encodes Collada file into LLMesh format - 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 + + + Decodes mesh asset. See + to furter decode it for rendering + true - - The name of the Avatar sending the group invitation + + Override the base classes AssetType - - A message containing the request information which includes - the name of the group, the groups charter and the fee to join details + + X position of this patch - - The Simulator + + Y position of this patch - - Set to true to accept invitation, false to decline + + 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 - Looking direction, must be a normalized vector - Up direction, must be a normalized vector + 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 + - + - Align the coordinate frame X and Y axis with a given rotation - around the Z axis in radians + Add a patch of terrain to a BitPacker - 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 + 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 - + - Avatar profile flags + Permission request flags, asked when a script wants to control an Avatar - - - Represents an avatar (other than your own) - + + Placeholder for empty values, shouldn't ever see this - - Groups that this avatar is a member of + + Script wants ability to take money from you - - Positive and negative ratings + + Script wants to take camera controls for you - - Avatar properties including about text, profile URL, image IDs and - publishing settings + + Script wants to remap avatars controls - - Avatar interests including spoken languages, skills, and "want to" - choices + + Script wants to trigger avatar animations + This function is not implemented on the grid - - Movement control flags for avatars. Typically not set or used by - clients. To move your avatar, use Client.Self.Movement instead + + Script wants to attach or detach the prim or primset to your avatar - - - Contains the visual parameters describing the deformation of the avatar - + + Script wants permission to release ownership + This function is not implemented on the grid + The concept of "public" objects does not exist anymore. - - - Default constructor - + + Script wants ability to link/delink with other prims - - First name + + Script wants permission to change joints + This function is not implemented on the grid - - Last name + + Script wants permissions to change permissions + This function is not implemented on the grid - - Full name + + Script wants to track avatars camera position and rotation - - Active group + + Script wants to control your camera - + + Script wants the ability to teleport you + + - Positive and negative ratings + Special commands used in Instant Messages - - Positive ratings for Behavior + + Indicates a regular IM from another agent - - Negative ratings for Behavior + + Simple notification box with an OK button - - Positive ratings for Appearance + + You've been invited to join a group. - - Negative ratings for Appearance + + Inventory offer - - Positive ratings for Building + + Accepted inventory offer - - Negative ratings for Building + + Declined inventory offer - - Positive ratings given by this avatar + + Group vote - - Negative ratings given by this avatar + + An object is offering its inventory - - - Avatar properties including about text, profile URL, image IDs and - publishing settings - + + Accept an inventory offer from an object - - First Life about text + + Decline an inventory offer from an object - - First Life image ID + + Unknown - - + + Start a session, or add users to a session - - + + Start a session, but don't prune offline users - - + + Start a session with your group - - + + Start a session without a calling card (finder or objects) - - Profile image ID + + Send a message to a session - - Flags of the profile + + Leave a session - - Web URL for this profile + + Indicates that the IM is from an object - - Should this profile be published on the web + + Sent an IM to a busy user, this is the auto response - - Avatar Online Status + + Shows the message in the console and chat history - - Is this a mature profile + + Send a teleport lure - - + + Response sent to the agent which inititiated a teleport invitation - - + + Response sent to the agent which inititiated a teleport invitation - - - Avatar interests including spoken languages, skills, and "want to" - choices - + + Only useful if you have Linden permissions - - Languages profile field + + Request a teleport lure - - + + IM to tell the user to go to an URL - - + + IM for help - - + + IM sent automatically on call for help, sends a lure + to each Helper reached - - + + Like an IM but won't go to email - - - Extract the avatar UUID encoded in a SIP URI - - - + + IM from a group officer to all group members - - - Permissions for control of object media - + + Unknown - - - Style of cotrols that shold be displayed to the user - + + Unknown - - - Class representing media data for a single face - + + Accept a group invitation - - Is display of the alternative image enabled + + Decline a group invitation - - Should media auto loop + + Unknown - - Shoule media be auto played + + An avatar is offering you friendship - - Auto scale media to prim face + + An avatar has accepted your friendship offer - - Should viewer automatically zoom in on the face when clicked + + An avatar has declined your friendship offer - - Should viewer interpret first click as interaction with the media - or when false should the first click be treated as zoom in commadn + + Indicates that a user has started typing - - Style of controls viewer should display when - viewer media on this face + + Indicates that a user has stopped typing - - Starting URL for the media + + + Flag in Instant Messages, whether the IM should be delivered to + offline avatars as well + - - Currently navigated URL + + Only deliver to online avatars - - Media height in pixes + + If the avatar is offline the message will be held until + they login next, and possibly forwarded to their e-mail account - - Media width in pixels + + + Conversion type to denote Chat Packet types in an easier-to-understand format + - - Who can controls the media + + Whisper (5m radius) - - Who can interact with the media + + Normal chat (10/20m radius), what the official viewer typically sends - - Is URL whitelist enabled + + Shouting! (100m radius) - - Array of URLs that are whitelisted + + Event message when an Avatar has begun to type - - - Serialize to OSD - - OSDMap with the serialized data + + Event message when an Avatar has stopped typing - - - Deserialize from OSD data - - Serialized OSD data - Deserialized object + + Send the message to the debug channel - - - Operation to apply when applying color to texture - + + Event message when an object uses llOwnerSay - - - Information needed to translate visual param value to RGBA color - + + Special value to support llRegionSay, never sent to the client - + - Construct VisualColorParam + Identifies the source of a chat message - Operation to apply when applying color to texture - Colors - + + Chat from the grid or simulator + + + Chat from another avatar + + + Chat from an object + + - Represents alpha blending and bump infor for a visual parameter - such as sleive length + - - Stregth of the alpha to apply - - - File containing the alpha channel + + - - Skip blending if parameter value is 0 + + - - Use miltiply insted of alpha blending + + - + - Create new alhpa information for a visual param + Effect type used in ViewerEffect packets - Stregth of the alpha to apply - File containing the alpha channel - Skip blending if parameter value is 0 - Use miltiply insted of alpha blending - - - A single visual characteristic of an avatar mesh, such as eyebrow height - + + - - Index of this visual param + + - - Internal name + + - - Group ID this parameter belongs to + + - - Name of the wearable this parameter belongs to + + - - Displayable label of this characteristic + + - - Displayable label for the minimum value of this characteristic + + - - Displayable label for the maximum value of this characteristic + + Project a beam from a source to a destination, such as + the one used when editing an object - - Default value + + - - Minimum value + + - - Maximum value + + - - Is this param used for creation of bump layer? + + Create a swirl of particles around an object - - Alpha blending/bump info + + - - Color information + + - - Array of param IDs that are drivers for this parameter + + Cause an avatar to look at an object - - - Set all the values through the constructor - - Index of this visual param - Internal name - - - Displayable label of this characteristic - Displayable label for the minimum value of this characteristic - Displayable label for the maximum value of this characteristic - Default value - Minimum value - Maximum value - Is this param used for creation of bump layer? - Array of param IDs that are drivers for this parameter - Alpha blending/bump info - Color information + + Cause an avatar to point at an object - + - Holds the Params array of all the avatar appearance parameters + The action an avatar is doing when looking at something, used in + ViewerEffect packets for the LookAt effect - - - 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; }); - - + + Deprecated - - 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 + The action an avatar is doing when pointing at something, used in + ViewerEffect packets for the PointAt effect - 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, - + Money transaction types - 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 + + - - - This is used to initialize and stop the Connector as a whole. The Connector - Create call must be completed successfully before any other requests are made - (typically during application initialization). The shutdown should be called - when the application is shutting down to gracefully release resources - - A string value indicting the Application name - URL for the management server - LoggingSettings - - + + - - - Shutdown Connector -- Should be called when the application is shutting down - to gracefully release resources - - Handle returned from successful Connector ‘create’ request + + - - - Mute or unmute the microphone - - Handle returned from successful Connector ‘create’ request - true (mute) or false (unmute) + + - - - Mute or unmute the speaker - - Handle returned from successful Connector ‘create’ request - true (mute) or false (unmute) + + - - - Set microphone volume - - Handle returned from successful Connector ‘create’ request - The level of the audio, a number between -100 and 100 where - 0 represents ‘normal’ speaking volume + + - - - Set local speaker volume - - Handle returned from successful Connector ‘create’ request - The level of the audio, a number between -100 and 100 where - 0 represents ‘normal’ speaking volume + + - - - Starts a thread that keeps the daemon running - - - + + - - - Stops the daemon and the thread keeping it running - + + - - - - - - - + + - - - This is used to get a list of audio devices that can be used for capture (input) of voice. - - + + - - - This is used to get a list of audio devices that can be used for render (playback) of voice. - + + - - - This command is used to select the render device. - - The name of the device as returned by the Aux.GetRenderDevices command. + + - - - This command is used to select the capture device. - - The name of the device as returned by the Aux.GetCaptureDevices command. + + - - - This command is used to start the audio capture process which will cause - AuxAudioProperty Events to be raised. These events can be used to display a - microphone VU meter for the currently selected capture device. This command - should not be issued if the user is on a call. - - (unused but required) - + + - - - This command is used to stop the audio capture process. - - + + - - - This command is used to set the mic volume while in the audio tuning process. - Once an acceptable mic level is attained, the application must issue a - connector set mic volume command to have that level be used while on voice - calls. - - the microphone volume (-100 to 100 inclusive) - + + - - - This command is used to set the speaker volume while in the audio tuning - process. Once an acceptable speaker level is attained, the application must - issue a connector set speaker volume command to have that level be used while - on voice calls. - - the speaker volume (-100 to 100 inclusive) - + + - - - Create a Session - Sessions typically represent a connection to a media session with one or more - participants. This is used to generate an ‘outbound’ call to another user or - channel. The specifics depend on the media types involved. A session handle is - required to control the local user functions within the session (or remote - users if the current account has rights to do so). Currently creating a - session automatically connects to the audio media, there is no need to call - Session.Connect at this time, this is reserved for future use. - - Handle returned from successful Connector ‘create’ request - This is the URI of the terminating point of the session (ie who/what is being called) - This is the display name of the entity being called (user or channel) - Only needs to be supplied when the target URI is password protected - This indicates the format of the password as passed in. This can either be - “ClearText” or “SHA1UserName”. If this element does not exist, it is assumed to be “ClearText”. If it is - “SHA1UserName”, the password as passed in is the SHA1 hash of the password and username concatenated together, - then base64 encoded, with the final “=” character stripped off. - - - + + - - - Used to accept a call - - SessionHandle such as received from SessionNewEvent - "default" - + + - - - This command is used to start the audio render process, which will then play - the passed in file through the selected audio render device. This command - should not be issued if the user is on a call. - - The fully qualified path to the sound file. - True if the file is to be played continuously and false if it is should be played once. - + + - - - This command is used to stop the audio render process. - - The fully qualified path to the sound file issued in the start render command. - + + - - - This is used to ‘end’ an established session (i.e. hang-up or disconnect). - - Handle returned from successful Session ‘create’ request or a SessionNewEvent - + + - - - Set the combined speaking and listening position in 3D space. - - Handle returned from successful Session ‘create’ request or a SessionNewEvent - Speaking position - Listening position - + + - - - Set User Volume for a particular user. Does not affect how other users hear that user. - - Handle returned from successful Session ‘create’ request or a SessionNewEvent - - The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume - + + - - - Start up the Voice service. - + + - - - Handle miscellaneous request status - - - - ///If something goes wrong, we log it. + + - - - Cleanup oject resources - + + - - - Request voice cap when changing regions - + + - - - Handle a change in session state - + + - - - Close a voice session - - + + - - - Locate a Session context from its handle - - Creates the session context if it does not exist. + + - - - Handle completion of main voice cap request. - - - - + + - - - Daemon has started so connect to it. - + + - - - The daemon TCP connection is open. - + + - - - Handle creation of the Connector. - + + - - - Handle response to audio output device query - + + - - - Handle response to audio input device query - + + - - - Set voice channel for new parcel - - + + - - - Request info from a parcel capability Uri. - - + + - - - Receive parcel voice cap - - - - + + - - - Tell Vivox where we are standing - - This has to be called when we move or turn. + + - - - Start and stop updating out position. - - + + - - - This is used to login a specific user account(s). It may only be called after - Connector initialization has completed successfully - - Handle returned from successful Connector ‘create’ request - User's account name - User's account password - Values may be “AutoAnswer” or “VerifyAnswer” - "" - This is an integer that specifies how often - the daemon will send participant property events while in a channel. If this is not set - the default will be “on state change”, which means that the events will be sent when - the participant starts talking, stops talking, is muted, is unmuted. - The valid values are: - 0 – Never - 5 – 10 times per second - 10 – 5 times per second - 50 – 1 time per second - 100 – on participant state change (this is the default) - false - + + - - - This is used to logout a user session. It should only be called with a valid AccountHandle. - - Handle returned from successful Connector ‘login’ request - + + - + + + + + + + + + + - 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 + + - + - List of audio input devices + - - - List of audio output devices - + + - - - Set audio test mode - + + - - 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 + Flags sent when a script takes or releases a control + NOTE: (need to verify) These might be a subset of the ControlFlags enum in Movement, - - - Constructor for default logging settings - + + No Flags set - - Audio Properties Events are sent after audio capture is started. These events are used to display a microphone VU meter + + Forward (W or up Arrow) - - - Abstract base for rendering plugins - + + Back (S or down arrow) - - - Generates a basic mesh structure from a primitive - - Primitive to generate the mesh from - Level of detail to generate the mesh at - The generated mesh + + Move left (shift+A or left arrow) - - - Generates a basic mesh structure from a sculpted primitive and - texture - - Sculpted primitive to generate the mesh from - Sculpt texture - Level of detail to generate the mesh at - The generated mesh + + Move right (shift+D or right arrow) - - - Generates a series of faces, each face containing a mesh and - metadata - - Primitive to generate the mesh from - Level of detail to generate the mesh at - The generated mesh + + Up (E or PgUp) - - - Generates a series of faces for a sculpted prim, each face - containing a mesh and metadata - - Sculpted primitive to generate the mesh from - Sculpt texture - Level of detail to generate the mesh at - The generated mesh + + Down (C or PgDown) + + + Rotate left (A or left arrow) + + + Rotate right (D or right arrow) + + + Left Mouse Button - + + Left Mouse button in MouseLook + + - Apply texture coordinate modifications from a - to a list of vertices + Currently only used to hide your group title - Vertex list to modify texture coordinates for - Center-point of the face - Face texture parameters - + + No flags set + + + Hide your group title + + - pre-defined built in sounds + Action state of the avatar, which can currently be typing and + editing - + - + - + - - + + + Current teleport status + - - + + Unknown status - - + + Teleport initialized - - + + Teleport in progress - - + + Teleport failed - - coins + + Teleport completed - - cash register bell + + Teleport cancelled - - + + + + - + + No flags set, or teleport failed + + + Set when newbie leaves help island for first time + + - - rubber + + Via Lure - - plastic + + Via Landmark - - flesh + + Via Location - - wood splintering? + + Via Home - - glass break + + Via Telehub - - metal clunk + + Via Login - - whoosh + + Linden Summoned - - shake + + Linden Forced me - + - - ding + + Agent Teleported Home via Script - + - + - + - - + + forced to new location for example when avatar is banned or ejected - - + + Teleport Finished via a Lure - - + + Finished, Sim Changed - - + + Finished, Same Sim - + + + + + + - + - + - + + + + + + - + - + - + - + - A dictionary containing all pre-defined sounds + Type of mute entry - 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 - - - Simulator (region) properties - + + Object muted by name - - No flags set + + Muted residet - - Agents can take damage and be killed + + Object muted by UUID - - Landmarks can be created here + + Muted group - - Home position can be set in this sim + + Muted external entry - - Home position is reset when an agent teleports away + + + Flags of mute entry + - - Sun does not move + + No exceptions - - No object, land, etc. taxes + + Don't mute text chat - - Disable heightmap alterations (agents can still plant - foliage) + + Don't mute voice chat - - Land cannot be released, sold, or purchased + + Don't mute particles - - All content is wiped nightly + + Don't mute sounds - - Unknown: Related to the availability of an overview world map tile.(Think mainland images when zoomed out.) + + Don't mute - - Unknown: Related to region debug flags. Possibly to skip processing of agent interaction with world. + + + Instant Message + - - Region does not update agent prim interest lists. Internal debugging option. + + Key of sender - - No collision detection for non-agent objects + + Name of sender - - No scripts are ran + + Key of destination avatar - - All physics processing is turned off + + ID of originating estate - - Region can be seen from other regions on world map. (Legacy world map option?) + + Key of originating region - - Region can be seen from mainland on world map. (Legacy world map option?) + + Coordinates in originating region - - Agents not explicitly on the access list can visit the region. - - - Traffic calculations are not run across entire region, overrides parcel settings. + + Instant message type - - Flight is disabled (not currently enforced by the sim) + + Group IM session toggle - - Allow direct (p2p) teleporting + + Key of IM session, for Group Messages, the groups UUID - - Estate owner has temporarily disabled scripting + + Timestamp of the instant message - - Restricts the usage of the LSL llPushObject function, applies to whole region. + + Instant message text - - Deny agents with no payment info on file + + Whether this message is held for offline avatars - - Deny agents with payment info on file + + Context specific packed data - - Deny agents who have made a monetary transaction + + Print the struct data as a string + A string containing the field name, and field value - - Parcels within the region may be joined or divided by anyone, not just estate owners/managers. + + Represents muted object or resident - - Abuse reports sent from within this region are sent to the estate owner defined email. + + Type of the mute entry - - Region is Voice Enabled + + UUID of the mute etnry - - Removes the ability from parcel owners to set their parcels to show in search. + + Mute entry name - - Deny agents who have not been age verified from entering the region. + + Mute flags - - - Access level for a simulator - + + Transaction detail sent with MoneyBalanceReply message - - Unknown or invalid access level + + Type of the transaction - - Trial accounts allowed + + UUID of the transaction source - - PG rating + + Is the transaction source a group - - Mature rating + + UUID of the transaction destination - - Adult rating + + Is transaction destination a group - - Simulator is offline + + Transaction amount - - Simulator does not exist + + Transaction description - + - + - + 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 - - - Initialize the UDP packet handler in server mode - - Port to listening for incoming UDP packets on + + Get the simulator sending the message - - - Initialize the UDP packet handler in client mode - - Remote UDP server to connect to + + Get the message sent - - - - + + Get the audible level of the message - - - - + + Get the type of message sent: whisper, shout, etc - - - - + + Get the source type of the message sender - - A public reference to the client that this Simulator object - is attached to + + Get the name of the agent or object sending the message - - A Unique Cache identifier for this simulator + + Get the ID of the agent or object sending the message - - The capabilities for this simulator + + Get the ID of the object owner, or the agent ID sending the message - - + + Get the position of the agent or object sending the message - - The current version of software this simulator is running + + 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 - - A 64x64 grid of parcel coloring values. The values stored - in this array are of the type + + Get the dialog message - - + + Get the name of the object that sent the dialog request - - + + Get the ID of the image to be displayed - - + + Get the ID of the primitive sending the dialog - - + + Get the first name of the senders owner - - + + Get the last name of the senders owner - - + + Get the communication channel the dialog was sent on, responses + should also send responses on this same channel - - + + Get 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 - - + + Get the ID of the script making the request - - + + Get the ID of the primitive containing the script making the request - - + + Get the name of the primitive making the request - - + + Get the name of the owner of the object making the request - - + + Get 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 - - true if your agent has Estate Manager rights on this region + + Get the ID of the object sending the request - - + + Get the ID of the owner of the object sending the request - - + + True if the object is owned by a group - - - - - Statistics information for this simulator and the - connection to the simulator, calculated by the simulator itself - and the library - - - The regions Unique ID + + Get the message sent with the request - - The physical data center the simulator is located - Known values are: - - Dallas - Chandler - SF - - + + Get the URL the object sent - - The CPU Class of the simulator - Most full mainland/estate sims appear to be 5, - Homesteads and Openspace appear to be 501 + + The date received from an ImprovedInstantMessage - - The number of regions sharing the same CPU as this one - "Full Sims" appear to be 1, Homesteads appear to be 4 + + + Construct a new instance of the InstantMessageEventArgs object + + the InstantMessage object + the simulator where the InstantMessage origniated - - 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) - - + + Get the InstantMessage object - - 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 - - + + Get the simulator where the InstantMessage origniated - - The current sequence number for packets sent to this - simulator. Must be Interlocked before modifying. Only - useful for applications manipulating sequence numbers + + Contains the currency balance - + - A thread-safe dictionary containing avatars in a simulator + Construct a new BalanceEventArgs object + The currenct balance - + - A thread-safe dictionary containing primitives in a simulator + Get the currenct balance - - - Provides access to an internal thread-safe dictionary containing parcel - information found in this simulator - + + Contains the transaction summary when an item is purchased, + money is given, or land is purchased - + - Checks simulator parcel map to make sure it has downloaded all data successfully + Construct a new instance of the MoneyBalanceReplyEventArgs object - true if map is full (contains no 0's) - - - Used internally to track sim disconnections + 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 - - Event that is triggered when the simulator successfully - establishes a connection + + Get the ID of the transaction - - Whether this sim is currently connected or not. Hooked up - to the property Connected + + True of the transaction was successful - - Coarse locations of avatars in this simulator + + Get the remaining currency balance - - AvatarPositions key representing TrackAgent target + + Get the meters credited - - Sequence numbers of packets we've received - (for duplicate checking) + + Get the meters comitted - - Packets we sent out that need ACKs from the simulator + + Get the description of the transaction - - Sequence number for pause/resume + + Detailed transaction information - - Indicates if UDP connection to the sim is fully established + + Data sent from the simulator containing information about your agent and active group information - + - + Construct a new instance of the AgentDataReplyEventArgs object - Reference to the GridClient object - IPEndPoint of the simulator - handle of the simulator + 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 - - - Called when this Simulator object is being destroyed - + + Get the agents first name - - - 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 + + Get the agents last name - - - Initiates connection to the simulator - + + Get the active group ID of your agent - - - Disconnect from this simulator - + + Get the active groups title of your agent - - - Instructs the simulator to stop sending update (and possibly other) packets - + + Get the combined group powers of your agent - - - Instructs the simulator to resume sending update packets (unpause) - + + Get the active group name of your agent - - - 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 + + Data sent by the simulator to indicate the active/changed animations + applied to your agent - + - Sends a packet + Construct a new instance of the AnimationsChangedEventArgs class - Packet to be sent + The dictionary that contains the changed animations - - - - + + Get the dictionary that contains the changed animations - + - Returns Simulator Name as a String + 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 - - - Sends out pending acknowledgements - - Number of ACKs sent + + Get the ID of the agent or object that collided with your agent - - - Resend unacknowledged packets - + + Get the ID of the agent that was attacked - - - Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped - to each 64x64 parcel's LocalID. - + + A value indicating the strength of the collision - - The IP address and port of the server + + Get the time the collision occurred - - 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 + + Data sent to your agent when it crosses region boundaries - + - Simulator Statistics + Construct a new instance of the RegionCrossedEventArgs class + The simulator your agent just left + The simulator your agent is now in - - Total number of packets sent by this simulator to this agent + + Get the simulator your agent just left - - Total number of packets received by this simulator to this agent + + Get the simulator your agent is now in - - Total number of bytes sent by this simulator to this agent + + Data sent from the simulator when your agent joins a group chat session - - Total number of bytes received by this simulator to this agent + + + 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 - - Time in seconds agent has been connected to simulator + + Get the ID of the group chat session - - Total number of packets that have been resent + + Get the name of the session - - Total number of resent packets recieved + + Get the temporary session ID used for establishing new sessions - - Total number of pings sent to this simulator by this agent + + True if your agent successfully joined the session - - Total number of ping replies sent to this agent by this simulator + + Data sent by the simulator containing urgent messages - + - Incoming bytes per second + Construct a new instance of the AlertMessageEventArgs class - It would be nice to have this claculated on the fly, but - this is far, far easier + The alert message - + + Get the alert message + + + Data sent by a script requesting to take or release specified controls to your agent + + - Outgoing bytes per second + Construct a new instance of the ScriptControlEventArgs class - It would be nice to have this claculated on the fly, but - this is far, far easier - - - Time last ping was sent + 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 - - ID of last Ping sent + + Get 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 - - Current time dilation of this simulator + + + Data sent from the simulator to an agent to indicate its view limits + - - Current Frames per second of simulator + + + Construct a new instance of the CameraConstraintEventArgs class + + The collision plane - - Current Physics frames per second of simulator + + 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 - - + + Get the ID of the group associated with the primitive - - + + Get the name of the primitive sending the sensor - - + + Get the ID of the primitive sending the sensor - - + + Get the ID of the owner of the primitive sending the sensor - - + + Get the position of the primitive sending the sensor - - Total number of objects Simulator is simulating + + Get the range the primitive specified to scan - - Total number of Active (Scripted) objects running + + Get the rotation of the primitive sending the sensor - - Number of agents currently in this simulator + + Get the type of sensor the primitive sent - - Number of agents in neighbor simulators + + Get the velocity of the primitive sending the sensor - - Number of Active scripts running in this simulator + + 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 - - + + True if the simulator Autopilot functions were involved - - Number of downloads pending + + Get the camera offset of the agent when seated - - Number of uploads pending + + Get the camera eye offset of the agent when seated - - + + True of the agent will be in mouselook mode when seated - - + + Get the position of the agent when seated - - Number of local uploads pending + + Get the rotation of the agent when seated - - Unacknowledged bytes in queue + + Data sent when an agent joins a chat session your agent is currently participating in - + - Checks the instance back into the object pool + Construct a new instance of the ChatSessionMemberAddedEventArgs object + 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 + + - Returns an instance of the class that has been checked out of the Object Pool. + Construct a new instance of the ChatSessionMemberLeftEventArgs object + 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 + + + Textual description of the status + + + Details of the newly set display name + + - Creates a new instance of the ObjectPoolBase class. Initialize MUST be called - after using this constructor. + 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 + + - Creates a new instance of the ObjectPool Base class. + Initializes a new AssetScriptText object with parameters - 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. + A unique specific to this asset + A byte array containing the raw asset data - + - Forces the segment cleanup algorithm to be run. This method is intended - primarly for use from the Unit Test libraries. + Encode a string containing the scripts contents into byte encoded AssetData - + - Responsible for allocate 1 instance of an object that will be stored in a segment. + Decode a byte array containing the scripts contents into a string - An instance of whatever objec the pool is pooling. + true if decoding is successful - + + Override the base classes AssetType + + - Checks in an instance of T owned by the object pool. This method is only intended to be called - by the WrappedObject class. + Type of gesture step - 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. + Base class for gesture steps - 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. + Retururns what kind of gesture step this is - + - 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. + Describes animation step of a gesture - + - The minimum number of segments. When segments are reclaimed, - this number of segments will always be left alone. These - segments are allocated at startup. + If true, this step represents start of animation, otherwise animation stop - + - 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. + Animation asset - + - The frequence which the cleanup thread runs. This is typically - expected to be in the 5 minute range. + Animation inventory name - + - Exception class to identify inventory exceptions + Returns what kind of gesture step this is - + - 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. + Describes sound step of a gesture - - 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 + Sound asset - 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 + Sound inventory name - The InventoryObject to store - + - Removes the InventoryObject and all related node data from Inventory. + Returns what kind of gesture step this is - The InventoryObject to remove. - + - Used to find out if Inventory contains the InventoryObject - specified by uuid. + Describes sound step of a gesture - The UUID to check. - true if inventory contains uuid, false otherwise - + - Saves the current inventory structure to a cache file + Text to output in chat - 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. + Returns what kind of gesture step this is - 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 - ... + + + Describes sound step of a gesture + - - Raised when the simulator sends us data containing - ... + + + If true in this step we wait for all animations to finish + - - Raised when the simulator sends us data containing - ... + + + If true gesture player should wait for the specified amount of time + - + - The root folder of this avatars inventory + Time in seconds to wait if WaitForAnimation is false - + - The default shared library folder + Returns what kind of gesture step this is - + - The root node of the avatars inventory + Describes the final step of a gesture - + - The root node of the default shared library + Returns what kind of gesture step this is - + - 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. + Represents a sequence of animations, sounds, and chat actions - The UUID of the InventoryObject to get or set, ignored if set to non-null value. - The InventoryObject corresponding to uuid. - + - Registers, unregisters, and fires events generated by incoming packets + Keyboard key that triggers the gestyre - - Reference to the GridClient object + + + Modifier to the trigger key + - + - Default constructor + String that triggers playing of the gesture sequence - - + - Register an event handler + Text that replaces trigger in chat once gesture is triggered - 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 + Sequence of gesture steps - Packet type to unregister the handler for - Callback to be unregistered - + - Fire the events registered for this packet type + Constructs guesture asset - 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 + Constructs guesture asset + A unique specific to this asset + A byte array containing the raw asset data - - 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 + Encodes gesture asset suitable for uplaod - - Reference to the GridClient object - - + - Default constructor + Decodes gesture assset into play sequence - Reference to the GridClient object + true if the asset data was decoded successfully - + - Register an new event handler for a capabilities event sent via the EventQueue + Returns asset type - 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 + pre-defined built in sounds - 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 + + - - - Represends individual HTTP Download request - + + - - URI of the item to fetch + + coins - - Timout specified in milliseconds + + cash register bell - - Download progress callback + + - - Download completed callback + + - - Accept the following content type + + rubber - - Default constructor + + plastic - - Constructor + + flesh - - - Manages async HTTP downloads with a limit on maximum - concurrent downloads - + + wood splintering? - - Default constructor + + glass break - - Cleanup method + + metal clunk - - Setup http download request + + whoosh - - Check the queue for pending work + + shake - - Enqueue a new HTPP download + + - - Maximum number of parallel downloads from a single endpoint + + ding - - Client certificate + + - - Positional vector of the users position + + - - Velocity vector of the position + + - - At Orientation (X axis) of the position + + - - Up Orientation (Y axis) of the position + + - - Left Orientation (Z axis) of the position + + - - - Represents Mesh asset - + + - - 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 a scripts contents into a LSO Bytecode file + 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 - + - TODO: Decode LSO Bytecode into a string + Avatar group management - true - - Override the base classes AssetType + + Key of Group Member - - - Static helper functions and global variables - + + Total land contribution - - This header flag signals that ACKs are appended to the packet + + Online status information - - This header flag signals that this packet has been sent before + + Abilities that the Group Member has - - This header flags signals that an ACK is expected for this packet + + Current group title - - This header flag signals that the message is compressed using zerocoding + + Is a group owner - + - + Role manager for a group - - - - - - - - - + + Key of the group - - - - - - - - - - - - - - + + Key of Role - - - 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 + + Name of Role - - - 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 + + Group Title associated with Role - - - 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 + + Description of Role - - - 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 + + Abilities Associated with Role - - - 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 + + Returns the role's title + The role's title - + - Calculates the CRC (cyclic redundancy check) needed to upload inventory. + Class to represent Group Title - 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 + + Key of the group - - - 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 + + ID of the role title belongs to - - - 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 + + Group Title - - - 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 + + Whether title is Active - - - 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); - } - - + + Returns group title - + - Passed to Logger.Log() to identify the severity of a log entry + Represents a group on the grid - - No logging information will be output + + Key of Group - - Non-noisy useful information, may be helpful in - debugging a problem + + Key of Group Insignia - - 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 + + Key of Group Founder - - 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 + + Key of Group Role for Owners - - 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. - + + Name of Group - - - A set of textures that are layered on texture of each other and "baked" - in to a single texture, for avatar appearances - + + Text of Group Charter - - Final baked texture + + Title of "everyone" role - - Component layers + + Is the group open for enrolement to everyone - - Width of the final baked image and scratchpad + + Will group show up in search - - Height of the final baked image and scratchpad + + - - Bake type + + - - - Default constructor - - Bake type + + - - - Adds layer for baking - - TexturaData struct that contains texture and its params + + Is the group Mature - - - Converts avatar texture index (face) to Bake type - - Face number (AvatarTextureIndex) - BakeType, layer to which this texture belongs to + + Cost of group membership - - - Make sure images exist, resize source if needed to match the destination - - Destination image - Source image - Sanitization was succefull + + - - - Fills a baked layer as a solid *appearing* color. The colors are - subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from - compressing it too far since it seems to cause upload failures if - the image is a pure solid color - - Color of the base of this layer + + - - - Fills a baked layer as a solid *appearing* color. The colors are - subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from - compressing it too far since it seems to cause upload failures if - the image is a pure solid color - - Red value - Green value - Blue value + + The total number of current members this group has - - Final baked texture + + The number of roles this group has configured - - Component layers + + Show this group in agent's profile - - Width of the final baked image and scratchpad + + Returns the name of the group + A string containing the name of the group - - Height of the final baked image and scratchpad + + + A group Vote + - - Bake type + + Key of Avatar who created Vote - - Is this one of the 3 skin bakes + + Text of the Vote proposal - + + Total number of votes + + - Represents an Animation + A group proposal - - Default Constructor + + The Text of the proposal - - - Construct an Asset object of type Animation - - A unique specific to this asset - A byte array containing the raw asset data + + The minimum number of members that must vote before proposal passes or failes - - Override the base classes AssetType + + 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 - - - Index of TextureEntry slots for avatar appearances - + + The duration in days votes are accepted - + - Bake layers for avatar appearance + - - Maximum number of concurrent downloads for wearable assets and textures - - - Maximum number of concurrent uploads for baked textures + + - - Timeout for fetching inventory listings + + - - Timeout for fetching a single wearable, or receiving a single packet response + + - - Timeout for fetching a single texture + + - - Timeout for uploading a single baked texture + + - - Number of times to retry bake upload + + - - When changing outfit, kick off rebake after - 20 seconds has passed since the last change + + - - Total number of wearables for each avatar + + - - Total number of baked textures on each avatar + + - - Total number of wearables per bake layer + + - - Mapping between BakeType and AvatarTextureIndex + + - - Map of what wearables are included in each bake + + - - Magic values to finalize the cache check hashes for each - bake + + - - Default avatar texture, used to detect when a custom - texture is not set for a face + + - - The event subscribers. null if no subcribers + + - - Raises the AgentWearablesReply event - An AgentWearablesReplyEventArgs object containing the - data returned from the data server + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the CachedBakesReply event - An AgentCachedBakesReplyEventArgs object containing the - data returned from the data server AgentCachedTextureResponse + + - - Thread sync lock object + + + Struct representing a group notice + - - The event subscribers. null if no subcribers + + - - Raises the AppearanceSet event - An AppearanceSetEventArgs object indicating if the operatin was successfull + + - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + - - Raises the RebakeAvatarRequested event - An RebakeAvatarTexturesEventArgs object containing the - data returned from the data server + + + + + - - Thread sync lock object + + + Struct representing a group notice list entry + - - A cache of wearables currently being worn + + Notice ID - - A cache of textures currently being worn + + Creation timestamp of notice - - Incrementing serial number for AgentCachedTexture packets + + Agent name who created notice - - Incrementing serial number for AgentSetAppearance packets + + Notice subject - - Indicates whether or not the appearance thread is currently - running, to prevent multiple appearance threads from running - simultaneously + + Is there an attachment? - - Reference to our agent + + Attachment Type - + - Timer used for delaying rebake on changing outfit + Struct representing a member of a group chat session and their settings - - - Main appearance thread - + + The of the Avatar - - - Default constructor - - A reference to our agent + + True if user has voice chat enabled - - - Obsolete method for setting appearance. This function no longer does anything. - Use RequestSetAppearance() to manually start the appearance thread - + + True of Avatar has moderator abilities - - - Obsolete method for setting appearance. This function no longer does anything. - Use RequestSetAppearance() to manually start the appearance thread - - Unused parameter + + True if a moderator has muted this avatars chat - - - Starts the appearance setting thread - + + True if a moderator has muted this avatars voice - + - Starts the appearance setting thread + Role update flags - True to force rebaking, otherwise false - - - Ask the server what textures our agent is currently wearing - + + - - - Build hashes out of the texture assetIDs for each baking layer to - ask the simulator whether it has cached copies of each baked texture - + + - - - Returns the AssetID of the asset that is currently being worn in a - given WearableType slot - - WearableType slot to get the AssetID for - The UUID of the asset being worn in the given slot, or - UUID.Zero if no wearable is attached to the given slot or wearables - have not been downloaded yet + + - - - Add a wearable to the current outfit and set appearance - - Wearable to be added to the outfit + + - - - Add a list of wearables to the current outfit and set appearance - - List of wearable inventory items to - be added to the outfit + + - - - Remove a wearable from the current outfit and set appearance - - Wearable to be removed from the outfit + + - - - Removes a list of wearables from the current outfit and set appearance - - List of wearable inventory items to - be removed from the outfit + + - - - Replace the current outfit with a list of wearables and set appearance - - List of wearable inventory items that - define a new outfit + + Can send invitations to groups default role - - - Checks if an inventory item is currently being worn - - The inventory item to check against the agent - wearables - The WearableType slot that the item is being worn in, - or WearbleType.Invalid if it is not currently being worn + + Can eject members from group - - - Returns a copy of the agents currently worn wearables - - A copy of the agents currently worn wearables - Avoid calling this function multiple times as it will make - a copy of all of the wearable data each time + + Can toggle 'Open Enrollment' and change 'Signup fee' - - - Calls either or - depending on the value of - replaceItems - - List of wearable inventory items to add - to the outfit or become a new outfit - True to replace existing items with the - new list of items, false to add these items to the existing outfit + + Member is visible in the public member list - - - Adds a list of attachments to our agent - - A List containing the attachments to add - If true, tells simulator to remove existing attachment - first + + Can create new roles - - - Attach an item to our agent at a specific attach point - - A to attach - the on the avatar - to attach the item to + + Can delete existing roles - - - Attach an item to our agent specifying attachment details - - The of the item to attach - The attachments owner - The name of the attachment - The description of the attahment - The to apply when attached - The of the attachment - The on the agent - to attach the item to + + Can change Role names, titles and descriptions - - - Detach an item from our agent using an object - - An object + + Can assign other members to assigners role - - - Detach an item from our agent - - The inventory itemID of the item to detach + + Can assign other members to any role - - - Inform the sim which wearables are part of our current outfit - + + Can remove members from roles - - - Replaces the Wearables collection with a list of new wearable items - - Wearable items to replace the Wearables collection with + + Can assign and remove abilities in roles - - - Calculates base color/tint for a specific wearable - based on its params - - All the color info gathered from wearable's VisualParams - passed as list of ColorParamInfo tuples - Base color/tint for the wearable + + Can change group Charter, Insignia, 'Publish on the web' and which + members are publicly visible in group member listings - - - Blocking method to populate the Wearables dictionary - - True on success, otherwise false + + Can buy land or deed land to group - - - Blocking method to populate the Textures array with cached bakes - - True on success, otherwise false + + Can abandon group owned land to Governor Linden on mainland, or Estate owner for + private estates - - - Populates textures and visual params from a decoded asset - - Wearable to decode + + Can set land for-sale information on group owned parcels - - - Blocking method to download and parse currently worn wearable assets - - True on success, otherwise false + + Can subdivide and join parcels - - - Get a list of all of the textures that need to be downloaded for a - single bake layer - - Bake layer to get texture AssetIDs for - A list of texture AssetIDs to download + + Can join group chat sessions - - - Helper method to lookup the TextureID for a single layer and add it - to a list if it is not already present - - - + + Can use voice chat in Group Chat sessions - - - Blocking method to download all of the textures needed for baking - the given bake layers - - A list of layers that need baking - No return value is given because the baking will happen - whether or not all textures are successfully downloaded + + Can moderate group chat sessions - - - Blocking method to create and upload baked textures for all of the - missing bakes - - True on success, otherwise false + + Can toggle "Show in Find Places" and set search category - - - Blocking method to create and upload a baked texture for a single - bake layer - - Layer to bake - True on success, otherwise false + + Can change parcel name, description, and 'Publish on web' settings - - - Blocking method to upload a baked texture - - Five channel JPEG2000 texture data to upload - UUID of the newly created asset on success, otherwise UUID.Zero + + Can set the landing point and teleport routing on group land - - - Creates a dictionary of visual param values from the downloaded wearables - - A dictionary of visual param indices mapping to visual param - values for our agent that can be fed to the Baker class + + Can change music and media settings - - - Create an AgentSetAppearance packet from Wearables data and the - Textures array and send it - + + Can toggle 'Edit Terrain' option in Land settings - - - Converts a WearableType to a bodypart or clothing WearableType - - A WearableType - AssetType.Bodypart or AssetType.Clothing or AssetType.Unknown + + Can toggle various About Land > Options settings - - - Converts a BakeType to the corresponding baked texture slot in AvatarTextureIndex - - A BakeType - The AvatarTextureIndex slot that holds the given BakeType + + Can always terraform land, even if parcel settings have it turned off - - - Gives the layer number that is used for morph mask - - >A BakeType - Which layer number as defined in BakeTypeToTextures is used for morph mask + + Can always fly while over group owned land - - - Converts a BakeType to a list of the texture slots that make up that bake - - A BakeType - A list of texture slots that are inputs for the given bake + + Can always rez objects on group owned land - - Triggered when an AgentWearablesUpdate packet is received, - telling us what our avatar is currently wearing - request. + + Can always create landmarks for group owned parcels - - Raised when an AgentCachedTextureResponse packet is - received, giving a list of cached bakes that were found on the - simulator - request. + + Can set home location on any group owned parcel - - - Raised when appearance data is sent to the simulator, also indicates - the main appearance thread is finished. - - request. + + Can modify public access settings for group owned parcels - - - Triggered when the simulator requests the agent rebake its appearance. - - + + Can manager parcel ban lists on group owned land - - - Returns true if AppearanceManager is busy and trying to set or change appearance will fail - + + Can manage pass list sales information - - - Contains information about a wearable inventory item - + + Can eject and freeze other avatars on group owned land - - Inventory ItemID of the wearable + + Can return objects set to group - - AssetID of the wearable asset + + Can return non-group owned/set objects - - WearableType of the wearable + + Can return group owned objects - - AssetType of the wearable + + Can landscape using Linden plants - - Asset data for the wearable + + Can deed objects to group - - - Data collected from visual params for each wearable - needed for the calculation of the color - + + Can move group owned objects - - - 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 - + + Can set group owned objects for-sale - - A texture AssetID + + Pay group liabilities and receive group dividends - - Asset data for the texture + + List and Host group events - - Collection of alpha masks that needs applying + + Can send group notices - - Tint that should be applied to the texture + + Can receive group notices - - Where on avatar does this texture belong + + Can create group proposals - - Contains the Event data returned from the data server from an AgentWearablesRequest + + Can vote on group proposals - - Construct a new instance of the AgentWearablesReplyEventArgs class + + + Handles all network traffic related to reading and writing group + information + - - Contains the Event data returned from the data server from an AgentCachedTextureResponse + + The event subscribers. null if no subcribers - - Construct a new instance of the AgentCachedBakesReplyEventArgs class + + Raises the CurrentGroups event + A CurrentGroupsEventArgs object containing the + data sent from the simulator - - Contains the Event data returned from an AppearanceSetRequest + + Thread sync lock object - - - Triggered when appearance data is sent to the sim and - the main appearance thread is done. - Indicates whether appearance setting was successful + + The event subscribers. null if no subcribers - - Indicates whether appearance setting was successful + + Raises the GroupNamesReply event + A GroupNamesEventArgs object containing the + data response from the simulator - - Contains the Event data returned from the data server from an RebakeAvatarTextures + + Thread sync lock object - - - Triggered when the simulator sends a request for this agent to rebake - its appearance - - The ID of the Texture Layer to bake + + The event subscribers. null if no subcribers - - The ID of the Texture Layer to bake + + Raises the GroupProfile event + An GroupProfileEventArgs object containing the + data returned from the simulator - - - The current status of a texture request as it moves through the pipeline or final result of a texture request. - + + Thread sync lock object - - The initial state given to a request. Requests in this state - are waiting for an available slot in the pipeline + + The event subscribers. null if no subcribers - - A request that has been added to the pipeline and the request packet - has been sent to the simulator + + Raises the GroupMembers event + A GroupMembersEventArgs object containing the + data returned from the simulator - - A request that has received one or more packets back from the simulator + + Thread sync lock object - - A request that has received all packets back from the simulator + + The event subscribers. null if no subcribers - - A request that has taken longer than - to download OR the initial packet containing the packet information was never received + + Raises the GroupRolesDataReply event + A GroupRolesDataReplyEventArgs object containing the + data returned from the simulator - - The texture request was aborted by request of the agent + + Thread sync lock object - - The simulator replied to the request that it was not able to find the requested texture + + The event subscribers. null if no subcribers - - - 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. + + Raises the GroupRoleMembersReply event + A GroupRolesRoleMembersReplyEventArgs object containing the + data returned from the simulator - - - 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. + + Thread sync lock object - - 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 + + The event subscribers. null if no subcribers - - Holds the reference to the client object + + Raises the GroupTitlesReply event + A GroupTitlesReplyEventArgs object containing the + data returned from the simulator - - Maximum concurrent texture requests allowed at a time + + Thread sync lock object - - An array of objects used to manage worker request threads + + The event subscribers. null if no subcribers - - An array of worker slots which shows the availablity status of the slot + + Raises the GroupAccountSummary event + A GroupAccountSummaryReplyEventArgs object containing the + data returned from the simulator - - The primary thread which manages the requests. + + Thread sync lock object - - true if the TexturePipeline is currently running + + The event subscribers. null if no subcribers - - A synchronization object used by the primary thread + + Raises the GroupCreated event + An GroupCreatedEventArgs object containing the + data returned from the simulator - - A refresh timer used to increase the priority of stalled requests + + Thread sync lock object - - - Default constructor, Instantiates a new copy of the TexturePipeline class - - Reference to the instantiated object + + The event subscribers. null if no subcribers - - - Initialize callbacks required for the TexturePipeline to operate - + + Raises the GroupJoined event + A GroupOperationEventArgs object containing the + result of the operation returned from the simulator - - - Shutdown the TexturePipeline and cleanup any callbacks or transfers - + + Thread sync lock object - - - 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 + + The event subscribers. null if no subcribers - - - 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 + + Raises the GroupLeft event + A GroupOperationEventArgs object containing the + result of the operation returned from the simulator - - - Cancel a pending or in process texture request - - The texture assets unique ID + + Thread sync lock object - - - Master Download Thread, Queues up downloads in the threadpool - + + The event subscribers. null if no subcribers - - - The worker thread that sends the request and handles timeouts - - A object containing the request details + + Raises the GroupDropped event + An GroupDroppedEventArgs object containing the + the group your agent left - - - 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 + + Thread sync lock object - - - Handles the remaining Image data that did not fit in the initial ImageData packet - - The sender - The EventArgs object containing the packet data + + The event subscribers. null if no subcribers - - - Handle the initial ImageDataPacket sent from the simulator - - The sender - The EventArgs object containing the packet data + + Raises the GroupMemberEjected event + An GroupMemberEjectedEventArgs object containing the + data returned from the simulator - - Current number of pending and in-process transfers + + Thread sync lock object - - - A request task containing information and status of a request as it is processed through the - + + The event subscribers. null if no subcribers - - The current which identifies the current status of the request + + Raises the GroupNoticesListReply event + An GroupNoticesListReplyEventArgs object containing the + data returned from the simulator - - The Unique Request ID, This is also the Asset ID of the texture being requested + + Thread sync lock object - - The slot this request is occupying in the threadpoolSlots array + + The event subscribers. null if no subcribers - - The ImageType of the request. + + Raises the GroupInvitation event + An GroupInvitationEventArgs object containing the + data returned from the simulator - - The callback to fire when the request is complete, will include - the and the - object containing the result data + + Thread sync lock object - - 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. + + A reference to the current instance - - An object that maintains the data of an request thats in-process. + + Currently-active group members requests - - - Wrapper around a byte array that allows bit to be packed and unpacked - one at a time or by a variable amount. Useful for very tightly packed - data like LayerData packets - + + 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 + + - Default constructor, initialize the bit packer / bit unpacker - with a byte array and starting position + Construct a new instance of the GroupManager class - Byte array to pack bits in to or unpack from - Starting position in the byte array + A reference to the current instance - + - Pack a floating point value in to the data + Request a current list of groups the avatar is a member of. - Floating point value to pack + CAPS Event Queue must be running for this to work since the results + come across CAPS. - + - Pack part or all of an integer in to the data + Lookup name of group based on groupID - Integer containing the data to pack - Number of bits of the integer to pack + groupID of group to lookup name for. - + - Pack part or all of an unsigned integer in to the data + Request lookup of multiple group names - Unsigned integer containing the data to pack - Number of bits of the integer to pack + List of group IDs to request. - - - Pack a single bit in to the data - - Bit to pack + + 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 - - - Unpacking a floating point value from the data - - Unpacked floating point value + + Request a groups Titles + Subscribe to OnGroupTitles event to receive the results. + group ID (UUID) + UUID of the request, use to index into cache - - - Unpack a variable number of bits from the data in to integer format - - Number of bits to unpack - An integer containing the unpacked bits - This function is only useful up to 32 bits + + 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) - - - Unpack a variable number of bits from the data in to unsigned - integer format - - Number of bits to unpack - An unsigned integer containing the unpacked bits - This function is only useful up to 32 bits + + 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 - - - Unpack a 16-bit signed integer - - 16-bit signed integer + + Set a group as the current active group + group ID (UUID) - - - Unpack a 16-bit unsigned integer - - 16-bit unsigned integer + + Change the role that determines your active title + Group ID to use + Role ID to change to - - - Unpack a 32-bit signed integer - - 32-bit signed integer + + Set this avatar's tier contribution + Group ID to change tier in + amount of tier to donate - + - Unpack a 32-bit unsigned integer + Save wheather agent wants to accept group notices and list this group in their profile - 32-bit unsigned integer - - - - - - + Group + Accept notices from this group + List this group in the profile - - - Class that handles the local asset cache - + + Request to join a group + Subscribe to OnGroupJoined event for confirmation. + group ID (UUID) to join. - + - Default constructor + Request to create a new group. If the group is successfully + created, L$100 will automatically be deducted - A reference to the GridClient object + Subscribe to OnGroupCreated event to receive confirmation. + Group struct containing the new group info - - - Disposes cleanup timer - + + Update a group's profile and other information + Groups ID (UUID) to update. + Group struct to update. - - - Only create timer when needed - + + Eject a user from a group + Group ID to eject the user from + Avatar's key to eject - - - Return bytes read from the local asset cache, null if it does not exist - - UUID of the asset we want to get - Raw bytes of the asset, or null on failure + + Update role information + Modified role to be updated - - - Returns ImageDownload object of the - image from the local image cache, null if it does not exist - - UUID of the image we want to get - ImageDownload object containing the image, or null on failure + + Create a new group role + Group ID to update + Role to create - - - Constructs a file name of the cached asset - - UUID of the asset - String with the file name of the cahced asset + + Delete a group role + Group ID to update + Role to delete - - - Saves an asset to the local cache - - UUID of the asset - Raw bytes the asset consists of - Weather the operation was successfull + + Remove an avatar from a role + Group ID to update + Role ID to be removed from + Avatar's Key to remove - - - Get the file name of the asset stored with gived UUID - - UUID of the asset - Null if we don't have that UUID cached on disk, file name if found in the cache folder + + Assign an avatar to a role + Group ID to update + Role ID to assign to + Avatar's ID to assign to role - - - Checks if the asset exists in the local cache - - UUID of the asset - True is the asset is stored in the cache, otherwise false + + Request the group notices list + Group ID to fetch notices for - - - Wipes out entire cache - + + Request a group notice by key + ID of group notice - - - Brings cache size to the 90% of the max size - + + Send out a group notice + Group ID to update + GroupNotice structure containing notice data - - - Asynchronously brings cache size to the 90% of the max size - + + Start a group proposal (vote) + The Group ID to send proposal to + GroupProposal structure containing the proposal - - - Adds up file sizes passes in a FileInfo array - + + Request to leave a group + Subscribe to OnGroupLeft event to receive confirmation + The group to leave - - - Checks whether caching is enabled - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Periodically prune the cache - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Nicely formats file sizes - - Byte size we want to output - String with humanly readable file size + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Allows setting weather to periodicale prune the cache if it grows too big - Default is enabled, when caching is enabled - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - How long (in ms) between cache checks (default is 5 min.) - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Helper class for sorting files by their last accessed time - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Capability to load TGAs to Bitmap - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Represents a Sound Asset - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Initializes a new instance of an AssetSound object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Initializes a new instance of an AssetSound object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - TODO: Encodes a sound file - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - TODO: Decode a sound file - - true + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Override the base classes AssetType + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Represents an LSL Text object containing a string of UTF encoded characters - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - A string of characters represting the script contents + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Initializes a new AssetScriptText object + + Raised when the simulator sends us data containing + our current group membership - - - Initializes a new AssetScriptText object with parameters - - A unique specific to this asset - A byte array containing the raw asset data + + Raised when the simulator responds to a RequestGroupName + or RequestGroupNames request - - - Encode a string containing the scripts contents into byte encoded AssetData - + + Raised when the simulator responds to a request - - - Decode a byte array containing the scripts contents into a string - - true if decoding is successful + + Raised when the simulator responds to a request - - Override the base classes AssetType + + Raised when the simulator responds to a request - - - Represents a Landmark with RegionID and Position vector - + + Raised when the simulator responds to a request - - UUID of the Landmark target region + + Raised when the simulator responds to a request - - Local position of the target + + Raised when a response to a RequestGroupAccountSummary is returned + by the simulator - - Construct an Asset of type Landmark + + Raised when a request to create a group is successful - - - Construct an Asset object of type Landmark - - A unique specific to this asset - A byte array containing the raw asset data + + Raised when a request to join a group either + fails or succeeds - - - Encode the raw contents of a string with the specific Landmark format - + + Raised when a request to leave a group either + fails or succeeds - - - Decode the raw asset data, populating the RegionID and Position - - true if the AssetData was successfully decoded to a UUID and Vector + + Raised when A group is removed from the group server - - Override the base classes AssetType + + Raised when a request to eject a member from a group either + fails or succeeds - - - Represents an that can be worn on an avatar - such as a Shirt, Pants, etc. - + + Raised when the simulator sends us group notices + - - Initializes a new instance of an AssetScriptBinary object + + Raised when another agent invites our avatar to join a group - - Initializes a new instance of an AssetScriptBinary object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + Contains the current groups your agent is a member of - - Override the base classes AssetType + + 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 + + - Main class to expose grid functionality to clients. All of the - classes needed for sending and receiving data are accessible through - this class. + Construct a new instance of the GroupMembersReplyEventArgs 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(); - } - } - } - - + The ID of the request + The ID of the group + The membership list of the group - - Networking subsystem + + Get the ID as returned by the request to correlate + this result set and the request - - Settings class including constant values and changeable - parameters for everything + + Get the ID of the group - - Parcel (subdivided simulator lots) subsystem + + Get the dictionary of members - - Our own avatars subsystem + + Represents the roles associated with a group - - Other avatars subsystem + + 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 - - Estate subsystem + + Get the ID as returned by the request to correlate + this result set and the request - - Friends list subsystem + + Get the ID of the group - - Grid (aka simulator group) subsystem + + Get the dictionary containing the roles - - Object subsystem + + Represents the Role to Member mappings for a group - - Group subsystem + + 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 - - Asset subsystem + + Get the ID as returned by the request to correlate + this result set and the request - - Appearance subsystem + + Get the ID of the group - - Inventory subsystem + + Get the member to roles map - - Directory searches including classifieds, people, land - sales, etc + + Represents the titles for a group - - Handles land, wind, and cloud heightmaps + + 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 - - Handles sound-related networking + + Get the ID as returned by the request to correlate + this result set and the request - - Throttling total bandwidth usage, or allocating bandwidth - for specific data stream types + + 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 + + - Default constructor + 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 + + - Return the full name of this instance + Level of Detail mesh - Client avatars full name - + - Attempts to convert an LLSD structure to a known Packet type + Represents an that can be worn on an avatar + such as a Shirt, Pants, etc. - Event name, this must match an actual - packet name for a Packet to be successfully built - LLSD to convert to a Packet - A Packet on success, otherwise null - + + 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 + + - Image width + Temporary code to do the bare minimum required to read a tar archive for our purposes - + - Image height + Binary reader for the underlying stream - + - Image channel flags + Used to trim off null chars - + - Red channel data + Used to trim off space chars - + - Green channel data + Generate a tar reader which reads from the given stream. + - + - Blue channel data - - - - - Alpha channel data - - - - - Bump channel data - - - - - Create a new blank image - - width - height - channel flags - - - - + Read the next entry in the tar file. - + + + the data for the entry. Returns null if there are no more entries - + - Convert the channels in the image. Channels are created or destroyed as required. + Read the next 512 byte chunk of data as a tar header. - new channel flags + A tar header struct. null if we have reached the end of the archive. - + - Resize or stretch the image using nearest neighbor (ugly) resampling + Read data following a header - new width - new height + + - + - Create a byte array containing 32-bit RGBA data with a bottom-left - origin, suitable for feeding directly into OpenGL + Convert octal bytes to a decimal representation - A byte array containing raw texture data + + + + - + - Represents a texture + Type of return to use when returning objects from a parcel - - A object containing image data - - + - - + + Return objects owned by parcel owner - - Initializes a new instance of an AssetTexture object + + Return objects set to group - - - Initializes a new instance of an AssetTexture object - - A unique specific to this asset - A byte array containing the raw asset data + + Return objects not owned by parcel owner or set to group - - - Initializes a new instance of an AssetTexture object - - A object containing texture data + + Return a specific list of objects on parcel - - - Populates the byte array with a JPEG2000 - encoded image created from the data in - + + Return objects that are marked for-sale - + - Decodes the JPEG2000 data in AssetData to the - object + Blacklist/Whitelist flags used in parcels Access List - True if the decoding was successful, otherwise false - - - Decodes the begin and end byte positions for each quality layer in - the image - - + + Agent is denied access - - Override the base classes AssetType + + Agent is granted access - + - Temporary code to do the bare minimum required to read a tar archive for our purposes + The result of a request for parcel properties - - - Binary reader for the underlying stream - + + No matches were found for the request - - - Used to trim off null chars - + + Request matched a single parcel - - - Used to trim off space chars - + + Request matched multiple parcels - + - Generate a tar reader which reads from the given stream. + Flags used in the ParcelAccessListRequest packet to specify whether + we want the access list (whitelist), ban list (blacklist), or both - - - - Read the next entry in the tar file. - - - - the data for the entry. Returns null if there are no more entries + + Request the access list - - - Read the next 512 byte chunk of data as a tar header. - - A tar header struct. null if we have reached the end of the archive. + + Request the ban list - - - Read data following a header - - - + + Request both White and Black lists - + - Convert octal bytes to a decimal representation + Sequence ID in ParcelPropertiesReply packets (sent when avatar + tries to cross a parcel border) - - - - - - X position of this patch + + Parcel is currently selected - - Y position of this patch + + Parcel restricted to a group the avatar is not a + member of - - A 16x16 array of floats holding decompressed layer data + + Avatar is banned from the parcel - - - 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 - + + Parcel is restricted to an access list that the + avatar is not on - - - 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 + + Response to hovering over a parcel - + - + The tool to use when modifying terrain levels - - No report + + Level the terrain - - Unknown report type + + Raise the terrain - - Bug report + + Lower the terrain - - Complaint report + + Smooth the terrain - - Customer service report + + Add random noise to the terrain - + + Revert terrain to simulator default + + - Bitflag field for ObjectUpdateCompressed data blocks, describing - which options are present for each object + The tool size to use when changing terrain levels - - Unknown + + Small - - Whether the object has a TreeSpecies + + Medium - - Whether the object has floating text ala llSetText + + Large - - Whether the object has an active particle system + + + Reasons agent is denied access to a parcel on the simulator + - - Whether the object has sound attached to it + + Agent is not denied, access is granted - - Whether the object is attached to a root object or not + + Agent is not a member of the group set for the parcel, or which owns the parcel - - Whether the object has texture animation settings + + Agent is not on the parcels specific allow list - - Whether the object has an angular velocity + + Agent is on the parcels ban list - - Whether the object has a name value pairs string + + Unknown - - Whether the object has a Media URL set + + Agent is not age verified and parcel settings deny access to non age verified avatars - + - Specific Flags for MultipleObjectUpdate requests + 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 - - None + + Public land - - Change position of prims + + Land is owned by another avatar - - Change rotation of prims + + Land is owned by a group - - Change size of prims + + Land is owned by the current avatar - - Perform operation on link set + + Land is for sale - - Scale prims uniformly, same as selecing ctrl+shift in the - viewer. Used in conjunction with Scale + + Land is being auctioned - - - Special values in PayPriceReply. If the price is not one of these - literal value of the price should be use - + + Land is private - - - Indicates that this pay option should be hidden - + + To the west of this area is a parcel border - - - Indicates that this pay option should have the default value - + + To the south of this area is a parcel border - + - Contains the variables sent in an object update packet for objects. - Used to track position and movement of prims and avatars + 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 - - - Handles all network traffic related to prims and avatar positions and - movement. - + + Access is restricted to a whitelist - - The event subscribers, null of no subscribers + + Ban blacklist is enabled - - Thread sync lock object + + Unknown - - The event subscribers, null of no subscribers + + List this parcel in the search directory - - Raises the ObjectProperties Event - A ObjectPropertiesEventArgs object containing - the data sent from the simulator + + Allow personally owned parcels to be deeded to group - - Thread sync lock object + + If Deeded, owner contributes required tier to group parcel is deeded to - - The event subscribers, null of no subscribers + + Restrict sounds originating on this parcel to the + parcel boundaries - - Raises the ObjectPropertiesUpdated Event - A ObjectPropertiesUpdatedEventArgs object containing - the data sent from the simulator + + Objects on this parcel are sold when the land is + purchsaed - - Thread sync lock object + + Allow this parcel to be published on the web - - The event subscribers, null of no subscribers + + The information for this parcel is mature content - - Raises the ObjectPropertiesFamily Event - A ObjectPropertiesFamilyEventArgs object containing - the data sent from the simulator + + The media URL is an HTML page - - Thread sync lock object + + The media URL is a raw HTML string - - The event subscribers, null of no subscribers + + Restrict foreign object pushes - - Raises the AvatarUpdate Event - A AvatarUpdateEventArgs object containing - the data sent from the simulator + + Ban all non identified/transacted avatars - - Thread sync lock object + + Allow group-owned scripts to run - - The event subscribers, null of no subscribers + + Allow object creation by group members or group + objects - - Thread sync lock object + + Allow all objects to enter this parcel - - The event subscribers, null of no subscribers + + Only allow group and owner objects to enter this parcel - - Raises the ObjectDataBlockUpdate Event - A ObjectDataBlockUpdateEventArgs object containing - the data sent from the simulator + + Voice Enabled on this parcel - - Thread sync lock object + + Use Estate Voice channel for Voice on this parcel - - The event subscribers, null of no subscribers + + Deny Age Unverified Users - - Raises the KillObject Event - A KillObjectEventArgs object containing - the data sent from the simulator + + + Parcel ownership status + - - Thread sync lock object + + Placeholder - - The event subscribers, null of no subscribers + + Parcel is leased (owned) by an avatar or group - - Raises the AvatarSitChanged Event - A AvatarSitChangedEventArgs object containing - the data sent from the simulator + + Parcel is in process of being leased (purchased) by an avatar or group - - Thread sync lock object + + Parcel has been abandoned back to Governor Linden - - The event subscribers, null of no subscribers + + + Category parcel is listed in under search + - - Raises the PayPriceReply Event - A PayPriceReplyEventArgs object containing - the data sent from the simulator + + No assigned category - - Thread sync lock object + + Linden Infohub or public area - - Reference to the GridClient object + + Adult themed area - - Does periodic dead reckoning calculation to convert - velocity and acceleration to new positions for objects + + Arts and Culture - - - Construct a new instance of the ObjectManager class - - A reference to the instance + + Business - - - Request information for a single object from a - you are currently connected to - - The the object is located - The Local ID of the object + + Educational - - - Request information for multiple objects contained in - the same simulator - - The the objects are located - An array containing the Local IDs of the objects + + Gaming - - - 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); - - + + Hangout or Club - - - 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 + + Newcomer friendly - - - 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 - + + Parks and Nature - - - 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 - + + Residential - - - 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 - + + Shopping - - - 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 - + + Not Used? - - - 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 + + Other - + + Not an actual category, only used for queries + + - Sets the sale properties of a single object + Type of teleport landing for a parcel - 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 + + Unset, simulator default - - - Deselect a single object - - The the object is located - The Local ID of the object + + Specific landing point set for this parcel - - - Deselect multiple objects. - - The the objects are located - An array containing the Local IDs of the objects + + No landing point set, direct teleports enabled for + this parcel - + - Perform a click action on an object + Parcel Media Command used in ParcelMediaCommandMessage - 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 + + Stop the media stream and go back to the first frame - - - 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 + + Pause the media stream (stop playing but stay on current frame) - - - 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 + + Start the current media stream playing and stop when the end is reached - - - 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 + + Start the current media stream playing, + loop to the beginning when the end is reached and continue to play - - - 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 + + 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. - - - 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 + + Specifies the movie URL (254 characters max) - - - 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) + + Specifies the time index at which to begin playing - - - 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 + + Specifies a single agent to apply the media command to - - - 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 + + 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. - - - 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 + + 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. - - - 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 + + Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). + Use "text/html" for HTML. - - - 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? + + Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). + This might still not be working - - - 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 + + Sets a description for the media being displayed (1.19.1 RC0 and later only). - + - Change the rotation of an object + Some information about a parcel of land returned from a DirectoryManager search - 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 + + Global Key of record - - - 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 + + Parcel Owners - - - 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 + + Name field of parcel, limited to 128 characters - - - 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 + + Description field of parcel, limited to 256 characters - - - 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 + + Total Square meters of parcel - - - 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 + + Total area billable as Tier, for group owned land this will be 10% less than ActualArea - - - 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 + + True of parcel is in Mature simulator - - - 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 + + Grid global X position of parcel - - - 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 + + Grid global Y position of parcel - - - 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 + + Grid global Z position of parcel (not used) - - - 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 + + Name of simulator parcel is located in - - - 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 + + Texture of parcels display picture - - - 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 + + Float representing calculated traffic based on time spent on parcel by avatars - - - 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 + + Sale price of parcel (not used) - - - 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 - The new Permissions mark to set - TODO: What does this do? + + Auction ID of parcel - + - Request additional properties for an object + Parcel Media Information - 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 + + A byte, if 0x1 viewer should auto scale media to fit object - - - 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 + + A boolean, if true the viewer should loop the media - - - 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 + + The Asset UUID of the Texture which when applied to a + primitive will display the media - - - 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 + + A URL which points to any Quicktime supported media type - - - Retrieve information about object media - - UUID of the primitive - Simulator where prim is located - Call this callback when done + + A description of the media - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + 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 + + - A terse object update, used when a transformation matrix or - velocity/acceleration for an object changes but nothing else - (scale/position/rotation/acceleration/velocity) + Parcel of land, a portion of virtual real estate in a simulator - 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 + + The total number of contiguous 4x4 meter blocks your agent owns within this parcel - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Deprecated, Value appears to always be 0 - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Simulator-local ID of this parcel - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + UUID of the owner of this parcel - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Whether the land is deeded to a group or not - - - Setup construction data for a basic primitive shape - - Primitive shape to construct - Construction data that can be plugged into a + + - - - - - - - - + + Date land was claimed - - - - - - + + Appears to always be zero - - - 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 + + This field is no longer used - - - 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 + + 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 - - Raised when the simulator sends us data containing - A , Foliage or Attachment - - + + Total parcel land area - - 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 + + Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used - - Raised when the simulator sends us data containing - additional and details - + + 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 - - Raised when the simulator sends us data containing - updated information for an + + Maximum number of primitives this parcel supports - - Raised when the simulator sends us data containing - and movement changes + + Total number of primitives on this parcel - - Raised when the simulator sends us data containing - updates to an Objects DataBlock + + 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 - - Raised when the simulator informs us an - or is no longer within view + + 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. - - Raised when the simulator sends us data containing - updated sit information for our + + Total number of prims owned by other avatars that are not set to group, or not the parcel owner - - Raised when the simulator sends us data containing - purchase price information for a + + 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 - - - 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 + + Autoreturn value in minutes for others' objects - - 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 + + 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 - - 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); - } - } - - - - + + Parcel Name - - - 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 + + Parcel Description - - Get the simulator the object originated from + + URL For Music Stream - - Get the data + + - - Get the simulator time dilation + + Price for a temporary pass - - true if the did not exist in the dictionary before this update (always true if avatar tracking has been disabled) + + How long is pass valid for - - 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 + + Key of authorized buyer - - Get the simulator the object is located + + Key of parcel snapshot - - Get the primitive properties + + The landing point location - - 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 - + + The landing point LookAt - - - Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class - - The simulator the object is located - The Primitive - The primitive Properties + + The type of landing enforced from the enum - - Get the simulator the object is located + + - - Get the primitive details + + - - Get 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 - + + Access list of who is whitelisted on this + parcel - - Get the simulator the object is located + + Access list of who is blacklisted on this + parcel - - + + TRUE of region denies access to age unverified users - - + + true to obscure (hide) media url - - Provides primitive data containing updated location, velocity, rotation, textures for the event - The event occurs when the simulator sends updated location, velocity, rotation, etc - + + true to obscure (hide) music url - - Get the simulator the object is located + + A struct containing media details - - Get the primitive 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 - - Get the simulator the object is located + + + Parcel (subdivided simulator lots) subsystem + - - Get the primitive details + + 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 - - Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the - event + + Thread sync lock object - - Get the simulator the object is located + + The event subscribers. null if no subcribers - - The LocalID of the object + + Raises the ParcelProperties event + A ParcelPropertiesEventArgs object containing the + data returned from the simulator - - - Provides updates sit position data - + + Thread sync lock object - - Get the simulator the object is located + + 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 - - Get the simulator the object is located + + 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 + + - Indicates if the operation was successful + Default constructor + A reference to the GridClient object - + - Media version string + Request basic information for a single parcel + Simulator-local ID of the parcel - + - Array of media entries indexed by face number + 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 - + - De-serialization constructor for the InventoryNode Class + Request all simulator parcel properties (used for populating the Simulator.Parcels + dictionary) + Simulator to request parcels from (must be connected) - + - Serialization handler for the InventoryNode Class + 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 - + - De-serialization handler for the InventoryNode Class + 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 - - - - - - - - - - - - - + - For inventory folder nodes specifies weather the folder needs to be - refreshed from the server + 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 - - 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 + Request prim owners of a parcel of land. + Simulator parcel is in + The parcels region specific local ID - + - Used internally when building the initial list of friends at login time + Return objects from a parcel - 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 + Simulator parcel is in + The parcels region specific local ID + the type of objects to return, + A list containing object owners s to return - + - FriendInfo represented as a string + Subdivide (split) a parcel - A string reprentation of both my rights and my friends rights + + + + + - + - System ID of the avatar + Join two parcels of land creating a single parcel + + + + + - + - full name of the avatar + 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. - + - True if the avatar is online + 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() - + - True if the friend can see if I am online + 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() - + - True if the friend can see me on the map + 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() - + - True if the freind can modify my objects + 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 - + - True if I can see if my friend is online + 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 - + - True if I can see if my friend is on the map + Eject and optionally ban a user from a parcel + target key of avatar to eject + true to also ban target - + - True if I can modify my friend's objects + Freeze or unfreeze an avatar over your land + target key to freeze + true to freeze, false to unfreeze - + - My friend's rights represented as bitmapped flags + Abandon a parcel of land + Simulator parcel is in + Simulator local ID of parcel - + - My rights represented as bitmapped flags + 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 - + - This class is used to add and remove avatars from your friends list and to manage their permission. + 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 - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - Raises the FriendOnline event - A FriendInfoEventArgs object containing the - data returned from the data server + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - Raises the FriendOffline event - A FriendInfoEventArgs object containing the - data returned from the data server + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - Raises the FriendRightsUpdate event - A FriendInfoEventArgs object containing the - data returned from the data server + + Raised when the simulator responds to a request - - Thread sync lock object + + Raised when the simulator responds to a request - - The event subscribers. null if no subcribers + + Raised when the simulator responds to a request - - Raises the FriendNames event - A FriendNamesEventArgs object containing the - data returned from the data server + + Raised when the simulator responds to a request - - Thread sync lock object + + Raised when the simulator responds to a request - - The event subscribers. null if no subcribers + + Raised when the simulator responds to a request - - Raises the FriendshipOffered event - A FriendshipOfferedEventArgs object containing the - data returned from the data server + + Raised when the simulator responds to a request - - Thread sync lock object + + Raised when the simulator responds to a Parcel Update request - - The event subscribers. null if no subcribers + + Raised when the parcel your agent is located sends a ParcelMediaCommand - - Raises the FriendshipResponse event - A FriendshipResponseEventArgs object containing the - data returned from the data server + + + Parcel Accesslist + - - Thread sync lock object + + Agents - - The event subscribers. null if no subcribers + + - - Raises the FriendshipTerminated event - A FriendshipTerminatedEventArgs object containing the - data returned from the data server + + Flags for specific entry in white/black lists - - Thread sync lock object + + + Owners of primitives on parcel + - - The event subscribers. null if no subcribers + + Prim Owners - - Raises the FriendFoundReply event - A FriendFoundReplyEventArgs object containing the - data returned from the data server + + True of owner is group - - Thread sync lock object + + Total count of prims owned by OwnerID - - - 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 - + + true of OwnerID is currently online and is not a group - - - 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 + + The date of the most recent prim left by OwnerID - + - Accept a friendship request + Called once parcel resource usage information has been collected - agentID of avatatar to form friendship with - imSessionID of the friendship request message + Indicates if operation was successfull + Parcel resource usage information - - - Decline a friendship request - - of friend - imSessionID of the friendship request message + + Contains a parcels dwell data returned from the simulator in response to an - + - Overload: Offer friendship to an avatar. + Construct a new instance of the ParcelDwellReplyEventArgs class - System ID of the avatar you are offering friendship to + The global ID of the parcel + The simulator specific ID of the parcel + The calculated dwell for the parcel - - - Offer friendship to an avatar. - - System ID of the avatar you are offering friendship to - A message to send with the request + + Get the global ID of the parcel - - - Terminate a friendship with an avatar - - System ID of the avatar you are terminating the friendship with + + Get the simulator specific ID of the parcel - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Get the calculated dwell - - - 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. + + Contains basic parcel information data returned from the + simulator in response to an request - + - Use to map a friends location on the grid. + Construct a new instance of the ParcelInfoReplyEventArgs class - Friends UUID to find - + The object containing basic parcel info - - - Use to track a friends movement on the grid - - Friends Key + + Get the object containing basic parcel info - - - Ask for a notification of friend's online status - - Friend's UUID + + Contains basic parcel information data returned from the simulator in response to an request - + - This handles the asynchronous response of a RequestAvatarNames call. + Construct a new instance of the ParcelPropertiesEventArgs class - - names cooresponding to the the list of IDs sent the the RequestAvatarNames call. + 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: - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Get the simulator the parcel is located in - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Get the object containing the details + If Result is NoData, this object will not contain valid data - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Get the result of the request - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Get the number of primitieves your agent is + currently selecting and or sitting on in this parcel - - - 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 + + Get the user assigned ID used to correlate a request with + these results - - Raised when the simulator sends notification one of the members in our friends list comes online + + TODO: - - Raised when the simulator sends notification one of the members in our friends list goes offline + + Contains blacklist and whitelist data returned from the simulator in response to an request - - Raised when the simulator sends notification one of the members in our friends list grants or revokes permissions + + + 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 - - Raised when the simulator sends us the names on our friends list + + Get the simulator the parcel is located in - - Raised when the simulator sends notification another agent is offering us friendship + + Get the user assigned ID used to correlate a request with + these results - - Raised when a request we sent to friend another agent is accepted or declined + + Get the simulator specific ID of the parcel - - Raised when the simulator sends notification one of the members in our friends list has terminated - our friendship + + TODO: - - Raised when the simulator sends the location of a friend we have - requested map location info for + + Get the list containing the white/blacklisted agents for the parcel - - Contains information on a member of our friends list + + Contains blacklist and whitelist data returned from the + simulator in response to an request - + - Construct a new instance of the FriendInfoEventArgs class + Construct a new instance of the ParcelObjectOwnersReplyEventArgs class - The FriendInfo - - - Get the FriendInfo - - - Contains Friend Names + The simulator the parcel is located in + The list containing prim ownership counts - - - 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 + + Get the simulator the parcel is located in - - A dictionary where the Key is the ID of the Agent, - and the Value is a string containing their name + + Get the list containing prim ownership counts - - Sent when another agent requests a friendship with our agent + + Contains the data returned when all parcel data has been retrieved from a simulator - + - Construct a new instance of the FriendshipOfferedEventArgs class + Construct a new instance of the SimParcelsDownloadedEventArgs 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 + 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 ID of the agent requesting friendship + + Get the simulator the parcel data was retrieved from - - Get the name of the agent requesting friendship + + A dictionary containing the parcel data where the key correlates to the ParcelMap entry - - Get the ID of the session, used in accepting or declining the - friendship offer + + Get the multidimensional array containing a x,y grid mapped + to each 64x64 parcel's LocalID. - - A response containing the results of our request to form a friendship with another agent + + Contains the data returned when a request - + - Construct a new instance of the FriendShipResponseEventArgs class + Construct a new instance of the ForceSelectObjectsReplyEventArgs 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 + 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 ID of the agent we requested a friendship with + + Get the simulator the parcel data was retrieved from - - Get the name of the agent we requested a friendship with + + Get the list of primitive IDs - - true if the agent accepted our friendship offer + + true if the list is clean and contains the information + only for a given request - - Contains data sent when a friend terminates a friendship with us + + Contains data when the media data for a parcel the avatar is on changes - + - Construct a new instance of the FrindshipTerminatedEventArgs class + Construct a new instance of the ParcelMediaUpdateReplyEventArgs class - The ID of the friend who terminated the friendship with us - The name of the friend who terminated the friendship with us + the simulator the parcel media data was updated in + The updated media information - - Get the ID of the agent that terminated the friendship with us + + Get the simulator the parcel media data was updated in - - Get the name of the agent that terminated the friendship with us + + Get the updated media information - + + Contains the media command for a parcel the agent is currently on + + - 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 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 + + + + + - Construct a new instance of the FriendFoundReplyEventArgs class + A Name Value pair with additional settings, used in the protocol + primarily to transmit avatar names and active group in object packets - 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 + + - + + + + + + + - Reads in a byte array of an Animation Asset created by the SecondLife(tm) client. + Constructor that takes all the fields as parameters + + + + + - + - Rotation Keyframe count (used internally) + 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 + + + + + - Position Keyframe count (used internally) + - + + + + + + + + + + + + + - Animation Priority + - + + + + + + + + + + + + + + + + - The animation length in seconds. + Abstract base for rendering plugins - + - Expression set in the client. Null if [None] is selected + Generates a basic mesh structure from a primitive + Primitive to generate the mesh from + Level of detail to generate the mesh at + The generated mesh - + - The time in seconds to start the animation + Generates a basic mesh structure from a sculpted primitive and + texture + Sculpted primitive to generate the mesh from + Sculpt texture + Level of detail to generate the mesh at + The generated mesh - + - The time in seconds to end the animation + Generates a series of faces, each face containing a mesh and + metadata + Primitive to generate the mesh from + Level of detail to generate the mesh at + The generated mesh - + - Loop the animation + Generates a series of faces for a sculpted prim, each face + containing a mesh and metadata + Sculpted primitive to generate the mesh from + Sculpt texture + Level of detail to generate the mesh at + The generated mesh - + - Meta data. Ease in Seconds. + Apply texture coordinate modifications from a + to a list of vertices + Vertex list to modify texture coordinates for + Center-point of the face + Face texture parameters + Scale of the prim - + - Meta data. Ease out seconds. + 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 + + - Meta Data for the Hand Pose + Construct an Asset object of type Landmark + A unique specific to this asset + A byte array containing the raw asset data - + - Number of joints defined in the animation + Encode the raw contents of a string with the specific Landmark format - + - Contains an array of joints + 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 + + - Searialize an animation asset into it's joints/keyframes/meta data + Temporary code to produce a tar archive in tar v7 format - - + - Variable length strings seem to be null terminated in the animation asset.. but.. - use with caution, home grown. - advances the index. + Binary writer for the underlying stream - The animation asset byte array - The offset to start reading - a string - + - Read in a Joint from an animation asset byte array - Variable length Joint fields, yay! - Advances the index + Write a directory entry to the tar archive. We can only handle one path level right now! - animation asset byte array - Byte Offset of the start of the joint - The Joint data serialized into the binBVHJoint structure + - + - Read Keyframes of a certain type - advance i + Write a file to the tar archive - Animation Byte array - Offset in the Byte Array. Will be advanced - Number of Keyframes - Scaling Min to pass to the Uint16ToFloat method - Scaling Max to pass to the Uint16ToFloat method - + + - + - A Joint and it's associated meta data and keyframes + Write a file to the tar archive + + - + - Name of the Joint. Matches the avatar_skeleton.xml in client distros + Finish writing the raw tar archive data to a stream. The stream will be closed on completion. - + - Joint Animation Override? Was the same as the Priority in testing.. + Write a particular entry + + + - + - Array of Rotation Keyframes in order from earliest to latest + Operation to apply when applying color to texture - + - Array of Position Keyframes in order from earliest to latest - This seems to only be for the Pelvis? + Information needed to translate visual param value to RGBA color - + - A Joint Keyframe. This is either a position or a rotation. + Construct VisualColorParam + Operation to apply when applying color to texture + Colors - + - Either a Vector3 position or a Vector3 Euler rotation + Represents alpha blending and bump infor for a visual parameter + such as sleive length - + + Stregth of the alpha to apply + + + File containing the alpha channel + + + Skip blending if parameter value is 0 + + + Use miltiply insted of alpha blending + + - Poses set in the animation metadata for the hands. + Create new alhpa information for a visual param + + Stregth of the alpha to apply + File containing the alpha channel + Skip blending if parameter value is 0 + Use miltiply insted of alpha blending + + + + A single visual characteristic of an avatar mesh, such as eyebrow height + + + + Index of this visual param + + + Internal name + + + Group ID this parameter belongs to + + + Name of the wearable this parameter belongs to + + + Displayable label of this characteristic + + + Displayable label for the minimum value of this characteristic + + + Displayable label for the maximum value of this characteristic + + + Default value + + + Minimum value + + + Maximum value + + + Is this param used for creation of bump layer? + + + Alpha blending/bump info + + + Color information + + + Array of param IDs that are drivers for this parameter + + + + Set all the values through the constructor + + Index of this visual param + Internal name + + + Displayable label of this characteristic + Displayable label for the minimum value of this characteristic + Displayable label for the maximum value of this characteristic + Default value + Minimum value + Maximum value + Is this param used for creation of bump layer? + Array of param IDs that are drivers for this parameter + Alpha blending/bump info + Color information + + + + Holds the Params array of all the avatar appearance parameters + + + + + + + + + + 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 + + + + + + + + + + + + + + @@ -16833,6313 +15052,8678 @@ + + + - + - Represents an AssetScriptBinary object containing the - LSO compiled bytecode of an LSL script + Represents an Animation - - Initializes a new instance of an AssetScriptBinary object + + Default Constructor - - Initializes a new instance of an AssetScriptBinary object with parameters + + + Construct an Asset object of type Animation + A unique specific to this asset A byte array containing the raw asset data - - - TODO: Encodes a scripts contents into a LSO Bytecode file - + + Override the base classes AssetType - + - TODO: Decode LSO Bytecode into a string + Static helper functions and global variables - true - - Override the base classes AssetType + + This header flag signals that ACKs are appended to the packet - - - Temporary code to produce a tar archive in tar v7 format - + + 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 + + - Binary writer for the underlying stream + + + - + - Write a directory entry to the tar archive. We can only handle one path level right now! + - + + + - + - Write a file to the tar archive + - - + + - + - Write a file to the tar archive + - - + + + - + - Finish writing the raw tar archive data to a stream. The stream will be closed on completion. + 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 - + - Write a particular entry + 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 - + - Thrown when a packet could not be successfully deserialized + 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 - + - Default constructor + 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 - + - Constructor that takes an additional error message + Converts a list of primitives to an object that can be serialized + with the LLSD system - An error message to attach to this exception + Primitives to convert to a serializable object + An object that can be serialized with LLSD - + - The header of a message template packet. Holds packet flags, sequence - number, packet ID, and any ACKs that will be appended at the end of - the packet + 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); + } + + + + - Convert the AckList to a byte array, used for packet serializing + Passed to Logger.Log() to identify the severity of a log entry - Reference to the target byte array - Beginning position to start writing to in the byte - array, will be updated with the ending position of the ACK list - + + 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. + + + - + Checks the instance back into the object pool - - - - - + - + Returns an instance of the class that has been checked out of the Object Pool. - - - - + - A block of data in a packet. Packets are composed of one or more blocks, - each block containing one or more fields + Creates a new instance of the ObjectPoolBase class. Initialize MUST be called + after using this constructor. - + - Create a block from a byte array + Creates a new instance of the ObjectPool Base class. - Byte array containing the serialized block - Starting position of the block in the byte array. - This will point to the data after the end of the block when the - call returns + 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. - + - Serialize this block into a byte array + Forces the segment cleanup algorithm to be run. This method is intended + primarly for use from the Unit Test libraries. - Byte array to serialize this block into - Starting position in the byte array to serialize to. - 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 + + + Responsible for allocate 1 instance of an object that will be stored in a segment. + + An instance of whatever objec the pool is pooling. - - A generic value, not an actual packet type + + + 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. + - - + + + Wrapper around a byte array that allows bit to be packed and unpacked + one at a time or by a variable amount. Useful for very tightly packed + data like LayerData packets + - - + + - - + + + Default constructor, initialize the bit packer / bit unpacker + with a byte array and starting position + + Byte array to pack bits in to or unpack from + Starting position in the byte array - - + + + Pack a floating point value in to the data + + Floating point value to pack - - + + + Pack part or all of an integer in to the data + + Integer containing the data to pack + Number of bits of the integer to pack - - + + + Pack part or all of an unsigned integer in to the data + + Unsigned integer containing the data to pack + Number of bits of the integer to pack - - + + + Pack a single bit in to the data + + Bit to pack - - + + + + + + + + - - + + + + + - - + + + + + - - + + + Unpacking a floating point value from the data + + Unpacked floating point value - - + + + Unpack a variable number of bits from the data in to integer format + + Number of bits to unpack + An integer containing the unpacked bits + This function is only useful up to 32 bits - - + + + Unpack a variable number of bits from the data in to unsigned + integer format + + Number of bits to unpack + An unsigned integer containing the unpacked bits + This function is only useful up to 32 bits - - + + + Unpack a 16-bit signed integer + + 16-bit signed integer - - + + + Unpack a 16-bit unsigned integer + + 16-bit unsigned integer - - + + + Unpack a 32-bit signed integer + + 32-bit signed integer - - + + + Unpack a 32-bit unsigned integer + + 32-bit unsigned integer - - + + - - + + - - + + + 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 - - + + 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. + - - + + + 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 - - + + + Class that handles the local asset cache + - - + + + Default constructor + + A reference to the GridClient object - - + + + Disposes cleanup timer + - - + + + Only create timer when needed + - - + + + Return bytes read from the local asset cache, null if it does not exist + + UUID of the asset we want to get + Raw bytes of the asset, or null on failure - - + + + Returns ImageDownload object of the + image from the local image cache, null if it does not exist + + UUID of the image we want to get + ImageDownload object containing the image, or null on failure - - + + + Constructs a file name of the cached asset + + UUID of the asset + String with the file name of the cahced asset - - + + + Constructs a file name of the static cached asset + + UUID of the asset + String with the file name of the static cached asset - - + + + Saves an asset to the local cache + + UUID of the asset + Raw bytes the asset consists of + Weather the operation was successfull - - + + + Get the file name of the asset stored with gived UUID + + UUID of the asset + Null if we don't have that UUID cached on disk, file name if found in the cache folder - - + + + Checks if the asset exists in the local cache + + UUID of the asset + True is the asset is stored in the cache, otherwise false - - + + + Wipes out entire cache + - - + + + Brings cache size to the 90% of the max size + - - + + + Asynchronously brings cache size to the 90% of the max size + - - + + + Adds up file sizes passes in a FileInfo array + - - + + + Checks whether caching is enabled + - - + + + Periodically prune the cache + - - + + + Nicely formats file sizes + + 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 + - - + + + Represents a single Voice Session to the Vivox service. + - - + + + Close this session. + - - + + + Look up an existing Participants in this session + + + - - + + + + - - + + + + - - + + + + - - + + + + - - + + + + + + - - + + + 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 - - + + + Reads in a byte array of an Animation Asset created by the SecondLife(tm) client. + - - + + + Rotation Keyframe count (used internally) + - - + + + Position Keyframe count (used internally) + - - + + + Animation Priority + - - + + + The animation length in seconds. + - - + + + Expression set in the client. Null if [None] is selected + - - + + + The time in seconds to start the animation + - - + + + The time in seconds to end the animation + - - + + + Loop the animation + - - + + + Meta data. Ease in Seconds. + - - + + + Meta data. Ease out seconds. + - - + + + Meta Data for the Hand Pose + - - + + + Number of joints defined in the animation + - - + + + Contains an array of joints + - - + + + Searialize an animation asset into it's joints/keyframes/meta data + + - - + + + Variable length strings seem to be null terminated in the animation asset.. but.. + use with caution, home grown. + advances the index. + + The animation asset byte array + The offset to start reading + a string - - + + + Read in a Joint from an animation asset byte array + Variable length Joint fields, yay! + Advances the index + + animation asset byte array + Byte Offset of the start of the joint + The Joint data serialized into the binBVHJoint structure - - + + + Read Keyframes of a certain type + advance i + + Animation Byte array + Offset in the Byte Array. Will be advanced + Number of Keyframes + Scaling Min to pass to the Uint16ToFloat method + Scaling Max to pass to the Uint16ToFloat method + - - + + + Determines whether the specified is equal to the current . + + + true if the specified is equal to the current ; otherwise, false. + + The to compare with the current . + The parameter is null. + 2 - - + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + 2 - - + + + A Joint and it's associated meta data and keyframes + - - + + + Indicates whether this instance and a specified object are equal. + + + true if and this instance are the same type and represent the same value; otherwise, false. + + Another object to compare to. + 2 - - + + + Returns the hash code for this instance. + + + A 32-bit signed integer that is the hash code for this instance. + + 2 - - + + + Name of the Joint. Matches the avatar_skeleton.xml in client distros + - - + + + Joint Animation Override? Was the same as the Priority in testing.. + - - + + + Array of Rotation Keyframes in order from earliest to latest + - - + + + Array of Position Keyframes in order from earliest to latest + This seems to only be for the Pelvis? + - - + + + Custom application data that can be attached to a joint + - - + + + A Joint Keyframe. This is either a position or a rotation. + - - + + + Either a Vector3 position or a Vector3 Euler rotation + - - + + + Poses set in the animation metadata for the hands. + - - + + + 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 - - + + + 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 + - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - + + - - + + - - + + + + - - + + - - + + - - + + - - + + - - + + + + + + - - + + + + - - + + - - + + - - + + - - + + - - + + + + + + - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + + - - + + + + - - + + + + + + - - + + + + + + - - + + + + + - - + + + + - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + - - + + + 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 - - + + + 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 - - + + + 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 + - - + + + 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 - - + + + + - - + + 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 + - - + + + + - - + + 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 - - + + + + - - + + + + + - - + + + De-serialization constructor for the InventoryNode Class + - - + + + Serialization handler for the InventoryNode Class + - - + + + De-serialization handler for the InventoryNode Class + - - + + + + + - - + + - - + + - - + + - - + + - - + + + For inventory folder nodes specifies weather the folder needs to be + refreshed from the server + - - + + + 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. - - + + + 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 - - + + + 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 - - + + - - + + - - + + - - - Represents a single Voice Session to the Vivox service. - + + - - - Close this session. - + + 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 - - - Look up an existing Participants in this session - - - + + 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 - - - An instance of DelegateWrapper which calls InvokeWrappedDelegate, - which in turn calls the DynamicInvoke method of the wrapped - delegate - + + 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 - - - Callback used to call EndInvoke on the asynchronously - invoked DelegateWrapper - + + 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 - - - Executes the specified delegate with the specified arguments - asynchronously on a thread pool thread - - - + + 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 - - - Invokes the wrapped delegate synchronously - - - + + 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 - - - Calls EndInvoke on the wrapper and Close on the resulting WaitHandle - to prevent resource leaks - - + + - - - Delegate to wrap another delegate and its arguments - - - + + - - The event subscribers. null if no subcribers + + Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases - - Raises the LandPatchReceived event - A LandPatchReceivedEventArgs object containing the - data returned from the simulator + + Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases - - Thread sync lock object + + Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases - + + + + - Default constructor + Land types to search dataserver for - - - - Raised when the simulator responds sends - - - Simulator from that sent tha data - - Sim coordinate of the patch + + Search Auction, Mainland and Estate - - Sim coordinate of the patch + + Land which is currently up for auction - - Size of tha patch + + Parcels which are on the mainland (Linden owned) continents - - Heightmap for the patch + + 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 - - Size of the byte array used to store raw packet data + + Include all ads in results - - Raw packet data buffer + + Include PG ads in results - - Length of the data to transmit + + Include Mature ads in results - - EndPoint of the remote host + + Include Adult ads in results - + - Create an allocated UDP packet buffer for receiving a packet + The For Sale flag in PlacesReplyData - - - Create an allocated UDP packet buffer for sending a packet - - EndPoint of the remote host + + Parcel is not listed for sale - - - Create an allocated UDP packet buffer for sending a packet - - EndPoint of the remote host - Size of the buffer to allocate for packet data + + Parcel is For Sale - + - Object pool for packet buffers. This is used to allocate memory for all - incoming and outgoing packets, and zerocoding buffers for those packets + A classified ad on the grid - - - Initialize the object pool in client mode - - Server to connect to - - + + UUID for this ad, useful for looking up detailed + information about it - - - Initialize the object pool in server mode - - - + + The title of this classified ad - - - 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 + + Flags that show certain options applied to the classified - - - Default constructor - + + Creation date of the ad - - - Check a packet buffer out of the pool - - A packet buffer object + + Expiration date of the ad - - - Singleton logging class for the entire library - + + Price that was paid for this ad - - log4net logging engine + + Print the struct data as a string + A string containing the field name, and field value - + - Default constructor + A parcel retrieved from the dataserver such as results from the + "For-Sale" listings or "Places" Search - - - Send a log message to the logging engine - - The log message - The severity of the log entry + + 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 + + - Send a log message to the logging engine + An Avatar returned from the dataserver - The log message - The severity of the log entry - Instance of the client - + + 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 + + - Send a log message to the logging engine + Response to a "Groups" Search - 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 + + The Group ID - - - 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 + + The name of the group - - - 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 + + The current number of members - - Triggered whenever a message is logged. If this is left - null, log messages will go to the console + + Print the struct data as a string + A string containing the field name, and field value - + - Callback used for client apps to receive log messages from - the library + 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 - Data being logged - The severity of the log entry from - - Sort by name + + The ID of the Agent of Group that owns the parcel - - Sort by date + + The name - - Sort folders by name, regardless of whether items are - sorted by name or date + + The description - - Place system folders at the top + + The Size of the parcel - - - Possible destinations for DeRezObject request - + + 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 - - Copy from in-world to agent inventory + + The Gridwide X position - - Derez to TaskInventory + + The Gridwide Y position - - + + The Z position of the parcel, or 0 if no landing point set - - Take Object + + The name of the Region the parcel is located in - - + + The Asset ID of the parcels Snapshot texture - - Delete Object + + The calculated visitor traffic - - Put an avatar attachment into agent inventory + + 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 - - Return an object back to the owner's inventory + + Get a SL URL for the parcel + A string, containing a standard SLURL - - Return a deeded object back to the last owner's inventory + + Print the struct data as a string + A string containing the field name, and field value - + - Upper half of the Flags field for inventory items + An "Event" Listing summary - - 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 + + The ID of the event creator - - If set, and a slam bit is set, indicates OwnerMask will be overwritten on Rez + + The name of the event - - If set, and a slam bit is set, indicates GroupMask will be overwritten on Rez + + The events ID - - If set, and a slam bit is set, indicates EveryoneMask will be overwritten on Rez + + A string containing the short date/time the event will begin - - If set, and a slam bit is set, indicates NextOwnerMask will be overwritten on Rez + + The event start time in Unixtime (seconds since epoch) - - Indicates whether this object is composed of multiple - items or not + + The events maturity rating - - 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 + + Print the struct data as a string + A string containing the field name, and field value - + - Base Class for Inventory Items + The details of an "Event" - - of item/folder + + The events ID - - of parent folder + + The ID of the event creator - - Name of item/folder + + The name of the event - - Item/Folder Owners + + The category - - - Constructor, takes an itemID as a parameter - - The of the item + + 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 - - - 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 + + Contains the Event data returned from the data server from an EventInfoRequest - - - Determine whether the specified object is equal to the current object - - InventoryBase object to compare against - true if objects are the same + + Construct a new instance of the EventInfoReplyEventArgs class + A single EventInfo object containing the details of an event - + - Determine whether the specified object is equal to the current object + A single EventInfo object containing the details of an event - InventoryBase object to compare against - true if objects are the same - - - An Item in Inventory - + + Contains the "Event" detail data returned from the data server - - The of this item + + 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 combined of this item + + The ID returned by - - The type of item from + + A list of "Events" returned by the data server - - The type of item from the enum + + Contains the "Event" list data returned from the data server - - The of the creator of this item + + 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 - - A Description of this item + + The ID returned by - - The s this item is set to or owned by + + A list of "Places" returned by the data server - - If true, item is owned by a group + + Contains the places data returned from the data server - - The price this item can be purchased for + + 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 type of sale from the enum + + The ID returned by - - Combined flags from + + A list containing Places data returned by the data server - - Time and date this inventory item was created, stored as - UTC (Coordinated Universal Time) + + Contains the classified data returned from the data server - - Used to update the AssetID in requests sent to the server + + Construct a new instance of the DirClassifiedsReplyEventArgs class + A list of classified ad data returned from the data server - - The of the previous owner of the item + + A list containing Classified Ads returned by the data server - - - Construct a new InventoryItem object - - The of the item + + Contains the group data returned from the data server - - - Construct a new InventoryItem object of a specific Type - - The type of item from - of the item + + 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 - - - Indicates inventory item is a link - - True if inventory item is a link to another inventory item + + The ID returned by - - - - - + + A list containing Groups data returned by the data server - - - - - + + Contains the people data returned from the data server - - - 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 + + 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 - - - Compares an object - - The object to compare - true if comparison object matches + + The ID returned by - - - Determine whether the specified object is equal to the current object - - The object to compare against - true if objects are the same + + A list containing People data returned by the data server - - - Determine whether the specified object is equal to the current object - - The object to compare against - true if objects are the same + + Contains the land sales data returned from the data server - - - InventoryTexture Class representing a graphical image - - + + Construct a new instance of the DirLandReplyEventArgs class + A list of parcels for sale returned by the data server - - - Construct an InventoryTexture object - - A which becomes the - objects AssetUUID + + A list containing land forsale data returned by the data server - + - Construct an InventoryTexture object from a serialization stream + Sent to the client to indicate a teleport request has completed - + - InventorySound Class representing a playable sound + Interface requirements for Messaging system - - - Construct an InventorySound object - - A which becomes the - objects AssetUUID + + The of the agent - - - Construct an InventorySound object from a serialization stream - + + - - - InventoryCallingCard Class, contains information on another avatar - + + The simulators handle the agent teleported to - - - Construct an InventoryCallingCard object - - A which becomes the - objects AssetUUID + + A Uri which contains a list of Capabilities the simulator supports - - - Construct an InventoryCallingCard object from a serialization stream - + + Indicates the level of access required + to access the simulator, or the content rating, or the simulators + map status - - - InventoryLandmark Class, contains details on a specific location - + + The IP Address of the simulator - - - Construct an InventoryLandmark object - - A which becomes the - objects AssetUUID + + The UDP Port the simulator will listen for UDP traffic on - + + Status flags indicating the state of the Agent upon arrival, Flying, etc. + + - Construct an InventoryLandmark object from a serialization stream + Serialize the object + An containing the objects data - + - Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited + Deserialize the message + An containing the data - + - InventoryObject Class contains details on a primitive or coalesced set of primitives + Sent to the viewer when a neighboring simulator is requesting the agent make a connection to it. - + - Construct an InventoryObject object + Serialize the object - A which becomes the - objects AssetUUID + An containing the objects data - + - Construct an InventoryObject object from a serialization stream + Deserialize the message + An containing the data - + - Gets or sets the upper byte of the Flags value + Serialize the object + An containing the objects data - + - Gets or sets the object attachment point, the lower byte of the Flags value + Deserialize the message + An containing the data - + - InventoryNotecard Class, contains details on an encoded text document + Serialize the object + An containing the objects data - + - Construct an InventoryNotecard object + Deserialize the message - A which becomes the - objects AssetUUID + An containing the data - + - Construct an InventoryNotecard object from a serialization stream + A message sent to the client which indicates a teleport request has failed + and contains some information on why it failed - + + + + + A string key of the reason the teleport failed e.g. CouldntTPCloser + Which could be used to look up a value in a dictionary or enum + + + The of the Agent + + + A string human readable message containing the reason + An example: Could not teleport closer to destination + + - InventoryCategory Class + Serialize the object - TODO: Is this even used for anything? + An containing the objects data - + - Construct an InventoryCategory object + Deserialize the message - A which becomes the - objects AssetUUID + An containing the data - + - Construct an InventoryCategory object from a serialization stream + Serialize the object + An containing the objects data - + - InventoryLSL Class, represents a Linden Scripting Language object + Deserialize the message + An containing the data - + - Construct an InventoryLSL object + Contains a list of prim owner information for a specific parcel in a simulator - A which becomes the - objects AssetUUID + + A Simulator will always return at least 1 entry + If agent does not have proper permission the OwnerID will be UUID.Zero + If agent does not have proper permission OR there are no primitives on parcel + the DataBlocksExtended map will not be sent from the simulator + - + + An Array of objects + + - Construct an InventoryLSL object from a serialization stream + Serialize the object + An containing the objects data - + - InventorySnapshot Class, an image taken with the viewer + Deserialize the message + An containing the data - + - Construct an InventorySnapshot object + Prim ownership information for a specified owner on a single parcel - A which becomes the - objects AssetUUID - + + The of the prim owner, + UUID.Zero if agent has no permission to view prim owner information + + + The total number of prims + + + True if the OwnerID is a + + + True if the owner is online + This is no longer used by the LL Simulators + + + The date the most recent prim was rezzed + + - Construct an InventorySnapshot object from a serialization stream + The details of a single parcel in a region, also contains some regionwide globals - + + Simulator-local ID of this parcel + + + Maximum corner of the axis-aligned bounding box for this + parcel + + + Minimum corner of the axis-aligned bounding box for this + parcel + + + Total parcel land area + + + + + + Key of authorized buyer + + + Bitmap describing land layout in 4x4m squares across the + entire region + + + + + + Date land was claimed + + + Appears to always be zero + + + Parcel Description + + + + + + + + + Total number of primitives owned by the parcel group on + this parcel + + + Whether the land is deeded to a group or not + + + + + + Maximum number of primitives this parcel supports + + + 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 byte, if 0x1 viewer should auto scale media to fit object + + + URL For Music Stream + + + Parcel Name + + + Autoreturn value in minutes for others' objects + + + + + + Total number of other primitives on this parcel + + + UUID of the owner of this parcel + + + Total number of primitives owned by the parcel owner on + this parcel + + + + + + How long is pass valid for + + + Price for a temporary pass + + + + + + Disallows people outside the parcel from being able to see in + + + + + + + + + + + + True if the region denies access to age unverified users + + + + + + This field is no longer used + + + The result of a request for parcel properties + + + 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 + + - InventoryAttachment Class, contains details on an attachable object + Number of primitives your avatar is currently + selecting and sitting on in this parcel - - - Construct an InventoryAttachment object - - A which becomes the - objects AssetUUID + + - + - Construct an InventoryAttachment object from a serialization stream + A number which increments by 1, starting at 0 for each ParcelProperties request. + Can be overriden by specifying the sequenceID with the ParcelPropertiesRequest being sent. + a Negative number indicates the action in has occurred. - - - Get the last AttachmentPoint this object was attached to - + + Maximum primitives across the entire simulator - - - InventoryWearable Class, details on a clothing item or body part - + + Total primitives across the entire simulator - - - Construct an InventoryWearable object - - A which becomes the - objects AssetUUID + + - - - Construct an InventoryWearable object from a serialization stream - + + Key of parcel snapshot - - - The , Skin, Shape, Skirt, Etc - + + Parcel ownership status - - - InventoryAnimation Class, A bvh encoded object which animates an avatar - + + Total number of primitives on this parcel - - - 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 - + + A description of the media - - - Construct an InventoryGesture object - - A which becomes the - objects AssetUUID + + An Integer which represents the height of the media - - - Construct an InventoryGesture object from a serialization stream - + + An integer which represents the width of the media - - - A folder contains s and has certain attributes specific - to itself - + + A boolean, if true the viewer should loop the media - - The Preferred for a folder. + + A string which contains the mime type of the media - - The Version of this folder + + true to obscure (hide) media url - - Number of child items this folder contains. + + true to obscure (hide) music url - + - Constructor + Serialize the object - UUID of the folder + An containing the objects data - + - + Deserialize the message - + An containing the data - - - Get Serilization data for this InventoryFolder object - + + A message sent from the viewer to the simulator to updated a specific parcels settings - - - Construct an InventoryFolder object from a serialization stream - + + The of the agent authorized to purchase this + parcel of land or a NULL if the sale is authorized to anyone - - - - - + + true to enable auto scaling of the parcel media - - - - - - + + The category of this parcel used when search is enabled to restrict + search results - - - - - - + + A string containing the description to set - - - - - - + + The of the which allows for additional + powers and restrictions. - - - Tools for dealing with agents inventory - + + The which specifies how avatars which teleport + to this parcel are handled - - Used for converting shadow_id to asset_id + + The LocalID of the parcel to update settings on - - The event subscribers, null of no subscribers + + A string containing the description of the media which can be played + to visitors - - 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 + + + Deserialize the message + + An containing the data - - Raises the SaveAssetToInventory Event - A SaveAssetToInventoryEventArgs object containing - the data sent from the simulator + + + Serialize the object + + An containing the objects data - - Thread sync lock object + + Base class used for the RemoteParcelRequest message - - The event subscribers, null of no subscribers + + + A message sent from the viewer to the simulator to request information + on a remote parcel + - - Raises the ScriptRunningReply Event - A ScriptRunningReplyEventArgs object containing - the data sent from the simulator + + Local sim position of the parcel we are looking up - - Thread sync lock object + + Region handle of the parcel we are looking up - - Partial mapping of AssetTypes to folder names + + Region of the parcel we are looking up - + - Default constructor + Serialize the object - Reference to the GridClient object + An containing the objects data - + - Fetch an inventory item from the dataserver + Deserialize the message - 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 + An containing the data - + - Request A single inventory item + A message sent from the simulator to the viewer in response to a + which will contain parcel information - The items - The item Owners - - + + The grid-wide unique parcel ID + + - Request inventory items + Serialize the object - Inventory items to request - Owners of the inventory items - + An containing the objects data - + - Get contents of a folder + Deserialize the message - 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 + An containing the data - + - Request the contents of an inventory folder + A message containing a request for a remote parcel from a viewer, or a response + from the simulator to that request - 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 - - + + The request or response details block + + - Returns the UUID of the folder (category) that defaults to - containing 'type'. The folder is not necessarily only for that - type + Serialize the object - 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 + An containing the objects data - + - Find an object in inventory using a specific path to search + Deserialize the message - 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 + An containing the data - + - Find inventory items by path + Serialize the object - 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 + An containing the objects data - + - Search inventory Store object for an item or folder + Deserialize the message - 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 + An containing the data - + - Move an inventory item or folder to a new location + Serialize the object - The item or folder to move - The to move item or folder to + An containing the objects data - + - Move an inventory item or folder to a new location and change its name + Deserialize the message - The item or folder to move - The to move item or folder to - The name to change the item or folder to + An containing the data - + - Move and rename a folder + A message sent from the simulator to an agent which contains + the groups the agent is in - The source folders - The destination folders - The name to change the folder to - + + 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 + + - Update folder properties + Serialize the object - of the folder to update - Sets folder's parent to - Folder name - Folder type + An containing the objects data - + - Move a folder + Deserialize the message - The source folders - The destination folders + An containing the data - + + Group Details specific to the agent + + + true of the agent accepts group notices + + + The agents tier contribution to the group + + + The Groups + + + The of the groups insignia + + + The name of the group + + + The aggregate permissions the agent has in the group for all roles the agent + is assigned + + + An optional block containing additional agent specific information + + + true of the agent allows this group to be + listed in their profile + + - Move multiple folders, the keys in the Dictionary parameter, - to a new parents, the value of that folder's key. + A message sent from the viewer to the simulator which + specifies the language and permissions for others to detect + the language specified - A Dictionary containing the - of the source as the key, and the - of the destination as the value - + + A string containng the default language + to use for the agent + + + true of others are allowed to + know the language setting + + - Move an inventory item to a new folder + Serialize the object - The of the source item to move - The of the destination folder + An containing the objects data - + - Move and rename an inventory item + Deserialize the message - The of the source item to move - The of the destination folder - The name to change the folder to + An containing the data - + - Move multiple inventory items to new locations + An EventQueue message sent from the simulator to an agent when the agent + leaves a group - 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 + An Array containing the AgentID and GroupID - The of the folder - + - Remove a single item from inventory + Serialize the object - The of the inventory item to remove + An containing the objects data - + - Remove a folder from inventory + Deserialize the message - The of the folder to remove + 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 + + - Remove multiple items or folders from inventory + The request state - 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 + Serialize the object + An containing the objects data - + - Empty the Trash folder + Deserialize the message + An containing the data - + - + A message sent from the viewer to the simulator to request a temporary upload capability + which allows an asset to be uploaded - - - - - Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. - - - - + + The Capability URL sent by the simulator to upload the baked texture to + + - + A message sent from the simulator that will inform the agent the upload is complete, + and the UUID of the uploaded asset - - - - - Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. - - - - - + + The uploaded texture asset ID + + - Creates a new inventory folder + A message sent from the viewer to the simulator to request a temporary + capability URI which is used to upload an agents baked appearance textures - ID of the folder to put this folder in - Name of the folder to create - The UUID of the newly created folder - + + Object containing request or response + + - Creates a new inventory folder + Serialize the object - 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 + An containing the objects data - + - Create an inventory item and upload asset data + Deserialize the message - 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 + An containing the data - + - Create an inventory item and upload asset data + A message sent from the simulator which indicates the minimum version required for + using voice chat - 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 - + + Major Version Required + + + Minor version required + + + The name of the region sending the version requrements + + - Creates inventory link to another inventory item or folder + Serialize the object - Put newly created link in folder with this UUID - Inventory item or folder - Method to call upon creation of the link + An containing the objects data - + - Creates inventory link to another inventory item + Deserialize the message - Put newly created link in folder with this UUID - Original inventory item - Method to call upon creation of the link + An containing the data - + - Creates inventory link to another inventory folder + A message sent from the simulator to the viewer containing the + voice server URI - Put newly created link in folder with this UUID - Original inventory folder - Method to call upon creation of the link - + + The Parcel ID which the voice server URI applies + + + The name of the region + + + A uri containing the server/channel information + which the viewer can utilize to participate in voice conversations + + - Creates inventory link to another inventory item or folder + Serialize the object - 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 + An containing the objects data - + - + Deserialize the message - - - - + An containing the data - + - - - - - - + + + + + + + - + Serialize the object - - - - - + An containing the objects data - + - Request a copy of an asset embedded within a notecard + Deserialize the message - 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 + An containing the data - + - + A message sent by the viewer to the simulator to request a temporary + capability for a script contained with in a Tasks inventory to be updated - - + + Object containing request or response + + - + Serialize the object - + An containing the objects data - + - + Deserialize the message - - + An containing the data - + - + A message sent from the simulator to the viewer to indicate + a Tasks scripts status. - - - - + + The Asset ID of the script + + + True of the script is compiled/ran using the mono interpreter, false indicates it + uses the older less efficient lsl2 interprter + + + The Task containing the scripts + + + true of the script is in a running state + + - Save changes to notecard embedded in object contents + Serialize the object - Encoded notecard asset data - Notecard UUID - Object's UUID - Called upon finish of the upload with status information + An containing the objects data - + - Upload new gesture asset for an inventory gesture item + Deserialize the message - Encoded gesture asset - Gesture inventory UUID - Callback whick will be called when upload is complete + An containing the data - + - Update an existing script in an agents Inventory + A message containing the request/response used for updating a gesture + contained with 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 - - + + Object containing request or response + + - Update an existing script in an task Inventory + Serialize the object - 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 - + An containing the objects data - + - Rez an object from inventory + Deserialize the message - Simulator to place object in - Rotation of the object when rezzed - Vector of where to place object - InventoryItem object containing item details + An containing the data - + - Rez an object from inventory + A message request/response which is used to update a notecard contained within + a tasks 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 - + + The of the Task containing the notecard asset to update + + + The notecard assets contained in the tasks inventory + + - Rez an object from inventory + Serialize the object - 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 + An containing the objects data - + - DeRez an object from the simulator to the agents Objects folder in the agents Inventory + Deserialize the message - The simulator Local ID of the object - If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed + An containing the data - + - DeRez an object from the simulator and return to inventory + A reusable class containing a message sent from the viewer to the simulator to request a temporary uploader capability + which is used to update an asset in an agents 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 + The Notecard AssetID to replace - - - - - + - Give an inventory item to another avatar + Serialize the object - 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 + An containing the objects data - + - Give an inventory Folder with contents to another avatar + Deserialize the message - 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 + An containing the data - + - Copy or move an from agent inventory to a task (primitive) inventory + A message containing the request/response used for updating a notecard + contained with an agents 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 - + + Object containing request or response + + - Retrieve a listing of the items contained in a task (Primitive) + Serialize the object - 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 + An containing the objects data - + - Request the contents of a tasks (primitives) inventory from the - current simulator + Deserialize the message - The LocalID of the object - + An containing the data - + - Request the contents of a tasks (primitives) inventory + Serialize the object - The simulator Local ID of the object - A reference to the simulator object that contains the object - + An containing the objects data - + - Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory + Deserialize the message - 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 + An containing the data - + - Remove an item from an objects (Prim) Inventory + A message sent from the simulator to the viewer which indicates + an error occurred while attempting to update a script in an agents or tasks + 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]); - - + + true of the script was successfully compiled by the simulator + + + A string containing the error which occured while trying + to update the script + + + A new AssetID assigned to the script - + - Request the running status of a script contained in a task (primitive) inventory + A message sent from the viewer to the simulator + requesting the update of an existing script contained + within a tasks 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 - - + + if true, set the script mode to running + + + The scripts InventoryItem ItemID to update + + + A lowercase string containing either "mono" or "lsl2" which + specifies the script is compiled and ran on the mono runtime, or the older + lsl runtime + + + The tasks which contains the script to update + + - Send a request to set the running state of a script contained in a task (primitive) inventory + Serialize the object - 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 + An containing the objects data - + - Create a CRC from an InventoryItem + Deserialize the message - The source InventoryItem - A uint representing the source InventoryItem as a CRC + An containing the data - + - Reverses a cheesy XORing with a fixed UUID to convert a shadow_id to an asset_id + A message containing either the request or response used in updating a script inside + a tasks inventory - Obfuscated shadow_id value - Deobfuscated asset_id value - + + Object containing request or response + + - Does a cheesy XORing with a fixed UUID to convert an asset_id to a shadow_id + Serialize the object - asset_id value to obfuscate - Obfuscated shadow_id value + An containing the objects data - + - Wrapper for creating a new object + Deserialize the message - The type of item from the enum - The of the newly created object - An object with the type and id passed + An containing the data - + - Parse the results of a RequestTaskInventory() response + Response from the simulator to notify the viewer the upload is completed, and + the UUID of the script asset and its compiled status - 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 + + The uploaded texture asset ID - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + true of the script was compiled successfully - + - 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 + A message sent from a viewer to the simulator requesting a temporary uploader capability + used to update a script contained in an agents inventory - 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 + + The existing asset if of the script in the agents inventory to replace - - Raised when the simulator sends us data containing - ... + + The language of the script + Defaults to lsl version 2, "mono" might be another possible option - - Raised when the simulator sends us data containing - ... + + + Serialize the object + + An containing the objects data - - Raised when the simulator sends us data containing - ... + + + Deserialize the message + + An containing the data - - Raised when the simulator sends us data containing - ... + + + A message containing either the request or response used in updating a script inside + an agents inventory + - - Raised when the simulator sends us data containing - ... + + Object containing request or response - + - Get this agents Inventory data + Serialize the object + An containing the objects data - + - Callback for inventory item creation finishing + Deserialize the message - Whether the request to create an inventory - item succeeded or not - Inventory item being created. If success is - false this will be null + An containing the data - + - Callback for an inventory item being create from an uploaded asset + Serialize the object - true if inventory item creation was successful - - - + An containing the objects data - + - + Deserialize the message - + An containing the data - + + Base class for Map Layers via Capabilities + + + + + - Reply received when uploading an inventory asset + Serialize the object - Has upload been successful - Error message if upload failed - Inventory asset UUID - New asset UUID + An containing the objects data - + - Delegate that is invoked when script upload is completed + Deserialize the message - 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 + An containing the data - + - 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. + Sent by an agent to the capabilities server to request map layers - + - Map layer request type + A message sent from the simulator to the viewer which contains an array of map images and their grid coordinates - - Objects and terrain are shown + + An array containing LayerData items - - Only the terrain is shown, no objects + + + Serialize the object + + An containing the objects data - - Overlay showing land for sale and for auction + + + Deserialize the message + + An containing the data - + - Type of grid item, such as telehub, event, populator location, etc. + An object containing map location details - - Telehub - - - PG rated event - - - Mature rated event + + The Asset ID of the regions tile overlay - - Popular location + + The grid location of the southern border of the map tile - - Locations of avatar groups in a region + + The grid location of the western border of the map tile - - Land for sale + + The grid location of the eastern border of the map tile - - Classified ad + + The grid location of the northern border of the map tile - - Adult rated event + + Object containing request or response - - Adult land for sale + + + Serialize the object + + An containing the objects data - + - Information about a region on the grid map + Deserialize the message + An containing the data - - Sim X position on World Map + + + New as of 1.23 RC1, no details yet. + - - Sim Y position on World Map + + + Serialize the object + + An containing the objects data - - Sim Name (NOTE: In lowercase!) + + + Deserialize the message + + An containing the data - - + + + Serialize the object + + An containing the objects data - - Appears to always be zero (None) + + + Deserialize the message + + An containing the data - - Sim's defined Water Height + + A string containing the method used - - + + + A request sent from an agent to the Simulator to begin a new conference. + Contains a list of Agents which will be included in the conference + - - UUID of the World Map image + + An array containing the of the agents invited to this conference - - Unique identifier for this region, a combination of the X - and Y position + + The conferences Session ID - + - + Serialize the object - + An containing the objects data - + - + Deserialize the message - + An containing the data - + - + A moderation request sent from a conference moderator + Contains an agent and an optional action to take + + + + The Session ID + + + + + + A list containing Key/Value pairs, known valid values: + key: text value: true/false - allow/disallow specified agents ability to use text in session + key: voice value: true/false - allow/disallow specified agents ability to use voice in session - - + "text" or "voice" - + + + + - Visual chunk of the grid map + Serialize the object + An containing the objects data - + - Base class for Map Items + Deserialize the message + An containing the data - - 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 + + + A message sent from the agent to the simulator which tells the + simulator we've accepted a conference invitation + - - Get the Handle of the region + + The conference SessionID - + - Represents an agent or group of agents location + Serialize the object + An containing the objects data - + - Represents a Telehub location + Deserialize the message + An containing the data - + - Represents a non-adult parcel of land for sale + Serialize the object + An containing the objects data - + - Represents an Adult parcel of land for sale + Deserialize the message + An containing the data - + - Represents a PG Event + Serialize the object + An containing the objects data - + - Represents a Mature event + Deserialize the message + An containing the data - + - Represents an Adult event + Serialize the object + An containing the objects data - + - Manages grid-wide tasks such as the world map + Deserialize the message + An containing the data - - The event subscribers. null if no subcribers - - - Raises the CoarseLocationUpdate event - A CoarseLocationUpdateEventArgs object containing the - data sent by simulator - - - Thread sync lock object + + Key of sender - - The event subscribers. null if no subcribers + + Name of sender - - Raises the GridRegion event - A GridRegionEventArgs object containing the - data sent by simulator + + Key of destination avatar - - Thread sync lock object + + ID of originating estate - - The event subscribers. null if no subcribers + + Key of originating region - - Raises the GridLayer event - A GridLayerEventArgs object containing the - data sent by simulator + + Coordinates in originating region - - Thread sync lock object + + Instant message type - - The event subscribers. null if no subcribers + + Group IM session toggle - - Raises the GridItems event - A GridItemEventArgs object containing the - data sent by simulator + + Key of IM session, for Group Messages, the groups UUID - - Thread sync lock object + + Timestamp of the instant message - - The event subscribers. null if no subcribers + + Instant message text - - Raises the RegionHandleReply event - A RegionHandleReplyEventArgs object containing the - data sent by simulator + + Whether this message is held for offline avatars - - Thread sync lock object + + Context specific packed data - - A dictionary of all the regions, indexed by region name + + Is this invitation for voice group/conference chat - - A dictionary of all the regions, indexed by region handle + + + Serialize the object + + An containing the objects data - + - Constructor + Deserialize the message - Instance of GridClient object to associate with this GridManager instance + An containing the data - + + Sent from the simulator to the viewer. + + When an agent initially joins a session the AgentUpdatesBlock object will contain a list of session members including + a boolean indicating they can use voice chat in this session, a boolean indicating they are allowed to moderate + this session, and lastly a string which indicates another agent is entering the session with the Transition set to "ENTER" + During the session lifetime updates on individuals are sent. During the update the booleans sent during the initial join are + excluded with the exception of the Transition field. This indicates a new user entering or exiting the session with + the string "ENTER" or "LEAVE" respectively. - - + - Request a map layer + Serialize the object - The name of the region - The type of layer + An containing the objects data - + - + Deserialize the message - - - - - - + An containing the data - + - + An EventQueue message sent when the agent is forcibly removed from a chatterbox session - - - - - - + - + A string containing the reason the agent was removed - - - - + - Request data for all mainland (Linden managed) simulators + The ChatterBoxSession's SessionID - + - Request the region handle for the specified region UUID + Serialize the object - UUID of the region to look up + An containing the objects data - + - Get grid region information using the region name, this function - will block until it can find the region or gives up + Deserialize the message - 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 + An containing the data - - Raised when the simulator sends a Region Data in response to - a Map request + + + Serialize the object + + An containing the objects data - - Raised when the simulator sends GridLayer object containing - a map tile coordinates and texture information + + + Deserialize the message + + An containing the data - - Raised when the simulator sends GridItems object containing - details on events, land sales at a specific location + + + Serialize the object + + An containing the objects data - - Raised in response to a Region lookup + + + Deserialize the message + + An containing the data - - Unknown + + + Serialize the object + + An containing the objects data - - Current direction of the sun + + + Deserialize the message + + An containing the data - - Current angular velocity of the sun + + + Serialize the object + + An containing the objects data - - Current world time + + + Deserialize the message + + An containing the data - + - - + + + Serialize the object + + An containing the objects data - - + + + Deserialize the message + + An containing the data - - + + + Serialize the object + + An containing the objects data - - + + + Deserialize the message + + An containing the data - - + + + Serialize the object + + An containing the objects data - - + + + Deserialize the message + + An containing the data - - + + + Event Queue message describing physics engine attributes of a list of objects + Sim sends these when object is selected + - + + Array with the list of physics properties + + - Login Request Parameters + Serializes the message + Serialized OSD - - The URL of the Login Server + + + Deseializes the message + + Incoming data to deserialize - - The number of milliseconds to wait before a login is considered - failed due to timeout + + + A message sent from the viewer to the simulator which + specifies that the user has changed current URL + of the specific media on a prim face + - - The request method - login_to_simulator is currently the only supported method + + + New URL + - - The Agents First name + + + Prim UUID where navigation occured + - - The Agents Last name + + + Face index + - - A md5 hashed password - plaintext password will be automatically hashed + + + Serialize the object + + An containing the objects data - - 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 + + + Deserialize the message + + An containing the data - - A string containing the client software channel information - Second Life Release + + Base class used for the ObjectMedia message - - 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 + + + Message used to retrive prim media data + - - A string containing the platform information the agent is running on + + + Prim UUID + - - A string hash of the network cards Mac Address + + + Requested operation, either GET or UPDATE + - - Unknown or deprecated + + + Serialize object + + Serialized object as OSDMap - - A string hash of the first disk drives ID used to identify this clients uniqueness + + + Deserialize the message + + An containing the data - - A string containing the viewers Software, this is not directly sent to the login server but - instead is used to generate the Version string + + + Message used to update prim media data + - - 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 + + + Prim UUID + - - If true, this agent agrees to the Terms of Service of the grid its connecting to + + + Array of media entries indexed by face number + - - Unknown + + + Media version string + - - An array of string sent to the login server to enable various options + + + Serialize object + + Serialized object as OSDMap - - 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 + + + Deserialize the message + + An containing the data - + - Default constuctor, initializes sane default values + Message used to update prim media data - + - Instantiates new LoginParams object and fills in the values + Prim UUID - 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 + Array of media entries indexed by face number - 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 + Requested operation, either GET or UPDATE - - true, false, indeterminate + + + Serialize object + + Serialized object as OSDMap - - Login message of the day + + + Deserialize the message + + An containing the data - - M or PG, also agent_region_access and agent_access_max + + + Message for setting or getting per face MediaEntry + - + + The request or response details block + + - Parse LLSD Login Reply Data + Serialize the object - An - contaning the login response data - XML-RPC logins do not require this as XML-RPC.NET - automatically populates the struct properly using attributes + An containing the objects data - + - + Deserialize the message + An containing the data - - OK + + Details about object resource usage - - Transfer completed + + Object UUID - - + + Object name - - + + Indicates if object is group owned - - Unknown error occurred + + Locatio of the object - - Equivalent to a 404 error + + Object owner - - Client does not have permission for that resource + + Resource usage, keys are resource names, values are resource usage for that specific resource - - Unknown status + + + Deserializes object from OSD + + An containing the data - + - + Makes an instance based on deserialized data + serialized data + Instance containg deserialized data - - + + Details about parcel resource usage - - Unknown + + Parcel UUID - - Virtually all asset transfers use this channel + + Parcel local ID - + + Parcel name + + + Indicates if parcel is group owned + + + Parcel owner + + + Array of containing per object resource usage + + - + Deserializes object from OSD + An containing the data - - + + + Makes an instance based on deserialized data + + serialized data + Instance containg deserialized data - - Asset from the asset server + + Resource usage base class, both agent and parcel resource + usage contains summary information - - Inventory item + + Summary of available resources, keys are resource names, + values are resource usage for that specific resource - - Estate asset, such as an estate covenant + + Summary resource usage, keys are resource names, + values are resource usage for that specific resource - + - + Serializes object + serialized data - - + + + Deserializes object from OSD + + An containing the data - - + + Agent resource usage - - + + Per attachment point object resource usage - + - + Deserializes object from OSD + An containing the data - - - - - - - + - Image file format + Makes an instance based on deserialized data + serialized data + Instance containg deserialized data - + - + Detects which class handles deserialization of this message + An containing the data + Object capable of decoding this message - - Number of milliseconds passed since the last transfer - packet was received + + Request message for parcel resource usage - + + UUID of the parel to request resource usage info + + - + Serializes object + serialized data - + - + Deserializes object from OSD + An containing the data - + + Response message for parcel resource usage + + + URL where parcel resource usage details can be retrieved + + + URL where parcel resource usage summary can be retrieved + + - + Serializes object + serialized data - + - + Deserializes object from OSD + An containing the data - + - + Detects which class handles deserialization of this message + An containing the data + Object capable of decoding this message - + + Parcel resource usage + + + Array of containing per percal resource usage + + - + Deserializes object from OSD - - - - + An containing the data - + - + Reply to request for bunch if display names - - Number of milliseconds to wait for a transfer header packet if out of order data was received + + Current display name - - The event subscribers. null if no subcribers + + Following UUIDs failed to return a valid display name - - Raises the XferReceived event - A XferReceivedEventArgs object containing the - data returned from the simulator + + + Serializes the message + + OSD containting the messaage - - Thread sync lock object + + + Message sent when requesting change of the display name + - - The event subscribers. null if no subcribers + + Current display name - - Raises the AssetUploaded event - A AssetUploadedEventArgs object containing the - data returned from the simulator + + Desired new display name - - Thread sync lock object + + + Serializes the message + + OSD containting the messaage - - The event subscribers. null if no subcribers + + + Message recieved in response to request to change display name + - - Raises the UploadProgress event - A UploadProgressEventArgs object containing the - data returned from the simulator + + New display name - - Thread sync lock object + + String message indicating the result of the operation - - The event subscribers. null if no subcribers + + Numerical code of the result, 200 indicates success - - Raises the InitiateDownload event - A InitiateDownloadEventArgs object containing the - data returned from the simulator + + + Serializes the message + + OSD containting the messaage - - Thread sync lock object + + + Message recieved when someone nearby changes their display name + - - The event subscribers. null if no subcribers + + Previous display name, empty string if default - - Raises the ImageReceiveProgress event - A ImageReceiveProgressEventArgs object containing the - data returned from the simulator + + New display name - - Thread sync lock object + + + Serializes the message + + OSD containting the messaage - - Texture download cache + + + Archives assets + - + - Default constructor + Archive assets - A reference to the GridClient object - + - Request an asset download + Archive the assets given to this archiver to the given archive. - Asset UUID - Asset type, must be correct for the transfer to succeed - Whether to give this transfer an elevated priority - The callback to fire when the simulator responds with the asset data + - + - Request an asset download + Write an assets metadata file to the given archive - Asset UUID - Asset type, must be correct for the transfer to succeed - Whether to give this transfer an elevated priority - Source location of the requested asset - The callback to fire when the simulator responds with the asset data + - + - Request an asset download + Write asset data files to the given archive - Asset UUID - Asset type, must be correct for the transfer to succeed - Whether to give this transfer an elevated priority - Source location of the requested asset - UUID of the transaction - The callback to fire when the simulator responds with the asset data + - + - Request an asset download through the almost deprecated Xfer system + Constants for the archiving module - Filename of the asset to request - Whether or not to delete the asset - off the server after it is retrieved - Use large transfer packets or not - UUID of the file to request, if filename is - left empty - Asset type of vFileID, or - AssetType.Unknown if filename is not empty - Sets the FilePath in the request to Cache - (4) if true, otherwise Unknown (0) is used - - + - + The location of the archive control file - Use UUID.Zero if you do not have the - asset ID but have all the necessary permissions - The item ID of this asset in the inventory - Use UUID.Zero if you are not requesting an - asset from an object inventory - The owner of this asset - Asset type - Whether to prioritize this asset download or not - - + - Used to force asset data into the PendingUpload property, ie: for raw terrain uploads + Path for the assets held in an archive - An AssetUpload object containing the data to upload to the simulator - + - Request an asset be uploaded to the simulator + Path for the prims file + + + + + Path for terrains. Technically these may be assets, but I think it's quite nice to split them out. - The Object containing the asset data - If True, the asset once uploaded will be stored on the simulator - in which the client was connected in addition to being stored on the asset server - The of the transfer, can be used to correlate the upload with - events being fired - + - Request an asset be uploaded to the simulator + Path for region settings. - The of the asset being uploaded - A byte array containing the encoded asset data - If True, the asset once uploaded will be stored on the simulator - in which the client was connected in addition to being stored on the asset server - The of the transfer, can be used to correlate the upload with - events being fired - + - Request an asset be uploaded to the simulator + The character the separates the uuid from extension information in an archived asset filename - - Asset type to upload this data as - A byte array containing the encoded asset data - If True, the asset once uploaded will be stored on the simulator - in which the client was connected in addition to being stored on the asset server - The of the transfer, can be used to correlate the upload with - events being fired - + - Initiate an asset upload + Extensions used for asset types in the archive - The ID this asset will have if the - upload succeeds - Asset type to upload this data as - Raw asset data to upload - Whether to store this asset on the local - simulator or the grid-wide asset server - The tranaction id for the upload - The transaction ID of this transfer - - - 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. Sending with value -1 combined with priority of 0 cancels an in-progress - transfer. - A bug exists in the Linden Simulator where a -1 will occasionally be sent with a non-zero priority - indicating an off-by-one error. - 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 - - Request an image and fire a callback when the request is complete - - Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); - - private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) - { - if(state == TextureRequestState.Finished) - { - Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", - asset.AssetID, - asset.AssetData.Length); - } - } - - Request an image and use an inline anonymous method to handle the downloaded texture data - - Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, delegate(TextureRequestState state, AssetTexture asset) - { - if(state == TextureRequestState.Finished) - { - Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", - asset.AssetID, - asset.AssetData.Length); - } - } - ); - - Request a texture, decode the texture to a bitmap image and apply it to a imagebox - - Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); - - private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) - { - if(state == TextureRequestState.Finished) - { - ManagedImage imgData; - Image bitmap; + + - if (state == TextureRequestState.Finished) - { - OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData, out bitmap); - picInsignia.Image = bitmap; - } - } - } - - + - + - Overload: 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 + An instance of DelegateWrapper which calls InvokeWrappedDelegate, + which in turn calls the DynamicInvoke method of the wrapped + delegate - The of the texture asset to download - The callback to fire when the image is retrieved. The callback - will contain the result of the request and the texture asset data - + - Overload: 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 + Callback used to call EndInvoke on the asynchronously + invoked DelegateWrapper - The of the texture asset to download - The of the texture asset. - Use for most textures, or for baked layer texture assets - The callback to fire when the image is retrieved. The callback - will contain the result of the request and the texture asset data - + - Overload: 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 + Executes the specified delegate with the specified arguments + asynchronously on a thread pool thread - The of the texture asset to download - The of the texture asset. - Use for most textures, or for baked layer texture assets - 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 + + - + - Cancel a texture request + Invokes the wrapped delegate synchronously - The texture assets + + - + - Requests download of a mesh asset + Calls EndInvoke on the wrapper and Close on the resulting WaitHandle + to prevent resource leaks - UUID of the mesh asset - Callback when the request completes + - + - Lets TexturePipeline class fire the progress event + Delegate to wrap another delegate and its arguments - The texture ID currently being downloaded - the number of bytes transferred - the total number of bytes expected - - - 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 + + Size of the byte array used to store raw packet data - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Raw packet data buffer - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Length of the data to transmit - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + EndPoint of the remote host - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Create an allocated UDP packet buffer for receiving a packet + - - Raised when the simulator responds sends + + + Create an allocated UDP packet buffer for sending a packet + + EndPoint of the remote host - - Raised during upload completes + + + Create an allocated UDP packet buffer for sending a packet + + EndPoint of the remote host + Size of the buffer to allocate for packet data - - Raised during upload with progres update + + + Object pool for packet buffers. This is used to allocate memory for all + incoming and outgoing packets, and zerocoding buffers for those packets + - - Fired when the simulator sends an InitiateDownloadPacket, used to download terrain .raw files + + + Initialize the object pool in client mode + + Server to connect to + + - - Fired when a texture is in the process of being downloaded by the TexturePipeline class + + + Initialize the object pool in server mode + + + - + - Callback used for various asset download requests + Returns a packet buffer with EndPoint set if the buffer is in + client mode, or with EndPoint set to null in server mode - Transfer information - Downloaded asset, null on fail + Initialized UDPPacketBuffer object - + - Callback used upon competition of baked texture upload + Default constructor - Asset UUID of the newly uploaded baked texture - + - A callback that fires upon the completition of the RequestMesh call + Check a packet buffer out of the pool - Was the download successfull - Resulting mesh or null on problems - - - Xfer data + A packet buffer object - - Upload data + + + + + Looking direction, must be a normalized vector + Up direction, must be a normalized vector - - Filename used on the simulator + + + 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 - - Filename used by the client + + Origin position of this coordinate frame - - UUID of the image that is in progress + + X axis of this coordinate frame, or Forward/At in grid terms - - Number of bytes received so far + + Y axis of this coordinate frame, or Left in grid terms - - Image size in bytes + + Z axis of this coordinate frame, or Up in grid terms @@ -23401,1668 +23985,2153 @@ Agent punching with right hand - - Agent acting repulsed + + Agent acting repulsed + + + Agent trying to be Chuck Norris + + + Rocks, Paper, Scissors 1, 2, 3 + + + Agent with hand flat over other hand + + + Agent with fist over other hand + + + Agent with two fingers spread over other hand + + + Agent running + + + Agent appearing sad + + + Agent saluting + + + Agent shooting bow (left handed) + + + Agent cupping mouth as if shouting + + + Agent shrugging shoulders + + + Agent in sit position + + + Agent in sit position (feminine) + + + Agent in sit position (generic) + + + Agent sitting on ground + + + Agent sitting on ground + + + + + + Agent sleeping on side + + + Agent smoking + + + Agent inhaling smoke + + + + + + Agent taking a picture + + + Agent standing + + + Agent standing up + + + Agent standing + + + Agent standing + + + Agent standing + + + Agent standing + + + Agent stretching + + + Agent in stride (fast walk) + + + Agent surfing + + + Agent acting surprised + + + Agent striking with a sword + + + Agent talking (lips moving) + + + Agent throwing a tantrum + + + Agent throwing an object (right handed) + + + Agent trying on a shirt + + + Agent turning to the left + + + Agent turning to the right + + + Agent typing + + + Agent walking + + + Agent whispering + + + Agent whispering with fingers in mouth + + + Agent winking + + + Agent winking + + + Agent worried + + + Agent nodding yes + + + Agent nodding yes with happy face + + + Agent floating with legs and arms crossed + + + + A dictionary containing all pre-defined animations + + A dictionary containing the pre-defined animations, + where the key is the animations ID, and the value is a string + containing a name to identify the purpose of the animation + + + + Extract the avatar UUID encoded in a SIP URI + + + + + + + Permissions for control of object media + + + + + Style of cotrols that shold be displayed to the user + + + + + Class representing media data for a single face + + + + Is display of the alternative image enabled + + + Should media auto loop + + + Shoule media be auto played + + + Auto scale media to prim face + + + Should viewer automatically zoom in on the face when clicked + + + Should viewer interpret first click as interaction with the media + or when false should the first click be treated as zoom in commadn + + + Style of controls viewer should display when + viewer media on this face - - Agent trying to be Chuck Norris + + Starting URL for the media - - Rocks, Paper, Scissors 1, 2, 3 + + Currently navigated URL - - Agent with hand flat over other hand + + Media height in pixes - - Agent with fist over other hand + + Media width in pixels - - Agent with two fingers spread over other hand + + Who can controls the media - - Agent running + + Who can interact with the media - - Agent appearing sad + + Is URL whitelist enabled - - Agent saluting + + Array of URLs that are whitelisted - - Agent shooting bow (left handed) + + + Serialize to OSD + + OSDMap with the serialized data - - Agent cupping mouth as if shouting + + + Deserialize from OSD data + + Serialized OSD data + Deserialized object - - Agent shrugging shoulders + + + A Wrapper around openjpeg to encode and decode images to and from byte arrays + - - Agent in sit position + + TGA Header size - - Agent in sit position (feminine) + + OpenJPEG is not threadsafe, so this object is used to lock + during calls into unmanaged code - - Agent in sit position (generic) + + + Encode a object into a byte array + + The object to encode + true to enable lossless conversion, only useful for small images ie: sculptmaps + A byte array containing the encoded Image object - - Agent sitting on ground + + + Encode a object into a byte array + + The object to encode + a byte array of the encoded image - - Agent sitting on ground + + + Decode JPEG2000 data to an and + + + JPEG2000 encoded data + ManagedImage object to decode to + Image object to decode to + True if the decode succeeds, otherwise false - - + + + + + + + - - Agent sleeping on side + + + + + + + + - - Agent smoking + + + Encode a object into a byte array + + The source object to encode + true to enable lossless decoding + A byte array containing the source Bitmap object - - Agent inhaling smoke + + + 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! + - - Agent taking a picture + + + Information about a single packet in a JPEG2000 stream + - - Agent standing + + Packet start position - - Agent standing up + + Packet header end position - - Agent standing + + Packet end position - - Agent standing + + + Represents a texture + - - Agent standing + + A object containing image data - - Agent standing + + - - Agent stretching + + - - Agent in stride (fast walk) + + Initializes a new instance of an AssetTexture object - - Agent surfing + + + Initializes a new instance of an AssetTexture object + + A unique specific to this asset + A byte array containing the raw asset data - - Agent acting surprised + + + Initializes a new instance of an AssetTexture object + + A object containing texture data - - Agent striking with a sword + + + Populates the byte array with a JPEG2000 + encoded image created from the data in + - - Agent talking (lips moving) + + + Decodes the JPEG2000 data in AssetData to the + object + + True if the decoding was successful, otherwise false - - Agent throwing a tantrum + + + Decodes the begin and end byte positions for each quality layer in + the image + + - - Agent throwing an object (right handed) + + Override the base classes AssetType - - Agent trying on a shirt + + + Represents an that represents an avatars body ie: Hair, Etc. + - - Agent turning to the left + + Initializes a new instance of an AssetBodyPart object - - Agent turning to the right + + Initializes a new instance of an AssetBodyPart object with parameters + A unique specific to this asset + A byte array containing the raw asset data - - Agent typing + + Override the base classes AssetType - - Agent walking + + + + - - Agent whispering + + The avatar has no rights - - Agent whispering with fingers in mouth + + The avatar can see the online status of the target avatar - - Agent winking + + The avatar can see the location of the target avatar on the map - - Agent winking + + The avatar can modify the ojects of the target avatar - - Agent worried + + + 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 + - - Agent nodding yes + + + 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 - - Agent nodding yes with happy face + + + FriendInfo represented as a string + + A string reprentation of both my rights and my friends rights - - Agent floating with legs and arms crossed + + + System ID of the avatar + - + - A dictionary containing all pre-defined animations + full name of the avatar - A dictionary containing the pre-defined animations, - where the key is the animations ID, and the value is a string - containing a name to identify the purpose of the animation - + - Level of Detail mesh + True if the avatar is online - + - A linkset asset, containing a parent primitive and zero or more children + True if the friend can see if I am online - - Initializes a new instance of an AssetPrim object + + + True if the friend can see me on the map + - + - Initializes a new instance of an AssetPrim object + True if the freind can modify my objects - A unique specific to this asset - A byte array containing the raw asset data - + - + True if I can see if my friend is online - + - + True if I can see if my friend is on the map - - - Override the base classes AssetType + + + True if I can modify my friend's objects + - + - Only used internally for XML serialization/deserialization + My friend's rights represented as bitmapped flags - + - The deserialized form of a single primitive in a linkset asset + 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 of no subscribers + + The event subscribers. null if no subcribers - - Raises the AttachedSound Event - A AttachedSoundEventArgs object containing - the data sent from the simulator + + Raises the FriendOnline event + A FriendInfoEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AttachedSoundGainChange Event - A AttachedSoundGainChangeEventArgs object containing - the data sent from the simulator + + Raises the FriendOffline event + A FriendInfoEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the SoundTrigger Event - A SoundTriggerEventArgs object containing - the data sent from the simulator + + Raises the FriendRightsUpdate event + A FriendInfoEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the PreloadSound Event - A PreloadSoundEventArgs object containing - the data sent from the simulator + + 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 + + - Construct a new instance of the SoundManager class, used for playing and receiving - sound assets + 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 reference to the current GridClient instance - + - Plays a sound in the current region at full volume from avatar position + 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. - UUID of the sound to be played + 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. - + - Plays a sound in the current region at full volume + Use to map a friends location on the grid. - UUID of the sound to be played. - position for the sound to be played at. Normally the avatar. + Friends UUID to find + - + - Plays a sound in the current region + Use to track a friends movement on the grid - 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 + Friends Key - + - Plays a sound in the specified sim + Ask for a notification of friend's online status - 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 + Friend's UUID - + - Play a sound asset + This handles the asynchronous response of a RequestAvatarNames call. - 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 + + 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 - - 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 + Populate FriendList with data from the login reply - Simulator where the event originated - The sound asset id - The ID of the owner - The ID of the object - The volume level - The + 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 - - Simulator where the event originated + + Raised when the simulator sends notification one of the members in our friends list comes online - - Get the sound asset id + + Raised when the simulator sends notification one of the members in our friends list goes offline - - Get the ID of the owner + + Raised when the simulator sends notification one of the members in our friends list grants or revokes permissions - - Get the ID of the Object + + Raised when the simulator sends us the names on our friends list - - Get the volume level + + Raised when the simulator sends notification another agent is offering us friendship - - Get the + + Raised when a request we sent to friend another agent is accepted or declined - - Provides data for the event - The event occurs when an attached sound - changes its volume level + + Raised when the simulator sends notification one of the members in our friends list has terminated + our friendship - - - Construct a new instance of the AttachedSoundGainChangedEventArgs class - - Simulator where the event originated - The ID of the Object - The new volume level + + Raised when the simulator sends the location of a friend we have + requested map location info for - - Simulator where the event originated + + Contains information on a member of our friends list - - Get the ID of the Object + + + Construct a new instance of the FriendInfoEventArgs class + + The FriendInfo - - Get the volume level + + Get the FriendInfo - - 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); - } - - + + Contains Friend Names - + - Construct a new instance of the SoundTriggerEventArgs class + Construct a new instance of the FriendNamesEventArgs 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 + A dictionary where the Key is the ID of the Agent, + and the Value is a string containing their name - - Get the ID of the owner + + A dictionary where the Key is the ID of the Agent, + and the Value is a string containing their name - - Get the ID of the Object + + Sent when another agent requests a friendship with our agent - - Get the ID of the objects parent + + + 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 volume level + + Get the ID of the agent requesting friendship - - Get the regionhandle + + Get the name of the agent requesting friendship - - Get the source position + + Get the ID of the session, used in accepting or declining the + friendship offer - - 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") - } - - + + A response containing the results of our request to form a friendship with another agent - + - Construct a new instance of the PreloadSoundEventArgs class + Construct a new instance of the FriendShipResponseEventArgs class - Simulator where the event originated - The sound asset id - The ID of the owner - The ID of the object + 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 - - Simulator where the event originated + + Get the ID of the agent we requested a friendship with - - Get the sound asset id + + Get the name of the agent we requested a friendship with - - Get the ID of the owner + + true if the agent accepted our friendship offer - - Get the ID of the Object + + Contains data sent when a friend terminates a friendship with us - + - A Name Value pair with additional settings, used in the protocol - primarily to transmit avatar names and active group in object packets + 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 - + - Constructor that takes all the fields as parameters + Data sent in response to a request which contains the information to allow us to map the friends location - - - - - - + - Constructor that takes a single line from a NameValue field + 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 - - Type of the value + + Get the ID of the agent we have received location information for - - Unknown + + Get the region handle where our mapped friend is located - - String value + + Get the simulator local position where our friend is located - - + + + + - - + + OK - + + Transfer completed + + - + - - Deprecated + + Unknown error occurred - - String value, but designated as an asset + + Equivalent to a 404 error - - + + Client does not have permission for that resource - + + Unknown status + + - - - - + - - + + Unknown - - + + Virtually all asset transfers use this channel - + - + - - + + Asset from the asset server - - + + Inventory item - + + Estate asset, such as an estate covenant + + + + + + + - + - - Describes tasks returned in LandStatReply + + - + - Estate level administration and utilities + When requesting image download, type of the image requested - - Textures for each of the four terrain height levels + + Normal in-world object texture - - Upper/lower texture boundaries for each corner of the sim + + Avatar texture - + + Server baked avatar texture + + - Constructor for EstateTools class + Image file format - - - The event subscribers. null if no subcribers + + + + - - Raises the TopCollidersReply event - A TopCollidersReplyEventArgs object containing the - data returned from the data server + + Number of milliseconds passed since the last transfer + packet was received - - 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 + + + + - + + Number of milliseconds to wait for a transfer header packet if out of order data was received + + The event subscribers. null if no subcribers - - Raises the EstateGroupsReply event - A EstateGroupsReplyEventArgs object containing the - data returned from the data server + + Raises the XferReceived event + A XferReceivedEventArgs object containing the + data returned from the simulator - + 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 + + Raises the AssetUploaded event + A AssetUploadedEventArgs object containing the + data returned from the simulator - + 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 + + Raises the UploadProgress event + A UploadProgressEventArgs object containing the + data returned from the simulator - + 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 + + Raises the InitiateDownload event + A InitiateDownloadEventArgs object containing the + data returned from the simulator - + 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 + + Raises the ImageReceiveProgress event + A ImageReceiveProgressEventArgs object containing the + data returned from the simulator - + Thread sync lock object - + + Texture download cache + + - Requests estate information such as top scripts and colliders + Default constructor - - - - - - - Requests estate settings, including estate manager and access/ban lists + A reference to the GridClient object - - Requests the "Top Scripts" list for the current region + + + Request an asset download + + Asset UUID + Asset type, must be correct for the transfer to succeed + Whether to give this transfer an elevated priority + The callback to fire when the simulator responds with the asset data - - Requests the "Top Colliders" list for the current region + + + Request an asset download + + Asset UUID + Asset type, must be correct for the transfer to succeed + Whether to give this transfer an elevated priority + Source location of the requested asset + The callback to fire when the simulator responds with the asset data - + - Set several estate specific configuration variables + Request an asset download - 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 + Asset UUID + Asset type, must be correct for the transfer to succeed + Whether to give this transfer an elevated priority + Source location of the requested asset + UUID of the transaction + The callback to fire when the simulator responds with the asset data - + - Request return of objects owned by specified avatar + Request an asset download through the almost deprecated Xfer system - 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 + Filename of the asset to request + Whether or not to delete the asset + off the server after it is retrieved + Use large transfer packets or not + UUID of the file to request, if filename is + left empty + Asset type of vFileID, or + AssetType.Unknown if filename is not empty + Sets the FilePath in the request to Cache + (4) if true, otherwise Unknown (0) is used + - - - - + + + + + Use UUID.Zero if you do not have the + asset ID but have all the necessary permissions + The item ID of this asset in the inventory + Use UUID.Zero if you are not requesting an + asset from an object inventory + The owner of this asset + Asset type + Whether to prioritize this asset download or not + - + - Used for setting and retrieving various estate panel settings + Used to force asset data into the PendingUpload property, ie: for raw terrain uploads - EstateOwnerMessage Method field - List of parameters to include + An AssetUpload object containing the data to upload to the simulator - + - Kick an avatar from an estate + Request an asset be uploaded to the simulator - Key of Agent to remove + The Object containing the asset data + If True, the asset once uploaded will be stored on the simulator + in which the client was connected in addition to being stored on the asset server + The of the transfer, can be used to correlate the upload with + events being fired - + - Ban an avatar from an estate - Key of Agent to remove - Ban user from this estate and all others owned by the estate owner + Request an asset be uploaded to the simulator + + The of the asset being uploaded + A byte array containing the encoded asset data + If True, the asset once uploaded will be stored on the simulator + in which the client was connected in addition to being stored on the asset server + The of the transfer, can be used to correlate the upload with + events being fired - - Unban an avatar from an estate - Key of Agent to remove - /// Unban user from this estate and all others owned by the estate owner + + + Request an asset be uploaded to the simulator + + + Asset type to upload this data as + A byte array containing the encoded asset data + If True, the asset once uploaded will be stored on the simulator + in which the client was connected in addition to being stored on the asset server + The of the transfer, can be used to correlate the upload with + events being fired - + - Send a message dialog to everyone in an entire estate + Initiate an asset upload - Message to send all users in the estate + The ID this asset will have if the + upload succeeds + Asset type to upload this data as + Raw asset data to upload + Whether to store this asset on the local + simulator or the grid-wide asset server + The tranaction id for the upload + The transaction ID of this transfer + + + + 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. Sending with value -1 combined with priority of 0 cancels an in-progress + transfer. + A bug exists in the Linden Simulator where a -1 will occasionally be sent with a non-zero priority + indicating an off-by-one error. + 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 + + Request an image and fire a callback when the request is complete + + Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); + + private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) + { + if(state == TextureRequestState.Finished) + { + Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", + asset.AssetID, + asset.AssetData.Length); + } + } + + Request an image and use an inline anonymous method to handle the downloaded texture data + + Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, delegate(TextureRequestState state, AssetTexture asset) + { + if(state == TextureRequestState.Finished) + { + Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", + asset.AssetID, + asset.AssetData.Length); + } + } + ); + + Request a texture, decode the texture to a bitmap image and apply it to a imagebox + + Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); + + private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) + { + if(state == TextureRequestState.Finished) + { + ManagedImage imgData; + Image bitmap; + + if (state == TextureRequestState.Finished) + { + OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData, out bitmap); + picInsignia.Image = bitmap; + } + } + } + + - + - Send a message dialog to everyone in a simulator + Overload: 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 - Message to send all users in the simulator + The of the texture asset to download + The callback to fire when the image is retrieved. The callback + will contain the result of the request and the texture asset data - + - Send an avatar back to their home location + Overload: 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 - Key of avatar to send home + The of the texture asset to download + The of the texture asset. + Use for most textures, or for baked layer texture assets + The callback to fire when the image is retrieved. The callback + will contain the result of the request and the texture asset data - + - Begin the region restart process + Overload: 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 + 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 - + - Cancels a region restart + Cancel a texture request + The texture assets - - 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 + Requests download of a mesh asset - A byte array containing the encoded terrain data - The name of the file being uploaded - The Id of the transfer request + UUID of the mesh asset + Callback when the request completes - + - Teleports all users home in current Estate + Fetach avatar texture on a grid capable of server side baking + ID of the avatar + ID of the texture + Name of the part of the avatar texture applies to + Callback invoked on operation completion - + - Remove estate manager - Key of Agent to Remove - removes manager to this estate and all others owned by the estate owner + Lets TexturePipeline class fire the progress event + + The texture ID currently being downloaded + the number of bytes transferred + the total number of bytes expected - - - Add estate manager - Key of Agent to Add - Add agent as manager to this estate and all others owned by the estate owner + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - 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 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Removes an agent from the estate Allowed list - Key of Agent to Remove - Removes agent as an allowed reisdent from All estates if true + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - - 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 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - - 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 - + 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 simulator responds sends - - Raised when the data server responds to a request. + + Raised during upload completes - - Raised when the data server responds to a request. + + Raised during upload with progres update - - Raised when the data server responds to a request. + + Fired when the simulator sends an InitiateDownloadPacket, used to download terrain .raw files - - Raised when the data server responds to a request. + + Fired when a texture is in the process of being downloaded by the TexturePipeline class - - Raised when the data server responds to a request. + + + Callback used for various asset download requests + + Transfer information + Downloaded asset, null on fail - - Raised when the data server responds to a request. + + + Callback used upon competition of baked texture upload + + Asset UUID of the newly uploaded baked texture - - Raised when the data server responds to a request. + + + A callback that fires upon the completition of the RequestMesh call + + Was the download successfull + Resulting mesh or null on problems - - Used in the ReportType field of a LandStatRequest + + Xfer data - - Used by EstateOwnerMessage packets + + Upload data - - Used by EstateOwnerMessage packets + + Filename used on the simulator - + + Filename used by the client + + + UUID of the image that is in progress + + + Number of bytes received so far + + + Image size in bytes + + + 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 + - - No flags set - - - Only return targets scripted objects + + Raised when the simulator responds sends - - Only return targets objects if on others land + + Simulator from that sent tha data - - Returns target's scripted objects and objects on other parcels + + Sim coordinate of the patch - - Ground texture settings for each corner of the region + + Sim coordinate of the patch - - Used by GroundTextureHeightSettings + + Size of tha patch - - The high and low texture thresholds for each corner of the sim + + Heightmap for the patch - - Raised on LandStatReply when the report type is for "top colliders" + + + Registers, unregisters, and fires events generated by incoming packets + - - Construct a new instance of the TopCollidersReplyEventArgs class - The number of returned items in LandStatReply - Dictionary of Object UUIDs to tasks returned in LandStatReply + + Reference to the GridClient object - + - The number of returned items in LandStatReply + Default constructor + - + - A Dictionary of Object UUIDs to tasks returned in LandStatReply + 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 - - 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 + + + Unregister an event handler + + Packet type to unregister the handler for + Callback to be unregistered - + - The number of scripts returned in LandStatReply + Fire the events registered for this packet type + Incoming packet type + Incoming packet + Simulator this packet was received from - + - A Dictionary of Object UUIDs to tasks returned in LandStatReply + Object that is passed to worker threads in the ThreadPool for + firing packet callbacks - - Returned, along with other info, upon a successful .RequestInfo() + + Callback to fire for this packet - - 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 + + Reference to the simulator that this packet came from - + + The packet that needs to be processed + + - The identifier of the estate + Registers, unregisters, and fires events generated by the Capabilities + event queue - + + Reference to the GridClient object + + - The number of returned itmes + Default constructor + Reference to the GridClient object - + - List of UUIDs of Banned Users + 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 - - 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 + + + Unregister a previously registered capabilities handler + + Capability event name unregister the + handler for + Callback to unregister - + - The identifier of the estate + Fire the events registered for this event type synchronously + Capability name + Decoded event body + Reference to the simulator that + generated this event - + - The number of returned items + Fire the events registered for this event type asynchronously + Capability name + Decoded event body + Reference to the simulator that + generated this event - + - List of UUIDs of Allowed Users + Object that is passed to worker threads in the ThreadPool for + firing CAPS callbacks - - Returned, along with other info, upon a successful .RequestInfo() + + Callback to fire for this packet - - Construct a new instance of the EstateGroupsReplyEventArgs class - The estate's identifier on the grid - The number of Groups - Allowed Groups UUIDs + + Name of the CAPS event - - - The identifier of the estate - + + Strongly typed decoded data - + + Reference to the simulator that generated this event + + + Describes tasks returned in LandStatReply + + - The number of returned items + Estate level administration and utilities - + + Textures for each of the four terrain height levels + + + Upper/lower texture boundaries for each corner of the sim + + - List of UUIDs of Allowed Groups + Constructor for EstateTools class + - - Returned, along with other info, upon a successful .RequestInfo() + + The event subscribers. null if no subcribers - - Construct a new instance of the EstateManagersReplyEventArgs class - The estate's identifier on the grid - The number of Managers - Managers UUIDs + + 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 + + - The identifier of the estate + 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 - + - The number of returned items + 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 - + - List of UUIDs of the Estate's Managers + 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 - - 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 + Used for setting and retrieving various estate panel settings + EstateOwnerMessage Method field + List of parameters to include - + - The timestamp + Kick an avatar from an estate + Key of Agent to remove - + - The Estate name - + 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 + + - The Estate Owner's ID (can be a GroupID) + Send a message dialog to everyone in an entire estate + Message to send all users in the estate - - 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 + Send a message dialog to everyone in a simulator + Message to send all users in the simulator - + - The Estate Owner's ID (can be a GroupID) + Send an avatar back to their home location + Key of avatar to send home - + - The identifier of the estate on the grid + Begin the region restart process - - - - + - Holds group information for Avatars such as those you might find in a profile + Cancels a region restart - - true of Avatar accepts group notices - - - Groups Key - - - Texture Key for groups insignia + + Estate panel "Region" tab settings - - Name of the group + + Estate panel "Debug" tab settings - - Powers avatar has in the group + + Used for setting the region's terrain textures for its four height levels + + + + - - Avatars Currently selected title + + Used for setting sim terrain texture heights - - true of Avatar has chosen to list this in their profile + + Requests the estate covenant - + - Contains an animation currently being played by an agent + 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 - - The ID of the animation asset - - - A number to indicate start order of currently playing animations - On Linden Grids this number is unique per region, with OpenSim it is per client - - - - - + - Holds group information on an individual profile pick + Teleports all users home in current Estate - + - Retrieve friend status notifications, and retrieve avatar names and - profiles - - - - The event subscribers, null of no subscribers - - - Raises the AvatarAnimation Event - An AvatarAnimationEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the AvatarAppearance Event - A AvatarAppearanceEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the UUIDNameReply Event - A UUIDNameReplyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the AvatarInterestsReply Event - A AvatarInterestsReplyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object - - - The event subscribers, null of no subscribers - - - Raises the AvatarPropertiesReply Event - A AvatarPropertiesReplyEventArgs object containing - the data sent from the simulator - - - Thread sync lock object + Remove estate manager + Key of Agent to Remove + removes manager to this estate and all others owned by the estate owner - - The event subscribers, null of no subscribers + + + Add estate manager + Key of Agent to Add + Add agent as manager to this estate and all others owned by the estate owner - - Raises the AvatarGroupsReply Event - A AvatarGroupsReplyEventArgs object containing - the data sent from the simulator + + + 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 - - Thread sync lock object + + + Removes an agent from the estate Allowed list + Key of Agent to Remove + Removes agent as an allowed reisdent from All estates if true - - The event subscribers, null of no subscribers + + + + 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 - - Raises the AvatarPickerReply Event - A AvatarPickerReplyEventArgs object containing - the data sent from the simulator + + + + Removes a group from the estate Allowed list + Key of Group to Remove + Removes Group as an allowed Group from All estates if true - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers, null of no subscribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the ViewerEffectPointAt Event - A ViewerEffectPointAtEventArgs object containing - the data sent from the simulator + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Raised when the data server responds to a request. - - The event subscribers, null of no subscribers + + Raised when the data server responds to a request. - - Raises the ViewerEffectLookAt Event - A ViewerEffectLookAtEventArgs object containing - the data sent from the simulator + + Raised when the data server responds to a request. - - Thread sync lock object + + Raised when the data server responds to a request. - - The event subscribers, null of no subscribers + + Raised when the data server responds to a request. - - Raises the ViewerEffect Event - A ViewerEffectEventArgs object containing - the data sent from the simulator + + Raised when the data server responds to a request. - - Thread sync lock object + + Raised when the data server responds to a request. - - The event subscribers, null of no subscribers + + Raised when the data server responds to a request. - - Raises the AvatarPicksReply Event - A AvatarPicksReplyEventArgs object containing - the data sent from the simulator + + Used in the ReportType field of a LandStatRequest - - Thread sync lock object + + Used by EstateOwnerMessage packets - - The event subscribers, null of no subscribers + + Used by EstateOwnerMessage packets - - Raises the PickInfoReply Event - A PickInfoReplyEventArgs object containing - the data sent from the simulator + + + + - - Thread sync lock object + + No flags set - - The event subscribers, null of no subscribers + + Only return targets scripted objects - - Raises the AvatarClassifiedReply Event - A AvatarClassifiedReplyEventArgs object containing - the data sent from the simulator + + Only return targets objects if on others land - - Thread sync lock object + + Returns target's scripted objects and objects on other parcels - - The event subscribers, null of no subscribers + + Ground texture settings for each corner of the region - - Raises the ClassifiedInfoReply Event - A ClassifiedInfoReplyEventArgs object containing - the data sent from the simulator + + Used by GroundTextureHeightSettings - - Thread sync lock object + + The high and low texture thresholds for each corner of the sim - - - Represents other avatars - - + + Raised on LandStatReply when the report type is for "top colliders" - - Tracks the specified avatar on your map - Avatar ID to track + + Construct a new instance of the TopCollidersReplyEventArgs class + The number of returned items in LandStatReply + Dictionary of Object UUIDs to tasks returned in LandStatReply - + - Request a single avatar name + The number of returned items in LandStatReply - The avatar key to retrieve a name for - + - Request a list of avatar names + A Dictionary of Object UUIDs to tasks returned in LandStatReply - The avatar keys to retrieve names for - - - Start a request for Avatar Properties - - + + 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 + + - Search for an avatar (first name, last name) + The number of scripts returned in LandStatReply - The name to search for - An ID to associate with this query - + - Start a request for Avatar Picks + A Dictionary of Object UUIDs to tasks returned in LandStatReply - UUID of the avatar - + + 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 + + - Start a request for Avatar Classifieds + The identifier of the estate - UUID of the avatar - + - Start a request for details of a specific profile pick + The number of returned itmes - UUID of the avatar - UUID of the profile pick - + - Start a request for details of a specific profile classified + List of UUIDs of Banned Users - UUID of the avatar - UUID of the profile classified - - - 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 + + Returned, along with other info, upon a successful .RequestInfo() - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Construct a new instance of the EstateUsersReplyEventArgs class + The estate's identifier on the grid + The number of users + Allowed users UUIDs - + - Crossed region handler for message that comes across the EventQueue. Sent to an agent - when the agent crosses a sim border into a new region. + The identifier of the estate - The message key - the IMessage object containing the deserialized data sent from the simulator - The which originated the packet - - - 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 + + + The number of returned items + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + List of UUIDs of Allowed Users + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Returned, along with other info, upon a successful .RequestInfo() - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Construct a new instance of the EstateGroupsReplyEventArgs class + The estate's identifier on the grid + The number of Groups + Allowed Groups UUIDs - - Raised when the simulator sends us data containing - an agents animation playlist + + + The identifier of the estate + - - Raised when the simulator sends us data containing - the appearance information for an agent + + + The number of returned items + - - Raised when the simulator sends us data containing - agent names/id values + + + List of UUIDs of Allowed Groups + - - Raised when the simulator sends us data containing - the interests listed in an agents profile + + Returned, along with other info, upon a successful .RequestInfo() - - Raised when the simulator sends us data containing - profile property information for an agent + + Construct a new instance of the EstateManagersReplyEventArgs class + The estate's identifier on the grid + The number of Managers + Managers UUIDs - - Raised when the simulator sends us data containing - the group membership an agent is a member of + + + The identifier of the estate + - - Raised when the simulator sends us data containing - name/id pair + + + The number of returned items + - - Raised when the simulator sends us data containing - the objects and effect when an agent is pointing at + + + List of UUIDs of the Estate's Managers + - - Raised when the simulator sends us data containing - the objects and effect when an agent is looking at + + Returned, along with other info, upon a successful .RequestInfo() - - Raised when the simulator sends us data containing - an agents viewer effect information + + 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) - - Raised when the simulator sends us data containing - the top picks from an agents profile + + + The Covenant + - - Raised when the simulator sends us data containing - the Pick details + + + The timestamp + - - Raised when the simulator sends us data containing - the classified ads an agent has placed + + + The Estate name + - - Raised when the simulator sends us data containing - the details of a classified ad + + + The Estate Owner's ID (can be a GroupID) + - - Provides data for the event - The event occurs when the simulator sends - the animation playlist for an agent - - The following code example uses the and - properties to display the animation playlist of an avatar on the window. - - // subscribe to the event - Client.Avatars.AvatarAnimation += Avatars_AvatarAnimation; - - private void Avatars_AvatarAnimation(object sender, AvatarAnimationEventArgs e) - { - // create a dictionary of "known" animations from the Animations class using System.Reflection - Dictionary<UUID, string> systemAnimations = new Dictionary<UUID, string>(); - Type type = typeof(Animations); - System.Reflection.FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); - foreach (System.Reflection.FieldInfo field in fields) - { - systemAnimations.Add((UUID)field.GetValue(type), field.Name); - } - - // find out which animations being played are known animations and which are assets - foreach (Animation animation in e.Animations) - { - if (systemAnimations.ContainsKey(animation.AnimationID)) - { - Console.WriteLine("{0} is playing {1} ({2}) sequence {3}", e.AvatarID, - systemAnimations[animation.AnimationID], animation.AnimationSequence); - } - else - { - Console.WriteLine("{0} is playing {1} (Asset) sequence {2}", e.AvatarID, - animation.AnimationID, animation.AnimationSequence); - } - } - } - - + + 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 + + + - Construct a new instance of the AvatarAnimationEventArgs class + The estate's name - The ID of the agent - The list of animations to start - - Get the ID of the agent + + + The Estate Owner's ID (can be a GroupID) + - - Get the list of animations to start + + + The identifier of the estate on the grid + - - 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 AvatarAppearanceEventArgs class + Represends individual HTTP Download request - 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 + + URI of the item to fetch - - Get the ID of the agent + + Timout specified in milliseconds - - true if the agent is a trial account + + Download progress callback - - Get the default agent texture + + Download completed callback - - Get the agents appearance layer textures + + Accept the following content type - - Get the for the agent + + How many times will this request be retried - - Represents the interests from the profile of an agent + + Current fetch attempt - - Get the ID of the agent + + Default constructor - - The properties of an agent + + Constructor - - Get the ID of the agent + + + Manages async HTTP downloads with a limit on maximum + concurrent downloads + - - Get the ID of the agent + + Default constructor - - Get the ID of the agent + + Cleanup method - - Get the ID of the avatar + + Setup http download request + + + Check the queue for pending work + + + Enqueue a new HTPP download + + + Maximum number of parallel downloads from a single endpoint + + + Client certificate diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index 3e210ba..9054a99 100755 Binary files a/bin/OpenMetaverse.dll and b/bin/OpenMetaverse.dll differ diff --git a/bin/OpenMetaverse.dll.config b/bin/OpenMetaverse.dll.config index f5423b2..6b7b999 100644 --- a/bin/OpenMetaverse.dll.config +++ b/bin/OpenMetaverse.dll.config @@ -1,5 +1,7 @@ - - - + + + + + diff --git a/bin/OpenMetaverseTypes.XML b/bin/OpenMetaverseTypes.XML index befc8d4..7d00b1b 100644 --- a/bin/OpenMetaverseTypes.XML +++ b/bin/OpenMetaverseTypes.XML @@ -4,114 +4,65 @@ OpenMetaverseTypes - + - A three-dimensional vector with doubleing-point values + A thread-safe lockless queue that supports multiple readers and + multiple writers - - X value - - - Y value - - - Z value - - - - Constructor, builds a vector from a byte array - - Byte array containing three eight-byte doubles - Beginning position in the byte array + + Queue head - - - Test if this vector is equal to another vector, within a given - tolerance range - - Vector to test against - The acceptable magnitude of difference - between the two vectors - True if the magnitude of difference between the two vectors - is less than the given tolerance, otherwise false + + Queue tail - - - IComparable.CompareTo implementation - + + Queue item count - + - Test if this vector is composed of all finite numbers + Constructor - + - Builds a vector from a byte array + Enqueue an item - Byte array containing a 24 byte vector - Beginning position in the byte array + Item to enqeue - + - Returns the raw bytes for this vector + Try to dequeue an item - A 24 byte array containing X, Y, and Z + Dequeued item if the dequeue was successful + True if an item was successfully deqeued, otherwise false - - - Writes the raw bytes for this vector to a byte array - - Destination byte array - Position in the destination array to start - writing. Must be at least 24 bytes before the end of the array + + Gets the current number of items in the queue. Since this + is a lockless collection this value should be treated as a close + estimate - + - Parse a vector from a string + Provides a node container for data in a singly linked list - A string representation of a 3D vector, enclosed - in arrow brackets and separated by commas - - - Interpolates between two vectors using a cubic equation - + + Pointer to the next node in list - - - Get a formatted string representation of the vector - - A string representation of the vector + + The data contained by the node - + - Get a string representation of the vector elements with up to three - decimal digits and separated by spaces only + Constructor - Raw string representation of the vector - + - Cross product between two vectors + Constructor - - A vector with a value of 0,0,0 - - - A vector with a value of 1,1,1 - - - A unit vector facing forward (X axis), value of 1,0,0 - - - A unit vector facing left (Y axis), value of 0,1,0 - - - A unit vector facing up (Z axis), value of 0,0,1 - Attribute class that allows extra attributes to be attached to ENUMs @@ -235,6 +186,15 @@ Linden mesh format + + Marketplace direct delivery inbox ("Received Items") + + + Marketplace direct delivery outbox + + + + Inventory Item Types, eg Script, Notecard, Folder, etc @@ -355,292 +315,259 @@ Tattoo + + Physics + Invalid wearable asset - + - A hierarchical token bucket for bandwidth throttling. See - http://en.wikipedia.org/wiki/Token_bucket for more information + An 8-bit color structure including an alpha channel - - Parent bucket to this bucket, or null if this is a root - bucket + + Red - - Size of the bucket in bytes. If zero, the bucket has - infinite capacity + + Green - - Rate that the bucket fills, in bytes per millisecond. If - zero, the bucket always remains full + + Blue - - Number of tokens currently in the bucket + + Alpha - - Time of the last drip, in system ticks + + + + + + + + - + - Default constructor + Builds a color from a byte array - Parent bucket if this is a child bucket, or - null if this is a root bucket - Maximum size of the bucket in bytes, or - zero if this bucket has no maximum capacity - Rate that the bucket fills, in bytes per - second. If zero, the bucket always remains full + Byte array containing a 16 byte color + Beginning position in the byte array + True if the byte array stores inverted values, + otherwise false. For example the color black (fully opaque) inverted + would be 0xFF 0xFF 0xFF 0x00 - + - Remove a given number of tokens from the bucket + Returns the raw bytes for this vector - Number of tokens to remove from the bucket - True if the requested number of tokens were removed from - the bucket, otherwise false + Byte array containing a 16 byte color + Beginning position in the byte array + True if the byte array stores inverted values, + otherwise false. For example the color black (fully opaque) inverted + would be 0xFF 0xFF 0xFF 0x00 + True if the alpha value is inverted in + addition to whatever the inverted parameter is. Setting inverted true + and alphaInverted true will flip the alpha value back to non-inverted, + but keep the other color bytes inverted + A 16 byte array containing R, G, B, and A - + - Remove a given number of tokens from the bucket + Copy constructor - Number of tokens to remove from the bucket - True if tokens were added to the bucket - during this call, otherwise false - True if the requested number of tokens were removed from - the bucket, otherwise false + Color to copy - + - Add tokens to the bucket over time. The number of tokens added each - call depends on the length of time that has passed since the last - call to Drip + IComparable.CompareTo implementation - True if tokens were added to the bucket, otherwise false + Sorting ends up like this: |--Grayscale--||--Color--|. + Alpha is only used when the colors are otherwise equivalent - + - 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 + Builds a color from a byte array + Byte array containing a 16 byte color + Beginning position in the byte array + True if the byte array stores inverted values, + otherwise false. For example the color black (fully opaque) inverted + would be 0xFF 0xFF 0xFF 0x00 + True if the alpha value is inverted in + addition to whatever the inverted parameter is. Setting inverted true + and alphaInverted true will flip the alpha value back to non-inverted, + but keep the other color bytes inverted - + - Maximum burst rate in bytes per second. This is the maximum number - of tokens that can accumulate in the bucket at any one time + Writes the raw bytes for this color to a byte array + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - + - The speed limit of this bucket in bytes per second. This is the - number of tokens that are added to the bucket per second + Serializes this color into four bytes in a byte array - Tokens are added to the bucket any time - is called, at the granularity of - the system tick interval (typically around 15-22ms) + Destination byte array + Position in the destination array to start + writing. Must be at least 4 bytes before the end of the array + True to invert the output (1.0 becomes 0 + instead of 255) - + - 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 + Writes the raw bytes for this color to a byte array + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - + - A thread-safe lockless queue that supports multiple readers and - multiple writers + Ensures that values are in range 0-1 - - Queue head - - - Queue tail - - - Queue item count - - + - Constructor + Create an RGB color from a hue, saturation, value combination + Hue + Saturation + Value + An fully opaque RGB color (alpha is 1.0) - + - Enqueue an item + Performs linear interpolation between two colors - Item to enqeue + Color to start at + Color to end at + Amount to interpolate + The interpolated color - - - Try to dequeue an item - - Dequeued item if the dequeue was successful - True if an item was successfully deqeued, otherwise false + + A Color4 with zero RGB values and fully opaque (alpha 1.0) - - Gets the current number of items in the queue. Since this - is a lockless collection this value should be treated as a close - estimate + + A Color4 with full RGB values (1.0) and fully opaque (alpha 1.0) - + - Provides a node container for data in a singly linked list + A three-dimensional vector with doubleing-point values - - Pointer to the next node in list + + X value - - The data contained by the node + + Y value - + + Z value + + - Constructor + Constructor, builds a vector from a byte array + Byte array containing three eight-byte doubles + Beginning position in the byte array - + - Constructor + Test if this vector is equal to another vector, within a given + tolerance range + Vector to test against + The acceptable magnitude of difference + between the two vectors + True if the magnitude of difference between the two vectors + is less than the given tolerance, otherwise false - + - An 8-bit color structure including an alpha channel + IComparable.CompareTo implementation - - Red - - - Green - - - Blue - - - Alpha - - + - + Test if this vector is composed of all finite numbers - - - - - + - Builds a color from a byte array + Builds a vector from a byte array - Byte array containing a 16 byte color + Byte array containing a 24 byte vector Beginning position in the byte array - True if the byte array stores inverted values, - otherwise false. For example the color black (fully opaque) inverted - would be 0xFF 0xFF 0xFF 0x00 - + Returns the raw bytes for this vector - Byte array containing a 16 byte color - Beginning position in the byte array - True if the byte array stores inverted values, - otherwise false. For example the color black (fully opaque) inverted - would be 0xFF 0xFF 0xFF 0x00 - True if the alpha value is inverted in - addition to whatever the inverted parameter is. Setting inverted true - and alphaInverted true will flip the alpha value back to non-inverted, - but keep the other color bytes inverted - A 16 byte array containing R, G, B, and A + A 24 byte array containing X, Y, and Z - + - Copy constructor + Writes the raw bytes for this vector to a byte array - Color to copy + Destination byte array + Position in the destination array to start + writing. Must be at least 24 bytes before the end of the array - + - IComparable.CompareTo implementation + Parse a vector from a string - Sorting ends up like this: |--Grayscale--||--Color--|. - Alpha is only used when the colors are otherwise equivalent + A string representation of a 3D vector, enclosed + in arrow brackets and separated by commas - + - Builds a color from a byte array + Interpolates between two vectors using a cubic equation - Byte array containing a 16 byte color - Beginning position in the byte array - True if the byte array stores inverted values, - otherwise false. For example the color black (fully opaque) inverted - would be 0xFF 0xFF 0xFF 0x00 - True if the alpha value is inverted in - addition to whatever the inverted parameter is. Setting inverted true - and alphaInverted true will flip the alpha value back to non-inverted, - but keep the other color bytes inverted - + - Writes the raw bytes for this color to a byte array + Get a formatted string representation of the vector - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array + A string representation of the vector - + - Serializes this color into four bytes in a byte array + Get a string representation of the vector elements with up to three + decimal digits and separated by spaces only - Destination byte array - Position in the destination array to start - writing. Must be at least 4 bytes before the end of the array - True to invert the output (1.0 becomes 0 - instead of 255) + Raw string representation of the vector - + - Writes the raw bytes for this color to a byte array + Cross product between two vectors - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array - + - Ensures that values are in range 0-1 + Implicit casting for Vector3 > Vector3d + + - - - Create an RGB color from a hue, saturation, value combination - - Hue - Saturation - Value - An fully opaque RGB color (alpha is 1.0) + + A vector with a value of 0,0,0 - - - Performs linear interpolation between two colors - - Color to start at - Color to end at - Amount to interpolate - The interpolated color + + A vector with a value of 1,1,1 - - A Color4 with zero RGB values and fully opaque (alpha 1.0) + + A unit vector facing forward (X axis), value of 1,0,0 - - A Color4 with full RGB values (1.0) and fully opaque (alpha 1.0) + + A unit vector facing left (Y axis), value of 0,1,0 + + + A unit vector facing up (Z axis), value of 0,0,1 @@ -661,193 +588,218 @@ Before the wait 'numWaiters' is incremented and is restored before leaving this routine. - + + X value + + + Y value + + + Z value + + + W value + + - Copy constructor + Build a quaternion from normalized float values - Circular queue to copy + X value from -1.0 to 1.0 + Y value from -1.0 to 1.0 + Z value from -1.0 to 1.0 - + - A 128-bit Universally Unique Identifier, used throughout the Second - Life networking protocol + Constructor, builds a quaternion object from a byte array + Byte array containing four four-byte floats + Offset in the byte array to start reading at + Whether the source data is normalized or + not. If this is true 12 bytes will be read, otherwise 16 bytes will + be read. - - The System.Guid object this struct wraps around + + + Normalizes the quaternion + - + - Constructor that takes a string UUID representation + Builds a quaternion object from a byte array - A string representation of a UUID, case - insensitive and can either be hyphenated or non-hyphenated - UUID("11f8aa9c-b071-4242-836b-13b7abe0d489") + The source byte array + Offset in the byte array to start reading at + Whether the source data is normalized or + not. If this is true 12 bytes will be read, otherwise 16 bytes will + be read. - + - Constructor that takes a System.Guid object + Normalize this quaternion and serialize it to a byte array - A Guid object that contains the unique identifier - to be represented by this UUID + A 12 byte array containing normalized X, Y, and Z floating + point values in order using little endian byte ordering - + - Constructor that takes a byte array containing a UUID + Writes the raw bytes for this quaternion to a byte array - Byte array containing a 16 byte UUID - Beginning offset in the array + Destination byte array + Position in the destination array to start + writing. Must be at least 12 bytes before the end of the array - + - Constructor that takes an unsigned 64-bit unsigned integer to - convert to a UUID + Convert this quaternion to euler angles - 64-bit unsigned integer to convert to a UUID + X euler angle + Y euler angle + Z euler angle - + - Copy constructor + Convert this quaternion to an angle around an axis - UUID to copy + Unit vector describing the axis + Angle around the axis, in radians - + - IComparable.CompareTo implementation + Returns the conjugate (spatial inverse) of a quaternion - + - Assigns this UUID from 16 bytes out of a byte array + Build a quaternion from an axis and an angle of rotation around + that axis - Byte array containing the UUID to assign this UUID to - Starting position of the UUID in the byte array - + - Returns a copy of the raw bytes for this UUID + Build a quaternion from an axis and an angle of rotation around + that axis - A 16 byte array containing this UUID + Axis of rotation + Angle of rotation - + - Writes the raw bytes for this UUID to a byte array + Creates a quaternion from a vector containing roll, pitch, and yaw + in radians - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array + Vector representation of the euler angles in + radians + Quaternion representation of the euler angles - + - Calculate an LLCRC (cyclic redundancy check) for this UUID + Creates a quaternion from roll, pitch, and yaw euler angles in + radians - The CRC checksum for this UUID + X angle in radians + Y angle in radians + Z angle in radians + Quaternion representation of the euler angles - + - Create a 64-bit integer representation from the second half of this UUID + Conjugates and renormalizes a vector - An integer created from the last eight bytes of this UUID - + - Generate a UUID from a string + Spherical linear interpolation between two quaternions - A string representation of a UUID, case - insensitive and can either be hyphenated or non-hyphenated - UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489") - + - Generate a UUID from a string + Get a string representation of the quaternion elements with up to three + decimal digits and separated by spaces only - A string representation of a UUID, case - insensitive and can either be hyphenated or non-hyphenated - Will contain the parsed UUID if successful, - otherwise null - True if the string was successfully parse, otherwise false - UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result) + Raw string representation of the quaternion - + + A quaternion with a value of 0,0,0,1 + + - Combine two UUIDs together by taking the MD5 hash of a byte array - containing both UUIDs + Copy constructor - First UUID to combine - Second UUID to combine - The UUID product of the combination + Circular queue to copy - + - + Same as Queue except Dequeue function blocks until there is an object to return. + Note: This class does not need to be synchronized - - + - Return a hash code for this UUID, used by .NET for hash tables + Create new BlockingQueue. - An integer composed of all the UUID bytes XORed together + The System.Collections.ICollection to copy elements from - + - Comparison function + Create new BlockingQueue. - An object to compare to this UUID - True if the object is a UUID and both UUIDs are equal + The initial number of elements that the queue can contain - + - Comparison function + Create new BlockingQueue. - UUID to compare to - True if the UUIDs are equal, otherwise false - + + + BlockingQueue Destructor (Close queue, resume any waiting thread). + + + + + Remove all objects from the Queue. + + + + + Remove all objects from the Queue, resume all dequeue threads. + + + + + Removes and returns the object at the beginning of the Queue. + + Object in queue. + + - Get a hyphenated string representation of this UUID + Removes and returns the object at the beginning of the Queue. - A string representation of this UUID, lowercase and - with hyphens - 11f8aa9c-b071-4242-836b-13b7abe0d489 + time to wait before returning + Object in queue. - + - Equals operator + Removes and returns the object at the beginning of the Queue. - First UUID for comparison - Second UUID for comparison - True if the UUIDs are byte for byte equal, otherwise false + time to wait before returning (in milliseconds) + Object in queue. - + - Not equals operator + Adds an object to the end of the Queue - First UUID for comparison - Second UUID for comparison - True if the UUIDs are not equal, otherwise true + Object to put in queue - + - XOR operator + Open Queue. - First UUID - Second UUID - A UUID that is a XOR combination of the two input UUIDs - + - String typecasting operator + Gets flag indicating if queue has been closed. - A UUID in string form. Case insensitive, - hyphenated or non-hyphenated - A UUID built from the string representation - - - An UUID with a value of all zeroes - - - A cache of UUID.Zero as a string to optimize a common path Used for converting degrees to radians @@ -1378,284 +1330,122 @@ A DateTime object containing the same time specified in the given timestamp - - - Convert a native DateTime object to a UNIX timestamp - - A DateTime object you want to convert to a - timestamp - An unsigned integer representing a UNIX timestamp - - - - Swap two values - - Type of the values to swap - First value - Second value - - - - Try to parse an enumeration value from a string - - Enumeration type - String value to parse - Enumeration value on success - True if the parsing succeeded, otherwise false - - - - Swaps the high and low words in a byte. Converts aaaabbbb to bbbbaaaa - - Byte to swap the words in - Byte value with the words swapped - - - - Attempts to convert a string representation of a hostname or IP - address to a - - Hostname to convert to an IPAddress - 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/ - - - X value - - - Y value - - - Z value - - - W value - - - - Build a quaternion from normalized float values - - X value from -1.0 to 1.0 - Y value from -1.0 to 1.0 - Z value from -1.0 to 1.0 - - - - Constructor, builds a quaternion object from a byte array - - Byte array containing four four-byte floats - Offset in the byte array to start reading at - Whether the source data is normalized or - not. If this is true 12 bytes will be read, otherwise 16 bytes will - be read. - - - - Normalizes the quaternion - - - - - Builds a quaternion object from a byte array - - The source byte array - Offset in the byte array to start reading at - Whether the source data is normalized or - not. If this is true 12 bytes will be read, otherwise 16 bytes will - be read. - - - - Normalize this quaternion and serialize it to a byte array - - A 12 byte array containing normalized X, Y, and Z floating - point values in order using little endian byte ordering - - - - Writes the raw bytes for this quaternion to a byte array - - Destination byte array - Position in the destination array to start - writing. Must be at least 12 bytes before the end of the array - - - - Convert this quaternion to euler angles - - X euler angle - Y euler angle - Z euler angle - - - - Convert this quaternion to an angle around an axis - - Unit vector describing the axis - Angle around the axis, in radians - - - - Returns the conjugate (spatial inverse) of a quaternion - - - - - Build a quaternion from an axis and an angle of rotation around - that axis - - - - - Build a quaternion from an axis and an angle of rotation around - that axis - - Axis of rotation - Angle of rotation - - - - Creates a quaternion from a vector containing roll, pitch, and yaw - in radians - - Vector representation of the euler angles in - radians - Quaternion representation of the euler angles - - - - Creates a quaternion from roll, pitch, and yaw euler angles in - radians - - X angle in radians - Y angle in radians - Z angle in radians - Quaternion representation of the euler angles - - - - Conjugates and renormalizes a vector - - - - - Spherical linear interpolation between two quaternions - - - - - Get a string representation of the quaternion elements with up to three - decimal digits and separated by spaces only - - Raw string representation of the quaternion - - - A quaternion with a value of 0,0,0,1 - - - - Same as Queue except Dequeue function blocks until there is an object to return. - Note: This class does not need to be synchronized - - - + - Create new BlockingQueue. + Convert a native DateTime object to a UNIX timestamp - The System.Collections.ICollection to copy elements from + A DateTime object you want to convert to a + timestamp + An unsigned integer representing a UNIX timestamp - + - Create new BlockingQueue. + Swap two values - The initial number of elements that the queue can contain + Type of the values to swap + First value + Second value - + - Create new BlockingQueue. + Try to parse an enumeration value from a string + Enumeration type + String value to parse + Enumeration value on success + True if the parsing succeeded, otherwise false - + - BlockingQueue Destructor (Close queue, resume any waiting thread). + Swaps the high and low words in a byte. Converts aaaabbbb to bbbbaaaa + Byte to swap the words in + Byte value with the words swapped - + - Remove all objects from the Queue. + Attempts to convert a string representation of a hostname or IP + address to a + Hostname to convert to an IPAddress + Converted IP address object, or null if the conversion + failed - + - Remove all objects from the Queue, resume all dequeue threads. + Operating system - + + Unknown + + + Microsoft Windows + + + Microsoft Windows CE + + + Linux + + + Apple OSX + + - Removes and returns the object at the beginning of the Queue. + Runtime platform - Object in queue. - + + .NET runtime + + + Mono runtime: http://www.mono-project.com/ + + + For thread safety + + + For thread safety + + - Removes and returns the object at the beginning of the Queue. + Purges expired objects from the cache. Called automatically by the purge timer. - time to wait before returning - Object in queue. - + - Removes and returns the object at the beginning of the Queue. + Convert this matrix to euler rotations - time to wait before returning (in milliseconds) - Object in queue. + X euler angle + Y euler angle + Z euler angle - + - Adds an object to the end of the Queue + Convert this matrix to a quaternion rotation - Object to put in queue + A quaternion representation of this rotation matrix - + - Open Queue. + Construct a matrix from euler rotation values in radians + X euler angle in radians + Y euler angle in radians + Z euler angle in radians - + - Gets flag indicating if queue has been closed. + Get a formatted string representation of the vector + A string representation of the vector + + + A 4x4 matrix containing all zeroes + + + A 4x4 identity matrix @@ -1709,136 +1499,273 @@ The number of concurrent execution threads to run A series of method bodies to execute - + + X value + + + Y value + + + Z value + + + W value + + - Convert this matrix to euler rotations + Constructor, builds a vector from a byte array - X euler angle - Y euler angle - Z euler angle + Byte array containing four four-byte floats + Beginning position in the byte array - + - Convert this matrix to a quaternion rotation + Test if this vector is equal to another vector, within a given + tolerance range - A quaternion representation of this rotation matrix + Vector to test against + The acceptable magnitude of difference + between the two vectors + True if the magnitude of difference between the two vectors + is less than the given tolerance, otherwise false - + - Construct a matrix from euler rotation values in radians + IComparable.CompareTo implementation - X euler angle in radians - Y euler angle in radians - Z euler angle in radians - + - Get a formatted string representation of the vector + Test if this vector is composed of all finite numbers - A string representation of the vector - - A 4x4 matrix containing all zeroes + + + Builds a vector from a byte array + + Byte array containing a 16 byte vector + Beginning position in the byte array - - A 4x4 identity matrix + + + Returns the raw bytes for this vector + + A 16 byte array containing X, Y, Z, and W - - X value + + + Writes the raw bytes for this vector to a byte array + + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - - Y value + + + Get a string representation of the vector elements with up to three + decimal digits and separated by spaces only + + Raw string representation of the vector - - Z value + + A vector with a value of 0,0,0,0 - - W value + + A vector with a value of 1,1,1,1 + + + A vector with a value of 1,0,0,0 + + + A vector with a value of 0,1,0,0 + + + A vector with a value of 0,0,1,0 + + + A vector with a value of 0,0,0,1 + + + + A 128-bit Universally Unique Identifier, used throughout the Second + Life networking protocol + + + + The System.Guid object this struct wraps around + + + + Constructor that takes a string UUID representation + + A string representation of a UUID, case + insensitive and can either be hyphenated or non-hyphenated + UUID("11f8aa9c-b071-4242-836b-13b7abe0d489") + + + + Constructor that takes a System.Guid object + + A Guid object that contains the unique identifier + to be represented by this UUID + + + + Constructor that takes a byte array containing a UUID + + Byte array containing a 16 byte UUID + Beginning offset in the array + + + + Constructor that takes an unsigned 64-bit unsigned integer to + convert to a UUID + + 64-bit unsigned integer to convert to a UUID + + + + Copy constructor + + UUID to copy + + + + IComparable.CompareTo implementation + - + - Constructor, builds a vector from a byte array + Assigns this UUID from 16 bytes out of a byte array - Byte array containing four four-byte floats - Beginning position in the byte array + Byte array containing the UUID to assign this UUID to + Starting position of the UUID in the byte array - + - Test if this vector is equal to another vector, within a given - tolerance range + Returns a copy of the raw bytes for this UUID - Vector to test against - The acceptable magnitude of difference - between the two vectors - True if the magnitude of difference between the two vectors - is less than the given tolerance, otherwise false + A 16 byte array containing this UUID - + - IComparable.CompareTo implementation + Writes the raw bytes for this UUID to a byte array + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - + - Test if this vector is composed of all finite numbers + Calculate an LLCRC (cyclic redundancy check) for this UUID + The CRC checksum for this UUID - + - Builds a vector from a byte array + Create a 64-bit integer representation from the second half of this UUID - Byte array containing a 16 byte vector - Beginning position in the byte array + An integer created from the last eight bytes of this UUID - + - Returns the raw bytes for this vector + Generate a UUID from a string - A 16 byte array containing X, Y, Z, and W + A string representation of a UUID, case + insensitive and can either be hyphenated or non-hyphenated + UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489") - + - Writes the raw bytes for this vector to a byte array + Generate a UUID from a string - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array + A string representation of a UUID, case + insensitive and can either be hyphenated or non-hyphenated + Will contain the parsed UUID if successful, + otherwise null + True if the string was successfully parse, otherwise false + UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result) - + - Get a string representation of the vector elements with up to three - decimal digits and separated by spaces only + Combine two UUIDs together by taking the MD5 hash of a byte array + containing both UUIDs - Raw string representation of the vector + First UUID to combine + Second UUID to combine + The UUID product of the combination - - A vector with a value of 0,0,0,0 + + + + + - - A vector with a value of 1,1,1,1 + + + Return a hash code for this UUID, used by .NET for hash tables + + An integer composed of all the UUID bytes XORed together - - A vector with a value of 1,0,0,0 + + + Comparison function + + An object to compare to this UUID + True if the object is a UUID and both UUIDs are equal - - A vector with a value of 0,1,0,0 + + + Comparison function + + UUID to compare to + True if the UUIDs are equal, otherwise false - - A vector with a value of 0,0,1,0 + + + Get a hyphenated string representation of this UUID + + A string representation of this UUID, lowercase and + with hyphens + 11f8aa9c-b071-4242-836b-13b7abe0d489 - - A vector with a value of 0,0,0,1 + + + Equals operator + + First UUID for comparison + Second UUID for comparison + True if the UUIDs are byte for byte equal, otherwise false - - For thread safety + + + Not equals operator + + First UUID for comparison + Second UUID for comparison + True if the UUIDs are not equal, otherwise true - - For thread safety + + + XOR operator + + First UUID + Second UUID + A UUID that is a XOR combination of the two input UUIDs - + - Purges expired objects from the cache. Called automatically by the purge timer. + String typecasting operator + A UUID in string form. Case insensitive, + hyphenated or non-hyphenated + A UUID built from the string representation + + + An UUID with a value of all zeroes + + + A cache of UUID.Zero as a string to optimize a common path @@ -1940,6 +1867,13 @@ Cross product between two vectors + + + Explicit casting for Vector3d > Vector3 + + + + A vector with a value of 0,0,0 @@ -1955,6 +1889,98 @@ A unit vector facing up (Z axis), value 0,0,1 + + + A hierarchical token bucket for bandwidth throttling. See + http://en.wikipedia.org/wiki/Token_bucket for more information + + + + Parent bucket to this bucket, or null if this is a root + bucket + + + Size of the bucket in bytes. If zero, the bucket has + infinite capacity + + + Rate that the bucket fills, in bytes per millisecond. If + zero, the bucket always remains full + + + Number of tokens currently in the bucket + + + Time of the last drip, in system ticks + + + + Default constructor + + Parent bucket if this is a child bucket, or + null if this is a root bucket + Maximum size of the bucket in bytes, or + zero if this bucket has no maximum capacity + Rate that the bucket fills, in bytes per + second. If zero, the bucket always remains full + + + + Remove a given number of tokens from the bucket + + Number of tokens to remove from the bucket + True if the requested number of tokens were removed from + the bucket, otherwise false + + + + Remove a given number of tokens from the bucket + + Number of tokens to remove from the bucket + True if tokens were added to the bucket + during this call, otherwise false + True if the requested number of tokens were removed from + the bucket, otherwise false + + + + Add tokens to the bucket over time. The number of tokens added each + call depends on the length of time that has passed since the last + call to Drip + + 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 + + + + + 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 + + Identifier code for primitive types @@ -2165,6 +2191,12 @@ Whether this object is a sculpted prim + + Whether this object is a light image map + + + Whether this object is a mesh + @@ -2391,6 +2423,12 @@ HUD Bottom-right + + Neck + + + Avatar Center + Tree foliage types @@ -2508,6 +2546,20 @@ Open parcel media + + + Type of physics representation used for this prim in the simulator + + + + Use prim physics form this object + + + No physics, prim doesn't collide + + + Use convex hull represantion of this prim + A two-dimensional vector with floating-point values diff --git a/bin/OpenMetaverseTypes.dll b/bin/OpenMetaverseTypes.dll index 6cc4c5a..00397a9 100755 Binary files a/bin/OpenMetaverseTypes.dll and b/bin/OpenMetaverseTypes.dll differ diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so new file mode 100644 index 0000000..193eca4 Binary files /dev/null and b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so differ diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so new file mode 100644 index 0000000..7a9bdfc Binary files /dev/null and b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so differ diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib new file mode 100644 index 0000000..91f7264 Binary files /dev/null and b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib differ -- cgit v1.1 From ce043c5141dde0ffed39d548bf680885a73e2908 Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 17 Apr 2013 22:41:12 -0700 Subject: Allow changes to TextureEntry to propagate to viewers when MaterialID changes --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 93d4da0..0e85b87 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4571,6 +4571,8 @@ namespace OpenSim.Region.Framework.Scenes if (oldFace.TextureID != newFace.TextureID) changeFlags |= Changed.TEXTURE; + if (oldFace.MaterialID != newFace.MaterialID) + changeFlags |= Changed.TEXTURE; // Max change, skip the rest of testing if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) -- cgit v1.1 From 53122fad400e2d5bac5f02a3e153b6e76c9112b3 Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 17 Apr 2013 23:10:02 -0700 Subject: Thanks lkalif for a fix to SendRegionHandshake() which fixes a potential crash with Server-side baking enabled viewers --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 110e50e..02b326e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -791,11 +791,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP handshake.RegionInfo3.ColoName = Utils.EmptyBytes; handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; - handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; - + + handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; + handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; + handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported + OutPacket(handshake, ThrottleOutPacketType.Task); } + public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) { AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); -- cgit v1.1 From 7c839f176fab8166d4787ddbdffdda5f8d9e55ca Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 17 Apr 2013 23:14:28 -0700 Subject: amend previous commit, a line was left out --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 02b326e..1609012 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -793,6 +793,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; + handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported -- cgit v1.1 From d5419f0a463d67ef40c2212484fc95ca0a4b3b5b Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 18 Apr 2013 01:03:19 -0700 Subject: Initial experimental support for materials-capable viewers. This is in a very early stage and this module is disabled by default and should only be used by developers for testing as this module could cause data corruption and/or viewer crashes. No materials are persisted yet. --- .../Materials/MaterialsDemoModule.cs | 382 +++++++++++++++++++++ prebuild.xml | 1 + 2 files changed, 383 insertions(+) create mode 100644 OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs new file mode 100644 index 0000000..de2c3fc --- /dev/null +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -0,0 +1,382 @@ +/* + * 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.Security.Cryptography; // for computing md5 hash +using log4net; +using Mono.Addins; +using Nini.Config; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +using Ionic.Zlib; + +// You will need to uncomment these lines if you are adding a region module to some other assembly which does not already +// specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans +// the available DLLs +//[assembly: Addin("MyModule", "1.0")] +//[assembly: AddinDependency("OpenSim", "0.5")] + +namespace OpenSim.Region.OptionalModules.MaterialsDemoModule +{ + /// + /// + // # # ## ##### # # # # # #### + // # # # # # # ## # # ## # # # + // # # # # # # # # # # # # # # + // # ## # ###### ##### # # # # # # # # ### + // ## ## # # # # # ## # # ## # # + // # # # # # # # # # # # #### + // + // + // + ////////////// WARNING ////////////////////////////////////////////////////////////////// + /// This is an *Experimental* module for developing support for materials-capable viewers + /// This module should NOT be used in a production environment! It may cause data corruption and + /// viewer crashes. It should be only used to evaluate implementations of materials. + /// + /// CURRENTLY NO MATERIALS ARE PERSISTED ACROSS SIMULATOR RESTARTS OR ARE STORED IN ANY INVENTORY OR ASSETS + /// This may change in future implementations. + /// + /// To enable this module, add this string at the bottom of OpenSim.ini: + /// [MaterialsDemoModule] + /// + /// + /// + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] + public class MaterialsDemoModule : INonSharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public string Name { get { return "MaterialsDemoModule"; } } + + public Type ReplaceableInterface { get { return null; } } + + private Scene m_scene = null; + private bool m_enabled = false; + + public void Initialise(IConfigSource source) + { + m_enabled = (source.Configs["MaterialsDemoModule"] != null); + if (!m_enabled) + return; + + m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); + + } + + public void Close() + { + if (!m_enabled) + return; + + m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { + if (!m_enabled) + return; + + m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); + m_scene = scene; + m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps); + } + + void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) + { + string capsBase = "/CAPS/" + caps.CapsObjectPath; + + IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); + caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); + + // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET + // and POST handlers, (at least at the time this was originally written), so we first set up a POST + // handler normally and then add a GET handler via MainServer + + IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); + MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); + } + + public void RemoveRegion(Scene scene) + { + if (!m_enabled) + return; + + m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { + if (!m_enabled) + return; + m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName); + } + + public string RenderMaterialsPostCap(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + m_log.Debug("[MaterialsDemoModule]: POST cap handler"); + + OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); + OSDMap resp = new OSDMap(); + + OSDMap materialsFromViewer = null; + + if (req.ContainsKey("Zipped")) + { + OSD osd = null; + + byte[] inBytes = req["Zipped"].AsBinary(); + + try + { + osd = ZDecompressBytesToOsd(inBytes); + + if (osd != null && osd is OSDMap) + { + materialsFromViewer = osd as OSDMap; + + if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) + { + OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; + if (matsOsd is OSDArray) + { + OSDArray matsArr = matsOsd as OSDArray; + + try + { + foreach (OSDMap matsMap in matsArr) + { + m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); + + uint matLocalID = 0; + try { matLocalID = matsMap["ID"].AsUInteger(); } + catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } + m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); + + + OSDMap mat = null; + try { mat = matsMap["Material"] as OSDMap; } + catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } + m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); + + UUID id = HashOsd(mat); + m_knownMaterials[id] = mat; + + + var sop = m_scene.GetSceneObjectPart(matLocalID); + if (sop == null) + m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); + else + { + var te = sop.Shape.Textures; + + if (te == null) + { + m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); + } + else + { + int face = -1; + + if (matsMap.ContainsKey("Face")) + { + face = matsMap["Face"].AsInteger(); + if (te.FaceTextures == null) // && face == 0) + { + if (te.DefaultTexture == null) + m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); + else + { + if (te.DefaultTexture.MaterialID == null) + m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); + else + { + te.DefaultTexture.MaterialID = id; + } + } + } + else + { + if (te.FaceTextures.Length >= face - 1) + { + if (te.FaceTextures[face] == null) + te.DefaultTexture.MaterialID = id; + else + te.FaceTextures[face].MaterialID = id; + } + } + } + else + { + if (te.DefaultTexture != null) + te.DefaultTexture.MaterialID = id; + } + + m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); + + sop.UpdateTextureEntry(te); + } + } + } + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); + } + } + } + } + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message); + //return ""; + } + m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); + } + + + string response = OSDParser.SerializeLLSDXmlString(resp); + + m_log.Debug("[MaterialsDemoModule]: cap request: " + request); + m_log.Debug("[MaterialsDemoModule]: cap response: " + response); + return response; + } + + + public string RenderMaterialsGetCap(string request, string path, + string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + m_log.Debug("[MaterialsDemoModule]: GET cap handler"); + + OSDMap resp = new OSDMap(); + + + int matsCount = 0; + + OSDArray allOsd = new OSDArray(); + + foreach (KeyValuePair kvp in m_knownMaterials) + { + OSDMap matMap = new OSDMap(); + + matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); + + matMap["Material"] = kvp.Value; + allOsd.Add(matMap); + matsCount++; + } + + + resp["Zipped"] = ZCompressOSD(allOsd, false); + m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); + + return OSDParser.SerializeLLSDXmlString(resp); + } + + public Dictionary m_knownMaterials = new Dictionary(); + + /// + /// computes a UUID by hashing a OSD object + /// + /// + /// + private static UUID HashOsd(OSD osd) + { + using (var md5 = MD5.Create()) + using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) + return new UUID(md5.ComputeHash(ms), 0); + } + + public static OSD ZCompressOSD(OSD inOsd, bool useHeader = true) + { + OSD osd = null; + + using (MemoryStream msSinkCompressed = new MemoryStream()) + { + using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, + Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) + { + CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); + zOut.Close(); + } + + msSinkCompressed.Seek(0L, SeekOrigin.Begin); + osd = OSD.FromBinary( msSinkCompressed.ToArray()); + } + + return osd; + } + + + public static OSD ZDecompressBytesToOsd(byte[] input) + { + OSD osd = null; + + using (MemoryStream msSinkUnCompressed = new MemoryStream()) + { + using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) + { + CopyStream(new MemoryStream(input), zOut); + zOut.Close(); + } + msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); + osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); + } + + return osd; + } + + static void CopyStream(System.IO.Stream input, System.IO.Stream output) + { + byte[] buffer = new byte[2048]; + int len; + while ((len = input.Read(buffer, 0, 2048)) > 0) + { + output.Write(buffer, 0, len); + } + + output.Flush(); + } + + } +} \ No newline at end of file diff --git a/prebuild.xml b/prebuild.xml index 050fe0f..2d35529 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1635,6 +1635,7 @@ + -- cgit v1.1 From 06829c4082ba10fc9d3b4b37f42f01ab005c5e23 Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 18 Apr 2013 01:29:50 -0700 Subject: remove default parameter value that apparently mono cant handle --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index de2c3fc..74a4ea7 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -327,7 +327,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule return new UUID(md5.ComputeHash(ms), 0); } - public static OSD ZCompressOSD(OSD inOsd, bool useHeader = true) + public static OSD ZCompressOSD(OSD inOsd, bool useHeader) { OSD osd = null; -- cgit v1.1 From 9ae24cac2fcf5ac00ec8e4ccae5e58e9ff90db74 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 19 Apr 2013 00:35:06 -0700 Subject: Materials-capable viewers send ImageUpdate packets when updating materials that are normally sent via RenderMaterials CAP. This can cause a race condition for updating TextureEntry fields. Therefore filter any TextureEntry updates so they only update if something actually changed. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 46 ++++++++++++++++------ 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 0e85b87..347a2b5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4549,6 +4549,14 @@ namespace OpenSim.Region.Framework.Scenes oldTex.DefaultTexture = fallbackOldFace; } + // Materials capable viewers can send a ObjectImage packet + // when nothing in TE has changed. MaterialID should be updated + // by the RenderMaterials CAP handler, so updating it here may cause a + // race condtion. Therefore, if no non-materials TE fields have changed, + // we should ignore any changes and not update Shape.TextureEntry + + bool otherFieldsChanged = false; + for (int i = 0 ; i < GetNumberOfSides(); i++) { @@ -4571,24 +4579,40 @@ namespace OpenSim.Region.Framework.Scenes if (oldFace.TextureID != newFace.TextureID) changeFlags |= Changed.TEXTURE; - if (oldFace.MaterialID != newFace.MaterialID) - changeFlags |= Changed.TEXTURE; // Max change, skip the rest of testing if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) break; + + if (!otherFieldsChanged) + { + if (oldFace.Bump != newFace.Bump) otherFieldsChanged = true; + if (oldFace.Fullbright != newFace.Fullbright) otherFieldsChanged = true; + if (oldFace.Glow != newFace.Glow) otherFieldsChanged = true; + if (oldFace.MediaFlags != newFace.MediaFlags) otherFieldsChanged = true; + if (oldFace.OffsetU != newFace.OffsetU) otherFieldsChanged = true; + if (oldFace.OffsetV != newFace.OffsetV) otherFieldsChanged = true; + if (oldFace.RepeatU != newFace.RepeatU) otherFieldsChanged = true; + if (oldFace.RepeatV != newFace.RepeatV) otherFieldsChanged = true; + if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true; + if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true; + if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true; + } } - m_shape.TextureEntry = newTex.GetBytes(); - if (changeFlags != 0) - TriggerScriptChangedEvent(changeFlags); - UpdateFlag = UpdateRequired.FULL; - ParentGroup.HasGroupChanged = true; + if (changeFlags != 0 || otherFieldsChanged) + { + m_shape.TextureEntry = newTex.GetBytes(); + if (changeFlags != 0) + TriggerScriptChangedEvent(changeFlags); + UpdateFlag = UpdateRequired.FULL; + ParentGroup.HasGroupChanged = true; - //This is madness.. - //ParentGroup.ScheduleGroupForFullUpdate(); - //This is sparta - ScheduleFullUpdate(); + //This is madness.. + //ParentGroup.ScheduleGroupForFullUpdate(); + //This is sparta + ScheduleFullUpdate(); + } } public void aggregateScriptEvents() -- cgit v1.1 From 258804cc043530927f442cd76337a3dab4ec742b Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 19 Apr 2013 22:19:57 -0700 Subject: RenderMaterials POST Cap now return material entries when invoked with an OSDArray of MaterialIDs --- .../Materials/MaterialsDemoModule.cs | 169 +++++++++++++-------- 1 file changed, 108 insertions(+), 61 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 74a4ea7..7002e66 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -48,7 +48,7 @@ using Ionic.Zlib; // You will need to uncomment these lines if you are adding a region module to some other assembly which does not already // specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans // the available DLLs -//[assembly: Addin("MyModule", "1.0")] +//[assembly: Addin("MaterialsDemoModule", "1.0")] //[assembly: AddinDependency("OpenSim", "0.5")] namespace OpenSim.Region.OptionalModules.MaterialsDemoModule @@ -159,6 +159,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule OSDMap materialsFromViewer = null; + OSDArray respArr = new OSDArray(); + if (req.ContainsKey("Zipped")) { OSD osd = null; @@ -169,101 +171,145 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { osd = ZDecompressBytesToOsd(inBytes); - if (osd != null && osd is OSDMap) + if (osd != null) { - materialsFromViewer = osd as OSDMap; - - if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) + if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries { - OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; - if (matsOsd is OSDArray) + foreach (OSD elem in (OSDArray)osd) { - OSDArray matsArr = matsOsd as OSDArray; try { - foreach (OSDMap matsMap in matsArr) + UUID id = new UUID(elem.AsBinary(), 0); + + if (m_knownMaterials.ContainsKey(id)) + { + m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); + OSDMap matMap = new OSDMap(); + matMap["ID"] = OSD.FromBinary(id.GetBytes()); + + matMap["Material"] = m_knownMaterials[id]; + respArr.Add(matMap); + } + else + m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); + } + catch (Exception e) + { + // report something here? + continue; + } + } + } + else if (osd is OSDMap) // reqest to assign a material + { + materialsFromViewer = osd as OSDMap; + + if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) + { + OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; + if (matsOsd is OSDArray) + { + OSDArray matsArr = matsOsd as OSDArray; + + try { - m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); + foreach (OSDMap matsMap in matsArr) + { + m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); - uint matLocalID = 0; - try { matLocalID = matsMap["ID"].AsUInteger(); } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } - m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); + uint matLocalID = 0; + try { matLocalID = matsMap["ID"].AsUInteger(); } + catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } + m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); - OSDMap mat = null; - try { mat = matsMap["Material"] as OSDMap; } - catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } - m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); + OSDMap mat = null; + try { mat = matsMap["Material"] as OSDMap; } + catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } + m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); - UUID id = HashOsd(mat); - m_knownMaterials[id] = mat; + UUID id = HashOsd(mat); + m_knownMaterials[id] = mat; - var sop = m_scene.GetSceneObjectPart(matLocalID); - if (sop == null) - m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); - else - { - var te = sop.Shape.Textures; - - if (te == null) - { - m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); - } + var sop = m_scene.GetSceneObjectPart(matLocalID); + if (sop == null) + m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); else { - int face = -1; + //var te = sop.Shape.Textures; + var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); - if (matsMap.ContainsKey("Face")) + if (te == null) + { + m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); + } + else { - face = matsMap["Face"].AsInteger(); - if (te.FaceTextures == null) // && face == 0) + int face = -1; + + if (matsMap.ContainsKey("Face")) { - if (te.DefaultTexture == null) - m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); - else + face = matsMap["Face"].AsInteger(); + if (te.FaceTextures == null) // && face == 0) { - if (te.DefaultTexture.MaterialID == null) - m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); + if (te.DefaultTexture == null) + m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); else { - te.DefaultTexture.MaterialID = id; + if (te.DefaultTexture.MaterialID == null) + m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); + else + { + te.DefaultTexture.MaterialID = id; + } + } + } + else + { + if (te.FaceTextures.Length >= face - 1) + { + if (te.FaceTextures[face] == null) + te.DefaultTexture.MaterialID = id; + else + te.FaceTextures[face].MaterialID = id; } } } else { - if (te.FaceTextures.Length >= face - 1) - { - if (te.FaceTextures[face] == null) - te.DefaultTexture.MaterialID = id; - else - te.FaceTextures[face].MaterialID = id; - } + if (te.DefaultTexture != null) + te.DefaultTexture.MaterialID = id; } - } - else - { - if (te.DefaultTexture != null) - te.DefaultTexture.MaterialID = id; - } - m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); + m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); + + //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually - sop.UpdateTextureEntry(te); + if (sop.ParentGroup != null) + { + sop.Shape.TextureEntry = te.GetBytes(); + sop.TriggerScriptChangedEvent(Changed.TEXTURE); + sop.UpdateFlag = UpdateRequired.FULL; + sop.ParentGroup.HasGroupChanged = true; + + sop.ScheduleFullUpdate(); + + } + } } } } - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); + } } } } } + } catch (Exception e) { @@ -273,7 +319,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); } - + + resp["Zipped"] = ZCompressOSD(respArr, false); string response = OSDParser.SerializeLLSDXmlString(resp); m_log.Debug("[MaterialsDemoModule]: cap request: " + request); -- cgit v1.1 From 233f76177997cbe12aa100a3511d45bc1e9ccc5f Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 20 Apr 2013 02:08:22 -0700 Subject: handle PUT verb for RenderMaterials Cap --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 7002e66..4501dad 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -130,7 +130,11 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule // handler normally and then add a GET handler via MainServer IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); - MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); + MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); + + // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well + IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap); + MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); } public void RemoveRegion(Scene scene) -- cgit v1.1 From f40abc493a34ce959bdc55d4e52b5381083935b6 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sat, 20 Apr 2013 11:54:05 -0400 Subject: Small fix to prebuild xml for building with mono tools --- prebuild.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prebuild.xml b/prebuild.xml index 2d35529..29d7c90 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1635,7 +1635,7 @@ - + -- cgit v1.1 From 855c88a9c0f419566ad63e440c0696dabf32313f Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sat, 20 Apr 2013 11:57:11 -0400 Subject: Fix spelling --- bin/Robust.ini.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index d932ce7..b98132e 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -18,13 +18,13 @@ ; Set path to directory for plugin registry. Information ; about the registered repositories and installed plugins ; will be stored here - ; The Robust.exe process must hvae R/W access to the location + ; The Robust.exe process must have R/W access to the location RegistryLocation = "." ; Modular configurations ; Set path to directory for modular ini files... - ; The Robust.exe process must hvae R/W access to the location + ; The Robust.exe process must have R/W access to the location ConfigDirectory = "/home/opensim/etc/Configs" [ServiceList] -- cgit v1.1 From 69f07fdb349a2671fe86f96f119c0ea1276faacb Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 20 Apr 2013 23:39:07 -0700 Subject: Materials persistence via SceneObjectPart.dynAttrs. This appears to work across region restarts and taking objects into inventory, but probably will not work across archiving via OAR or IAR as materials texture assets may not be adequately referenced to trigger archiving. --- .../Materials/MaterialsDemoModule.cs | 162 ++++++++++++++++++++- 1 file changed, 154 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 4501dad..4ab6609 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -62,15 +62,21 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule // ## ## # # # # # ## # # ## # # // # # # # # # # # # # # #### // - // + // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! // ////////////// WARNING ////////////////////////////////////////////////////////////////// /// This is an *Experimental* module for developing support for materials-capable viewers /// This module should NOT be used in a production environment! It may cause data corruption and /// viewer crashes. It should be only used to evaluate implementations of materials. /// - /// CURRENTLY NO MATERIALS ARE PERSISTED ACROSS SIMULATOR RESTARTS OR ARE STORED IN ANY INVENTORY OR ASSETS - /// This may change in future implementations. + /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature + /// of OpenSimulator and is not field proven at the time this module was written. Persistence + /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials + /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means + /// of archiving however the texture resources used by these materials probably will not as they + /// may not be adequately referenced to ensure proper archiving. + /// + /// /// /// To enable this module, add this string at the bottom of OpenSim.ini: /// [MaterialsDemoModule] @@ -89,6 +95,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule private Scene m_scene = null; private bool m_enabled = false; + + public Dictionary m_knownMaterials = new Dictionary(); public void Initialise(IConfigSource source) { @@ -97,7 +105,6 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule return; m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); - } public void Close() @@ -116,6 +123,14 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); m_scene = scene; m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps); + m_scene.EventManager.OnObjectAddedToScene += new Action(EventManager_OnObjectAddedToScene); + } + + void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) + { + foreach (var part in obj.Parts) + if (part != null) + GetStoredMaterialsForPart(part); } void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) @@ -147,11 +162,130 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule public void RegionLoaded(Scene scene) { - if (!m_enabled) + } + + OSDMap GetMaterial(UUID id) + { + OSDMap map = null; + if (m_knownMaterials.ContainsKey(id)) + { + map = new OSDMap(); + map["ID"] = OSD.FromBinary(id.GetBytes()); + map["Material"] = m_knownMaterials[id]; + } + return map; + } + + void GetStoredMaterialsForPart(SceneObjectPart part) + { + OSDMap OSMaterials = null; + OSDArray matsArr = null; + + if (part.DynAttrs == null) + { + m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); + } + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsKey("OS:Materials")) + OSMaterials = part.DynAttrs["OS:Materials"]; + if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) + { + + OSD osd = OSMaterials["Materials"]; + if (osd is OSDArray) + matsArr = osd as OSDArray; + } + } + + if (OSMaterials == null) return; - m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} LOADED", scene.RegionInfo.RegionName); + + m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); + + + if (matsArr == null) + { + m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); + return; + } + + foreach (OSD elemOsd in matsArr) + { + if (elemOsd != null && elemOsd is OSDMap) + { + + OSDMap matMap = elemOsd as OSDMap; + if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) + { + try + { + m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material: " + e.ToString()); + } + } + } + } } + + void StoreMaterialsForPart(SceneObjectPart part) + { + try + { + if (part == null || part.Shape == null) + return; + + Dictionary mats = new Dictionary(); + + Primitive.TextureEntry te = part.Shape.Textures; + + if (te.DefaultTexture != null) + { + if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) + mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; + } + + if (te.FaceTextures != null) + { + foreach (var face in te.FaceTextures) + { + if (face != null) + { + if (m_knownMaterials.ContainsKey(face.MaterialID)) + mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; + } + } + } + if (mats.Count == 0) + return; + + OSDArray matsArr = new OSDArray(); + foreach (KeyValuePair kvp in mats) + { + OSDMap matOsd = new OSDMap(); + matOsd["ID"] = OSD.FromUUID(kvp.Key); + matOsd["Material"] = kvp.Value; + matsArr.Add(matOsd); + } + + OSDMap OSMaterials = new OSDMap(); + OSMaterials["Materials"] = matsArr; + + lock (part.DynAttrs) + part.DynAttrs["OS:Materials"] = OSMaterials; + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart(): " + e.ToString()); + } + } + + public string RenderMaterialsPostCap(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) @@ -300,6 +434,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule sop.ScheduleFullUpdate(); + StoreMaterialsForPart(sop); } } } @@ -327,7 +462,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule resp["Zipped"] = ZCompressOSD(respArr, false); string response = OSDParser.SerializeLLSDXmlString(resp); - m_log.Debug("[MaterialsDemoModule]: cap request: " + request); + //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); + m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); m_log.Debug("[MaterialsDemoModule]: cap response: " + response); return response; } @@ -364,7 +500,17 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule return OSDParser.SerializeLLSDXmlString(resp); } - public Dictionary m_knownMaterials = new Dictionary(); + static string ZippedOsdBytesToString(byte[] bytes) + { + try + { + return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); + } + catch (Exception e) + { + return "ZippedOsdBytesToString caught an exception: " + e.ToString(); + } + } /// /// computes a UUID by hashing a OSD object -- cgit v1.1 From 6ddc39a676916009e60d38ab24e7353b9646994e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Apr 2013 16:56:18 -0700 Subject: Clean up unused config and config comments. --- bin/config-include/StandaloneCommon.ini.example | 14 +++++++------- bin/config-include/StandaloneHypergrid.ini | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index f80044e..2547244 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -85,7 +85,7 @@ Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; === HG ONLY === - ;; If you have this set under [Startup], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; GatekeeperURI="http://127.0.0.1:9000" [LibraryModule] @@ -94,7 +94,7 @@ [LoginService] WelcomeMessage = "Welcome, Avatar!" - ;; If you have Gatekeeper set under [Startup], no need to set it here, leave it commented + ;; If you have Gatekeeper set under [Hypergrid], no need to set it here, leave it commented ; GatekeeperURI = "http://127.0.0.1:9000" SRV_HomeURI = "http://127.0.0.1:9000" @@ -240,7 +240,7 @@ ;; HG configurations ;; [GatekeeperService] - ;; If you have GatekeeperURI set under [Startup], no need to set it here, leave it commented + ;; If you have GatekeeperURI set under [Hypergrid], no need to set it here, leave it commented ; ExternalName = "http://127.0.0.1:9000" ; Does this grid allow incoming links to any region in it? @@ -297,11 +297,11 @@ ; AllowExcept_Level_200 = "http://griefer.com:8002, http://enemy.com:8002" [HGInventoryService] - ;; If you have this set under [Startup], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; HomeURI = "http://127.0.0.1:9000" [HGAssetService] - ;; If you have this set under [Startup], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; HomeURI = "http://127.0.0.1:9000" ;; The asset types that this grid can export to / import from other grids. @@ -318,7 +318,7 @@ [HGInventoryAccessModule] - ;; If you have these set under [Startup], no need to set it here, leave it commented + ;; If you have these set under [Hypergrid], no need to set it here, leave it commented ; HomeURI = "http://127.0.0.1:9000" ; GatekeeperURI = "http://127.0.0.1:9000" @@ -337,7 +337,7 @@ [Messaging] ; === HG ONLY === - ;; If you have this set under [Startup], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; GatekeeperURI = "http://127.0.0.1:9000" diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index 195e780..ba92030 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -55,8 +55,6 @@ HypergridAssetService = "OpenSim.Services.Connectors.dll:HGAssetServiceConnector" [InventoryService] - LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService" - ; For HGInventoryBroker LocalGridInventoryService = "OpenSim.Services.InventoryService.dll:XInventoryService" @@ -147,6 +145,9 @@ FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" + ;; This switch creates the minimum set of body parts and avatar entries for a viewer 2 to show a default "Ruth" avatar rather than a cloud. + CreateDefaultAvatarEntries = true + ;; The interface that local users get when they are in other grids ;; This greatly restricts the inventory operations while in other grids -- cgit v1.1 From 293a024c141d3567d42169f625bc449b89a1b59d Mon Sep 17 00:00:00 2001 From: Melanie Date: Mon, 22 Apr 2013 22:24:41 +0200 Subject: Allow callers to set the invoice parameter for GenericMessage --- OpenSim/Framework/IClientAPI.cs | 4 ++-- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 14 ++++++++++++-- .../CoreModules/World/LightShare/LightShareModule.cs | 4 ++-- .../Agent/InternetRelayClientView/Server/IRCClientView.cs | 4 ++-- OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | 4 ++-- OpenSim/Tests/Common/Mock/TestClient.cs | 4 ++-- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index f6b7689..10ead39 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1116,8 +1116,8 @@ namespace OpenSim.Framework void SendInstantMessage(GridInstantMessage im); - void SendGenericMessage(string method, List message); - void SendGenericMessage(string method, List message); + void SendGenericMessage(string method, UUID invoice, List message); + void SendGenericMessage(string method, UUID invoice, List message); void SendLayerData(float[] map); void SendLayerData(int px, int py, float[] map); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 1609012..1eb953c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -900,9 +900,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = AgentId; + gmp.AgentData.SessionID = m_sessionId; + gmp.AgentData.TransactionID = invoice; + gmp.MethodData.Method = Util.StringToBytes256(method); gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; int i = 0; @@ -915,9 +920,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(gmp, ThrottleOutPacketType.Task); } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { GenericMessagePacket gmp = new GenericMessagePacket(); + + gmp.AgentData.AgentID = AgentId; + gmp.AgentData.SessionID = m_sessionId; + gmp.AgentData.TransactionID = invoice; + gmp.MethodData.Method = Util.StringToBytes256(method); gmp.ParamList = new GenericMessagePacket.ParamListBlock[message.Count]; int i = 0; diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs index 4e20196..89f3280 100644 --- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs +++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs @@ -195,12 +195,12 @@ namespace OpenSim.Region.CoreModules.World.LightShare if (m_scene.RegionInfo.WindlightSettings.valid) { List param = compileWindlightSettings(wl); - client.SendGenericMessage("Windlight", param); + client.SendGenericMessage("Windlight", UUID.Random(), param); } else { List param = new List(); - client.SendGenericMessage("WindlightReset", param); + client.SendGenericMessage("WindlightReset", UUID.Random(), param); } } } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 0ac56fa..915ebd8 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -971,12 +971,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server // TODO } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 6bd27f0..0ee00e9 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -620,12 +620,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 2d4fef1..d26e3f7 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -541,12 +541,12 @@ namespace OpenSim.Tests.Common.Mock } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } - public void SendGenericMessage(string method, List message) + public void SendGenericMessage(string method, UUID invoice, List message) { } -- cgit v1.1 From e1ac68315491a0962bd4d089f7190e1b82607f43 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 21 Apr 2013 15:59:39 -0700 Subject: BulletSim: fix crash when deleting llVolumeDetect enabled objects. Bullet's check for an object being linked into the world does not work for Bullet's ghost objects so BulletSim was deleting the object while it was still linked into the physical world structures. --- OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index bfa69b2..1976c42 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -162,11 +162,8 @@ public sealed class BSShapeCollection : IDisposable // If the caller needs to know the old body is going away, pass the event up. if (bodyCallback != null) bodyCallback(body); - if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) - { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); - } + // Removing an object not in the world is a NOOP + PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); // Zero any reference to the shape so it is not freed when the body is deleted. PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); -- cgit v1.1 From 115e0aaf830d31530680b38afd705380be3f284a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Apr 2013 21:54:32 +0100 Subject: Fix issue in ConciergeModule where UpdateBroker was sending malformed XML if any number of avatars other than 1 was in the region. I don't know how well the rest of ConiergeModule works since I've practically never looked at this code. Addresses http://opensimulator.org/mantis/view.php?id=6605 --- OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs index 018357a..c48e585 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs @@ -375,11 +375,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge scene.GetRootAgentCount(), scene.RegionInfo.RegionName, scene.RegionInfo.RegionID, DateTime.UtcNow.ToString("s"))); + scene.ForEachRootScenePresence(delegate(ScenePresence sp) { - list.Append(String.Format(" \n", sp.Name, sp.UUID)); - list.Append(""); + list.Append(String.Format(" \n", sp.Name, sp.UUID)); }); + + list.Append(""); string payload = list.ToString(); // post via REST to broker -- cgit v1.1 From ed2201464664c2f923201414bd42b5998fbc96f9 Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 23 Apr 2013 15:01:20 -0700 Subject: revert CSJ2K.dll to version in use prior to commit d4fa2c69ed2895dcab76e0df1b26252246883c07 --- bin/CSJ2K.dll | Bin 495616 -> 502784 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/CSJ2K.dll b/bin/CSJ2K.dll index 581e410..238291f 100755 Binary files a/bin/CSJ2K.dll and b/bin/CSJ2K.dll differ -- cgit v1.1 From 522ab85045066cb58bb76881032adab7cc6a2d68 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Apr 2013 18:31:12 -0700 Subject: BulletSim: improve avatar stair walking up. Add more parameters to control force of both position change and up force that move avatars over barrier. Default parameters are for steps up to 0.5m in height. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 103 +++++++++++++++++---- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 15 ++- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 22 ++++- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 5 + .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 3 + 5 files changed, 123 insertions(+), 25 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 8416740..bd5ee0b1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -40,10 +40,16 @@ public class BSActorAvatarMove : BSActor { BSVMotor m_velocityMotor; + // Set to true if we think we're going up stairs. + // This state is remembered because collisions will turn on and off as we go up stairs. + int m_walkingUpStairs; + float m_lastStepUp; + public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { m_velocityMotor = null; + m_walkingUpStairs = 0; m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); } @@ -119,6 +125,8 @@ public class BSActorAvatarMove : BSActor SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); m_physicsScene.BeforeStep += Mover; + + m_walkingUpStairs = 0; } } @@ -216,8 +224,6 @@ public class BSActorAvatarMove : BSActor // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; - // Should we check for move force being small and forcing velocity to zero? - // Add special movement force to allow avatars to walk up stepped surfaces. moveForce += WalkUpStairs(); @@ -233,24 +239,33 @@ public class BSActorAvatarMove : BSActor { OMV.Vector3 ret = OMV.Vector3.Zero; + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", + m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, + m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); // This test is done if moving forward, not flying and is colliding with something. - // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", - // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); - if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) + // Check for stairs climbing if colliding, not flying and moving forward + if ( m_controllingPrim.IsColliding + && !m_controllingPrim.Flying + && m_controllingPrim.TargetVelocitySpeed > 0.1f ) { // The range near the character's feet where we will consider stairs - float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; + // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; + // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off + // from the height. Revisit size and this computation when height is scaled properly. + float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f; float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; - // Look for a collision point that is near the character's feet and is oriented the same as the charactor is + // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. + // Find the highest 'good' collision. + OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; foreach (KeyValuePair kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) { // Don't care about collisions with the terrain if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) { OMV.Vector3 touchPosition = kvp.Value.Position; - // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", - // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", + m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) { // This contact is within the 'near the feet' range. @@ -261,24 +276,76 @@ public class BSActorAvatarMove : BSActor float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); if (diff < BSParam.AvatarStepApproachFactor) { - // Found the stairs contact point. Push up a little to raise the character. - float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; - ret = new OMV.Vector3(0f, 0f, upForce); - - // Also move the avatar up for the new height - OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); - m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + if (highestTouchPosition.Z < touchPosition.Z) + highestTouchPosition = touchPosition; } - m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", - m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); } } } + m_walkingUpStairs = 0; + // If there is a good step sensing, move the avatar over the step. + if (highestTouchPosition != OMV.Vector3.Zero) + { + // Remember that we are going up stairs. This is needed because collisions + // will stop when we move up so this smoothes out that effect. + m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; + + m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; + ret = ComputeStairCorrection(m_lastStepUp); + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", + m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); + } + } + else + { + // If we used to be going up stairs but are not now, smooth the case where collision goes away while + // we are bouncing up the stairs. + if (m_walkingUpStairs > 0) + { + m_walkingUpStairs--; + ret = ComputeStairCorrection(m_lastStepUp); + } } return ret; } + private OMV.Vector3 ComputeStairCorrection(float stepUp) + { + OMV.Vector3 ret = OMV.Vector3.Zero; + OMV.Vector3 displacement = OMV.Vector3.Zero; + + if (stepUp > 0f) + { + // Found the stairs contact point. Push up a little to raise the character. + if (BSParam.AvatarStepForceFactor > 0f) + { + float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; + ret = new OMV.Vector3(0f, 0f, upForce); + } + + // Also move the avatar up for the new height + if (BSParam.AvatarStepUpCorrectionFactor > 0f) + { + // Move the avatar up related to the height of the collision + displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + else + { + if (BSParam.AvatarStepUpCorrectionFactor < 0f) + { + // Move the avatar up about the specified step height + displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + } + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}", + m_controllingPrim.LocalID, displacement, ret); + + } + return ret; + } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 06df85e..980d405 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -128,6 +128,8 @@ public static class BSParam public static float AvatarStepHeight { get; private set; } public static float AvatarStepApproachFactor { get; private set; } public static float AvatarStepForceFactor { get; private set; } + public static float AvatarStepUpCorrectionFactor { get; private set; } + public static int AvatarStepSmoothingSteps { get; private set; } // Vehicle parameters public static float VehicleMaxLinearVelocity { get; private set; } @@ -234,6 +236,7 @@ public static class BSParam objectSet = pObjSetter; } /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work + * TODO: Maybe use reflection and the name of the variable to create a reference for the getter/setter. public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc) : base(pName, pDesc) { @@ -561,7 +564,7 @@ public static class BSParam (s) => { return AvatarBelowGroundUpCorrectionMeters; }, (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", - 0.3f, + 0.6f, (s) => { return AvatarStepHeight; }, (s,v) => { AvatarStepHeight = v; } ), new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", @@ -569,9 +572,17 @@ public static class BSParam (s) => { return AvatarStepApproachFactor; }, (s,v) => { AvatarStepApproachFactor = v; } ), new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", - 2.0f, + 1.0f, (s) => { return AvatarStepForceFactor; }, (s,v) => { AvatarStepForceFactor = v; } ), + new ParameterDefn("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", + 1.0f, + (s) => { return AvatarStepUpCorrectionFactor; }, + (s,v) => { AvatarStepUpCorrectionFactor = v; } ), + new ParameterDefn("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", + 2, + (s) => { return AvatarStepSmoothingSteps; }, + (s,v) => { AvatarStepSmoothingSteps = v; } ), new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", 1000.0f, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 98eb4ca..309d004 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -96,7 +96,7 @@ public abstract class BSPhysObject : PhysicsActor SetMaterial((int)MaterialAttributes.Material.Wood); CollisionCollection = new CollisionEventUpdate(); - CollisionsLastTick = CollisionCollection; + CollisionsLastReported = CollisionCollection; SubscribedEventsMs = 0; CollidingStep = 0; CollidingGroundStep = 0; @@ -368,11 +368,14 @@ public abstract class BSPhysObject : PhysicsActor } } - // The collisions that have been collected this tick + // The collisions that have been collected for the next collision reporting (throttled by subscription) protected CollisionEventUpdate CollisionCollection; - // Remember collisions from last tick for fancy collision based actions + // This is the collision collection last reported to the Simulator. + public CollisionEventUpdate CollisionsLastReported; + // Remember the collisions recorded in the last tick for fancy collision checking // (like a BSCharacter walking up stairs). public CollisionEventUpdate CollisionsLastTick; + private long CollisionsLastTickStep = -1; // The simulation step is telling this object about a collision. // Return 'true' if a collision was processed and should be sent up. @@ -399,6 +402,15 @@ public abstract class BSPhysObject : PhysicsActor // For movement tests, remember if we are colliding with an object that is moving. ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; + // Make a collection of the collisions that happened the last simulation tick. + // This is different than the collection created for sending up to the simulator as it is cleared every tick. + if (CollisionsLastTickStep != PhysicsScene.SimulationStep) + { + CollisionsLastTick = new CollisionEventUpdate(); + CollisionsLastTickStep = PhysicsScene.SimulationStep; + } + CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + // If someone has subscribed for collision events log the collision so it will be reported up if (SubscribedEvents()) { CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); @@ -419,7 +431,7 @@ public abstract class BSPhysObject : PhysicsActor bool ret = true; // If the 'no collision' call, force it to happen right now so quick collision_end - bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); + bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); // throttle the collisions to the number of milliseconds specified in the subscription if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) @@ -438,7 +450,7 @@ public abstract class BSPhysObject : PhysicsActor base.SendCollisionUpdate(CollisionCollection); // Remember the collisions from this tick for some collision specific processing. - CollisionsLastTick = CollisionCollection; + CollisionsLastReported = CollisionCollection; // The CollisionCollection instance is passed around in the simulator. // Make sure we don't have a handle to that one and that a new one is used for next time. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 3423d2e..4bc266b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -69,12 +69,17 @@ public class BSPrim : BSPhysObject private int CrossingFailures { get; set; } + // Keep a handle to the vehicle actor so it is easy to set parameters on same. public BSDynamics VehicleActor; public const string VehicleActorName = "BasicVehicle"; + // Parameters for the hover actor public const string HoverActorName = "HoverActor"; + // Parameters for the axis lock actor public const String LockedAxisActorName = "BSPrim.LockedAxis"; + // Parameters for the move to target actor public const string MoveToTargetActorName = "MoveToTargetActor"; + // Parameters for the setForce and setTorque actors public const string SetForceActorName = "SetForceActor"; public const string SetTorqueActorName = "SetTorqueActor"; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index a0131c7..1284ae7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -42,6 +42,8 @@ One sided meshes? Should terrain be built into a closed shape? VEHICLES TODO LIST: ================================================= +UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: + https://github.com/UbitUmarov/Ubit-opensim Border crossing with linked vehicle causes crash 20121129.1411: editting/moving phys object across region boundries causes crash getPos-> btRigidBody::upcast -> getBodyType -> BOOM @@ -167,6 +169,7 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint) MORE ====================================================== +Compute avatar size and scale correctly. Now it is a bit off from the capsule size. Create tests for different interface components Have test objects/scripts measure themselves and turn color if correct/bad Test functions in SL and calibrate correctness there -- cgit v1.1 From e324f6f3f0f8d894190cd7a9733687ac4308b2c1 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 24 Apr 2013 08:03:45 -0700 Subject: BulletSim: update DLLs and SOs to they have no dependencies on newer glibc (2.14) since that is not yet in some Linux distributions. Add unmanaged API calls and code for creating single convex hull shapes. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 27 +++++++++++++++++++++ OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 10 ++++++++ .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 7 ++++++ bin/lib32/BulletSim.dll | Bin 1008640 -> 1010176 bytes bin/lib32/libBulletSim.so | Bin 2093987 -> 2096572 bytes bin/lib64/BulletSim.dll | Bin 1140224 -> 1142272 bytes bin/lib64/libBulletSim.so | Bin 2258808 -> 2265980 bytes 7 files changed, 44 insertions(+) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index f5b84d4..fdf2cb9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -268,6 +268,25 @@ public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShap BSPhysicsShapeType.SHAPE_HULL); } +public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = meshShape as BulletShapeUnman; + return new BulletShapeUnman( + BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), + BSPhysicsShapeType.SHAPE_CONVEXHULL); +} + +public override BulletShape CreateConvexHullShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_CONVEXHULL); +} + public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) { BulletWorldUnman worldu = world as BulletWorldUnman; @@ -1414,6 +1433,14 @@ public static extern IntPtr CreateHullShape2(IntPtr world, public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateConvexHullShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index f6b4359..b37265a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -1778,6 +1778,16 @@ private sealed class BulletConstraintXNA : BulletConstraint /* TODO */ return null; } + public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) + { + /* TODO */ return null; + } + + public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + /* TODO */ return null; + } + public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) { //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index d0d9f34..bfeec24 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -70,6 +70,7 @@ public enum BSPhysicsShapeType SHAPE_COMPOUND = 22, SHAPE_HEIGHTMAP = 23, SHAPE_AVATAR = 24, + SHAPE_CONVEXHULL= 25, }; // The native shapes have predefined shape hash keys @@ -325,6 +326,12 @@ public abstract BulletShape CreateHullShape(BulletWorld world, public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); +public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); + +public abstract BulletShape CreateConvexHullShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); public abstract bool IsNativeShape(BulletShape shape); diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 618d4bd..1e94d05 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index e3b40fb..d79896a 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 491ac22..68cfcc4 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index a8ad533..08c00af 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From c22a2ab7d21803050317527476c2e18aa2edb40f Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 24 Apr 2013 08:05:42 -0700 Subject: BulletSim: partial addition of BSShape class code preparing for different physical mesh representations (simplified convex meshes) and avatar mesh. --- .../Physics/BulletSPlugin/BSShapeCollection.cs | 28 +-- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 215 +++++++++++++++++---- 2 files changed, 191 insertions(+), 52 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 1976c42..bc26460 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -612,7 +612,7 @@ public sealed class BSShapeCollection : IDisposable newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod); // Take evasive action if the mesh was not constructed. - newShape = VerifyMeshCreated(newShape, prim); + newShape = VerifyMeshCreated(PhysicsScene, newShape, prim); ReferenceShape(newShape); @@ -719,7 +719,7 @@ public sealed class BSShapeCollection : IDisposable newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod); // It might not have been created if we're waiting for an asset. - newShape = VerifyMeshCreated(newShape, prim); + newShape = VerifyMeshCreated(PhysicsScene, newShape, prim); ReferenceShape(newShape); @@ -923,7 +923,7 @@ public sealed class BSShapeCollection : IDisposable // Create a hash of all the shape parameters to be used as a key // for this particular shape. - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) { // level of detail based on size and type of the object float lod = BSParam.MeshLOD; @@ -944,7 +944,7 @@ public sealed class BSShapeCollection : IDisposable return pbs.GetMeshKey(size, lod); } // For those who don't want the LOD - private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) { float lod; return ComputeShapeKey(size, pbs, out lod); @@ -957,7 +957,7 @@ public sealed class BSShapeCollection : IDisposable // us to not loop forever. // Called after creating a physical mesh or hull. If the physical shape was created, // just return. - private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) + public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) { // If the shape was successfully created, nothing more to do if (newShape.HasPhysicalShape) @@ -969,7 +969,7 @@ public sealed class BSShapeCollection : IDisposable if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", + physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); } else @@ -981,14 +981,14 @@ public sealed class BSShapeCollection : IDisposable && prim.BaseShape.SculptTexture != OMV.UUID.Zero ) { - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); + physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); // Multiple requestors will know we're waiting for this asset prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; BSPhysObject xprim = prim; Util.FireAndForget(delegate { - RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; + RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; if (assetProvider != null) { BSPhysObject yprim = xprim; // probably not necessary, but, just in case. @@ -1016,7 +1016,7 @@ public sealed class BSShapeCollection : IDisposable yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; else yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); }); @@ -1024,8 +1024,8 @@ public sealed class BSShapeCollection : IDisposable else { xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", - LogHeader, PhysicsScene.Name); + physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", + LogHeader, physicsScene.Name); } }); } @@ -1033,15 +1033,15 @@ public sealed class BSShapeCollection : IDisposable { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) { - PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", + physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); } } } // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. - BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); + BulletShape fillinShape = physicsScene.Shapes.BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); return fillinShape; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index ee18379..dd5ae1a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -29,6 +29,9 @@ using System; using System.Collections.Generic; using System.Text; +using OpenSim.Framework; +using OpenSim.Region.Physics.Manager; + using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin @@ -37,11 +40,19 @@ public abstract class BSShape { public int referenceCount { get; set; } public DateTime lastReferenced { get; set; } + public BulletShape physShapeInfo { get; set; } public BSShape() { referenceCount = 0; lastReferenced = DateTime.Now; + physShapeInfo = new BulletShape(); + } + public BSShape(BulletShape pShape) + { + referenceCount = 0; + lastReferenced = DateTime.Now; + physShapeInfo = pShape; } // Get a reference to a physical shape. Create if it doesn't exist @@ -79,21 +90,30 @@ public abstract class BSShape return ret; } - public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { + BSShapeMesh.GetReference(physicsScene, forceRebuild, prim); + BSShapeHull.GetReference(physicsScene, forceRebuild, prim); return null; } - public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + + // Called when this shape is being used again. + public virtual void IncrementReference() { - return null; + referenceCount++; + lastReferenced = DateTime.Now; + } + + // Called when this shape is being used again. + public virtual void DecrementReference() + { + referenceCount--; + lastReferenced = DateTime.Now; } // Release the use of a physical shape. public abstract void Dereference(BSScene physicsScene); - // All shapes have a static call to get a reference to the physical shape - // protected abstract static BSShape GetReference(); - // Returns a string for debugging that uniquily identifies the memory used by this instance public virtual string AddrString { @@ -112,6 +132,7 @@ public abstract class BSShape } } +// ============================================================================================================ public class BSShapeNull : BSShape { public BSShapeNull() : base() @@ -121,23 +142,39 @@ public class BSShapeNull : BSShape public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } } +// ============================================================================================================ public class BSShapeNative : BSShape { private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; - public BSShapeNative() : base() + public BSShapeNative(BulletShape pShape) : base(pShape) { } + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { // Native shapes are not shared and are always built anew. - //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); - return null; + return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); } - private BSShapeNative(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + // Make this reference to the physical shape go away since native shapes are not shared. + public override void Dereference(BSScene physicsScene) + { + // Native shapes are not tracked and are released immediately + if (physShapeInfo.HasPhysicalShape) + { + physicsScene.DetailLog("{0},BSShapeNative.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } + physShapeInfo.Clear(); + // Garbage collection will free up this instance. + } + + private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { + BulletShape newShape; + ShapeData nativeShapeData = new ShapeData(); nativeShapeData.Type = shapeType; nativeShapeData.ID = prim.LocalID; @@ -146,63 +183,164 @@ public class BSShapeNative : BSShape nativeShapeData.MeshKey = (ulong)shapeKey; nativeShapeData.HullKey = (ulong)shapeKey; - - /* if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) { - ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); - physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); + newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); + physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); } else { - ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); + newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); } - if (ptr == IntPtr.Zero) + if (!newShape.HasPhysicalShape) { physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", LogHeader, prim.LocalID, shapeType); } - type = shapeType; - key = (UInt64)shapeKey; - */ - } - // Make this reference to the physical shape go away since native shapes are not shared. - public override void Dereference(BSScene physicsScene) - { - /* - // Native shapes are not tracked and are released immediately - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); - PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); - ptr = IntPtr.Zero; - // Garbage collection will free up this instance. - */ + newShape.type = shapeType; + newShape.isNativeShape = true; + newShape.shapeKey = (UInt64)shapeKey; + return newShape; } + } +// ============================================================================================================ public class BSShapeMesh : BSShape { private static string LogHeader = "[BULLETSIM SHAPE MESH]"; private static Dictionary Meshes = new Dictionary(); - public BSShapeMesh() : base() + public BSShapeMesh(BulletShape pShape) : base(pShape) { } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeMesh,create,oldKey={1},newKey={2},size={3},lod={4}", + prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeMesh retMesh; + lock (Meshes) + { + if (Meshes.TryGetValue(newMeshKey, out retMesh)) + { + // The mesh has already been created. Return a new reference to same. + retMesh.IncrementReference(); + } + else + { + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + // Take evasive action if the mesh was not constructed. + newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); + + retMesh = new BSShapeMesh(newShape); + + Meshes.Add(newMeshKey, retMesh); + } + } + return retMesh; + } + public override void Dereference(BSScene physicsScene) + { + lock (Meshes) + { + this.DecrementReference(); + // TODO: schedule aging and destruction of unused meshes. + } + } + + private static BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + BulletShape newShape = null; + + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, + false, // say it is not physical so a bounding box is not built + false // do not cache the mesh and do not use previously built versions + ); + + if (meshData != null) + { + + int[] indices = meshData.getIndexListAsInt(); + int realIndicesIndex = indices.Length; + float[] verticesAsFloats = meshData.getVertexListAsFloat(); + + if (BSParam.ShouldRemoveZeroWidthTriangles) + { + // Remove degenerate triangles. These are triangles with two of the vertices + // are the same. This is complicated by the problem that vertices are not + // made unique in sculpties so we have to compare the values in the vertex. + realIndicesIndex = 0; + for (int tri = 0; tri < indices.Length; tri += 3) + { + // Compute displacements into vertex array for each vertex of the triangle + int v1 = indices[tri + 0] * 3; + int v2 = indices[tri + 1] * 3; + int v3 = indices[tri + 2] * 3; + // Check to see if any two of the vertices are the same + if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) + || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) + || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) + ) + { + // None of the vertices of the triangles are the same. This is a good triangle; + indices[realIndicesIndex + 0] = indices[tri + 0]; + indices[realIndicesIndex + 1] = indices[tri + 1]; + indices[realIndicesIndex + 2] = indices[tri + 2]; + realIndicesIndex += 3; + } + } + } + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", + BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); + + if (realIndicesIndex != 0) + { + newShape = physicsScene.PE.CreateMeshShape(physicsScene.World, + realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); + } + else + { + physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", + LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); + } + } + newShape.shapeKey = newMeshKey; + + return newShape; + } } +// ============================================================================================================ public class BSShapeHull : BSShape { private static string LogHeader = "[BULLETSIM SHAPE HULL]"; private static Dictionary Hulls = new Dictionary(); - public BSShapeHull() : base() + public BSShapeHull(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + return new BSShapeNull(); + } + public override void Dereference(BSScene physicsScene) { } - public static BSShape GetReference() { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { } } +// ============================================================================================================ public class BSShapeCompound : BSShape { private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; @@ -216,6 +354,7 @@ public class BSShapeCompound : BSShape public override void Dereference(BSScene physicsScene) { } } +// ============================================================================================================ public class BSShapeAvatar : BSShape { private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; -- cgit v1.1 From 70081a40a4892b5d3e58218a8cd15a689d875ad0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Apr 2013 12:45:19 -0700 Subject: Bug fix: compare tolower. This should fix the issue where HG visitors currently in the region were not being found by the avatar picker window. --- .../Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 77e8b00..7b823ba 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -200,7 +200,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // search the local cache foreach (UserData data in m_UserCache.Values) if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && - (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query))) + (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) users.Add(data); AddAdditionalUsers(avatarID, query, users); -- cgit v1.1 From 1593d795ea72bb87f18c8ed2d1bec87871974ec5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 24 Apr 2013 15:01:11 -0700 Subject: BulletSim: version of libBulletSim.so for 32 bit systems that doesn't crash on startup. Doesn't yet solve the new glibcxx dependencies. --- bin/lib32/libBulletSim.so | Bin 2096572 -> 2096576 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index d79896a..6216a65 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ -- cgit v1.1 From 6f3c905744e674f3cca555a4d36ede2139fcb9d7 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 25 Apr 2013 00:24:48 +0100 Subject: Add Avination's support for parcel eject and freeze --- .../CoreModules/World/Land/LandManagementModule.cs | 85 ++++++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 40 ++++++---- 2 files changed, 110 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index dbf5138..693de1d 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -210,6 +210,9 @@ namespace OpenSim.Region.CoreModules.World.Land client.OnParcelInfoRequest += ClientOnParcelInfoRequest; client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; client.OnPreAgentUpdate += ClientOnPreAgentUpdate; + client.OnParcelEjectUser += ClientOnParcelEjectUser; + client.OnParcelFreezeUser += ClientOnParcelFreezeUser; + EntityBase presenceEntity; if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) @@ -1738,6 +1741,88 @@ namespace OpenSim.Region.CoreModules.World.Land UpdateLandObject(localID, land.LandData); } + Dictionary Timers = new Dictionary(); + + public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) + { + ScenePresence targetAvatar = null; + ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar); + ScenePresence parcelManager = null; + ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager); + System.Threading.Timer Timer; + + if (targetAvatar.UserLevel == 0) + { + ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y); + if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze)) + return; + if (flags == 0) + { + targetAvatar.AllowMovement = false; + targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world."); + parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen."); + System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen); + Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0); + Timers.Add(targetAvatar.UUID, Timer); + } + else + { + targetAvatar.AllowMovement = true; + targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you."); + parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen."); + Timers.TryGetValue(targetAvatar.UUID, out Timer); + Timers.Remove(targetAvatar.UUID); + Timer.Dispose(); + } + } + } + + private void OnEndParcelFrozen(object avatar) + { + ScenePresence targetAvatar = (ScenePresence)avatar; + targetAvatar.AllowMovement = true; + System.Threading.Timer Timer; + Timers.TryGetValue(targetAvatar.UUID, out Timer); + Timers.Remove(targetAvatar.UUID); + targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false); + } + + public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target) + { + ScenePresence targetAvatar = null; + ScenePresence parcelManager = null; + + // Must have presences + if (!m_scene.TryGetScenePresence(target, out targetAvatar) || + !m_scene.TryGetScenePresence(client.AgentId, out parcelManager)) + return; + + // Cannot eject estate managers or gods + if (m_scene.Permissions.IsAdministrator(target)) + return; + + // Check if you even have permission to do this + ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y); + if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) && + !m_scene.Permissions.IsAdministrator(client.AgentId)) + return; + Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land); + + targetAvatar.TeleportWithMomentum(pos, null); + targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname); + parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected."); + + if ((flags & 1) != 0) // Ban TODO: Remove magic number + { + LandAccessEntry entry = new LandAccessEntry(); + entry.AgentID = targetAvatar.UUID; + entry.Flags = AccessList.Ban; + entry.Expires = 0; // Perm + + land.LandData.ParcelAccessList.Add(entry); + } + } + protected void InstallInterfaces() { Command clearCommand diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f50d3cd..69fe137 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5138,9 +5138,14 @@ namespace OpenSim.Region.Framework.Scenes get { return m_allowScriptCrossings; } } - public Vector3? GetNearestAllowedPosition(ScenePresence avatar) + public Vector3 GetNearestAllowedPosition(ScenePresence avatar) { - ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); + return GetNearestAllowedPosition(avatar, null); + } + + public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel) + { + ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel); if (nearestParcel != null) { @@ -5149,10 +5154,7 @@ namespace OpenSim.Region.Framework.Scenes Vector3? nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); if (nearestPoint != null) { -// m_log.DebugFormat( -// "[SCENE]: Found a sane previous position based on velocity for {0}, sending them to {1} in {2}", -// avatar.Name, nearestPoint, nearestParcel.LandData.Name); - + Debug.WriteLine("Found a sane previous position based on velocity, sending them to: " + nearestPoint.ToString()); return nearestPoint.Value; } @@ -5162,24 +5164,27 @@ namespace OpenSim.Region.Framework.Scenes nearestPoint = GetNearestPointInParcelAlongDirectionFromPoint(avatar.AbsolutePosition, dir, nearestParcel); if (nearestPoint != null) { -// m_log.DebugFormat( -// "[SCENE]: {0} had a zero velocity, sending them to {1}", avatar.Name, nearestPoint); - + Debug.WriteLine("They had a zero velocity, sending them to: " + nearestPoint.ToString()); return nearestPoint.Value; } - //Ultimate backup if we have no idea where they are -// m_log.DebugFormat( -// "[SCENE]: No idea where {0} is, sending them to {1}", avatar.Name, avatar.lastKnownAllowedPosition); + ILandObject dest = LandChannel.GetLandObject(avatar.lastKnownAllowedPosition.X, avatar.lastKnownAllowedPosition.Y); + if (dest != excludeParcel) + { + // Ultimate backup if we have no idea where they are and + // the last allowed position was in another parcel + Debug.WriteLine("Have no idea where they are, sending them to: " + avatar.lastKnownAllowedPosition.ToString()); + return avatar.lastKnownAllowedPosition; + } - return avatar.lastKnownAllowedPosition; + // else fall through to region edge } //Go to the edge, this happens in teleporting to a region with no available parcels Vector3 nearestRegionEdgePoint = GetNearestRegionEdgePosition(avatar); //Debug.WriteLine("They are really in a place they don't belong, sending them to: " + nearestRegionEdgePoint.ToString()); - + return nearestRegionEdgePoint; } @@ -5206,13 +5211,18 @@ namespace OpenSim.Region.Framework.Scenes public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y) { + return GetNearestAllowedParcel(avatarId, x, y, null); + } + + public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel) + { List all = AllParcels(); float minParcelDistance = float.MaxValue; ILandObject nearestParcel = null; foreach (var parcel in all) { - if (!parcel.IsEitherBannedOrRestricted(avatarId)) + if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel) { float parcelDistance = GetParcelDistancefromPoint(parcel, x, y); if (parcelDistance < minParcelDistance) -- cgit v1.1 From 5cd77a460ca434f50c231ba261647e82e9f033dc Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 25 Apr 2013 00:51:57 +0100 Subject: Commit Avination's God Kick feature. --- .../Region/CoreModules/Avatar/Gods/GodsModule.cs | 199 ++++++++++++++------- 1 file changed, 137 insertions(+), 62 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index 5a7446f..d9badcd 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -32,14 +32,35 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Specialized; +using System.Reflection; +using System.IO; +using System.Web; +using System.Xml; +using log4net; using Mono.Addins; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.StructuredData; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OSDArray = OpenMetaverse.StructuredData.OSDArray; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + namespace OpenSim.Region.CoreModules.Avatar.Gods { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GodsModule")] public class GodsModule : INonSharedRegionModule, IGodsModule { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// Special UUID for actions that apply to all agents private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); @@ -65,6 +86,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods m_scene = scene; m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += SubscribeToClientEvents; + m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; + scene.EventManager.OnIncomingInstantMessage += + OnIncomingInstantMessage; } public void RemoveRegion(Scene scene) @@ -98,6 +122,47 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods client.OnRequestGodlikePowers -= RequestGodlikePowers; } + private void OnRegisterCaps(UUID agentID, Caps caps) + { + string uri = "/CAPS/" + UUID.Random(); + + caps.RegisterHandler("UntrustedSimulatorMessage", + new RestStreamHandler("POST", uri, + HandleUntrustedSimulatorMessage)); + } + + private string HandleUntrustedSimulatorMessage(string request, + string path, string param, IOSHttpRequest httpRequest, + IOSHttpResponse httpResponse) + { + OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request); + + string message = osd["message"].AsString(); + + if (message == "GodKickUser") + { + OSDMap body = (OSDMap)osd["body"]; + OSDArray userInfo = (OSDArray)body["UserInfo"]; + OSDMap userData = (OSDMap)userInfo[0]; + + UUID agentID = userData["AgentID"].AsUUID(); + UUID godID = userData["GodID"].AsUUID(); + UUID godSessionID = userData["GodSessionID"].AsUUID(); + uint kickFlags = userData["KickFlags"].AsUInteger(); + string reason = userData["Reason"].AsString(); + ScenePresence god = m_scene.GetScenePresence(godID); + if (god == null || god.ControllingClient.SessionId != godSessionID) + return String.Empty; + + KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason)); + } + else + { + m_log.ErrorFormat("[GOD]: Unhandled UntrustedSimulatorMessage: {0}", message); + } + return String.Empty; + } + public void RequestGodlikePowers( UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) { @@ -146,76 +211,86 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods /// 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) { - UUID kickUserID = ALL_AGENTS; - + if (!m_scene.Permissions.IsGod(godID)) + return; + ScenePresence sp = m_scene.GetScenePresence(agentID); - if (sp != null || agentID == kickUserID) + if (sp == null && agentID != ALL_AGENTS) { - if (m_scene.Permissions.IsGod(godID)) + IMessageTransferModule transferModule = + m_scene.RequestModuleInterface(); + if (transferModule != null) { - if (kickflags == 0) - { - if (agentID == kickUserID) - { - string reasonStr = Utils.BytesToString(reason); - - m_scene.ForEachClient( - delegate(IClientAPI controller) - { - if (controller.AgentId != godID) - controller.Kick(reasonStr); - } - ); - - // This is a bit crude. It seems the client will be null before it actually stops the thread - // The thread will kill itself eventually :/ - // Is there another way to make sure *all* clients get this 'inter region' message? - m_scene.ForEachRootClient( - delegate(IClientAPI client) - { - if (client.AgentId != godID) - { - client.Close(); - } - } - ); - } - else - { - m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent); + m_log.DebugFormat("[GODS]: Sending nonlocal kill for agent {0}", agentID); + transferModule.SendInstantMessage(new GridInstantMessage( + m_scene, godID, "God", agentID, (byte)250, false, + Utils.BytesToString(reason), UUID.Zero, true, + new Vector3(), new byte[] {(byte)kickflags}, true), + delegate(bool success) {} ); + } + return; + } - sp.ControllingClient.Kick(Utils.BytesToString(reason)); - sp.ControllingClient.Close(); - } - } - - if (kickflags == 1) - { - sp.AllowMovement = false; - if (DialogModule != null) - { - DialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); - DialogModule.SendAlertToUser(godID, "User Frozen"); - } - } - - if (kickflags == 2) - { - sp.AllowMovement = true; - if (DialogModule != null) - { - DialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); - DialogModule.SendAlertToUser(godID, "User Unfrozen"); - } - } + switch (kickflags) + { + case 0: + if (sp != null) + { + KickPresence(sp, Utils.BytesToString(reason)); } - else + else if (agentID == ALL_AGENTS) { - if (DialogModule != null) - DialogModule.SendAlertToUser(godID, "Kick request denied"); + 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) + { + sp.AllowMovement = false; + m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); + m_dialogModule.SendAlertToUser(godID, "User Frozen"); + } + break; + case 2: + if (sp != null) + { + sp.AllowMovement = true; + m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason)); + m_dialogModule.SendAlertToUser(godID, "User Unfrozen"); + } + break; + default: + break; + } + } + + private void KickPresence(ScenePresence sp, string reason) + { + if (sp.IsChildAgent) + return; + sp.ControllingClient.Kick(reason); + sp.MakeChildAgent(); + sp.ControllingClient.Close(); + } + + private void OnIncomingInstantMessage(GridInstantMessage msg) + { + if (msg.dialog == (uint)250) // Nonlocal kick + { + UUID agentID = new UUID(msg.toAgentID); + string reason = msg.message; + UUID godID = new UUID(msg.fromAgentID); + uint kickMode = (uint)msg.binaryBucket[0]; + + KickUser(godID, UUID.Zero, agentID, kickMode, Util.StringToBytes1024(reason)); } } } -} \ No newline at end of file +} -- cgit v1.1 From ec4f981f1d371b329d227e17cb2f5aaaba364fad Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 25 Apr 2013 01:39:22 +0200 Subject: Adding the dynamic menu module which allows registering new menu options in compliant viewers --- .../Framework/Interfaces/IDynamicMenuModule.cs | 57 +++++ .../ViewerSupport/DynamicMenuModule.cs | 282 +++++++++++++++++++++ 2 files changed, 339 insertions(+) create mode 100644 OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs create mode 100644 OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs diff --git a/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs new file mode 100644 index 0000000..08b71e4 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IDynamicMenuModule.cs @@ -0,0 +1,57 @@ +/* + * 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.Collections.Generic; +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Region.Framework.Interfaces +{ + public enum InsertLocation : int + { + Agent = 1, + World = 2, + Tools = 3, + Advanced = 4, + Admin = 5 + } + + public enum UserMode : int + { + Normal = 0, + God = 3 + } + + public delegate void CustomMenuHandler(string action, UUID agentID, List selection); + + public interface IDynamicMenuModule + { + void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler); + void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler); + void RemoveMenuItem(string action); + } +} diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs new file mode 100644 index 0000000..917911f --- /dev/null +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs @@ -0,0 +1,282 @@ +// ****************************************************************** +// Copyright (c) 2008, 2009 Melanie Thielker +// +// All rights reserved +// + +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Collections.Generic; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim; +using OpenSim.Region; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework; +//using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Nini.Config; +using log4net; +using Mono.Addins; +using Caps = OpenSim.Framework.Capabilities.Caps; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; + +namespace OpenSim.Region.OptionalModules.ViewerSupport +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DynamicMenu")] + public class DynamicMenuModule : INonSharedRegionModule, IDynamicMenuModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private class MenuItemData + { + public string Title; + public UUID AgentID; + public InsertLocation Location; + public UserMode Mode; + public CustomMenuHandler Handler; + } + + private Dictionary> m_menuItems = + new Dictionary>(); + + private Scene m_scene; + + public string Name + { + get { return "DynamicMenuModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Initialise(IConfigSource config) + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_scene = scene; + scene.EventManager.OnRegisterCaps += OnRegisterCaps; + m_scene.RegisterModuleInterface(this); + } + + public void RegionLoaded(Scene scene) + { + ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface(); + + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + } + + public void RemoveRegion(Scene scene) + { + } + + private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + { + OSD menus = new OSDMap(); + if (features.ContainsKey("menus")) + menus = features["menus"]; + + OSDMap agent = new OSDMap(); + OSDMap world = new OSDMap(); + OSDMap tools = new OSDMap(); + OSDMap advanced = new OSDMap(); + OSDMap admin = new OSDMap(); + if (((OSDMap)menus).ContainsKey("agent")) + agent = (OSDMap)((OSDMap)menus)["agent"]; + if (((OSDMap)menus).ContainsKey("world")) + world = (OSDMap)((OSDMap)menus)["world"]; + if (((OSDMap)menus).ContainsKey("tools")) + tools = (OSDMap)((OSDMap)menus)["tools"]; + if (((OSDMap)menus).ContainsKey("advanced")) + advanced = (OSDMap)((OSDMap)menus)["advanced"]; + if (((OSDMap)menus).ContainsKey("admin")) + admin = (OSDMap)((OSDMap)menus)["admin"]; + + if (m_menuItems.ContainsKey(UUID.Zero)) + { + foreach (MenuItemData d in m_menuItems[UUID.Zero]) + { + if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID))) + continue; + + OSDMap loc = null; + switch (d.Location) + { + case InsertLocation.Agent: + loc = agent; + break; + case InsertLocation.World: + loc = world; + break; + case InsertLocation.Tools: + loc = tools; + break; + case InsertLocation.Advanced: + loc = advanced; + break; + case InsertLocation.Admin: + loc = admin; + break; + } + + if (loc == null) + continue; + + loc[d.Title] = OSD.FromString(d.Title); + } + } + + if (m_menuItems.ContainsKey(agentID)) + { + foreach (MenuItemData d in m_menuItems[agentID]) + { + if (d.Mode == UserMode.God && (!m_scene.Permissions.IsGod(agentID))) + continue; + + OSDMap loc = null; + switch (d.Location) + { + case InsertLocation.Agent: + loc = agent; + break; + case InsertLocation.World: + loc = world; + break; + case InsertLocation.Tools: + loc = tools; + break; + case InsertLocation.Advanced: + loc = advanced; + break; + case InsertLocation.Admin: + loc = admin; + break; + } + + if (loc == null) + continue; + + loc[d.Title] = OSD.FromString(d.Title); + } + } + + + ((OSDMap)menus)["agent"] = agent; + ((OSDMap)menus)["world"] = world; + ((OSDMap)menus)["tools"] = tools; + ((OSDMap)menus)["advanced"] = advanced; + ((OSDMap)menus)["admin"] = admin; + + features["menus"] = menus; + } + + private void OnRegisterCaps(UUID agentID, Caps caps) + { + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + capUrl = "/CAPS/" + UUID.Random() + "/"; + caps.RegisterHandler("CustomMenuAction", new MenuActionHandler(capUrl, "CustomMenuAction", agentID, this, m_scene)); + } + + internal void HandleMenuSelection(string action, UUID agentID, List selection) + { + if (m_menuItems.ContainsKey(agentID)) + { + foreach (MenuItemData d in m_menuItems[agentID]) + { + if (d.Title == action) + d.Handler(action, agentID, selection); + } + } + + if (m_menuItems.ContainsKey(UUID.Zero)) + { + foreach (MenuItemData d in m_menuItems[UUID.Zero]) + { + if (d.Title == action) + d.Handler(action, agentID, selection); + } + } + } + + public void AddMenuItem(string title, InsertLocation location, UserMode mode, CustomMenuHandler handler) + { + AddMenuItem(UUID.Zero, title, location, mode, handler); + } + + public void AddMenuItem(UUID agentID, string title, InsertLocation location, UserMode mode, CustomMenuHandler handler) + { + if (!m_menuItems.ContainsKey(agentID)) + m_menuItems[agentID] = new List(); + + m_menuItems[agentID].Add(new MenuItemData() { Title = title, AgentID = agentID, Location = location, Mode = mode, Handler = handler }); + } + + public void RemoveMenuItem(string action) + { + foreach (KeyValuePair> kvp in m_menuItems) + { + List pendingDeletes = new List(); + foreach (MenuItemData d in kvp.Value) + { + if (d.Title == action) + pendingDeletes.Add(d); + } + + foreach (MenuItemData d in pendingDeletes) + kvp.Value.Remove(d); + } + } + } + + public class MenuActionHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private UUID m_agentID; + private Scene m_scene; + private DynamicMenuModule m_module; + + public MenuActionHandler(string path, string name, UUID agentID, DynamicMenuModule module, Scene scene) + :base("POST", path, name, agentID.ToString()) + { + m_agentID = agentID; + m_scene = scene; + m_module = module; + } + + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader reader = new StreamReader(request); + string requestBody = reader.ReadToEnd(); + + OSD osd = OSDParser.DeserializeLLSDXml(requestBody); + + string action = ((OSDMap)osd)["action"].AsString(); + OSDArray selection = (OSDArray)((OSDMap)osd)["selection"]; + List sel = new List(); + for (int i = 0 ; i < selection.Count ; i++) + sel.Add(selection[i].AsUInteger()); + + Util.FireAndForget(x => { m_module.HandleMenuSelection(action, m_agentID, sel); }); + + Encoding encoding = Encoding.UTF8; + return encoding.GetBytes(OSDParser.SerializeLLSDXmlString(new OSD())); + } + } +} -- cgit v1.1 From 0e22021c650a84ae1b9ed86d7c8df3beeb6e54ed Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Apr 2013 19:00:41 -0700 Subject: Make the kicked user's avie truly disappear when it's god-kicked. --- OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index d9badcd..16673ec 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -276,8 +276,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods if (sp.IsChildAgent) return; sp.ControllingClient.Kick(reason); - sp.MakeChildAgent(); - sp.ControllingClient.Close(); + sp.Scene.IncomingCloseAgent(sp.UUID, true); } private void OnIncomingInstantMessage(GridInstantMessage msg) -- cgit v1.1 From c10405330d0fa5855c3f8180fdc8347cb87fed4f Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 24 Apr 2013 20:43:15 -0700 Subject: UUIDGatherer now includes UUIDs which reference texture assets used as materials --- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 66 +++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index ad33607..0e83781 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -34,6 +34,7 @@ using System.Threading; using log4net; using OpenMetaverse; using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Services.Interfaces; @@ -184,6 +185,9 @@ namespace OpenSim.Region.Framework.Scenes if (!assetUuids.ContainsKey(tii.AssetID)) GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); } + + // get any texture UUIDs used for materials such as normal and specular maps + GatherMaterialsUuids(part, assetUuids); } catch (Exception e) { @@ -208,6 +212,68 @@ namespace OpenSim.Region.Framework.Scenes // } // } + + /// + /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps + /// + /// + /// + public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) + { + // scan thru the dynAttrs map of this part for any textures used as materials + OSDMap OSMaterials = null; + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsKey("OS:Materials")) + OSMaterials = part.DynAttrs["OS:Materials"]; + if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) + { + OSD osd = OSMaterials["Materials"]; + //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); + + if (osd is OSDArray) + { + OSDArray matsArr = osd as OSDArray; + foreach (OSDMap matMap in matsArr) + { + try + { + if (matMap.ContainsKey("Material")) + { + OSDMap mat = matMap["Material"] as OSDMap; + if (mat.ContainsKey("NormMap")) + { + UUID normalMapId = mat["NormMap"].AsUUID(); + if (normalMapId != UUID.Zero) + { + assetUuids[normalMapId] = AssetType.Texture; + //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); + } + } + if (mat.ContainsKey("SpecMap")) + { + UUID specularMapId = mat["SpecMap"].AsUUID(); + if (specularMapId != UUID.Zero) + { + assetUuids[specularMapId] = AssetType.Texture; + //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); + } + } + } + + } + catch (Exception e) + { + m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); + } + } + } + } + } + } + + /// /// Get an asset synchronously, potentially using an asynchronous callback. If the /// asynchronous callback is used, we will wait for it to complete. -- cgit v1.1 From 3bc801746466cbd401f481295876b357fa27125b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 25 Apr 2013 09:23:15 -0700 Subject: Recover a lost "virtual". Downstream projects need this. --- OpenSim/Data/MySQL/MySQLSimulationData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 9cc6f40..2d20eaf 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -52,7 +52,7 @@ namespace OpenSim.Data.MySQL private string m_connectionString; private object m_dbLock = new object(); - protected Assembly Assembly + protected virtual Assembly Assembly { get { return GetType().Assembly; } } -- cgit v1.1 From 5d0a8ff39149a41d332dc40ae0bb1dc0972d0512 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 25 Apr 2013 20:48:12 +0100 Subject: Change copyright notice on DynamicMenuModule to proper BSD --- .../ViewerSupport/DynamicMenuModule.cs | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs index 917911f..1ea1c20 100644 --- a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs @@ -1,8 +1,29 @@ -// ****************************************************************** -// Copyright (c) 2008, 2009 Melanie Thielker -// -// All rights reserved -// +/* + * 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.IO; -- cgit v1.1 From 03c9d8ae4fa9a47cda66814177071c258f5b4437 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 25 Apr 2013 21:35:18 +0100 Subject: Change EconomyDataRequest signature to use an IClientAPI rather than UUID. This is needed because recent LL viewer codebases call this earlier in login when the client is not yet established in the sim and can't be found by UUID. Sending the reply requires having the IClientAPI. --- OpenSim/Framework/IClientAPI.cs | 2 +- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- .../World/MoneyModule/SampleMoneyModule.cs | 17 ++++++----------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 10ead39..4d5ec3a 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -313,7 +313,7 @@ namespace OpenSim.Framework public delegate void ObjectPermissions( IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set); - public delegate void EconomyDataRequest(UUID agentID); + public delegate void EconomyDataRequest(IClientAPI client); public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 1eb953c..bede379 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -9682,7 +9682,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP EconomyDataRequest handlerEconomoyDataRequest = OnEconomyDataRequest; if (handlerEconomoyDataRequest != null) { - handlerEconomoyDataRequest(AgentId); + handlerEconomoyDataRequest(this); } return true; } diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index 7bbf500..37af8c7 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs @@ -688,19 +688,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// Event called Economy Data Request handler. /// /// - public void EconomyDataRequestHandler(UUID agentId) + public void EconomyDataRequestHandler(IClientAPI user) { - IClientAPI user = LocateClientObject(agentId); + Scene s = LocateSceneClientIn(user.AgentId); - if (user != null) - { - Scene s = LocateSceneClientIn(user.AgentId); - - user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, - PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, - PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, - TeleportMinPrice, TeleportPriceExponent); - } + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, + PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, + PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, + TeleportMinPrice, TeleportPriceExponent); } private void ValidateLandBuy(Object osender, EventManager.LandBuyArgs e) -- cgit v1.1 From 0e162511cf0e2b507a94ad91a5e36be76eda18ef Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 25 Apr 2013 17:01:57 -0700 Subject: Groups: make some methods protected. --- OpenSim/Addons/Groups/Service/GroupsService.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index 0668870..6a4348b 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -723,12 +723,12 @@ namespace OpenSim.Groups #region Actions without permission checks - private void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) { _AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty); } - public void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) + protected void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID) { // 1. Delete membership m_Database.DeleteMember(GroupID, AgentID); @@ -780,7 +780,7 @@ namespace OpenSim.Groups } - private bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add) + protected bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add) { RoleData data = m_Database.RetrieveRole(groupID, roleID); @@ -810,12 +810,12 @@ namespace OpenSim.Groups return m_Database.StoreRole(data); } - private void _RemoveGroupRole(UUID groupID, UUID roleID) + protected void _RemoveGroupRole(UUID groupID, UUID roleID) { m_Database.DeleteRole(groupID, roleID); } - private void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) + protected void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID) { RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID); if (data != null) @@ -840,7 +840,7 @@ namespace OpenSim.Groups } - private List _GetGroupRoles(UUID groupID) + protected List _GetGroupRoles(UUID groupID) { List roles = new List(); @@ -865,7 +865,7 @@ namespace OpenSim.Groups return roles; } - private List _GetGroupRoleMembers(UUID GroupID, bool isInGroup) + protected List _GetGroupRoleMembers(UUID GroupID, bool isInGroup) { List rmembers = new List(); -- cgit v1.1 From ef08ab68a7a8870e4ec300a0da5533ea097a9577 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 27 Apr 2013 17:42:54 +0100 Subject: Small oversight in EconomyDataRequest - this would have affected everyone NOT using a money module. --- OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index 37af8c7..5863379 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs @@ -690,8 +690,6 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// public void EconomyDataRequestHandler(IClientAPI user) { - Scene s = LocateSceneClientIn(user.AgentId); - user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, -- cgit v1.1 From cbb3bb62dae548917a899171bd69972e85a1642d Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 27 Apr 2013 17:56:39 +0100 Subject: Unbreak the sample money module --- OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index 5863379..35f44d0 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs @@ -690,6 +690,8 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule /// public void EconomyDataRequestHandler(IClientAPI user) { + Scene s = (Scene)user.Scene; + user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload, -- cgit v1.1 From f675d465b27bfecab59213bd19c6e070a6482f88 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Apr 2013 10:34:13 -0700 Subject: Make method virtual --- OpenSim/Services/UserAccountService/GridUserService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index 43fa04b..8388180 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -73,7 +73,7 @@ namespace OpenSim.Services.UserAccountService return info; } - public GridUserInfo[] GetGridUserInfo(string[] userIDs) + public virtual GridUserInfo[] GetGridUserInfo(string[] userIDs) { List ret = new List(); -- cgit v1.1 From 90a6891a7d5af39013efc49f12dc69a8d7b240de Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Apr 2013 10:34:23 -0700 Subject: Better error reporting --- OpenSim/Server/Base/ServerUtils.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 210a314..25957d3 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -286,6 +286,7 @@ namespace OpenSim.Server.Base e.InnerException == null ? e.Message : e.InnerException.Message, e.StackTrace); } + m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0}: {1}", dllName, e.Message); return null; } -- cgit v1.1 From 222f530411eccf43279ff0d789c1f5c3bc4530eb Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Apr 2013 21:23:29 -0700 Subject: Added an interface to an external ban service. With this commit, the interface is used only in Hypergrided worlds (Gatekeeper), although in those, it applies to both local and foreign users. The Ban service itself is not in core; it is to be provided externally. --- .../Services/HypergridService/GatekeeperService.cs | 25 +++++++++-- OpenSim/Services/Interfaces/IBansService.cs | 48 ++++++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 OpenSim/Services/Interfaces/IBansService.cs diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 97a0afc..0cf1c14 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -58,6 +58,7 @@ namespace OpenSim.Services.HypergridService private static IUserAgentService m_UserAgentService; private static ISimulationService m_SimulationService; private static IGridUserService m_GridUserService; + private static IBansService m_BansService; private static string m_AllowedClients = string.Empty; private static string m_DeniedClients = string.Empty; @@ -87,6 +88,7 @@ namespace OpenSim.Services.HypergridService string presenceService = serverConfig.GetString("PresenceService", String.Empty); string simulationService = serverConfig.GetString("SimulationService", String.Empty); string gridUserService = serverConfig.GetString("GridUserService", String.Empty); + string bansService = serverConfig.GetString("BansService", String.Empty); // These are mandatory, the others aren't if (gridService == string.Empty || presenceService == string.Empty) @@ -121,6 +123,8 @@ namespace OpenSim.Services.HypergridService m_UserAgentService = ServerUtils.LoadPlugin(homeUsersService, args); if (gridUserService != string.Empty) m_GridUserService = ServerUtils.LoadPlugin(gridUserService, args); + if (bansService != string.Empty) + m_BansService = ServerUtils.LoadPlugin(bansService, args); if (simService != null) m_SimulationService = simService; @@ -223,7 +227,7 @@ namespace OpenSim.Services.HypergridService m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9} Teleport Flags {10}", aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName, aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0, aCircuit.teleportFlags.ToString()); - + // // Check client // @@ -287,17 +291,16 @@ namespace OpenSim.Services.HypergridService } } } - m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok"); // // Foreign agents allowed? Exceptions? // - if (account == null) + if (account == null) { bool allowed = m_ForeignAgentsAllowed; if (m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsAllowedExceptions)) - allowed = false; + allowed = false; if (!m_ForeignAgentsAllowed && IsException(aCircuit, m_ForeignsDisallowedExceptions)) allowed = true; @@ -311,6 +314,20 @@ namespace OpenSim.Services.HypergridService } } + // + // Is the user banned? + // This uses a Ban service that's more powerful than the configs + // + string uui = (account != null ? aCircuit.AgentID.ToString() : Util.ProduceUserUniversalIdentifier(aCircuit)); + if (m_BansService != null && m_BansService.IsBanned(uui, aCircuit.IPAddress, aCircuit.Id0, authURL)) + { + reason = "You are banned from this world"; + m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: user {0} is banned", uui); + return false; + } + + m_log.DebugFormat("[GATEKEEPER SERVICE]: User is OK"); + bool isFirstLogin = false; // // Login the presence, if it's not there yet (by the login service) diff --git a/OpenSim/Services/Interfaces/IBansService.cs b/OpenSim/Services/Interfaces/IBansService.cs new file mode 100644 index 0000000..8fd3521 --- /dev/null +++ b/OpenSim/Services/Interfaces/IBansService.cs @@ -0,0 +1,48 @@ +/* + * 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 OpenSim.Framework; +using OpenMetaverse; + +namespace OpenSim.Services.Interfaces +{ + public interface IBansService + { + /// + /// Are any of the given arguments banned from the grid? + /// + /// + /// + /// + /// + /// + bool IsBanned(string userID, string ip, string id0, string origin); + } + +} -- cgit v1.1 From a517e597f5960e5ce5eeea89e9087ac32a42bf06 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Apr 2013 09:03:09 -0700 Subject: Fix wrong sql statement in offline im. --- OpenSim/Data/MySQL/MySQLOfflineIMData.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs index 252f358..bafd204 100644 --- a/OpenSim/Data/MySQL/MySQLOfflineIMData.cs +++ b/OpenSim/Data/MySQL/MySQLOfflineIMData.cs @@ -47,13 +47,10 @@ namespace OpenSim.Data.MySQL public void DeleteOld() { - uint now = (uint)Util.UnixTimeSinceEpoch(); - using (MySqlCommand cmd = new MySqlCommand()) { - cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm); - cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old - + cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 WEEK", m_Realm); + ExecuteNonQuery(cmd); } -- cgit v1.1 From 3ff7391495271fed152aadc7a588ae976e09bafc Mon Sep 17 00:00:00 2001 From: Melanie Date: Mon, 29 Apr 2013 00:55:34 +0100 Subject: Some more pieces of Avination's ban system - if an avatar isn't allowed on any parcel in the sim, keep them out entirely. --- OpenSim/Region/Framework/Scenes/Scene.cs | 95 +++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 69fe137..829a7e9 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3693,7 +3693,7 @@ namespace OpenSim.Region.Framework.Scenes //On login test land permisions if (vialogin) { - if (land != null && !TestLandRestrictions(agent, land, out reason)) + if (land != null && !TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) { return false; } @@ -3868,20 +3868,37 @@ namespace OpenSim.Region.Framework.Scenes return true; } - private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason) + public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY) { - bool banned = land.IsBannedFromLand(agent.AgentID); - bool restricted = land.IsRestrictedFromLand(agent.AgentID); + if (posX < 0) + posX = 0; + else if (posX >= 256) + posX = 255.999f; + if (posY < 0) + posY = 0; + else if (posY >= 256) + posY = 255.999f; + + reason = String.Empty; + if (Permissions.IsGod(agentID)) + return true; + + ILandObject land = LandChannel.GetLandObject(posX, posY); + if (land == null) + return false; + + bool banned = land.IsBannedFromLand(agentID); + bool restricted = land.IsRestrictedFromLand(agentID); if (banned || restricted) { - ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y); + ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY); if (nearestParcel != null) { //Move agent to nearest allowed Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); - agent.startpos.X = newPosition.X; - agent.startpos.Y = newPosition.Y; + posX = newPosition.X; + posY = newPosition.Y; } else { @@ -5466,6 +5483,8 @@ namespace OpenSim.Region.Framework.Scenes /// public bool QueryAccess(UUID agentID, Vector3 position, out string reason) { + reason = "You are banned from the region"; + if (EntityTransferModule.IsInTransit(agentID)) { reason = "Agent is still in transit from this region"; @@ -5477,6 +5496,12 @@ namespace OpenSim.Region.Framework.Scenes return false; } + if (Permissions.IsGod(agentID)) + { + reason = String.Empty; + return true; + } + // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check. // However, the long term fix is to make sure root agent count is always accurate. m_sceneGraph.RecalculateStats(); @@ -5497,6 +5522,41 @@ namespace OpenSim.Region.Framework.Scenes } } + ScenePresence presence = GetScenePresence(agentID); + IClientAPI client = null; + AgentCircuitData aCircuit = null; + + if (presence != null) + { + client = presence.ControllingClient; + if (client != null) + aCircuit = client.RequestClientInfo(); + } + + // We may be called before there is a presence or a client. + // Fake AgentCircuitData to keep IAuthorizationModule smiling + if (client == null) + { + aCircuit = new AgentCircuitData(); + aCircuit.AgentID = agentID; + aCircuit.firstname = String.Empty; + aCircuit.lastname = String.Empty; + } + + try + { + if (!AuthorizeUser(aCircuit, out reason)) + { + // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); + return false; + } + } + catch (Exception e) + { + m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} "+ e.StackTrace, e.Message); + return false; + } + if (position == Vector3.Zero) // Teleport { if (!RegionInfo.EstateSettings.AllowDirectTeleport) @@ -5530,6 +5590,27 @@ namespace OpenSim.Region.Framework.Scenes } } } + + float posX = 128.0f; + float posY = 128.0f; + + if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY)) + { + // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID); + return false; + } + } + else // Walking + { + ILandObject land = LandChannel.GetLandObject(position.X, position.Y); + if (land == null) + return false; + + bool banned = land.IsBannedFromLand(agentID); + bool restricted = land.IsRestrictedFromLand(agentID); + + if (banned || restricted) + return false; } reason = String.Empty; -- cgit v1.1 From 890cb6a29373a54dde2d06b13e42d07676710dc2 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 27 Apr 2013 14:00:58 -0700 Subject: BulletSim: complete BSShape classes. --- .../Physics/BulletSPlugin/BSShapeCollection.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 327 ++++++++++++++++++++- .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 6 +- 3 files changed, 316 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index bc26460..0f9b3c3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -499,7 +499,7 @@ public sealed class BSShapeCollection : IDisposable } // return 'true' if this shape description does not include any cutting or twisting. - private bool PrimHasNoCuts(PrimitiveBaseShape pbs) + public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) { return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 && pbs.ProfileHollow == 0 diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index dd5ae1a..e427dbc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -31,6 +31,7 @@ using System.Text; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Physics.ConvexDecompositionDotNet; using OMV = OpenMetaverse; @@ -73,7 +74,7 @@ public abstract class BSShape if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) { // Getting a reference to a compound shape gets you the compound shape with the root prim shape added - ret = BSShapeCompound.GetReference(prim); + ret = BSShapeCompound.GetReference(physicsScene, prim); physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); } @@ -92,6 +93,7 @@ public abstract class BSShape } private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { + // TODO: work needed here!! BSShapeMesh.GetReference(physicsScene, forceRebuild, prim); BSShapeHull.GetReference(physicsScene, forceRebuild, prim); return null; @@ -209,7 +211,7 @@ public class BSShapeNative : BSShape public class BSShapeMesh : BSShape { private static string LogHeader = "[BULLETSIM SHAPE MESH]"; - private static Dictionary Meshes = new Dictionary(); + public static Dictionary Meshes = new Dictionary(); public BSShapeMesh(BulletShape pShape) : base(pShape) { @@ -219,10 +221,10 @@ public class BSShapeMesh : BSShape float lod; System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - physicsScene.DetailLog("{0},BSShapeMesh,create,oldKey={1},newKey={2},size={3},lod={4}", + physicsScene.DetailLog("{0},BSShapeMesh,getReference,oldKey={1},newKey={2},size={3},lod={4}", prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); - BSShapeMesh retMesh; + BSShapeMesh retMesh = new BSShapeMesh(new BulletShape()); lock (Meshes) { if (Meshes.TryGetValue(newMeshKey, out retMesh)) @@ -233,13 +235,17 @@ public class BSShapeMesh : BSShape else { // An instance of this mesh has not been created. Build and remember same. - BulletShape newShape = CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); - // Take evasive action if the mesh was not constructed. - newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); + BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); - retMesh = new BSShapeMesh(newShape); + // Check to see if mesh was created (might require an asset). + newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); + if (newShape.type == BSPhysicsShapeType.SHAPE_MESH) + { + // If a mesh was what was created, remember the built shape for later sharing. + Meshes.Add(newMeshKey, retMesh); + } - Meshes.Add(newMeshKey, retMesh); + retMesh.physShapeInfo = newShape; } } return retMesh; @@ -252,8 +258,28 @@ public class BSShapeMesh : BSShape // TODO: schedule aging and destruction of unused meshes. } } + // Loop through all the known meshes and return the description based on the physical address. + public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) + { + bool ret = false; + BSShapeMesh foundDesc = null; + lock (Meshes) + { + foreach (BSShapeMesh sm in Meshes.Values) + { + if (sm.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sm; + ret = true; + break; + } - private static BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + } + } + outMesh = foundDesc; + return ret; + } + private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = null; @@ -326,32 +352,301 @@ public class BSShapeMesh : BSShape public class BSShapeHull : BSShape { private static string LogHeader = "[BULLETSIM SHAPE HULL]"; - private static Dictionary Hulls = new Dictionary(); + public static Dictionary Hulls = new Dictionary(); public BSShapeHull(BulletShape pShape) : base(pShape) { } public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { - return new BSShapeNull(); + float lod; + System.UInt64 newHullKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeHull,getReference,oldKey={1},newKey={2},size={3},lod={4}", + prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"), prim.Size, lod); + + BSShapeHull retHull = new BSShapeHull(new BulletShape()); + lock (Hulls) + { + if (Hulls.TryGetValue(newHullKey, out retHull)) + { + // The mesh has already been created. Return a new reference to same. + retHull.IncrementReference(); + } + else + { + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); + + // Check to see if mesh was created (might require an asset). + newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); + if (newShape.type == BSPhysicsShapeType.SHAPE_MESH) + { + // If a mesh was what was created, remember the built shape for later sharing. + Hulls.Add(newHullKey, retHull); + } + + retHull = new BSShapeHull(newShape); + retHull.physShapeInfo = newShape; + } + } + return retHull; } public override void Dereference(BSScene physicsScene) { } + List m_hulls; + private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + BulletShape newShape = new BulletShape(); + IntPtr hullPtr = IntPtr.Zero; + + if (BSParam.ShouldUseBulletHACD) + { + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); + BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); + + if (meshShape.physShapeInfo.HasPhysicalShape) + { + HACDParams parms; + parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; + parms.minClusters = BSParam.BHullMinClusters; + parms.compacityWeight = BSParam.BHullCompacityWeight; + parms.volumeWeight = BSParam.BHullVolumeWeight; + parms.concavity = BSParam.BHullConcavity; + parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); + parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); + parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); + parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); + + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); + newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + } + // Now done with the mesh shape. + meshShape.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + } + if (!newShape.HasPhysicalShape) + { + // Build a new hull in the physical world. + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); + if (meshData != null) + { + int[] indices = meshData.getIndexListAsInt(); + List vertices = meshData.getVertexList(); + + //format conversion from IMesh format to DecompDesc format + List convIndices = new List(); + List convVertices = new List(); + for (int ii = 0; ii < indices.GetLength(0); ii++) + { + convIndices.Add(indices[ii]); + } + foreach (OMV.Vector3 vv in vertices) + { + convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + } + + uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; + if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + { + // Simple primitive shapes we know are convex so they are better implemented with + // fewer hulls. + // Check for simple shape (prim without cuts) and reduce split parameter if so. + if (BSShapeCollection.PrimHasNoCuts(pbs)) + { + maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; + } + } + + // setup and do convex hull conversion + m_hulls = new List(); + DecompDesc dcomp = new DecompDesc(); + dcomp.mIndices = convIndices; + dcomp.mVertices = convVertices; + dcomp.mDepth = maxDepthSplit; + dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; + dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; + dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; + dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; + ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); + // create the hull into the _hulls variable + convexBuilder.process(dcomp); + + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", + BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); + + // Convert the vertices and indices for passing to unmanaged. + // The hull information is passed as a large floating point array. + // The format is: + // convHulls[0] = number of hulls + // convHulls[1] = number of vertices in first hull + // convHulls[2] = hull centroid X coordinate + // convHulls[3] = hull centroid Y coordinate + // convHulls[4] = hull centroid Z coordinate + // convHulls[5] = first hull vertex X + // convHulls[6] = first hull vertex Y + // convHulls[7] = first hull vertex Z + // convHulls[8] = second hull vertex X + // ... + // convHulls[n] = number of vertices in second hull + // convHulls[n+1] = second hull centroid X coordinate + // ... + // + // TODO: is is very inefficient. Someday change the convex hull generator to return + // data structures that do not need to be converted in order to pass to Bullet. + // And maybe put the values directly into pinned memory rather than marshaling. + int hullCount = m_hulls.Count; + int totalVertices = 1; // include one for the count of the hulls + foreach (ConvexResult cr in m_hulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (ConvexResult cr in m_hulls) + { + // copy vertices for index access + float3[] verts = new float3[cr.HullVertices.Count]; + int kk = 0; + foreach (float3 ff in cr.HullVertices) + { + verts[kk++] = ff; + } + + // add to the array one hull's worth of data + convHulls[jj++] = cr.HullIndices.Count; + convHulls[jj++] = 0f; // centroid x,y,z + convHulls[jj++] = 0f; + convHulls[jj++] = 0f; + foreach (int ind in cr.HullIndices) + { + convHulls[jj++] = verts[ind].x; + convHulls[jj++] = verts[ind].y; + convHulls[jj++] = verts[ind].z; + } + } + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + } + newShape.shapeKey = newHullKey; + } + return newShape; + } + // Callback from convex hull creater with a newly created hull. + // Just add it to our collection of hulls for this shape. + private void HullReturn(ConvexResult result) + { + m_hulls.Add(result); + return; + } + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) + { + bool ret = false; + BSShapeHull foundDesc = null; + lock (Hulls) + { + foreach (BSShapeHull sh in Hulls.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; + return ret; + } } + // ============================================================================================================ public class BSShapeCompound : BSShape { private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; - public BSShapeCompound() : base() + public BSShapeCompound(BulletShape pShape) : base(pShape) { } - public static BSShape GetReference(BSPhysObject prim) + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim) { - return new BSShapeNull(); + // Compound shapes are not shared so a new one is created every time. + return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene, prim)); + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + if (!physicsScene.PE.IsCompound(physShapeInfo)) + { + // Failed the sanity check!! + physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", + LogHeader, physShapeInfo.type, physShapeInfo.AddrString); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", + BSScene.DetailLogZero, physShapeInfo.type, physShapeInfo.AddrString); + return; + } + + int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", + BSScene.DetailLogZero, physShapeInfo, numChildren); + + // Loop through all the children dereferencing each. + for (int ii = numChildren - 1; ii >= 0; ii--) + { + BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); + DereferenceAnonCollisionShape(physicsScene, childShape); + } + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } + private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene, BSPhysObject prim) + { + BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); + return cShape; + } + // Sometimes we have a pointer to a collision shape but don't know what type it is. + // Figure out type and call the correct dereference routine. + // Called at taint-time. + private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) + { + BSShapeMesh meshDesc; + if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) + { + meshDesc.Dereference(physicsScene); + } + else + { + BSShapeHull hullDesc; + if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) + { + hullDesc.Dereference(physicsScene); + } + else + { + if (physicsScene.PE.IsCompound(pShape)) + { + BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); + recursiveCompound.Dereference(physicsScene); + } + else + { + if (physicsScene.PE.IsNativeShape(pShape)) + { + BSShapeNative nativeShape = new BSShapeNative(pShape); + nativeShape.Dereference(physicsScene); + } + } + } + } } - public override void Dereference(BSScene physicsScene) { } } // ============================================================================================================ diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 1284ae7..c67081a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -11,6 +11,8 @@ Deleting a linkset while standing on the root will leave the physical shape of t Linkset child rotations. Nebadon spiral tube has middle sections which are rotated wrong. Select linked spiral tube. Delink and note where the middle section ends up. +Refarb compound linkset creation to create a pseudo-root for center-of-mass + Let children change their shape to physical indendently and just add shapes to compound Vehicle angular vertical attraction vehicle angular banking Center-of-gravity @@ -27,14 +29,13 @@ llLookAt Avatars walking up stairs (HALF DONE) Avatar movement flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) - walking up stairs is not calibrated correctly (stairs out of Kepler cabin) + walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) Vehicle script tuning/debugging Avanti speed script Weapon shooter script Move material definitions (friction, ...) into simulator. Add material densities to the material types. -Terrain detail: double terrain mesh detail One sided meshes? Should terrain be built into a closed shape? When meshes get partially wedged into the terrain, they cannot push themselves out. It is possible that Bullet processes collisions whether entering or leaving a mesh. @@ -347,4 +348,5 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. Nebadon vehicles turning funny in arena (DONE) Lock axis (DONE 20130401) +Terrain detail: double terrain mesh detail (DONE) -- cgit v1.1 From e5582939fd8d78b61c6f1eeda6de45d94f4b4926 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 28 Apr 2013 14:44:21 -0700 Subject: BulletSim: massive refactor of shape classes. Removed shape specific code from BSShapeCollection. Using BSShape* classes to hold references to shape. Simplified shape dependency callbacks. Remove 'PreferredShape' methods and have each class specify shape type. Disable compound shape linkset for a later commit that will simplify linkset implementation. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 6 +- OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 4 +- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 4 +- .../Region/Physics/BulletSPlugin/BSActorHover.cs | 4 +- .../Physics/BulletSPlugin/BSActorLockAxis.cs | 4 +- .../Physics/BulletSPlugin/BSActorMoveToTarget.cs | 4 +- .../Physics/BulletSPlugin/BSActorSetForce.cs | 4 +- .../Physics/BulletSPlugin/BSActorSetTorque.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 6 +- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 19 +- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 9 +- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 35 +- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 4 +- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 11 +- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 34 +- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 9 +- .../Physics/BulletSPlugin/BSShapeCollection.cs | 966 ++------------------- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 203 +++-- .../Region/Physics/BulletSPlugin/BulletSimData.cs | 6 +- 20 files changed, 290 insertions(+), 1050 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index fdf2cb9..8a22bc7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -79,7 +79,7 @@ private sealed class BulletShapeUnman : BulletShape : base() { ptr = xx; - type = typ; + shapeType = typ; } public override bool HasPhysicalShape { @@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape } public override BulletShape Clone() { - return new BulletShapeUnman(ptr, type); + return new BulletShapeUnman(ptr, shapeType); } public override bool ReferenceSame(BulletShape other) { @@ -375,7 +375,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha { BulletWorldUnman worldu = world as BulletWorldUnman; BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); + return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); } public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index b37265a..1ef8b17 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -85,7 +85,7 @@ private sealed class BulletShapeXNA : BulletShape : base() { shape = xx; - type = typ; + shapeType = typ; } public override bool HasPhysicalShape { @@ -97,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape } public override BulletShape Clone() { - return new BulletShapeXNA(shape, type); + return new BulletShapeXNA(shape, shapeType); } public override bool ReferenceSame(BulletShape other) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index bd5ee0b1..ac05979 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -87,8 +87,8 @@ public class BSActorAvatarMove : BSActor // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. // Called at taint-time. - // BSActor.RemoveBodyDependencies() - public override void RemoveBodyDependencies() + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { // Nothing to do for the hoverer since it is all software at pre-step action time. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs index 92ace66..3630ca8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs @@ -87,8 +87,8 @@ public class BSActorHover : BSActor // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. // Called at taint-time. - // BSActor.RemoveBodyDependencies() - public override void RemoveBodyDependencies() + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { // Nothing to do for the hoverer since it is all software at pre-step action time. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index 09ee32b..6059af5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs @@ -85,8 +85,8 @@ public class BSActorLockAxis : BSActor // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. // Called at taint-time. - // BSActor.RemoveBodyDependencies() - public override void RemoveBodyDependencies() + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { if (LockAxisConstraint != null) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs index 56aacc5..1b598fd 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs @@ -88,8 +88,8 @@ public class BSActorMoveToTarget : BSActor // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. // Called at taint-time. - // BSActor.RemoveBodyDependencies() - public override void RemoveBodyDependencies() + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { // Nothing to do for the moveToTarget since it is all software at pre-step action time. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs index 3ad138d..c0f40fd 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs @@ -89,8 +89,8 @@ public class BSActorSetForce : BSActor // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. // Called at taint-time. - // BSActor.RemoveBodyDependencies() - public override void RemoveBodyDependencies() + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { // Nothing to do for the hoverer since it is all software at pre-step action time. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs index 7a791ec..b3806e1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs @@ -89,8 +89,8 @@ public class BSActorSetTorque : BSActor // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. // Called at taint-time. - // BSActor.RemoveBodyDependencies() - public override void RemoveBodyDependencies() + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { // Nothing to do for the hoverer since it is all software at pre-step action time. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index 12a8817..5e3f1c4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -106,9 +106,9 @@ public class BSActorCollection { ForEachActor(a => a.Refresh()); } - public void RemoveBodyDependencies() + public void RemoveDependencies() { - ForEachActor(a => a.RemoveBodyDependencies()); + ForEachActor(a => a.RemoveDependencies()); } } @@ -154,7 +154,7 @@ public abstract class BSActor public abstract void Refresh(); // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). // Register a prestep action to restore physical requirements before the next simulation step. - public abstract void RemoveBodyDependencies(); + public abstract void RemoveDependencies(); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index a0d58d3..da23a262 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -123,8 +123,8 @@ public sealed class BSCharacter : BSPhysObject { PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); - PhysShape.Clear(); + PhysShape.Dereference(PhysicsScene); + PhysShape = new BSShapeNull(); }); } @@ -146,8 +146,8 @@ public sealed class BSCharacter : BSPhysObject Flying = _flying; PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); - PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); - PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); + PhysicsScene.PE.SetMargin(PhysShape.physShapeInfo, PhysicsScene.Params.collisionMargin); + PhysicsScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); if (BSParam.CcdMotionThreshold > 0f) { @@ -205,9 +205,9 @@ public sealed class BSCharacter : BSPhysObject PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() { - if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) + if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) { - PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); + PhysicsScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); UpdatePhysicalMassProperties(RawMass, true); // Make sure this change appears as a property update event PhysicsScene.PE.PushUpdate(PhysBody); @@ -221,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject { set { BaseShape = value; } } - // I want the physics engine to make an avatar capsule - public override BSPhysicsShapeType PreferredPhysicalShape - { - get {return BSPhysicsShapeType.SHAPE_CAPSULE; } - } public override bool Grabbed { set { _grabbed = value; } @@ -381,7 +376,7 @@ public sealed class BSCharacter : BSPhysObject } public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) { - OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); + OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 612c68b..e2e807e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -625,7 +625,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Vehicles report collision events so we know when it's on the ground m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape, m_vehicleMass); + ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); @@ -649,7 +649,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } // BSActor.RemoveBodyDependencies - public override void RemoveBodyDependencies() + public override void RemoveDependencies() { Refresh(); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 4ece1eb..df1dd34 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -93,13 +93,6 @@ public abstract class BSLinkset // to the physical representation is done via the tainting mechenism. protected object m_linksetActivityLock = new Object(); - // Some linksets have a preferred physical shape. - // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. - public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) - { - return BSPhysicsShapeType.SHAPE_UNKNOWN; - } - // We keep the prim's mass in the linkset structure since it could be dependent on other prims public float LinksetMass { get; protected set; } @@ -263,7 +256,7 @@ public abstract class BSLinkset // This is called when the root body is changing. // Returns 'true' of something was actually removed and would need restoring // Called at taint-time!! - public abstract bool RemoveBodyDependencies(BSPrimLinkable child); + public abstract bool RemoveDependencies(BSPrimLinkable child); // ================================================================ protected virtual float ComputeLinksetMass() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e05562a..a20bbc3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -98,19 +98,6 @@ public sealed class BSLinksetCompound : BSLinkset { } - // For compound implimented linksets, if there are children, use compound shape for the root. - public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) - { - // Returning 'unknown' means we don't have a preference. - BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - if (IsRoot(requestor) && HasAnyChildren) - { - ret = BSPhysicsShapeType.SHAPE_COMPOUND; - } - // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); - return ret; - } - // When physical properties are changed the linkset needs to recalculate // its internal properties. public override void Refresh(BSPrimLinkable requestor) @@ -218,22 +205,22 @@ public sealed class BSLinksetCompound : BSLinkset // and that is caused by us updating the object. if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) { - // Find the physical instance of the child - if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) + // Find the physical instance of the child + if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) { // It is possible that the linkset is still under construction and the child is not yet // inserted into the compound shape. A rebuild of the linkset in a pre-step action will // build the whole thing with the new position or rotation. // The index must be checked because Bullet references the child array but does no validity // checking of the child index passed. - int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); + int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); if (updated.LinksetChildIndex < numLinksetChildren) { - BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); + BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); if (linksetChildShape.HasPhysicalShape) { // Found the child shape within the compound shape - PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, + PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, updated.RawPosition - LinksetRoot.RawPosition, updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), true /* shouldRecalculateLocalAabb */); @@ -278,7 +265,7 @@ public sealed class BSLinksetCompound : BSLinkset // Since we don't keep in world relationships, do nothing unless it's a child changing. // Returns 'true' of something was actually removed and would need restoring // Called at taint-time!! - public override bool RemoveBodyDependencies(BSPrimLinkable child) + public override bool RemoveDependencies(BSPrimLinkable child) { bool ret = false; @@ -404,11 +391,12 @@ public sealed class BSLinksetCompound : BSLinkset { try { + /* // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) Rebuilding = true; // Cause the root shape to be rebuilt as a compound object with just the root in it - LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); + LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime ); // The center of mass for the linkset is the geometric center of the group. // Compute a displacement for each component so it is relative to the center-of-mass. @@ -430,10 +418,10 @@ public sealed class BSLinksetCompound : BSLinkset LinksetRoot.ForcePosition = LinksetRoot.RawPosition; // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM - PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, + PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, 0 /* childIndex , -centerDisplacement, OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, - false /* shouldRecalculateLocalAabb (is done later after linkset built) */); + false /* shouldRecalculateLocalAabb (is done later after linkset built) ); DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); @@ -501,6 +489,7 @@ public sealed class BSLinksetCompound : BSLinkset // Enable the physical position updator to return the position and rotation of the root shape PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); + */ } finally { @@ -508,7 +497,7 @@ public sealed class BSLinksetCompound : BSLinkset } // See that the Aabb surrounds the new shape - PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); + PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); } } } \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 6d252ca..1811772 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset // up to rebuild the constraints before the next simulation step. // Returns 'true' of something was actually removed and would need restoring // Called at taint-time!! - public override bool RemoveBodyDependencies(BSPrimLinkable child) + public override bool RemoveDependencies(BSPrimLinkable child) { bool ret = false; - DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", + DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); lock (m_linksetActivityLock) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 309d004..b6eb619 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -88,7 +88,7 @@ public abstract class BSPhysObject : PhysicsActor // We don't have any physical representation yet. PhysBody = new BulletBody(localID); - PhysShape = new BulletShape(); + PhysShape = new BSShapeNull(); PrimAssetState = PrimAssetCondition.Unknown; @@ -138,7 +138,7 @@ public abstract class BSPhysObject : PhysicsActor // Reference to the physical body (btCollisionObject) of this object public BulletBody PhysBody; // Reference to the physical shape (btCollisionShape) of this object - public BulletShape PhysShape; + public BSShape PhysShape; // The physical representation of the prim might require an asset fetch. // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. @@ -151,13 +151,6 @@ public abstract class BSPhysObject : PhysicsActor // The objects base shape information. Null if not a prim type shape. public PrimitiveBaseShape BaseShape { get; protected set; } - // Some types of objects have preferred physical representations. - // Returns SHAPE_UNKNOWN if there is no preference. - public virtual BSPhysicsShapeType PreferredPhysicalShape - { - get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } - } - // When the physical properties are updated, an EntityProperty holds the update values. // Keep the current and last EntityProperties to enable computation of differences // between the current update and the previous values. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 4bc266b..5d12338 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -134,8 +134,8 @@ public class BSPrim : BSPhysObject // If there are physical body and shape, release my use of same. PhysicsScene.Shapes.DereferenceBody(PhysBody, null); PhysBody.Clear(); - PhysicsScene.Shapes.DereferenceShape(PhysShape, null); - PhysShape.Clear(); + PhysShape.Dereference(PhysicsScene); + PhysShape = new BSShapeNull(); }); } @@ -161,25 +161,13 @@ public class BSPrim : BSPhysObject ForceBodyShapeRebuild(false); } } - // 'unknown' says to choose the best type - public override BSPhysicsShapeType PreferredPhysicalShape - { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } } - public override bool ForceBodyShapeRebuild(bool inTaintTime) { - if (inTaintTime) + PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() { _mass = CalculateMass(); // changing the shape changes the mass CreateGeomAndObject(true); - } - else - { - PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate() - { - _mass = CalculateMass(); // changing the shape changes the mass - CreateGeomAndObject(true); - }); - } + }); return true; } public override bool Grabbed { @@ -462,7 +450,7 @@ public class BSPrim : BSPhysObject Gravity = ComputeGravity(Buoyancy); PhysicsScene.PE.SetGravity(PhysBody, Gravity); - Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); + Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); PhysicsScene.PE.UpdateInertiaTensor(PhysBody); @@ -805,7 +793,8 @@ public class BSPrim : BSPhysObject PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", - LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); + LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), + CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); } // "Making dynamic" means changing to and from static. @@ -1463,12 +1452,13 @@ public class BSPrim : BSPhysObject // Create the correct physical representation for this type of object. // Updates base.PhysBody and base.PhysShape with the new information. // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. - PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) + PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, delegate(BulletBody pBody, BulletShape pShape) { // Called if the current prim body is about to be destroyed. // Remove all the physical dependencies on the old body. // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) - RemoveBodyDependencies(); + // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. + RemoveDependencies(); }); // Make sure the properties are set on the new object @@ -1477,9 +1467,9 @@ public class BSPrim : BSPhysObject } // Called at taint-time - protected virtual void RemoveBodyDependencies() + protected virtual void RemoveDependencies() { - PhysicalActors.RemoveBodyDependencies(); + PhysicalActors.RemoveDependencies(); } // The physics engine says that properties have updated. Update same and inform diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 28242d4..81104ec 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -61,9 +61,6 @@ public class BSPrimLinkable : BSPrimDisplaced base.Destroy(); } - public override BSPhysicsShapeType PreferredPhysicalShape - { get { return Linkset.PreferredPhysicalShape(this); } } - public override void link(Manager.PhysicsActor obj) { BSPrimLinkable parent = obj as BSPrimLinkable; @@ -149,10 +146,10 @@ public class BSPrimLinkable : BSPrimDisplaced } // Body is being taken apart. Remove physical dependencies and schedule a rebuild. - protected override void RemoveBodyDependencies() + protected override void RemoveDependencies() { - Linkset.RemoveBodyDependencies(this); - base.RemoveBodyDependencies(); + Linkset.RemoveDependencies(this); + base.RemoveDependencies(); } public override void UpdateProperties(EntityProperties entprop) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 0f9b3c3..3c23509 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -38,38 +38,15 @@ public sealed class BSShapeCollection : IDisposable { private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; - private BSScene PhysicsScene { get; set; } + private BSScene m_physicsScene { get; set; } private Object m_collectionActivityLock = new Object(); - // Description of a Mesh - private struct MeshDesc - { - public BulletShape shape; - public int referenceCount; - public DateTime lastReferenced; - public UInt64 shapeKey; - } - - // Description of a hull. - // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. - private struct HullDesc - { - public BulletShape shape; - public int referenceCount; - public DateTime lastReferenced; - public UInt64 shapeKey; - } - - // The sharable set of meshes and hulls. Indexed by their shape hash. - private Dictionary Meshes = new Dictionary(); - private Dictionary Hulls = new Dictionary(); - private bool DDetail = false; public BSShapeCollection(BSScene physScene) { - PhysicsScene = physScene; + m_physicsScene = physScene; // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) // While detailed debugging is still active, this is better than commenting out all the // DetailLog statements. When debugging slows down, this and the protected logging @@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable // Mostly used for changing bodies out from under Linksets. // Useful for other cases where parameters need saving. // Passing 'null' says no callback. - public delegate void ShapeDestructionCallback(BulletShape shape); - public delegate void BodyDestructionCallback(BulletBody body); + public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape); // Called to update/change the body and shape for an object. - // First checks the shape and updates that if necessary then makes - // sure the body is of the right type. + // The object has some shape and body on it. Here we decide if that is the correct shape + // for the current state of the object (static/dynamic/...). + // If bodyCallback is not null, it is called if either the body or the shape are changed + // so dependencies (like constraints) can be removed before the physical object is dereferenced. // Return 'true' if either the body or the shape changed. - // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before - // the current shape or body is destroyed. This allows the caller to remove any - // higher level dependencies on the shape or body. Mostly used for LinkSets to - // remove the physical constraints before the body is destroyed. - // Called at taint-time!! - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, - ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) + // Called at taint-time. + public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) { - PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); + m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); bool ret = false; @@ -111,12 +84,12 @@ public sealed class BSShapeCollection : IDisposable // Do we have the correct geometry for this type of object? // Updates prim.BSShape with information/pointers to shape. // Returns 'true' of BSShape is changed to a new shape. - bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); + bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); // If we had to select a new shape geometry for the object, // rebuild the body around it. // Updates prim.BSBody with information/pointers to requested body // Returns 'true' if BSBody was changed. - bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); + bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); ret = newGeom || newBody; } DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", @@ -127,271 +100,20 @@ public sealed class BSShapeCollection : IDisposable public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) { - return GetBodyAndShape(forceRebuild, sim, prim, null, null); - } - - // Track another user of a body. - // We presume the caller has allocated the body. - // Bodies only have one user so the body is just put into the world if not already there. - private void ReferenceBody(BulletBody body) - { - lock (m_collectionActivityLock) - { - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); - if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) - { - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); - } - } - } - - // Release the usage of a body. - // Called when releasing use of a BSBody. BSShape is handled separately. - // Called in taint time. - public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback ) - { - if (!body.HasPhysicalBody) - return; - - PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); - - lock (m_collectionActivityLock) - { - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); - // If the caller needs to know the old body is going away, pass the event up. - if (bodyCallback != null) bodyCallback(body); - - // Removing an object not in the world is a NOOP - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); - - // Zero any reference to the shape so it is not freed when the body is deleted. - PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); - PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); - } - } - - // Track the datastructures and use count for a shape. - // When creating a hull, this is called first to reference the mesh - // and then again to reference the hull. - // Meshes and hulls for the same shape have the same hash key. - // NOTE that native shapes are not added to the mesh list or removed. - // Returns 'true' if this is the initial reference to the shape. Otherwise reused. - public bool ReferenceShape(BulletShape shape) - { - bool ret = false; - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_MESH: - MeshDesc meshDesc; - if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) - { - // There is an existing instance of this mesh. - meshDesc.referenceCount++; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); - } - else - { - // This is a new reference to a mesh - meshDesc.shape = shape.Clone(); - meshDesc.shapeKey = shape.shapeKey; - // We keep a reference to the underlying IMesh data so a hull can be built - meshDesc.referenceCount = 1; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); - ret = true; - } - meshDesc.lastReferenced = System.DateTime.Now; - Meshes[shape.shapeKey] = meshDesc; - break; - case BSPhysicsShapeType.SHAPE_HULL: - HullDesc hullDesc; - if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) - { - // There is an existing instance of this hull. - hullDesc.referenceCount++; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); - } - else - { - // This is a new reference to a hull - hullDesc.shape = shape.Clone(); - hullDesc.shapeKey = shape.shapeKey; - hullDesc.referenceCount = 1; - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", - BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); - ret = true; - - } - hullDesc.lastReferenced = System.DateTime.Now; - Hulls[shape.shapeKey] = hullDesc; - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - // Native shapes are not tracked and they don't go into any list - break; - } - return ret; - } - - // Release the usage of a shape. - public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - if (!shape.HasPhysicalShape) - return; - - PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape"); - - if (shape.HasPhysicalShape) - { - if (shape.isNativeShape) - { - // Native shapes are not tracked and are released immediately - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}", - BSScene.DetailLogZero, shape.AddrString); - if (shapeCallback != null) shapeCallback(shape); - PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); - } - else - { - switch (shape.type) - { - case BSPhysicsShapeType.SHAPE_HULL: - DereferenceHull(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_MESH: - DereferenceMesh(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_COMPOUND: - DereferenceCompound(shape, shapeCallback); - break; - case BSPhysicsShapeType.SHAPE_UNKNOWN: - break; - default: - break; - } - } - } - } - - // Count down the reference count for a mesh shape - // Called at taint-time. - private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - MeshDesc meshDesc; - if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) - { - meshDesc.referenceCount--; - // TODO: release the Bullet storage - if (shapeCallback != null) shapeCallback(shape); - meshDesc.lastReferenced = System.DateTime.Now; - Meshes[shape.shapeKey] = meshDesc; - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", - BSScene.DetailLogZero, shape, meshDesc.referenceCount); - - } + return GetBodyAndShape(forceRebuild, sim, prim, null); } - // Count down the reference count for a hull shape - // Called at taint-time. - private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) + // If the existing prim's shape is to be replaced, remove the tie to the existing shape + // before replacing it. + private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { - HullDesc hullDesc; - if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) + if (prim.PhysShape.HasPhysicalShape) { - hullDesc.referenceCount--; - // TODO: release the Bullet storage (aging old entries?) - - // Tell upper layers that, if they have dependencies on this shape, this link is going away - if (shapeCallback != null) shapeCallback(shape); - - hullDesc.lastReferenced = System.DateTime.Now; - Hulls[shape.shapeKey] = hullDesc; - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", - BSScene.DetailLogZero, shape, hullDesc.referenceCount); - } - } - - // Remove a reference to a compound shape. - // Taking a compound shape apart is a little tricky because if you just delete the - // physical shape, it will free all the underlying children. We can't do that because - // they could be shared. So, this removes each of the children from the compound and - // dereferences them separately before destroying the compound collision object itself. - // Called at taint-time. - private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) - { - if (!PhysicsScene.PE.IsCompound(shape)) - { - // Failed the sanity check!! - PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", - LogHeader, shape.type, shape.AddrString); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", - BSScene.DetailLogZero, shape.type, shape.AddrString); - return; - } - - int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); - - for (int ii = numChildren - 1; ii >= 0; ii--) - { - BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); - DereferenceAnonCollisionShape(childShape); - } - PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); - } - - // Sometimes we have a pointer to a collision shape but don't know what type it is. - // Figure out type and call the correct dereference routine. - // Called at taint-time. - private void DereferenceAnonCollisionShape(BulletShape shapeInfo) - { - MeshDesc meshDesc; - HullDesc hullDesc; - - if (TryGetMeshByPtr(shapeInfo, out meshDesc)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; - shapeInfo.shapeKey = meshDesc.shapeKey; - } - else - { - if (TryGetHullByPtr(shapeInfo, out hullDesc)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; - shapeInfo.shapeKey = hullDesc.shapeKey; - } - else - { - if (PhysicsScene.PE.IsCompound(shapeInfo)) - { - shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; - } - else - { - if (PhysicsScene.PE.IsNativeShape(shapeInfo)) - { - shapeInfo.isNativeShape = true; - shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) - } - } - } - } - - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); - - if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) - { - DereferenceShape(shapeInfo, null); - } - else - { - PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", - LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); + if (shapeCallback != null) + shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); + prim.PhysShape.Dereference(m_physicsScene); } + prim.PhysShape = new BSShapeNull(); } // Create the geometry information in Bullet for later use. @@ -402,40 +124,7 @@ public sealed class BSShapeCollection : IDisposable // Info in prim.BSShape is updated to the new shape. // Returns 'true' if the geometry was rebuilt. // Called at taint-time! - private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - bool ret = false; - bool haveShape = false; - - if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // an avatar capsule is close to a native shape (it is not shared) - GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); - ret = true; - haveShape = true; - } - - // Compound shapes are handled special as they are rebuilt from scratch. - // This isn't too great a hardship since most of the child shapes will have already been created. - if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) - { - ret = GetReferenceToCompoundShape(prim, shapeCallback); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); - haveShape = true; - } - - if (!haveShape) - { - ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); - } - - return ret; - } - - // Create a mesh, hull or native shape. - // Return 'true' if the prim's shape was changed. - public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) + private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { bool ret = false; bool haveShape = false; @@ -443,19 +132,21 @@ public sealed class BSShapeCollection : IDisposable PrimitiveBaseShape pbs = prim.BaseShape; // If the prim attributes are simple, this could be a simple Bullet native shape + // Native shapes work whether to object is static or physical. if (!haveShape && nativeShapePossible && pbs != null - && !pbs.SculptEntry - && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) + && PrimHasNoCuts(pbs) + && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) + ) { // Get the scale of any existing shape so we can see if the new shape is same native type and same size. OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; if (prim.PhysShape.HasPhysicalShape) - scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); + scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", - prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); + prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); // It doesn't look like Bullet scales native spheres so make sure the scales are all equal if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) @@ -463,26 +154,28 @@ public sealed class BSShapeCollection : IDisposable { haveShape = true; if (forceRebuild - || prim.Scale != scaleOfExistingShape - || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE - ) + || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE + ) { - ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, - FixedShapeKey.KEY_SPHERE, shapeCallback); + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", prim.LocalID, forceRebuild, ret, prim.PhysShape); } + // If we didn't make a sphere, maybe a box will work. if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) { haveShape = true; if (forceRebuild || prim.Scale != scaleOfExistingShape - || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX + || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX ) { - ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, - FixedShapeKey.KEY_BOX, shapeCallback); + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", prim.LocalID, forceRebuild, ret, prim.PhysShape); @@ -511,7 +204,7 @@ public sealed class BSShapeCollection : IDisposable } // return 'true' if the prim's shape was changed. - public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) + private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { bool ret = false; @@ -520,537 +213,70 @@ public sealed class BSShapeCollection : IDisposable if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) { // Update prim.BSShape to reference a hull of this shape. - ret = GetReferenceToHull(prim, shapeCallback); + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); + prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X")); } else { - ret = GetReferenceToMesh(prim, shapeCallback); + // Update prim.BSShape to reference a mesh of this shape. + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); + prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X")); } return ret; } - // Creates a native shape and assignes it to prim.BSShape. - // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). - private bool GetReferenceToNativeShape(BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, - ShapeDestructionCallback shapeCallback) - { - // release any previous shape - DereferenceShape(prim.PhysShape, shapeCallback); - - BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); - - // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. - if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", - prim.LocalID, newShape, prim.Scale); - - // native shapes are scaled by Bullet - prim.PhysShape = newShape; - return true; - } - - private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType, - FixedShapeKey shapeKey) - { - BulletShape newShape; - // Need to make sure the passed shape information is for the native type. - ShapeData nativeShapeData = new ShapeData(); - nativeShapeData.Type = shapeType; - nativeShapeData.ID = prim.LocalID; - nativeShapeData.Scale = prim.Scale; - nativeShapeData.Size = prim.Scale; // unneeded, I think. - nativeShapeData.MeshKey = (ulong)shapeKey; - nativeShapeData.HullKey = (ulong)shapeKey; - - if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) - { - - newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); - if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); - } - else - { - // Native shapes are scaled in Bullet so set the scaling to the size - newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); - - } - if (!newShape.HasPhysicalShape) - { - PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", - LogHeader, prim.LocalID, shapeType); - } - newShape.shapeKey = (System.UInt64)shapeKey; - newShape.isNativeShape = true; - - return newShape; - } - - // Builds a mesh shape in the physical world and updates prim.BSShape. - // Dereferences previous shape in BSShape and adds a reference for this new shape. - // Returns 'true' of a mesh was actually built. Otherwise . - // Called at taint-time! - private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - BulletShape newShape = new BulletShape(); - - float lod; - System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - // if this new shape is the same as last time, don't recreate the mesh - if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) - return false; - - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); - - // Since we're recreating new, get rid of the reference to the previous shape - DereferenceShape(prim.PhysShape, shapeCallback); - - newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod); - // Take evasive action if the mesh was not constructed. - newShape = VerifyMeshCreated(PhysicsScene, newShape, prim); - - ReferenceShape(newShape); - - prim.PhysShape = newShape; - - return true; // 'true' means a new shape has been added to this prim - } - - private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + // Track another user of a body. + // We presume the caller has allocated the body. + // Bodies only have one user so the body is just put into the world if not already there. + private void ReferenceBody(BulletBody body) { - BulletShape newShape = new BulletShape(); - - MeshDesc meshDesc; - if (Meshes.TryGetValue(newMeshKey, out meshDesc)) - { - // If the mesh has already been built just use it. - newShape = meshDesc.shape.Clone(); - } - else + lock (m_collectionActivityLock) { - IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, - false, // say it is not physical so a bounding box is not built - false // do not cache the mesh and do not use previously built versions - ); - - if (meshData != null) + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); + if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) { - - int[] indices = meshData.getIndexListAsInt(); - int realIndicesIndex = indices.Length; - float[] verticesAsFloats = meshData.getVertexListAsFloat(); - - if (BSParam.ShouldRemoveZeroWidthTriangles) - { - // Remove degenerate triangles. These are triangles with two of the vertices - // are the same. This is complicated by the problem that vertices are not - // made unique in sculpties so we have to compare the values in the vertex. - realIndicesIndex = 0; - for (int tri = 0; tri < indices.Length; tri += 3) - { - // Compute displacements into vertex array for each vertex of the triangle - int v1 = indices[tri + 0] * 3; - int v2 = indices[tri + 1] * 3; - int v3 = indices[tri + 2] * 3; - // Check to see if any two of the vertices are the same - if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] - && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] - && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) - || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] - && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] - && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) - || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] - && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] - && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) - ) - { - // None of the vertices of the triangles are the same. This is a good triangle; - indices[realIndicesIndex + 0] = indices[tri + 0]; - indices[realIndicesIndex + 1] = indices[tri + 1]; - indices[realIndicesIndex + 2] = indices[tri + 2]; - realIndicesIndex += 3; - } - } - } - DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", - BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); - - if (realIndicesIndex != 0) - { - newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, - realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); - } - else - { - PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", - LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name); - } + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); } } - newShape.shapeKey = newMeshKey; - - return newShape; - } - - // See that hull shape exists in the physical world and update prim.BSShape. - // We could be creating the hull because scale changed or whatever. - // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance. - private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - BulletShape newShape; - - float lod; - System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - // if the hull hasn't changed, don't rebuild it - if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) - return false; - - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); - - // Remove usage of the previous shape. - DereferenceShape(prim.PhysShape, shapeCallback); - - newShape = CreatePhysicalHull(prim, newHullKey, prim.BaseShape, prim.Size, lod); - // It might not have been created if we're waiting for an asset. - newShape = VerifyMeshCreated(PhysicsScene, newShape, prim); - - ReferenceShape(newShape); - - prim.PhysShape = newShape; - return true; // 'true' means a new shape has been added to this prim } - List m_hulls; - private BulletShape CreatePhysicalHull(BSPhysObject prim, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + // Release the usage of a body. + // Called when releasing use of a BSBody. BSShape is handled separately. + // Called in taint time. + public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) { + if (!body.HasPhysicalBody) + return; - BulletShape newShape = new BulletShape(); - IntPtr hullPtr = IntPtr.Zero; + m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); - HullDesc hullDesc; - if (Hulls.TryGetValue(newHullKey, out hullDesc)) - { - // If the hull shape already has been created, just use the one shared instance. - newShape = hullDesc.shape.Clone(); - } - else + lock (m_collectionActivityLock) { - if (BSParam.ShouldUseBulletHACD) - { - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); - MeshDesc meshDesc; - if (!Meshes.TryGetValue(newHullKey, out meshDesc)) - { - // That's odd because the mesh should have been created before the hull - // but, since it doesn't exist, create it. - newShape = CreatePhysicalMesh(prim, newHullKey, prim.BaseShape, prim.Size, lod); - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,noMeshBuiltNew,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); - - if (newShape.HasPhysicalShape) - { - ReferenceShape(newShape); - Meshes.TryGetValue(newHullKey, out meshDesc); - } - } - if (meshDesc.shape.HasPhysicalShape) - { - HACDParams parms; - parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; - parms.minClusters = BSParam.BHullMinClusters; - parms.compacityWeight = BSParam.BHullCompacityWeight; - parms.volumeWeight = BSParam.BHullVolumeWeight; - parms.concavity = BSParam.BHullConcavity; - parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); - parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); - parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); - parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); - - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); - newShape = PhysicsScene.PE.BuildHullShapeFromMesh(PhysicsScene.World, meshDesc.shape, parms); - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); - } - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); - } - if (!newShape.HasPhysicalShape) - { - // Build a new hull in the physical world. - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); - if (meshData != null) - { - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) - { - convIndices.Add(indices[ii]); - } - foreach (OMV.Vector3 vv in vertices) - { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); - } - - uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; - if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) - { - // Simple primitive shapes we know are convex so they are better implemented with - // fewer hulls. - // Check for simple shape (prim without cuts) and reduce split parameter if so. - if (PrimHasNoCuts(pbs)) - { - maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; - } - } - - // setup and do convex hull conversion - m_hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - dcomp.mDepth = maxDepthSplit; - dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; - dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; - dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; - dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", - BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); - - // Convert the vertices and indices for passing to unmanaged. - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = m_hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in m_hulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in m_hulls) - { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) - { - verts[kk++] = ff; - } - - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) - { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; - } - } - // create the hull data structure in Bullet - newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); - } - } - newShape.shapeKey = newHullKey; - } - - return newShape; - } - - // Callback from convex hull creater with a newly created hull. - // Just add it to our collection of hulls for this shape. - private void HullReturn(ConvexResult result) - { - m_hulls.Add(result); - return; - } - - // Compound shapes are always built from scratch. - // This shouldn't be to bad since most of the parts will be meshes that had been built previously. - private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) - { - // Remove reference to the old shape - // Don't need to do this as the shape is freed when the new root shape is created below. - // DereferenceShape(prim.PhysShape, true, shapeCallback); - - BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); - - // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. - CreateGeomMeshOrHull(prim, shapeCallback); - PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); - if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", - prim.LocalID, cShape, prim.PhysShape); - - prim.PhysShape = cShape; - - return true; - } - - // Create a hash of all the shape parameters to be used as a key - // for this particular shape. - public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) - { - // level of detail based on size and type of the object - float lod = BSParam.MeshLOD; - - // prims with curvy internal cuts need higher lod - if (pbs.HollowShape == HollowShape.Circle) - lod = BSParam.MeshCircularLOD; - - if (pbs.SculptEntry) - lod = BSParam.SculptLOD; - - // Mega prims usually get more detail because one can interact with shape approximations at this size. - float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); - if (maxAxis > BSParam.MeshMegaPrimThreshold) - lod = BSParam.MeshMegaPrimLOD; - - retLod = lod; - return pbs.GetMeshKey(size, lod); - } - // For those who don't want the LOD - public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) - { - float lod; - return ComputeShapeKey(size, pbs, out lod); - } - - // The creation of a mesh or hull can fail if an underlying asset is not available. - // There are two cases: 1) the asset is not in the cache and it needs to be fetched; - // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). - // The first case causes the asset to be fetched. The second case requires - // us to not loop forever. - // Called after creating a physical mesh or hull. If the physical shape was created, - // just return. - public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) - { - // If the shape was successfully created, nothing more to do - if (newShape.HasPhysicalShape) - return newShape; + if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); + // If the caller needs to know the old body is going away, pass the event up. + if (bodyCallback != null) + bodyCallback(body, null); - // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been - // fetched but we end up here again, the meshing of the asset must have failed. - // Prevent trying to keep fetching the mesh by declaring failure. - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) - { - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", - LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); - } - else - { - // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset - if (prim.BaseShape.SculptEntry - && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed - && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting - && prim.BaseShape.SculptTexture != OMV.UUID.Zero - ) - { - physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); - // Multiple requestors will know we're waiting for this asset - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; + // Removing an object not in the world is a NOOP + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); - BSPhysObject xprim = prim; - Util.FireAndForget(delegate - { - RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; - if (assetProvider != null) - { - BSPhysObject yprim = xprim; // probably not necessary, but, just in case. - assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) - { - bool assetFound = false; - string mismatchIDs = String.Empty; // DEBUG DEBUG - if (asset != null && yprim.BaseShape.SculptEntry) - { - if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) - { - yprim.BaseShape.SculptData = asset.Data; - // This will cause the prim to see that the filler shape is not the right - // one and try again to build the object. - // No race condition with the normal shape setting since the rebuild is at taint time. - yprim.ForceBodyShapeRebuild(false /* inTaintTime */); - assetFound = true; - } - else - { - mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; - } - } - if (assetFound) - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; - else - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", - yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); + // Zero any reference to the shape so it is not freed when the body is deleted. + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); - }); - } - else - { - xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", - LogHeader, physicsScene.Name); - } - }); - } - else - { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) - { - physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", - LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); - } - } + m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); } - - // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. - BulletShape fillinShape = physicsScene.Shapes.BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); - - return fillinShape; } // Create a body object in Bullet. // Updates prim.BSBody with the information about the new body if one is created. // Returns 'true' if an object was actually created. // Called at taint-time. - private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) + private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) { bool ret = false; @@ -1061,7 +287,7 @@ public sealed class BSShapeCollection : IDisposable // If not a solid object, body is a GhostObject. Otherwise a RigidBody. if (!mustRebuild) { - CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); + CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) { @@ -1079,12 +305,12 @@ public sealed class BSShapeCollection : IDisposable BulletBody aBody; if (prim.IsSolid) { - aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); + aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); } else { - aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); + aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); } @@ -1098,46 +324,10 @@ public sealed class BSShapeCollection : IDisposable return ret; } - private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) - { - bool ret = false; - MeshDesc foundDesc = new MeshDesc(); - foreach (MeshDesc md in Meshes.Values) - { - if (md.shape.ReferenceSame(shape)) - { - foundDesc = md; - ret = true; - break; - } - - } - outDesc = foundDesc; - return ret; - } - - private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) - { - bool ret = false; - HullDesc foundDesc = new HullDesc(); - foreach (HullDesc hd in Hulls.Values) - { - if (hd.shape.ReferenceSame(shape)) - { - foundDesc = hd; - ret = true; - break; - } - - } - outDesc = foundDesc; - return ret; - } - private void DetailLog(string msg, params Object[] args) { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); + if (m_physicsScene.PhysicsLogging.Enabled) + m_physicsScene.DetailLog(msg, args); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index e427dbc..a7b3f02 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -39,6 +39,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public abstract class BSShape { + private static string LogHeader = "[BULLETSIM SHAPE]"; + public int referenceCount { get; set; } public DateTime lastReferenced { get; set; } public BulletShape physShapeInfo { get; set; } @@ -56,49 +58,6 @@ public abstract class BSShape physShapeInfo = pShape; } - // Get a reference to a physical shape. Create if it doesn't exist - public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - BSShape ret = null; - - if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) - { - // an avatar capsule is close to a native shape (it is not shared) - ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, - FixedShapeKey.KEY_CAPSULE); - physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); - } - - // Compound shapes are handled special as they are rebuilt from scratch. - // This isn't too great a hardship since most of the child shapes will have already been created. - if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) - { - // Getting a reference to a compound shape gets you the compound shape with the root prim shape added - ret = BSShapeCompound.GetReference(physicsScene, prim); - physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); - } - - // Avatars have their own unique shape - if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR) - { - // Getting a reference to a compound shape gets you the compound shape with the root prim shape added - ret = BSShapeAvatar.GetReference(prim); - physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret); - } - - if (ret == null) - ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); - - return ret; - } - private static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - // TODO: work needed here!! - BSShapeMesh.GetReference(physicsScene, forceRebuild, prim); - BSShapeHull.GetReference(physicsScene, forceRebuild, prim); - return null; - } - // Called when this shape is being used again. public virtual void IncrementReference() { @@ -116,6 +75,27 @@ public abstract class BSShape // Release the use of a physical shape. public abstract void Dereference(BSScene physicsScene); + // Return 'true' if there is an allocated physics physical shape under this class instance. + public virtual bool HasPhysicalShape + { + get + { + if (physShapeInfo != null) + return physShapeInfo.HasPhysicalShape; + return false; + } + } + public virtual BSPhysicsShapeType ShapeType + { + get + { + BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) + ret = physShapeInfo.shapeType; + return ret; + } + } + // Returns a string for debugging that uniquily identifies the memory used by this instance public virtual string AddrString { @@ -132,6 +112,119 @@ public abstract class BSShape buff.Append(">"); return buff.ToString(); } + + // Create a hash of all the shape parameters to be used as a key for this particular shape. + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) + { + // level of detail based on size and type of the object + float lod = BSParam.MeshLOD; + if (pbs.SculptEntry) + lod = BSParam.SculptLOD; + + // Mega prims usually get more detail because one can interact with shape approximations at this size. + float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); + if (maxAxis > BSParam.MeshMegaPrimThreshold) + lod = BSParam.MeshMegaPrimLOD; + + retLod = lod; + return pbs.GetMeshKey(size, lod); + } + + // The creation of a mesh or hull can fail if an underlying asset is not available. + // There are two cases: 1) the asset is not in the cache and it needs to be fetched; + // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). + // The first case causes the asset to be fetched. The second case requires + // us to not loop forever. + // Called after creating a physical mesh or hull. If the physical shape was created, + // just return. + public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) + { + // If the shape was successfully created, nothing more to do + if (newShape.HasPhysicalShape) + return newShape; + + // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been + // fetched but we end up here again, the meshing of the asset must have failed. + // Prevent trying to keep fetching the mesh by declaring failure. + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", + LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); + } + else + { + // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset + if (prim.BaseShape.SculptEntry + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting + && prim.BaseShape.SculptTexture != OMV.UUID.Zero + ) + { + physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); + // Multiple requestors will know we're waiting for this asset + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; + + BSPhysObject xprim = prim; + Util.FireAndForget(delegate + { + RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; + if (assetProvider != null) + { + BSPhysObject yprim = xprim; // probably not necessary, but, just in case. + assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) + { + bool assetFound = false; + string mismatchIDs = String.Empty; // DEBUG DEBUG + if (asset != null && yprim.BaseShape.SculptEntry) + { + if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) + { + yprim.BaseShape.SculptData = asset.Data; + // This will cause the prim to see that the filler shape is not the right + // one and try again to build the object. + // No race condition with the normal shape setting since the rebuild is at taint time. + yprim.ForceBodyShapeRebuild(false /* inTaintTime */); + assetFound = true; + } + else + { + mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; + } + } + if (assetFound) + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; + else + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); + }); + } + else + { + xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", + LogHeader, physicsScene.Name); + } + }); + } + else + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + { + physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", + LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); + } + } + } + + // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. + BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); + + return fillShape.physShapeInfo; + } + } // ============================================================================================================ @@ -199,7 +292,7 @@ public class BSShapeNative : BSShape physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", LogHeader, prim.LocalID, shapeType); } - newShape.type = shapeType; + newShape.shapeType = shapeType; newShape.isNativeShape = true; newShape.shapeKey = (UInt64)shapeKey; return newShape; @@ -219,10 +312,11 @@ public class BSShapeMesh : BSShape public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { float lod; - System.UInt64 newMeshKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); physicsScene.DetailLog("{0},BSShapeMesh,getReference,oldKey={1},newKey={2},size={3},lod={4}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); + prim.LocalID, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"), + newMeshKey.ToString("X"), prim.Size, lod); BSShapeMesh retMesh = new BSShapeMesh(new BulletShape()); lock (Meshes) @@ -238,8 +332,8 @@ public class BSShapeMesh : BSShape BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); // Check to see if mesh was created (might require an asset). - newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); - if (newShape.type == BSPhysicsShapeType.SHAPE_MESH) + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (newShape.shapeType == BSPhysicsShapeType.SHAPE_MESH) { // If a mesh was what was created, remember the built shape for later sharing. Meshes.Add(newMeshKey, retMesh); @@ -360,10 +454,10 @@ public class BSShapeHull : BSShape public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) { float lod; - System.UInt64 newHullKey = BSShapeCollection.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); physicsScene.DetailLog("{0},BSShapeHull,getReference,oldKey={1},newKey={2},size={3},lod={4}", - prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"), prim.Size, lod); + prim.LocalID, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"), newHullKey.ToString("X"), prim.Size, lod); BSShapeHull retHull = new BSShapeHull(new BulletShape()); lock (Hulls) @@ -379,8 +473,8 @@ public class BSShapeHull : BSShape BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); // Check to see if mesh was created (might require an asset). - newShape = BSShapeCollection.VerifyMeshCreated(physicsScene, newShape, prim); - if (newShape.type == BSPhysicsShapeType.SHAPE_MESH) + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (newShape.shapeType == BSPhysicsShapeType.SHAPE_MESH) { // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); @@ -569,7 +663,6 @@ public class BSShapeHull : BSShape } } - // ============================================================================================================ public class BSShapeCompound : BSShape { @@ -589,9 +682,9 @@ public class BSShapeCompound : BSShape { // Failed the sanity check!! physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", - LogHeader, physShapeInfo.type, physShapeInfo.AddrString); + LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", - BSScene.DetailLogZero, physShapeInfo.type, physShapeInfo.AddrString); + BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); return; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs index 8012d91..906e4f9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs @@ -104,11 +104,11 @@ public class BulletShape { public BulletShape() { - type = BSPhysicsShapeType.SHAPE_UNKNOWN; + shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN; shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; isNativeShape = false; } - public BSPhysicsShapeType type; + public BSPhysicsShapeType shapeType; public System.UInt64 shapeKey; public bool isNativeShape; @@ -133,7 +133,7 @@ public class BulletShape buff.Append(") is its center-of-mass - OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition; - if (!disableCOM) // DEBUG DEBUG - { - // Compute a center-of-mass in world coordinates. - centerOfMassW = ComputeLinksetCenterOfMass(); - } + OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); @@ -414,20 +416,7 @@ public sealed class BSLinksetCompound : BSLinkset OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); - // This causes the physical position of the root prim to be offset to accomodate for the displacements - LinksetRoot.ForcePosition = LinksetRoot.RawPosition; - - // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM - PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, 0 /* childIndex , - -centerDisplacement, - OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, - false /* shouldRecalculateLocalAabb (is done later after linkset built) ); - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", - LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", - LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); + // TODO: add phantom root shape to be the center-of-mass // Add a shape for each of the other children in the linkset int memberIndex = 1; @@ -440,56 +429,31 @@ public sealed class BSLinksetCompound : BSLinkset else { cPrim.LinksetChildIndex = memberIndex; + } - if (cPrim.PhysShape.isNativeShape) - { - // A native shape is turned into a hull collision shape because native - // shapes are not shared so we have to hullify it so it will be tracked - // and freed at the correct time. This also solves the scaling problem - // (native shapes scale but hull/meshes are assumed to not be). - // TODO: decide of the native shape can just be used in the compound shape. - // Use call to CreateGeomNonSpecial(). - BulletShape saveShape = cPrim.PhysShape; - cPrim.PhysShape.Clear(); // Don't let the create free the child's shape - PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); - BulletShape newShape = cPrim.PhysShape; - cPrim.PhysShape = saveShape; - - OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; - OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; - PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", - LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); - } - else - { - // For the shared shapes (meshes and hulls), just use the shape in the child. - // The reference count added here will be decremented when the compound shape - // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). - if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) - { - PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", - LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); - } - OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; - OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; - PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", + BSShape childShape = cPrim.PhysShape; + childShape.IncrementReference(); + OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; + OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; + PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); - } - memberIndex++; - } + memberIndex++; + return false; // 'false' says to move onto the next child in the list }); + // Sneak the built compound shape in as the shape of the root prim. + // Note this doesn't touch the root prim's PhysShape so be sure the manage the difference. + PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, LinksetRoot.PhysBody, LinksetShape.physShapeInfo); + // With all of the linkset packed into the root prim, it has the mass of everyone. LinksetMass = ComputeLinksetMass(); LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); // Enable the physical position updator to return the position and rotation of the root shape PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); - */ } finally { -- cgit v1.1 From ad1787770ed02f71feaa002ab689467e187803bb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 28 Apr 2013 21:50:47 -0700 Subject: BulletSim: rename variable 'PhysicsScene' to be either 'PhysScene' or 'm_physicsScene' to match coding conventions and reduce confusion. --- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 112 ++++++------ OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 8 +- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 10 +- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 34 ++-- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 16 +- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 52 +++--- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 188 ++++++++++----------- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 8 +- .../Physics/BulletSPlugin/BSTerrainHeightmap.cs | 28 +-- .../Physics/BulletSPlugin/BSTerrainManager.cs | 56 +++--- .../Region/Physics/BulletSPlugin/BSTerrainMesh.cs | 52 +++--- 11 files changed, 282 insertions(+), 282 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index da23a262..e12fc8e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -95,18 +95,18 @@ public sealed class BSCharacter : BSPhysObject // the avatar seeking to reach the motor's target speed. // This motor runs as a prestep action for the avatar so it will keep the avatar // standing as well as moving. Destruction of the avatar will destroy the pre-step action. - m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName); + m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); PhysicalActors.Add(AvatarMoveActorName, m_moveActor); DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, Density, _avatarVolume, RawMass); // do actual creation in taint time - PhysicsScene.TaintedObject("BSCharacter.create", delegate() + PhysScene.TaintedObject("BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape - PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); + PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); SetPhysicalProperties(); }); @@ -119,18 +119,18 @@ public sealed class BSCharacter : BSPhysObject base.Destroy(); DetailLog("{0},BSCharacter.Destroy", LocalID); - PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() + PhysScene.TaintedObject("BSCharacter.destroy", delegate() { - PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); + PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); PhysBody.Clear(); - PhysShape.Dereference(PhysicsScene); + PhysShape.Dereference(PhysScene); PhysShape = new BSShapeNull(); }); } private void SetPhysicalProperties() { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); ZeroMotion(true); ForcePosition = _position; @@ -145,35 +145,35 @@ public sealed class BSCharacter : BSPhysObject // Needs to be reset especially when an avatar is recreated after crossing a region boundry. Flying = _flying; - PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); - PhysicsScene.PE.SetMargin(PhysShape.physShapeInfo, PhysicsScene.Params.collisionMargin); - PhysicsScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); - PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); + PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); if (BSParam.CcdMotionThreshold > 0f) { - PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); } UpdatePhysicalMassProperties(RawMass, false); // Make so capsule does not fall over - PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); + PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); // The avatar mover sets some parameters. PhysicalActors.Refresh(); - PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); + PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); + PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); - PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); + PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); // Do this after the object has been added to the world PhysBody.collisionType = CollisionType.Avatar; - PhysBody.ApplyCollisionMask(PhysicsScene); + PhysBody.ApplyCollisionMask(PhysScene); } @@ -203,14 +203,14 @@ public sealed class BSCharacter : BSPhysObject DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, Density, _avatarVolume, RawMass); - PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() + PhysScene.TaintedObject("BSCharacter.setSize", delegate() { if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) { - PhysicsScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); UpdatePhysicalMassProperties(RawMass, true); // Make sure this change appears as a property update event - PhysicsScene.PE.PushUpdate(PhysBody); + PhysScene.PE.PushUpdate(PhysBody); } }); @@ -247,24 +247,24 @@ public sealed class BSCharacter : BSPhysObject _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties directly into the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.ClearAllForces(PhysBody); + PhysScene.PE.ClearAllForces(PhysBody); }); } public override void ZeroAngularMotion(bool inTaintTime) { _rotationalVelocity = OMV.Vector3.Zero; - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); - PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); + PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); + PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); // The next also get rid of applied linear force but the linear velocity is untouched. - PhysicsScene.PE.ClearForces(PhysBody); + PhysScene.PE.ClearForces(PhysBody); } }); } @@ -286,7 +286,7 @@ public sealed class BSCharacter : BSPhysObject set { _position = value; - PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() + PhysScene.TaintedObject("BSCharacter.setPosition", delegate() { DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); PositionSanityCheck(); @@ -296,14 +296,14 @@ public sealed class BSCharacter : BSPhysObject } public override OMV.Vector3 ForcePosition { get { - _position = PhysicsScene.PE.GetPosition(PhysBody); + _position = PhysScene.PE.GetPosition(PhysBody); return _position; } set { _position = value; if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); } } } @@ -317,18 +317,18 @@ public sealed class BSCharacter : BSPhysObject bool ret = false; // TODO: check for out of bounds - if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) + if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) { // The character is out of the known/simulated area. // Force the avatar position to be within known. ScenePresence will use the position // plus the velocity to decide if the avatar is moving out of the region. - RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); + RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); return true; } // If below the ground, move the avatar up - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); + float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); if (Position.Z < terrainHeight) { DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); @@ -337,7 +337,7 @@ public sealed class BSCharacter : BSPhysObject } if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) { - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); if (Position.Z < waterHeight) { _position.Z = waterHeight; @@ -358,7 +358,7 @@ public sealed class BSCharacter : BSPhysObject { // The new position value must be pushed into the physics engine but we can't // just assign to "Position" because of potential call loops. - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() + PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() { DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); ForcePosition = _position; @@ -376,8 +376,8 @@ public sealed class BSCharacter : BSPhysObject } public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) { - OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); - PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); + OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); + PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); } public override OMV.Vector3 Force { @@ -385,11 +385,11 @@ public sealed class BSCharacter : BSPhysObject set { RawForce = value; // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); - PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() + PhysScene.TaintedObject("BSCharacter.SetForce", delegate() { DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetObjectForce(PhysBody, RawForce); + PhysScene.PE.SetObjectForce(PhysBody, RawForce); }); } } @@ -432,7 +432,7 @@ public sealed class BSCharacter : BSPhysObject set { RawVelocity = value; // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); - PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() + PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() { if (m_moveActor != null) m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); @@ -445,11 +445,11 @@ public sealed class BSCharacter : BSPhysObject public override OMV.Vector3 ForceVelocity { get { return RawVelocity; } set { - PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); + PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); RawVelocity = value; - PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); - PhysicsScene.PE.Activate(PhysBody, true); + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + PhysScene.PE.Activate(PhysBody, true); } } public override OMV.Vector3 Torque { @@ -479,7 +479,7 @@ public sealed class BSCharacter : BSPhysObject if (_orientation != value) { _orientation = value; - PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() + PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() { ForceOrientation = _orientation; }); @@ -491,7 +491,7 @@ public sealed class BSCharacter : BSPhysObject { get { - _orientation = PhysicsScene.PE.GetOrientation(PhysBody); + _orientation = PhysScene.PE.GetOrientation(PhysBody); return _orientation; } set @@ -500,7 +500,7 @@ public sealed class BSCharacter : BSPhysObject if (PhysBody.HasPhysicalBody) { // _position = PhysicsScene.PE.GetPosition(BSBody); - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); } } } @@ -549,14 +549,14 @@ public sealed class BSCharacter : BSPhysObject public override bool FloatOnWater { set { _floatOnWater = value; - PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() + PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() { if (PhysBody.HasPhysicalBody) { if (_floatOnWater) - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); else - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); } }); } @@ -577,7 +577,7 @@ public sealed class BSCharacter : BSPhysObject public override float Buoyancy { get { return _buoyancy; } set { _buoyancy = value; - PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() + PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() { DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); ForceBuoyancy = _buoyancy; @@ -587,7 +587,7 @@ public sealed class BSCharacter : BSPhysObject public override float ForceBuoyancy { get { return _buoyancy; } set { - PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); + PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); _buoyancy = value; DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); @@ -595,7 +595,7 @@ public sealed class BSCharacter : BSPhysObject float grav = BSParam.Gravity * (1f - _buoyancy); Gravity = new OMV.Vector3(0f, 0f, grav); if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetGravity(PhysBody, Gravity); + PhysScene.PE.SetGravity(PhysBody, Gravity); } } @@ -613,7 +613,7 @@ public sealed class BSCharacter : BSPhysObject public override void AddForce(OMV.Vector3 force, bool pushforce) { // Since this force is being applied in only one step, make this a force per second. - OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; + OMV.Vector3 addForce = force / PhysScene.LastTimeStep; AddForce(addForce, pushforce, false); } private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { @@ -622,13 +622,13 @@ public sealed class BSCharacter : BSPhysObject OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); - PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() + PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() { // Bullet adds this central force to the total force for this tick // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); + PhysScene.PE.ApplyCentralForce(PhysBody, addForce); } }); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index e2e807e..56d2415 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -789,7 +789,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) { lastRememberedHeightPos = pos; - m_knownTerrainHeight = ControllingPrim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); + m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); m_knownHas |= m_knownChangedTerrainHeight; } return m_knownTerrainHeight; @@ -801,7 +801,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if ((m_knownHas & m_knownChangedWaterLevel) == 0) { - m_knownWaterLevel = ControllingPrim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); + m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); m_knownHas |= m_knownChangedWaterLevel; } return (float)m_knownWaterLevel; @@ -1637,8 +1637,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Invoke the detailed logger and output something if it's enabled. private void VDetailLog(string msg, params Object[] args) { - if (ControllingPrim.PhysicsScene.VehicleLoggingEnabled) - ControllingPrim.PhysicsScene.DetailLog(msg, args); + if (ControllingPrim.PhysScene.VehicleLoggingEnabled) + ControllingPrim.PhysScene.DetailLog(msg, args); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index df1dd34..6d0d0eb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -80,7 +80,7 @@ public abstract class BSLinkset public BSPrimLinkable LinksetRoot { get; protected set; } - public BSScene PhysicsScene { get; private set; } + protected BSScene m_physicsScene { get; private set; } static int m_nextLinksetID = 1; public int LinksetID { get; private set; } @@ -115,7 +115,7 @@ public abstract class BSLinkset // We create LOTS of linksets. if (m_nextLinksetID <= 0) m_nextLinksetID = 1; - PhysicsScene = scene; + m_physicsScene = scene; LinksetRoot = parent; m_children = new HashSet(); LinksetMass = parent.RawMass; @@ -158,7 +158,7 @@ public abstract class BSLinkset } // The child is down to a linkset of just itself - return BSLinkset.Factory(PhysicsScene, child); + return BSLinkset.Factory(m_physicsScene, child); } // Return 'true' if the passed object is the root object of this linkset @@ -316,8 +316,8 @@ public abstract class BSLinkset // Invoke the detailed logger and output something if it's enabled. protected void DetailLog(string msg, params Object[] args) { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); + if (m_physicsScene.PhysicsLogging.Enabled) + m_physicsScene.DetailLog(msg, args); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index be01808..01ada3f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -121,7 +121,7 @@ public sealed class BSLinksetCompound : BSLinkset // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. if (!Rebuilding && HasAnyChildren) { - PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() + m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() { if (HasAnyChildren) RecomputeLinksetCompound(); @@ -147,10 +147,10 @@ public sealed class BSLinksetCompound : BSLinkset { // The origional prims are removed from the world as the shape of the root compound // shape takes over. - PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); + m_physicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + m_physicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); // We don't want collisions from the old linkset children. - PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + m_physicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); child.PhysBody.collisionType = CollisionType.LinksetChild; @@ -175,12 +175,12 @@ public sealed class BSLinksetCompound : BSLinkset else { // The non-physical children can come back to life. - PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + m_physicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); child.PhysBody.collisionType = CollisionType.LinksetChild; // Don't force activation so setting of DISABLE_SIMULATION can stay if used. - PhysicsScene.PE.Activate(child.PhysBody, false); + m_physicsScene.PE.Activate(child.PhysBody, false); ret = true; } return ret; @@ -196,7 +196,7 @@ public sealed class BSLinksetCompound : BSLinkset // but it also means all the child positions get updated. // What would cause an unnecessary rebuild so we make sure the linkset is in a // region before bothering to do a rebuild. - if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) + if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) { // If a child of the linkset is updating only the position or rotation, that can be done // without rebuilding the linkset. @@ -209,21 +209,21 @@ public sealed class BSLinksetCompound : BSLinkset if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) { // Find the physical instance of the child - if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) + if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) { // It is possible that the linkset is still under construction and the child is not yet // inserted into the compound shape. A rebuild of the linkset in a pre-step action will // build the whole thing with the new position or rotation. // The index must be checked because Bullet references the child array but does no validity // checking of the child index passed. - int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); + int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); if (updated.LinksetChildIndex < numLinksetChildren) { - BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); + BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); if (linksetChildShape.HasPhysicalShape) { // Found the child shape within the compound shape - PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, + m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, updated.RawPosition - LinksetRoot.RawPosition, updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), true /* shouldRecalculateLocalAabb */); @@ -401,9 +401,9 @@ public sealed class BSLinksetCompound : BSLinkset // Here we build the compound shape made up of all the children. // Free up any shape we'd previously built. - LinksetShape.Dereference(PhysicsScene); + LinksetShape.Dereference(m_physicsScene); - LinksetShape = BSShapeCompound.GetReference(PhysicsScene, LinksetRoot); + LinksetShape = BSShapeCompound.GetReference(m_physicsScene, LinksetRoot); // The center of mass for the linkset is the geometric center of the group. // Compute a displacement for each component so it is relative to the center-of-mass. @@ -435,7 +435,7 @@ public sealed class BSLinksetCompound : BSLinkset childShape.IncrementReference(); OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; - PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); + m_physicsScene.PE.AddChildShapeToCompoundShape(LinksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); @@ -446,14 +446,14 @@ public sealed class BSLinksetCompound : BSLinkset // Sneak the built compound shape in as the shape of the root prim. // Note this doesn't touch the root prim's PhysShape so be sure the manage the difference. - PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, LinksetRoot.PhysBody, LinksetShape.physShapeInfo); + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, LinksetShape.physShapeInfo); // With all of the linkset packed into the root prim, it has the mass of everyone. LinksetMass = ComputeLinksetMass(); LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); // Enable the physical position updator to return the position and rotation of the root shape - PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); } finally { @@ -461,7 +461,7 @@ public sealed class BSLinksetCompound : BSLinkset } // See that the Aabb surrounds the new shape - PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); + m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); } } } \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 1811772..a06a44d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -51,7 +51,7 @@ public sealed class BSLinksetConstraints : BSLinkset if (HasAnyChildren && IsRoot(requestor)) { // Queue to happen after all the other taint processing - PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() { if (HasAnyChildren && IsRoot(requestor)) RecomputeLinksetConstraints(); @@ -142,7 +142,7 @@ public sealed class BSLinksetConstraints : BSLinkset rootx.LocalID, rootx.PhysBody.AddrString, childx.LocalID, childx.PhysBody.AddrString); - PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() + m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() { PhysicallyUnlinkAChildFromRoot(rootx, childx); }); @@ -187,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 BSConstraint6Dof constrain = new BSConstraint6Dof( - PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); + m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); /* NOTE: below is an attempt to build constraint with full frame computation, etc. @@ -216,7 +216,7 @@ public sealed class BSLinksetConstraints : BSLinkset // ================================================================================== */ - PhysicsScene.Constraints.AddConstraint(constrain); + m_physicsScene.Constraints.AddConstraint(constrain); // zero linear and angular limits makes the objects unable to move in relation to each other constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); @@ -248,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset childPrim.LocalID, childPrim.PhysBody.AddrString); // Find the constraint for this link and get rid of it from the overall collection and from my list - if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) + if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) { // Make the child refresh its location - PhysicsScene.PE.PushUpdate(childPrim.PhysBody); + m_physicsScene.PE.PushUpdate(childPrim.PhysBody); ret = true; } @@ -265,7 +265,7 @@ public sealed class BSLinksetConstraints : BSLinkset { DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); - return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); + return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); } // Call each of the constraints that make up this linkset and recompute the @@ -289,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset child.UpdatePhysicalMassProperties(linksetMass, true); BSConstraint constrain; - if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) { // If constraint doesn't exist yet, create it. constrain = BuildConstraint(LinksetRoot, child); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index b6eb619..6a3ada2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -72,14 +72,14 @@ public abstract class BSPhysObject : PhysicsActor } protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) { - PhysicsScene = parentScene; + PhysScene = parentScene; LocalID = localID; PhysObjectName = name; Name = name; // PhysicsActor also has the name of the object. Someday consolidate. TypeName = typeName; // The collection of things that push me around - PhysicalActors = new BSActorCollection(PhysicsScene); + PhysicalActors = new BSActorCollection(PhysScene); // Initialize variables kept in base. GravModifier = 1.0f; @@ -112,13 +112,13 @@ public abstract class BSPhysObject : PhysicsActor public virtual void Destroy() { PhysicalActors.Enable(false); - PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() + PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() { PhysicalActors.Dispose(); }); } - public BSScene PhysicsScene { get; protected set; } + public BSScene PhysScene { get; protected set; } // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor public string PhysObjectName { get; protected set; } public string TypeName { get; protected set; } @@ -270,7 +270,7 @@ public abstract class BSPhysObject : PhysicsActor public void ActivateIfPhysical(bool forceIt) { if (IsPhysical && PhysBody.HasPhysicalBody) - PhysicsScene.PE.Activate(PhysBody, forceIt); + PhysScene.PE.Activate(PhysBody, forceIt); } // 'actors' act on the physical object to change or constrain its motion. These can range from @@ -333,29 +333,29 @@ public abstract class BSPhysObject : PhysicsActor protected long CollisionAccumulation { get; set; } public override bool IsColliding { - get { return (CollidingStep == PhysicsScene.SimulationStep); } + get { return (CollidingStep == PhysScene.SimulationStep); } set { if (value) - CollidingStep = PhysicsScene.SimulationStep; + CollidingStep = PhysScene.SimulationStep; else CollidingStep = 0; } } public override bool CollidingGround { - get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } + get { return (CollidingGroundStep == PhysScene.SimulationStep); } set { if (value) - CollidingGroundStep = PhysicsScene.SimulationStep; + CollidingGroundStep = PhysScene.SimulationStep; else CollidingGroundStep = 0; } } public override bool CollidingObj { - get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } + get { return (CollidingObjectStep == PhysScene.SimulationStep); } set { if (value) - CollidingObjectStep = PhysicsScene.SimulationStep; + CollidingObjectStep = PhysScene.SimulationStep; else CollidingObjectStep = 0; } @@ -380,14 +380,14 @@ public abstract class BSPhysObject : PhysicsActor bool ret = false; // The following lines make IsColliding(), CollidingGround() and CollidingObj work - CollidingStep = PhysicsScene.SimulationStep; - if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) + CollidingStep = PhysScene.SimulationStep; + if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) { - CollidingGroundStep = PhysicsScene.SimulationStep; + CollidingGroundStep = PhysScene.SimulationStep; } else { - CollidingObjectStep = PhysicsScene.SimulationStep; + CollidingObjectStep = PhysScene.SimulationStep; } CollisionAccumulation++; @@ -397,10 +397,10 @@ public abstract class BSPhysObject : PhysicsActor // Make a collection of the collisions that happened the last simulation tick. // This is different than the collection created for sending up to the simulator as it is cleared every tick. - if (CollisionsLastTickStep != PhysicsScene.SimulationStep) + if (CollisionsLastTickStep != PhysScene.SimulationStep) { CollisionsLastTick = new CollisionEventUpdate(); - CollisionsLastTickStep = PhysicsScene.SimulationStep; + CollisionsLastTickStep = PhysScene.SimulationStep; } CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); @@ -427,9 +427,9 @@ public abstract class BSPhysObject : PhysicsActor bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); // throttle the collisions to the number of milliseconds specified in the subscription - if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) + if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) { - NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; + NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; // We are called if we previously had collisions. If there are no collisions // this time, send up one last empty event so OpenSim can sense collision end. @@ -464,10 +464,10 @@ public abstract class BSPhysObject : PhysicsActor // make sure first collision happens NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); - PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() + PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() { if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); }); } else @@ -479,11 +479,11 @@ public abstract class BSPhysObject : PhysicsActor public override void UnSubscribeEvents() { // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); SubscribedEventsMs = 0; - PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() + PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() { // Make sure there is a body there because sometimes destruction happens in an un-ideal order. if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); }); } // Return 'true' if the simulator wants collision events @@ -497,7 +497,7 @@ public abstract class BSPhysObject : PhysicsActor { // Scale the collision count by the time since the last collision. // The "+1" prevents dividing by zero. - long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; + long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; CollisionScore = CollisionAccumulation / timeAgo; } public override float CollisionScore { get; set; } @@ -524,8 +524,8 @@ public abstract class BSPhysObject : PhysicsActor // High performance detailed logging routine used by the physical objects. protected void DetailLog(string msg, params Object[] args) { - if (PhysicsScene.PhysicsLogging.Enabled) - PhysicsScene.DetailLog(msg, args); + if (PhysScene.PhysicsLogging.Enabled) + PhysScene.DetailLog(msg, args); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 5d12338..0d45579 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -101,21 +101,21 @@ public class BSPrim : BSPhysObject _isVolumeDetect = false; // We keep a handle to the vehicle actor so we can set vehicle parameters later. - VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); + VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName); PhysicalActors.Add(VehicleActorName, VehicleActor); _mass = CalculateMass(); // DetailLog("{0},BSPrim.constructor,call", LocalID); // do the actual object creation at taint time - PhysicsScene.TaintedObject("BSPrim.create", delegate() + PhysScene.TaintedObject("BSPrim.create", delegate() { // Make sure the object is being created with some sanity. ExtremeSanityCheck(true /* inTaintTime */); CreateGeomAndObject(true); - CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); + CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); }); } @@ -128,13 +128,13 @@ public class BSPrim : BSPhysObject // Undo any vehicle properties this.VehicleType = (int)Vehicle.TYPE_NONE; - PhysicsScene.TaintedObject("BSPrim.Destroy", delegate() + PhysScene.TaintedObject("BSPrim.Destroy", delegate() { DetailLog("{0},BSPrim.Destroy,taint,", LocalID); // If there are physical body and shape, release my use of same. - PhysicsScene.Shapes.DereferenceBody(PhysBody, null); + PhysScene.Shapes.DereferenceBody(PhysBody, null); PhysBody.Clear(); - PhysShape.Dereference(PhysicsScene); + PhysShape.Dereference(PhysScene); PhysShape = new BSShapeNull(); }); } @@ -163,7 +163,7 @@ public class BSPrim : BSPhysObject } public override bool ForceBodyShapeRebuild(bool inTaintTime) { - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() { _mass = CalculateMass(); // changing the shape changes the mass CreateGeomAndObject(true); @@ -180,7 +180,7 @@ public class BSPrim : BSPhysObject if (value != _isSelected) { _isSelected = value; - PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() + PhysScene.TaintedObject("BSPrim.setSelected", delegate() { DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); SetObjectDynamic(false); @@ -226,23 +226,23 @@ public class BSPrim : BSPhysObject _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties in the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.ClearAllForces(PhysBody); + PhysScene.PE.ClearAllForces(PhysBody); }); } public override void ZeroAngularMotion(bool inTaintTime) { _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties in the physics engine - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() { // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); - PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); + PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); + PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); } }); } @@ -260,11 +260,11 @@ public class BSPrim : BSPhysObject EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate() { - return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName); + return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); }); // Update parameters so the new actor's Refresh() action is called at the right time. - PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() + PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() { UpdatePhysicalParameters(); }); @@ -294,7 +294,7 @@ public class BSPrim : BSPhysObject _position = value; PositionSanityCheck(false); - PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() + PhysScene.TaintedObject("BSPrim.setPosition", delegate() { DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); ForcePosition = _position; @@ -304,14 +304,14 @@ public class BSPrim : BSPhysObject public override OMV.Vector3 ForcePosition { get { - _position = PhysicsScene.PE.GetPosition(PhysBody); + _position = PhysScene.PE.GetPosition(PhysBody); return _position; } set { _position = value; if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); ActivateIfPhysical(false); } } @@ -328,7 +328,7 @@ public class BSPrim : BSPhysObject if (!IsPhysicallyActive) return ret; - if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) + if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) { // The physical object is out of the known/simulated area. // Upper levels of code will handle the transition to other areas so, for @@ -336,7 +336,7 @@ public class BSPrim : BSPhysObject return ret; } - float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); + float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); OMV.Vector3 upForce = OMV.Vector3.Zero; float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); if ((RawPosition.Z + approxSize / 2f) < terrainHeight) @@ -357,7 +357,7 @@ public class BSPrim : BSPhysObject if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) { - float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); // TODO: a floating motor so object will bob in the water if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) { @@ -365,7 +365,7 @@ public class BSPrim : BSPhysObject upForce.Z = (waterHeight - RawPosition.Z) * 1f; // Apply upforce and overcome gravity. - OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; + OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); AddForce(correctionForce, false, inTaintTime); ret = true; @@ -431,10 +431,10 @@ public class BSPrim : BSPhysObject { if (IsStatic) { - PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); + PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); Inertia = OMV.Vector3.Zero; - PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); - PhysicsScene.PE.UpdateInertiaTensor(PhysBody); + PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); + PhysScene.PE.UpdateInertiaTensor(PhysBody); } else { @@ -443,16 +443,16 @@ public class BSPrim : BSPhysObject // Changing interesting properties doesn't change proxy and collision cache // information. The Bullet solution is to re-add the object to the world // after parameters are changed. - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); } // The computation of mass props requires gravity to be set on the object. Gravity = ComputeGravity(Buoyancy); - PhysicsScene.PE.SetGravity(PhysBody, Gravity); + PhysScene.PE.SetGravity(PhysBody, Gravity); - Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); - PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); - PhysicsScene.PE.UpdateInertiaTensor(PhysBody); + Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); + PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); + PhysScene.PE.UpdateInertiaTensor(PhysBody); DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, Gravity, inWorld); @@ -468,7 +468,7 @@ public class BSPrim : BSPhysObject // Return what gravity should be set to this very moment public OMV.Vector3 ComputeGravity(float buoyancy) { - OMV.Vector3 ret = PhysicsScene.DefaultGravity; + OMV.Vector3 ret = PhysScene.DefaultGravity; if (!IsStatic) { @@ -497,7 +497,7 @@ public class BSPrim : BSPhysObject RawForce = value; EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() { - return new BSActorSetForce(PhysicsScene, this, SetForceActorName); + return new BSActorSetForce(PhysScene, this, SetForceActorName); }); } } @@ -509,7 +509,7 @@ public class BSPrim : BSPhysObject set { Vehicle type = (Vehicle)value; - PhysicsScene.TaintedObject("setVehicleType", delegate() + PhysScene.TaintedObject("setVehicleType", delegate() { // Vehicle code changes the parameters for this vehicle type. VehicleActor.ProcessTypeChange(type); @@ -519,7 +519,7 @@ public class BSPrim : BSPhysObject } public override void VehicleFloatParam(int param, float value) { - PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() + PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() { VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); ActivateIfPhysical(false); @@ -527,7 +527,7 @@ public class BSPrim : BSPhysObject } public override void VehicleVectorParam(int param, OMV.Vector3 value) { - PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() + PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() { VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); ActivateIfPhysical(false); @@ -535,7 +535,7 @@ public class BSPrim : BSPhysObject } public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { - PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() + PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() { VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); ActivateIfPhysical(false); @@ -543,7 +543,7 @@ public class BSPrim : BSPhysObject } public override void VehicleFlags(int param, bool remove) { - PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() + PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() { VehicleActor.ProcessVehicleFlags(param, remove); }); @@ -555,7 +555,7 @@ public class BSPrim : BSPhysObject if (_isVolumeDetect != newValue) { _isVolumeDetect = newValue; - PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() + PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() { // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); SetObjectDynamic(true); @@ -566,7 +566,7 @@ public class BSPrim : BSPhysObject public override void SetMaterial(int material) { base.SetMaterial(material); - PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() + PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() { UpdatePhysicalParameters(); }); @@ -579,7 +579,7 @@ public class BSPrim : BSPhysObject if (base.Friction != value) { base.Friction = value; - PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() + PhysScene.TaintedObject("BSPrim.setFriction", delegate() { UpdatePhysicalParameters(); }); @@ -594,7 +594,7 @@ public class BSPrim : BSPhysObject if (base.Restitution != value) { base.Restitution = value; - PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() + PhysScene.TaintedObject("BSPrim.setRestitution", delegate() { UpdatePhysicalParameters(); }); @@ -611,7 +611,7 @@ public class BSPrim : BSPhysObject if (base.Density != value) { base.Density = value; - PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() + PhysScene.TaintedObject("BSPrim.setDensity", delegate() { UpdatePhysicalParameters(); }); @@ -626,7 +626,7 @@ public class BSPrim : BSPhysObject if (base.GravModifier != value) { base.GravModifier = value; - PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() + PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() { UpdatePhysicalParameters(); }); @@ -637,7 +637,7 @@ public class BSPrim : BSPhysObject get { return RawVelocity; } set { RawVelocity = value; - PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() + PhysScene.TaintedObject("BSPrim.setVelocity", delegate() { // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); ForceVelocity = RawVelocity; @@ -647,13 +647,13 @@ public class BSPrim : BSPhysObject public override OMV.Vector3 ForceVelocity { get { return RawVelocity; } set { - PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); + PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); if (PhysBody.HasPhysicalBody) { DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); - PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); ActivateIfPhysical(false); } } @@ -664,7 +664,7 @@ public class BSPrim : BSPhysObject RawTorque = value; EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() { - return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName); + return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); }); DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); } @@ -687,7 +687,7 @@ public class BSPrim : BSPhysObject return; _orientation = value; - PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() + PhysScene.TaintedObject("BSPrim.setOrientation", delegate() { ForceOrientation = _orientation; }); @@ -698,14 +698,14 @@ public class BSPrim : BSPhysObject { get { - _orientation = PhysicsScene.PE.GetOrientation(PhysBody); + _orientation = PhysScene.PE.GetOrientation(PhysBody); return _orientation; } set { _orientation = value; if (PhysBody.HasPhysicalBody) - PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); } } public override int PhysicsActorType { @@ -718,7 +718,7 @@ public class BSPrim : BSPhysObject if (_isPhysical != value) { _isPhysical = value; - PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() + PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() { DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); SetObjectDynamic(true); @@ -773,7 +773,7 @@ public class BSPrim : BSPhysObject // Mangling all the physical properties requires the object not be in the physical world. // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); // Set up the object physicalness (does gravity and collisions move this object) MakeDynamic(IsStatic); @@ -790,7 +790,7 @@ public class BSPrim : BSPhysObject AddObjectToPhysicalWorld(); // Rebuild its shape - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); + PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), @@ -807,28 +807,28 @@ public class BSPrim : BSPhysObject if (makeStatic) { // Become a Bullet 'static' object type - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); // Stop all movement ZeroMotion(true); // Set various physical properties so other object interact properly - PhysicsScene.PE.SetFriction(PhysBody, Friction); - PhysicsScene.PE.SetRestitution(PhysBody, Restitution); - PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + PhysScene.PE.SetFriction(PhysBody, Friction); + PhysScene.PE.SetRestitution(PhysBody, Restitution); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); // Mass is zero which disables a bunch of physics stuff in Bullet UpdatePhysicalMassProperties(0f, false); // Set collision detection parameters if (BSParam.CcdMotionThreshold > 0f) { - PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); } // The activation state is 'disabled' so Bullet will not try to act on it. // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); // Start it out sleeping and physical actions could wake it up. - PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); // This collides like a static object PhysBody.collisionType = CollisionType.Static; @@ -836,11 +836,11 @@ public class BSPrim : BSPhysObject else { // Not a Bullet static object - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); // Set various physical properties so other object interact properly - PhysicsScene.PE.SetFriction(PhysBody, Friction); - PhysicsScene.PE.SetRestitution(PhysBody, Restitution); + PhysScene.PE.SetFriction(PhysBody, Friction); + PhysScene.PE.SetRestitution(PhysBody, Restitution); // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 @@ -858,22 +858,22 @@ public class BSPrim : BSPhysObject // Set collision detection parameters if (BSParam.CcdMotionThreshold > 0f) { - PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); } // Various values for simulation limits - PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); - PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); - PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); - PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); + PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); + PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); // This collides like an object. PhysBody.collisionType = CollisionType.Dynamic; // Force activation of the object so Bullet will act on it. // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. - PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); } } @@ -883,7 +883,7 @@ public class BSPrim : BSPhysObject // the functions after this one set up the state of a possibly newly created collision body. private void MakeSolid(bool makeSolid) { - CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); + CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); if (makeSolid) { // Verify the previous code created the correct shape for this type of thing. @@ -891,7 +891,7 @@ public class BSPrim : BSPhysObject { m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); } - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); } else { @@ -899,7 +899,7 @@ public class BSPrim : BSPhysObject { m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); } - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); // Change collision info from a static object to a ghosty collision object PhysBody.collisionType = CollisionType.VolumeDetect; @@ -911,11 +911,11 @@ public class BSPrim : BSPhysObject { if (wantsCollisionEvents) { - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); } else { - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); } } @@ -926,7 +926,7 @@ public class BSPrim : BSPhysObject { if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); + PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); } else { @@ -961,12 +961,12 @@ public class BSPrim : BSPhysObject public override bool FloatOnWater { set { _floatOnWater = value; - PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() + PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() { if (_floatOnWater) - CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); else - CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); }); } } @@ -978,7 +978,7 @@ public class BSPrim : BSPhysObject _rotationalVelocity = value; Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); - PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() + PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() { ForceRotationalVelocity = _rotationalVelocity; }); @@ -993,7 +993,7 @@ public class BSPrim : BSPhysObject if (PhysBody.HasPhysicalBody) { DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); - PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); + PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); ActivateIfPhysical(false); } @@ -1009,7 +1009,7 @@ public class BSPrim : BSPhysObject get { return _buoyancy; } set { _buoyancy = value; - PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() + PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() { ForceBuoyancy = _buoyancy; }); @@ -1032,7 +1032,7 @@ public class BSPrim : BSPhysObject base.MoveToTargetActive = value; EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() { - return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName); + return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); }); } } @@ -1044,7 +1044,7 @@ public class BSPrim : BSPhysObject base.HoverActive = value; EnableActor(HoverActive, HoverActorName, delegate() { - return new BSActorHover(PhysicsScene, this, HoverActorName); + return new BSActorHover(PhysScene, this, HoverActorName); }); } } @@ -1054,7 +1054,7 @@ public class BSPrim : BSPhysObject OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); // Since this force is being applied in only one step, make this a force per second. - addForce /= PhysicsScene.LastTimeStep; + addForce /= PhysScene.LastTimeStep; AddForce(addForce, pushforce, false /* inTaintTime */); } @@ -1069,13 +1069,13 @@ public class BSPrim : BSPhysObject // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); OMV.Vector3 addForce = force; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() { // Bullet adds this central force to the total force for this tick DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); + PhysScene.PE.ApplyCentralForce(PhysBody, addForce); ActivateIfPhysical(false); } }); @@ -1097,13 +1097,13 @@ public class BSPrim : BSPhysObject OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() { // Bullet adds this impulse immediately to the velocity DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); + PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); ActivateIfPhysical(false); } }); @@ -1122,12 +1122,12 @@ public class BSPrim : BSPhysObject if (force.IsFinite()) { OMV.Vector3 angForce = force; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() { if (PhysBody.HasPhysicalBody) { DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); - PhysicsScene.PE.ApplyTorque(PhysBody, angForce); + PhysScene.PE.ApplyTorque(PhysBody, angForce); ActivateIfPhysical(false); } }); @@ -1146,11 +1146,11 @@ public class BSPrim : BSPhysObject public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) { OMV.Vector3 applyImpulse = impulse; - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() + PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() { if (PhysBody.HasPhysicalBody) { - PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); + PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); ActivateIfPhysical(false); } }); @@ -1452,7 +1452,7 @@ public class BSPrim : BSPhysObject // Create the correct physical representation for this type of object. // Updates base.PhysBody and base.PhysShape with the new information. // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. - PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, delegate(BulletBody pBody, BulletShape pShape) + PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) { // Called if the current prim body is about to be destroyed. // Remove all the physical dependencies on the old body. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 81104ec..5236909 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -47,9 +47,9 @@ public class BSPrimLinkable : BSPrimDisplaced OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) { - Linkset = BSLinkset.Factory(PhysicsScene, this); + Linkset = BSLinkset.Factory(PhysScene, this); - PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() + PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() { Linkset.Refresh(this); }); @@ -99,7 +99,7 @@ public class BSPrimLinkable : BSPrimDisplaced set { base.Position = value; - PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() + PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate() { Linkset.UpdateProperties(UpdatedProperties.Position, this); }); @@ -113,7 +113,7 @@ public class BSPrimLinkable : BSPrimDisplaced set { base.Orientation = value; - PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() + PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() { Linkset.UpdateProperties(UpdatedProperties.Orientation, this); }); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index e4fecc3..5a19797 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs @@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys private void BuildHeightmapTerrain() { // Create the terrain shape from the mapInfo - m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, + m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); @@ -103,26 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); - m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, + m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, m_mapInfo.ID, centerPos, Quaternion.Identity); // Set current terrain attributes - PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); - PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); - PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); - PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); + m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); + m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); + m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); + m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); // Return the new terrain to the world of physical objects - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); // redo its bounding box now that it is in the world - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; - m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); + m_mapInfo.terrainBody.ApplyCollisionMask(m_physicsScene); // Make it so the terrain will not move or be considered for movement. - PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); + m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); return; } @@ -134,9 +134,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys { if (m_mapInfo.terrainBody.HasPhysicalBody) { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); // Frees both the body and the shape. - PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); } } m_mapInfo = null; @@ -155,7 +155,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys catch { // Sometimes they give us wonky values of X and Y. Give a warning and return something. - PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", + m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", LogHeader, m_mapInfo.terrainRegionBase, pos); ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; } @@ -165,7 +165,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys // The passed position is relative to the base of the region. public override float GetWaterLevelAtXYZ(Vector3 pos) { - return PhysicsScene.SimpleWaterLevel; + return m_physicsScene.SimpleWaterLevel; } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 5240ad8..0d16eda 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable Mesh = 1 } - public BSScene PhysicsScene { get; private set; } + protected BSScene m_physicsScene { get; private set; } // Base of the region in world coordinates. Coordinates inside the region are relative to this. public Vector3 TerrainBase { get; private set; } public uint ID { get; private set; } public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) { - PhysicsScene = physicsScene; + m_physicsScene = physicsScene; TerrainBase = regionBase; ID = id; } @@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); // The scene that I am part of - private BSScene PhysicsScene { get; set; } + private BSScene m_physicsScene { get; set; } // The ground plane created to keep thing from falling to infinity. private BulletBody m_groundPlane; @@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable public BSTerrainManager(BSScene physicsScene) { - PhysicsScene = physicsScene; + m_physicsScene = physicsScene; m_terrains = new Dictionary(); // Assume one region of default size @@ -132,21 +132,21 @@ public sealed class BSTerrainManager : IDisposable // safe to call Bullet in real time. We hope no one is moving prims around yet. public void CreateInitialGroundPlaneAndTerrain() { - DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); + DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); // The ground plane is here to catch things that are trying to drop to negative infinity - BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); - m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, + BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); + m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); // Ground plane does not move - PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); + m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); // Everything collides with the ground plane. m_groundPlane.collisionType = CollisionType.Groundplane; - m_groundPlane.ApplyCollisionMask(PhysicsScene); + m_groundPlane.ApplyCollisionMask(m_physicsScene); - BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); + BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); lock (m_terrains) { // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. @@ -157,12 +157,12 @@ public sealed class BSTerrainManager : IDisposable // Release all the terrain structures we might have allocated public void ReleaseGroundPlaneAndTerrain() { - DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); + DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); if (m_groundPlane.HasPhysicalBody) { - if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) + if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) { - PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); } m_groundPlane.Clear(); } @@ -188,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable float[] localHeightMap = heightMap; // If there are multiple requests for changes to the same terrain between ticks, // only do that last one. - PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() + m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() { if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) { @@ -219,7 +219,7 @@ public sealed class BSTerrainManager : IDisposable private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) { // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. - PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() + m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() { UpdateTerrain(id, heightMap, minCoords, maxCoords); }); @@ -318,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable // TODO: redo terrain implementation selection to allow other base types than heightMap. private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) { - PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", - LogHeader, PhysicsScene.RegionName, terrainRegionBase, + m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", + LogHeader, m_physicsScene.RegionName, terrainRegionBase, (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); BSTerrainPhys newTerrainPhys = null; switch ((int)BSParam.TerrainImplementation) { case (int)BSTerrainPhys.TerrainImplementation.Heightmap: - newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, + newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, heightMap, minCoords, maxCoords); break; case (int)BSTerrainPhys.TerrainImplementation.Mesh: - newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, + newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, heightMap, minCoords, maxCoords); break; default: - PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", + m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", LogHeader, (int)BSParam.TerrainImplementation, BSParam.TerrainImplementation, - PhysicsScene.RegionName, terrainRegionBase); + m_physicsScene.RegionName, terrainRegionBase); break; } return newTerrainPhys; @@ -429,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable } else { - PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", - LogHeader, PhysicsScene.RegionName, tX, tY); + m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", + LogHeader, m_physicsScene.RegionName, tX, tY); DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", BSScene.DetailLogZero, pos, terrainBaseXYZ); } @@ -451,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable } else { - PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", - LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); + m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", + LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); } return ret; } @@ -564,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable private void DetailLog(string msg, params Object[] args) { - PhysicsScene.PhysicsLogging.Write(msg, args); + m_physicsScene.PhysicsLogging.Write(msg, args); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index 2ce1513..ee2a1f2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs @@ -80,7 +80,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys if (BSParam.TerrainMeshMagnification == 1) { // If a magnification of one, use the old routine that is tried and true. - meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, + meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, initialMap, m_sizeX, m_sizeY, // input size Vector3.Zero, // base for mesh out indicesCount, out indices, out verticesCount, out vertices); @@ -88,7 +88,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys else { // Other magnifications use the newer routine - meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene, + meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, initialMap, m_sizeX, m_sizeY, // input size BSParam.TerrainMeshMagnification, physicsScene.TerrainManager.DefaultRegionSize, @@ -98,21 +98,21 @@ public sealed class BSTerrainMesh : BSTerrainPhys if (!meshCreationSuccess) { // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); - PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); + m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); // Something is very messed up and a crash is in our future. return; } - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); - m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); + m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); if (!m_terrainShape.HasPhysicalShape) { // DISASTER!! - PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); - PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); + m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); // Something is very messed up and a crash is in our future. return; } @@ -120,52 +120,52 @@ public sealed class BSTerrainMesh : BSTerrainPhys Vector3 pos = regionBase; Quaternion rot = Quaternion.Identity; - m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); + m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); if (!m_terrainBody.HasPhysicalBody) { // DISASTER!! - PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); + m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); // Something is very messed up and a crash is in our future. return; } physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); // Set current terrain attributes - PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); - PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); - PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); - PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); - PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); + m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); + m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); + m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); + m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); + m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); // Static objects are not very massive. - PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); + m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); // Put the new terrain to the world of physical objects - PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); // Redo its bounding box now that it is in the world - PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); m_terrainBody.collisionType = CollisionType.Terrain; - m_terrainBody.ApplyCollisionMask(PhysicsScene); + m_terrainBody.ApplyCollisionMask(m_physicsScene); if (BSParam.UseSingleSidedMeshes) { - PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); - PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); + m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); + m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); } // Make it so the terrain will not move or be considered for movement. - PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); + m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); } public override void Dispose() { if (m_terrainBody.HasPhysicalBody) { - PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); // Frees both the body and the shape. - PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); m_terrainBody.Clear(); m_terrainShape.Clear(); } @@ -185,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys catch { // Sometimes they give us wonky values of X and Y. Give a warning and return something. - PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", + m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", LogHeader, TerrainBase, pos); ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; } @@ -195,7 +195,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys // The passed position is relative to the base of the region. public override float GetWaterLevelAtXYZ(Vector3 pos) { - return PhysicsScene.SimpleWaterLevel; + return m_physicsScene.SimpleWaterLevel; } // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). -- cgit v1.1 From 92ee288d666963aae2a058cc964be009a504f084 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 29 Apr 2013 07:54:50 -0700 Subject: BulletSim: remove trailing white space to make git happier. No functional changes. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 6 +- OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 138 ++++++++++----------- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 2 +- .../Physics/BulletSPlugin/BSActorLockAxis.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 2 +- .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 6 +- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 6 +- .../Physics/BulletSPlugin/BSConstraintHinge.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 22 ++-- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 2 +- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 12 +- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 6 +- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 8 +- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 20 +-- .../Physics/BulletSPlugin/BSTerrainHeightmap.cs | 6 +- .../Physics/BulletSPlugin/BSTerrainManager.cs | 10 +- .../Region/Physics/BulletSPlugin/BSTerrainMesh.cs | 6 +- .../Region/Physics/BulletSPlugin/BulletSimData.cs | 42 +++---- 20 files changed, 152 insertions(+), 152 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 8a22bc7..231f0f8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -75,7 +75,7 @@ private sealed class BulletBodyUnman : BulletBody private sealed class BulletShapeUnman : BulletShape { public IntPtr ptr; - public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) + public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) : base() { ptr = xx; @@ -255,7 +255,7 @@ public override BulletShape CreateHullShape(BulletWorld world, int hullCount, fl { BulletWorldUnman worldu = world as BulletWorldUnman; return new BulletShapeUnman( - BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), + BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), BSPhysicsShapeType.SHAPE_HULL); } @@ -1503,7 +1503,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj); public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, +public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float scaleFactor, float collisionMargin); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 1ef8b17..59780ae 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -81,7 +81,7 @@ private sealed class BulletBodyXNA : BulletBody private sealed class BulletShapeXNA : BulletShape { public CollisionShape shape; - public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) + public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) : base() { shape = xx; @@ -137,8 +137,8 @@ private sealed class BulletConstraintXNA : BulletConstraint internal int LastEntityProperty = 0; internal EntityProperties[] UpdatedObjects; - internal Dictionary specialCollisionObjects; - + internal Dictionary specialCollisionObjects; + private static int m_collisionsThisFrame; private BSScene PhysicsScene { get; set; } @@ -151,7 +151,7 @@ private sealed class BulletConstraintXNA : BulletConstraint } /// - /// + /// /// /// /// @@ -174,7 +174,7 @@ private sealed class BulletConstraintXNA : BulletConstraint DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); - + return true; } @@ -300,7 +300,7 @@ private sealed class BulletConstraintXNA : BulletConstraint public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; return world.GetForceUpdateAllAabbs(); - + } public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) { @@ -404,7 +404,7 @@ private sealed class BulletConstraintXNA : BulletConstraint IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); mat._origin = vposition; collisionObject.SetWorldTransform(mat); - + } public override Vector3 GetPosition(BulletBody pCollisionObject) @@ -457,7 +457,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; collisionObject.Activate(pforceactivation); - + } public override Quaternion GetOrientation(BulletBody pCollisionObject) @@ -486,7 +486,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; return collisionObject.GetCcdSweptSphereRadius(); - + } public override IntPtr GetUserPointer(BulletBody pCollisionObject) @@ -559,8 +559,8 @@ private sealed class BulletConstraintXNA : BulletConstraint } - public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, + public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) { @@ -604,7 +604,7 @@ private sealed class BulletConstraintXNA : BulletConstraint } /// - /// + /// /// /// /// @@ -824,7 +824,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { RigidBody body = (pBody as BulletBodyXNA).rigidBody; float angularDamping = body.GetAngularDamping(); - body.SetDamping(lin_damping, angularDamping); + body.SetDamping(lin_damping, angularDamping); } public override float GetLinearDamping(BulletBody pBody) @@ -907,7 +907,7 @@ private sealed class BulletConstraintXNA : BulletConstraint RigidBody bo = co as RigidBody; if (bo == null) { - + if (world.IsInWorld(co)) { world.RemoveCollisionObject(co); @@ -915,7 +915,7 @@ private sealed class BulletConstraintXNA : BulletConstraint } else { - + if (world.IsInWorld(bo)) { world.RemoveRigidBody(bo); @@ -947,7 +947,7 @@ private sealed class BulletConstraintXNA : BulletConstraint // TODO: Turn this from a reference copy to a Value Copy. BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); - + return shape2; } @@ -957,7 +957,7 @@ private sealed class BulletConstraintXNA : BulletConstraint return false; } //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); - + public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) { CollisionWorld world = (pWorld as BulletWorldXNA).world; @@ -993,11 +993,11 @@ private sealed class BulletConstraintXNA : BulletConstraint m_startWorldTransform = IndexedMatrix.Identity; */ body.SetUserPointer(pLocalID); - + return new BulletBodyXNA(pLocalID, body); } - + public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) { @@ -1025,7 +1025,7 @@ private sealed class BulletConstraintXNA : BulletConstraint public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { - /* TODO */ + /* TODO */ return Vector3.Zero; } public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } @@ -1035,7 +1035,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; return collisionObject.IsStaticObject(); - + } public override bool IsKinematicObject(BulletBody pCollisionObject) { @@ -1098,10 +1098,10 @@ private sealed class BulletConstraintXNA : BulletConstraint return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); } - private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, + private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, ConfigurationParameters[] o, int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, - int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, + int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, object mDebugLogCallbackHandle) { CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); @@ -1138,9 +1138,9 @@ private sealed class BulletConstraintXNA : BulletConstraint p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; - + p.vehicleAngularDamping = BSParam.VehicleAngularDamping; - + p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; @@ -1160,7 +1160,7 @@ private sealed class BulletConstraintXNA : BulletConstraint p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; p.physicsLoggingFrames = o[0].physicsLoggingFrames; DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); - + DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); @@ -1263,7 +1263,7 @@ private sealed class BulletConstraintXNA : BulletConstraint } } return ret; - + } public override float GetAngularMotionDisc(BulletShape pShape) @@ -1353,10 +1353,10 @@ private sealed class BulletConstraintXNA : BulletConstraint CollisionShape shape = (pShape as BulletShapeXNA).shape; gObj.SetCollisionShape(shape); gObj.SetUserPointer(pLocalID); - + if (specialCollisionObjects.ContainsKey(pLocalID)) specialCollisionObjects[pLocalID] = gObj; - else + else specialCollisionObjects.Add(pLocalID, gObj); // TODO: Add to Special CollisionObjects! @@ -1447,8 +1447,8 @@ private sealed class BulletConstraintXNA : BulletConstraint return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); } - public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { - + public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { + if (cShape == null) return null; CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; @@ -1456,7 +1456,7 @@ private sealed class BulletConstraintXNA : BulletConstraint BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); - return retShape; + return retShape; } public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) @@ -1598,8 +1598,8 @@ private sealed class BulletConstraintXNA : BulletConstraint return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); } - public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, + public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) { @@ -1745,7 +1745,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; CompoundShape compoundshape = new CompoundShape(false); - + compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); int ii = 1; @@ -1761,7 +1761,7 @@ private sealed class BulletConstraintXNA : BulletConstraint int ender = ((ii + 4) + (vertexCount*3)); for (int iii = ii + 4; iii < ender; iii+=3) { - + virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); } ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); @@ -1769,7 +1769,7 @@ private sealed class BulletConstraintXNA : BulletConstraint compoundshape.AddChildShape(ref childTrans, convexShape); ii += (vertexCount*3 + 4); } - + return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); } @@ -1791,13 +1791,13 @@ private sealed class BulletConstraintXNA : BulletConstraint public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) { //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); - + for (int iter = 0; iter < pVerticesCount; iter++) { if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; } - + ObjectArray indicesarr = new ObjectArray(indices); ObjectArray vertices = new ObjectArray(verticesAsFloats); DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); @@ -1811,7 +1811,7 @@ private sealed class BulletConstraintXNA : BulletConstraint mesh.m_vertexStride = 3; mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; mesh.m_triangleIndexStride = 3; - + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); @@ -1822,7 +1822,7 @@ private sealed class BulletConstraintXNA : BulletConstraint } public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) { - + String fileName = "objTest3.raw"; String completePath = System.IO.Path.Combine(Util.configDir(), fileName); StreamWriter sw = new StreamWriter(completePath); @@ -1848,7 +1848,7 @@ private sealed class BulletConstraintXNA : BulletConstraint string s = vertices[indices[i * 3]].ToString("0.0000"); s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - + sw.Write(s + "\n"); } @@ -1870,7 +1870,7 @@ private sealed class BulletConstraintXNA : BulletConstraint mesh.m_vertexStride = 3; mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; mesh.m_triangleIndexStride = 3; - + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); @@ -1901,7 +1901,7 @@ private sealed class BulletConstraintXNA : BulletConstraint sw.Close(); } - public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, float scaleFactor, float collisionMargin) { const int upAxis = 2; @@ -1943,14 +1943,14 @@ private sealed class BulletConstraintXNA : BulletConstraint /* TODO */ updatedEntityCount = 0; collidersCount = 0; - + int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); return ret; } - private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, + private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders) { @@ -1959,24 +1959,24 @@ private sealed class BulletConstraintXNA : BulletConstraint return epic; } - private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, + private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) { int numSimSteps = 0; Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); LastEntityProperty=0; - + LastCollisionDesc=0; - + updatedEntityCount = 0; collidersCount = 0; - + if (pWorld is BulletWorldXNA) { @@ -2033,7 +2033,7 @@ private sealed class BulletConstraintXNA : BulletConstraint collidersCount = LastCollisionDesc; colliders = UpdatedCollisions; - + } else @@ -2041,15 +2041,15 @@ private sealed class BulletConstraintXNA : BulletConstraint //if (updatedEntities is null) //updatedEntities = new List(); //updatedEntityCount = 0; - - + + //collidersCount = 0; - + updatedEntities = new EntityProperties[0]; - + colliders = new CollisionDesc[0]; - + } return numSimSteps; } @@ -2057,7 +2057,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { IOverlappingPairCache cache = obj.GetOverlappingPairCache(); ObjectArray pairs = cache.GetOverlappingPairArray(); - + DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); BroadphasePair collisionPair; @@ -2069,7 +2069,7 @@ private sealed class BulletConstraintXNA : BulletConstraint ManifoldPoint pt; int numPairs = pairs.Count; - + for (int i = 0; i < numPairs; i++) { manifoldArray.Clear(); @@ -2078,7 +2078,7 @@ private sealed class BulletConstraintXNA : BulletConstraint collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); if (collisionPair == null) continue; - + collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); for (int j = 0; j < manifoldArray.Count; j++) { @@ -2101,7 +2101,7 @@ private sealed class BulletConstraintXNA : BulletConstraint } private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) { - + IndexedVector3 contactNormal = norm; if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) @@ -2171,11 +2171,11 @@ private sealed class BulletConstraintXNA : BulletConstraint if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) { CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; - + IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); using ( - ClosestNotMeRayResultCallback rayCallback = + ClosestNotMeRayResultCallback rayCallback = new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) ) { @@ -2191,9 +2191,9 @@ private sealed class BulletConstraintXNA : BulletConstraint return false; } } - - + + public class SimMotionState : DefaultMotionState { @@ -2286,12 +2286,12 @@ private sealed class BulletConstraintXNA : BulletConstraint m_lastProperties = m_properties; if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); - + //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; } - - - + + + } public override void SetRigidBody(RigidBody body) @@ -2314,7 +2314,7 @@ private sealed class BulletConstraintXNA : BulletConstraint (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); } - + } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index ac05979..4e067b5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -115,7 +115,7 @@ public class BSActorAvatarMove : BSActor if (m_velocityMotor == null) { // Infinite decay and timescale values so motor only changes current to target values. - m_velocityMotor = new BSVMotor("BSCharacter.Velocity", + m_velocityMotor = new BSVMotor("BSCharacter.Velocity", 0.2f, // time scale BSMotor.Infinite, // decay time scale BSMotor.InfiniteVector, // friction timescale diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index 6059af5..7801d8e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs @@ -63,7 +63,7 @@ public class BSActorLockAxis : BSActor // BSActor.Refresh() public override void Refresh() { - m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", + m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", m_controllingPrim.LocalID, m_controllingPrim.LockedAxis, Enabled, m_controllingPrim.IsPhysicallyActive); // If all the axis are free, we don't need to exist if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index 5e3f1c4..fff63e4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -117,7 +117,7 @@ public class BSActorCollection /// Each physical object can have 'actors' who are pushing the object around. /// This can be used for hover, locking axis, making vehicles, etc. /// Each physical object can have multiple actors acting on it. -/// +/// /// An actor usually registers itself with physics scene events (pre-step action) /// and modifies the parameters on the host physical object. /// diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index bfeec24..3378c93 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -298,7 +298,7 @@ public abstract class BSAPITemplate { // Returns the name of the underlying Bullet engine public abstract string BulletEngineName { get; } -public abstract string BulletEngineVersion { get; protected set;} +public abstract string BulletEngineVersion { get; protected set;} // Initialization and simulation public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, @@ -373,7 +373,7 @@ public abstract void DestroyObject(BulletWorld sim, BulletBody obj); // ===================================================================================== public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); -public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, +public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, float scaleFactor, float collisionMargin); // ===================================================================================== @@ -388,7 +388,7 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, - Vector3 frameInBloc, Quaternion frameInBrot, + Vector3 frameInBloc, Quaternion frameInBrot, bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index e12fc8e..542f732 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -371,7 +371,7 @@ public sealed class BSCharacter : BSPhysObject public override float Mass { get { return _mass; } } // used when we only want this prim's mass and not the linkset thing - public override float RawMass { + public override float RawMass { get {return _mass; } } public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) @@ -586,7 +586,7 @@ public sealed class BSCharacter : BSPhysObject } public override float ForceBuoyancy { get { return _buoyancy; } - set { + set { PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); _buoyancy = value; @@ -647,7 +647,7 @@ public sealed class BSCharacter : BSPhysObject private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) { OMV.Vector3 newScale; - + // Bullet's capsule total height is the "passed height + radius * 2"; // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) // The number we pass in for 'scaling' is the multiplier to get that base diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs index 7714a03..ed89f63 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs @@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint m_body1 = obj1; m_body2 = obj2; m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, - pivotInA, pivotInB, axisInA, axisInB, + pivotInA, pivotInB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); m_enabled = true; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 56d2415..f535e50 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1019,7 +1019,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG VehicleVelocity /= VehicleVelocity.Length(); VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; - VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", + VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); } else if (newVelocityLengthSq < 0.001f) @@ -1094,7 +1094,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin if (VehiclePosition.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = VehiclePosition.Z; } - + if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) { if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) @@ -1188,7 +1188,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // used with conjunction with banking: the strength of the banking will decay when the // vehicle no longer experiences collisions. The decay timescale is the same as // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering - // when they are in mid jump. + // when they are in mid jump. // TODO: this code is wrong. Also, what should it do for boats (height from water)? // This is just using the ground and a general collision check. Should really be using // a downward raycast to find what is below. @@ -1254,7 +1254,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin VehicleAddForce(appliedGravity); - VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", + VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", ControllingPrim.LocalID, m_VehicleGravity, ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); } @@ -1330,7 +1330,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : // This flag prevents linear deflection parallel to world z-axis. This is useful // for preventing ground vehicles with large linear deflection, like bumper cars, - // from climbing their linear deflection into the sky. + // from climbing their linear deflection into the sky. // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement // TODO: This is here because this is where ODE put it but documentation says it // is a linear effect. Where should this check go? @@ -1463,7 +1463,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", - Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, + Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); */ } @@ -1530,13 +1530,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude // of the yaw effect will be proportional to the // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's - // velocity along its preferred axis of motion. + // velocity along its preferred axis of motion. // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any // positive rotation (by the right-hand rule) about the roll-axis will effect a // (negative) torque around the yaw-axis, making it turn to the right--that is the // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. // Negating the banking coefficient will make it so that the vehicle leans to the - // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). + // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making // banking vehicles do what you want rather than what the laws of physics allow. // For example, consider a real motorcycle...it must be moving forward in order for @@ -1548,11 +1548,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the // banking effect depends only on the vehicle's rotation about its roll-axis compared // to "dynamic" where the banking is also proportional to its velocity along its - // roll-axis. Finding the best value of the "mixture" will probably require trial and error. + // roll-axis. Finding the best value of the "mixture" will probably require trial and error. // The time it takes for the banking behavior to defeat a preexisting angular velocity about the // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to // bank quickly then give it a banking timescale of about a second or less, otherwise you can - // make a sluggish vehicle by giving it a timescale of several seconds. + // make a sluggish vehicle by giving it a timescale of several seconds. public void ComputeAngularBanking() { if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) @@ -1581,7 +1581,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; VehicleRotationalVelocity += bankingContributionV; - + VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 6d0d0eb..76c2187 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -214,7 +214,7 @@ public abstract class BSLinkset // I am the root of a linkset and a new child is being added // Called while LinkActivity is locked. protected abstract void AddChildToLinkset(BSPrimLinkable child); - + // I am the root of a linkset and one of my children is being removed. // Safe to call even if the child is not really in my linkset. protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 01ada3f..1fd541f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -114,7 +114,7 @@ public sealed class BSLinksetCompound : BSLinkset // Schedule a refresh to happen after all the other taint processing. private void ScheduleRebuild(BSPrimLinkable requestor) { - DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", + DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. @@ -208,7 +208,7 @@ public sealed class BSLinksetCompound : BSLinkset // and that is caused by us updating the object. if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) { - // Find the physical instance of the child + // Find the physical instance of the child if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) { // It is possible that the linkset is still under construction and the child is not yet diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 9501e2d..0128d8d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -102,7 +102,7 @@ public class BSVMotor : BSMotor return ErrorIsZero(LastError); } public virtual bool ErrorIsZero(Vector3 err) - { + { return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); } @@ -115,7 +115,7 @@ public class BSVMotor : BSMotor CurrentValue = TargetValue = Vector3.Zero; ErrorZeroThreshold = 0.001f; } - public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) + public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) : this(useName) { TimeScale = timeScale; @@ -237,7 +237,7 @@ public class BSVMotor : BSMotor MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", BSScene.DetailLogZero, UseName, - TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, + TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, CurrentValue, TargetValue); LastError = BSMotor.InfiniteVector; @@ -248,7 +248,7 @@ public class BSVMotor : BSMotor BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); } MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); - + } @@ -279,7 +279,7 @@ public class BSFMotor : BSMotor return ErrorIsZero(LastError); } public virtual bool ErrorIsZero(float err) - { + { return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); } @@ -410,7 +410,7 @@ public class BSPIDVMotor : BSVMotor // The factors are vectors for the three dimensions. This is the proportional of each // that is applied. This could be multiplied through the actual factors but it // is sometimes easier to manipulate the factors and their mix separately. - // to + // to public Vector3 FactorMix; // Arbritrary factor range. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 980d405..5ebeace 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -37,7 +37,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public static class BSParam { - private static string LogHeader = "[BULLETSIM PARAMETERS]"; + private static string LogHeader = "[BULLETSIM PARAMETERS]"; // Tuning notes: // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 @@ -51,7 +51,7 @@ public static class BSParam // This is separate/independent from the collision margin. The collision margin increases the object a bit // to improve collision detection performance and accuracy. // =================== - // From: + // From: // Level of Detail values kept as float because that's what the Meshmerizer wants public static float MeshLOD { get; private set; } @@ -636,7 +636,7 @@ public static class BSParam new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", false, (s) => { return ShouldDisableContactPoolDynamicAllocation; }, - (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; + (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", false, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 6a3ada2..28d4bd7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -38,7 +38,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin * Class to wrap all objects. * The rest of BulletSim doesn't need to keep checking for avatars or prims * unless the difference is significant. - * + * * Variables in the physicsl objects are in three forms: * VariableName: used by the simulator and performs taint operations, etc * RawVariableName: direct reference to the BulletSim storage for the variable value @@ -52,7 +52,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v - * BS.ApplyCentralForce BS.ApplyTorque + * BS.ApplyCentralForce BS.ApplyTorque */ // Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. @@ -353,7 +353,7 @@ public abstract class BSPhysObject : PhysicsActor } public override bool CollidingObj { get { return (CollidingObjectStep == PhysScene.SimulationStep); } - set { + set { if (value) CollidingObjectStep = PhysScene.SimulationStep; else @@ -447,7 +447,7 @@ public abstract class BSPhysObject : PhysicsActor // The CollisionCollection instance is passed around in the simulator. // Make sure we don't have a handle to that one and that a new one is used for next time. - // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, + // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, // a race condition is created for the other users of this instance. CollisionCollection = new CollisionEventUpdate(); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 0d45579..7e2af78 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -420,7 +420,7 @@ public class BSPrim : BSPhysObject get { return _mass; } } // used when we only want this prim's mass and not the linkset thing - public override float RawMass { + public override float RawMass { get { return _mass; } } // Set the physical mass to the passed mass. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index bfc7ae7..5c58ad5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -142,7 +142,7 @@ public abstract class BSShape // If the shape was successfully created, nothing more to do if (newShape.HasPhysicalShape) return newShape; - + // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been // fetched but we end up here again, the meshing of the asset must have failed. // Prevent trying to keep fetching the mesh by declaring failure. @@ -155,7 +155,7 @@ public abstract class BSShape else { // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset - if (prim.BaseShape.SculptEntry + if (prim.BaseShape.SculptEntry && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting && prim.BaseShape.SculptTexture != OMV.UUID.Zero @@ -164,7 +164,7 @@ public abstract class BSShape physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset", prim.LocalID); // Multiple requestors will know we're waiting for this asset prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; - + BSPhysObject xprim = prim; Util.FireAndForget(delegate { @@ -245,8 +245,8 @@ public class BSShapeNative : BSShape { } - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) { // Native shapes are not shared and are always built anew. return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); @@ -379,7 +379,7 @@ public class BSShapeMesh : BSShape { BulletShape newShape = null; - IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, false, // say it is not physical so a bounding box is not built false // do not cache the mesh and do not use previously built versions ); @@ -671,8 +671,8 @@ public class BSShapeCompound : BSShape public BSShapeCompound(BulletShape pShape) : base(pShape) { } - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim) - { + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + { // Compound shapes are not shared so a new one is created every time. return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene, prim)); } @@ -750,8 +750,8 @@ public class BSShapeAvatar : BSShape public BSShapeAvatar() : base() { } - public static BSShape GetReference(BSPhysObject prim) - { + public static BSShape GetReference(BSPhysObject prim) + { return new BSShapeNull(); } public override void Dereference(BSScene physicsScene) { } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 5a19797..c7deb4e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs @@ -68,7 +68,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys // This minCoords and maxCoords passed in give the size of the terrain (min and max Z // are the high and low points of the heightmap). - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, + public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, Vector3 minCoords, Vector3 maxCoords) : base(physicsScene, regionBase, id) { @@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys private void BuildHeightmapTerrain() { // Create the terrain shape from the mapInfo - m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, + m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); @@ -103,7 +103,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); - m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, + m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, m_mapInfo.ID, centerPos, Quaternion.Identity); // Set current terrain attributes diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 0d16eda..c4807c4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -135,7 +135,7 @@ public sealed class BSTerrainManager : IDisposable DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); // The ground plane is here to catch things that are trying to drop to negative infinity BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); - m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, + m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); @@ -318,8 +318,8 @@ public sealed class BSTerrainManager : IDisposable // TODO: redo terrain implementation selection to allow other base types than heightMap. private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) { - m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", - LogHeader, m_physicsScene.RegionName, terrainRegionBase, + m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", + LogHeader, m_physicsScene.RegionName, terrainRegionBase, (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); BSTerrainPhys newTerrainPhys = null; switch ((int)BSParam.TerrainImplementation) @@ -334,8 +334,8 @@ public sealed class BSTerrainManager : IDisposable break; default: m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", - LogHeader, - (int)BSParam.TerrainImplementation, + LogHeader, + (int)BSParam.TerrainImplementation, BSParam.TerrainImplementation, m_physicsScene.RegionName, terrainRegionBase); break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index ee2a1f2..e4ca098 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs @@ -51,7 +51,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys BulletShape m_terrainShape; BulletBody m_terrainBody; - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) : base(physicsScene, regionBase, id) { } @@ -62,7 +62,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys } // Create terrain mesh from a heightmap. - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, Vector3 minCoords, Vector3 maxCoords) : base(physicsScene, regionBase, id) { @@ -104,7 +104,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys return; } - m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs index 906e4f9..d5060e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs @@ -224,42 +224,42 @@ public static class BulletSimData // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code // but, instead, use references to this dictionary. Finding and debugging // collision flag problems will be made easier. -public static Dictionary CollisionTypeMasks +public static Dictionary CollisionTypeMasks = new Dictionary() { - { CollisionType.Avatar, - new CollisionTypeFilterGroup(CollisionType.Avatar, - (uint)CollisionFilterGroups.BCharacterGroup, + { CollisionType.Avatar, + new CollisionTypeFilterGroup(CollisionType.Avatar, + (uint)CollisionFilterGroups.BCharacterGroup, (uint)CollisionFilterGroups.BAllGroup) }, - { CollisionType.Groundplane, - new CollisionTypeFilterGroup(CollisionType.Groundplane, - (uint)CollisionFilterGroups.BGroundPlaneGroup, + { CollisionType.Groundplane, + new CollisionTypeFilterGroup(CollisionType.Groundplane, + (uint)CollisionFilterGroups.BGroundPlaneGroup, (uint)CollisionFilterGroups.BAllGroup) }, - { CollisionType.Terrain, - new CollisionTypeFilterGroup(CollisionType.Terrain, - (uint)CollisionFilterGroups.BTerrainGroup, + { CollisionType.Terrain, + new CollisionTypeFilterGroup(CollisionType.Terrain, + (uint)CollisionFilterGroups.BTerrainGroup, (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) }, - { CollisionType.Static, - new CollisionTypeFilterGroup(CollisionType.Static, - (uint)CollisionFilterGroups.BStaticGroup, + { CollisionType.Static, + new CollisionTypeFilterGroup(CollisionType.Static, + (uint)CollisionFilterGroups.BStaticGroup, (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) }, - { CollisionType.Dynamic, - new CollisionTypeFilterGroup(CollisionType.Dynamic, - (uint)CollisionFilterGroups.BSolidGroup, + { CollisionType.Dynamic, + new CollisionTypeFilterGroup(CollisionType.Dynamic, + (uint)CollisionFilterGroups.BSolidGroup, (uint)(CollisionFilterGroups.BAllGroup)) }, - { CollisionType.VolumeDetect, - new CollisionTypeFilterGroup(CollisionType.VolumeDetect, - (uint)CollisionFilterGroups.BSensorTrigger, + { CollisionType.VolumeDetect, + new CollisionTypeFilterGroup(CollisionType.VolumeDetect, + (uint)CollisionFilterGroups.BSensorTrigger, (uint)(~CollisionFilterGroups.BSensorTrigger)) }, { CollisionType.LinksetChild, - new CollisionTypeFilterGroup(CollisionType.LinksetChild, - (uint)CollisionFilterGroups.BLinksetChildGroup, + new CollisionTypeFilterGroup(CollisionType.LinksetChild, + (uint)CollisionFilterGroups.BLinksetChildGroup, (uint)(CollisionFilterGroups.BNoneGroup)) // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) }, -- cgit v1.1 From 12054aaa9ff66cc785d2018526ff6f3e94f86915 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Apr 2013 17:14:44 +0100 Subject: Fix bug where an agent that declined an inventory offer and subsequently emptied their trash would make the item invalid in the giver's inventory This was because the original item/folder ID was sent in the session slot of the offer IM rather than the copy. --- .../Avatar/Inventory/Transfer/InventoryTransferModule.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index bcb7f42..e1ada97 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -213,7 +213,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer user.ControllingClient.SendBulkUpdateInventory(folderCopy); // HACK!! - im.imSessionID = folderID.Guid; + // Insert the ID of the copied item into the IM so that we know which item to move to trash if it + // is rejected. + // XXX: This is probably a misuse of the session ID slot. + im.imSessionID = copyID.Guid; } else { @@ -243,7 +246,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer user.ControllingClient.SendBulkUpdateInventory(itemCopy); // HACK!! - im.imSessionID = itemID.Guid; + // Insert the ID of the copied item into the IM so that we know which item to move to trash if it + // is rejected. + // XXX: This is probably a misuse of the session ID slot. + im.imSessionID = copyID.Guid; } // Send the IM to the recipient. The item is already -- cgit v1.1 From a7cbb9edc98fabc6d2705d69310f4356e84c7596 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Apr 2013 20:50:49 +0100 Subject: Add regression test for offer, accept and subsequent receiver delete of an item offered via instant message. --- .../Inventory/Transfer/InventoryTransferModule.cs | 83 +--------------------- OpenSim/Tests/Common/Mock/TestClient.cs | 12 ++++ prebuild.xml | 1 + 3 files changed, 16 insertions(+), 80 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index e1ada97..c292700 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer /// private List m_Scenelist = new List(); -// private Dictionary m_AgentRegions = -// new Dictionary(); - private IMessageTransferModule m_TransferModule = null; + private IMessageTransferModule m_TransferModule; private bool m_Enabled = true; #region Region Module interface @@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer // scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; -// scene.EventManager.OnClientClosed += ClientLoggedOut; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; -// scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene; } public void RegionLoaded(Scene scene) @@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); m_Enabled = false; - m_Scenelist.Clear(); - scene.EventManager.OnNewClient -= OnNewClient; -// scene.EventManager.OnClientClosed -= ClientLoggedOut; +// m_Scenelist.Clear(); +// scene.EventManager.OnNewClient -= OnNewClient; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; -// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene; } } } @@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer public void RemoveRegion(Scene scene) { scene.EventManager.OnNewClient -= OnNewClient; -// scene.EventManager.OnClientClosed -= ClientLoggedOut; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; -// scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene; m_Scenelist.Remove(scene); } @@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer // Inventory giving is conducted via instant message client.OnInstantMessage += OnInstantMessage; } - -// protected void OnSetRootAgentScene(UUID id, Scene scene) -// { -// m_AgentRegions[id] = scene; -// } private Scene FindClientScene(UUID agentId) { @@ -460,70 +447,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer } } -// public bool NeedSceneCacheClear(UUID agentID, Scene scene) -// { -// if (!m_AgentRegions.ContainsKey(agentID)) -// { -// // Since we can get here two ways, we need to scan -// // the scenes here. This is somewhat more expensive -// // but helps avoid a nasty bug -// // -// -// foreach (Scene s in m_Scenelist) -// { -// ScenePresence presence; -// -// if (s.TryGetScenePresence(agentID, out presence)) -// { -// // If the agent is in this scene, then we -// // are being called twice in a single -// // teleport. This is wasteful of cycles -// // but harmless due to this 2nd level check -// // -// // If the agent is found in another scene -// // then the list wasn't current -// // -// // If the agent is totally unknown, then what -// // are we even doing here?? -// // -// if (s == scene) -// { -// //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName); -// return true; -// } -// else -// { -// //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName); -// return false; -// } -// } -// } -// //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName); -// return true; -// } -// -// // The agent is left in current Scene, so we must be -// // going to another instance -// // -// if (m_AgentRegions[agentID] == scene) -// { -// //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName); -// m_AgentRegions.Remove(agentID); -// return true; -// } -// -// // Another region has claimed the agent -// // -// //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName); -// return false; -// } -// -// public void ClientLoggedOut(UUID agentID, Scene scene) -// { -// if (m_AgentRegions.ContainsKey(agentID)) -// m_AgentRegions.Remove(agentID); -// } - /// /// /// diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index d26e3f7..b7a7463 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -484,6 +484,18 @@ namespace OpenSim.Tests.Common.Mock OnCompleteMovementToRegion(this, true); } + /// + /// Emulate sending an IM from the viewer to the simulator. + /// + /// + public void HandleImprovedInstantMessage(GridInstantMessage im) + { + ImprovedInstantMessage handlerInstantMessage = OnInstantMessage; + + if (handlerInstantMessage != null) + handlerInstantMessage(this, im); + } + public virtual void ActivateGesture(UUID assetId, UUID gestureId) { } diff --git a/prebuild.xml b/prebuild.xml index 29d7c90..9fbe08b 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3055,6 +3055,7 @@ + -- cgit v1.1 From 0beccf23c0c2e7b2420f4f150d5f2566f0d63370 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Apr 2013 21:11:44 +0100 Subject: Add regression test for inventory item give, reject and subsequent trash folder purge by receiver. This commit also actually adds the InventoryTransferModuleTests file which I previously forgot --- .../Transfer/Tests/InventoryTransferModuleTests.cs | 256 +++++++++++++++++++++ OpenSim/Tests/Common/Mock/TestClient.cs | 4 +- 2 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs new file mode 100644 index 0000000..b07d38c --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs @@ -0,0 +1,256 @@ +/* + * 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.Reflection; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests +{ + [TestFixture] + public class InventoryTransferModuleTests : OpenSimTestCase + { + protected TestScene m_scene; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Messaging"); + config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule()); + } + + [Test] + public void TestAcceptGivenItem() + { +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID itemId = TestHelpers.ParseTail(0x100); + UUID assetId = TestHelpers.ParseTail(0x200); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + // Create the object to test give + InventoryItemBase originalItem + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); + + byte[] giveImBinaryBucket = new byte[17]; + byte[] itemIdBytes = itemId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + GridInstantMessage acceptIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, + false, + "inventory accepted msg", + initialSessionId, + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(acceptIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryItemBase originalItemAfterGive + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterGive, Is.Not.Null); + Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); + + // Test for item successfully making it into the receiver's inventory + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj"); + + Assert.That(receivedItem, Is.Not.Null); + Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List() { receivedItem.ID }); + + InventoryItemBase originalItemAfterDelete + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterDelete, Is.Not.Null); + + // TODO: Test scenario where giver deletes their item first. + } + + /// + /// Test user rejection of a given item. + /// + /// + /// A rejected item still ends up in the user's trash folder. + /// + [Test] + public void TestRejectGivenItem() + { +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID itemId = TestHelpers.ParseTail(0x100); + UUID assetId = TestHelpers.ParseTail(0x200); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + // Create the object to test give + InventoryItemBase originalItem + = UserInventoryHelpers.CreateInventoryItem( + m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); + + GridInstantMessage receivedIm = null; + receiverClient.OnReceivedInstantMessage += im => receivedIm = im; + + byte[] giveImBinaryBucket = new byte[17]; + byte[] itemIdBytes = itemId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + // Session ID is now the created item ID (!) + GridInstantMessage rejectIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryDeclined, + false, + "inventory declined msg", + new UUID(receivedIm.imSessionID), + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(rejectIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryItemBase originalItemAfterGive + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterGive, Is.Not.Null); + Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); + + // Test for item successfully making it into the receiver's inventory + InventoryItemBase receivedItem + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj"); + + InventoryFolderBase trashFolder + = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder); + + Assert.That(receivedItem, Is.Not.Null); + Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID)); + Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.PurgeFolder(trashFolder); + + InventoryItemBase originalItemAfterDelete + = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); + + Assert.That(originalItemAfterDelete, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index b7a7463..41402a4 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -61,6 +61,7 @@ namespace OpenSim.Tests.Common.Mock // Test client specific events - for use by tests to implement some IClientAPI behaviour. public event Action OnReceivedMoveAgentIntoRegion; public event Action OnTestClientInformClientOfNeighbour; + public event Action OnReceivedInstantMessage; // disable warning: public events, part of the public API #pragma warning disable 67 @@ -550,7 +551,8 @@ namespace OpenSim.Tests.Common.Mock public void SendInstantMessage(GridInstantMessage im) { - + if (OnReceivedInstantMessage != null) + OnReceivedInstantMessage(im); } public void SendGenericMessage(string method, UUID invoice, List message) -- cgit v1.1 From 67789201c3ae40bd4697f3479eb183599baa3658 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Apr 2013 22:14:13 +0100 Subject: Add TestRejectGivenFolder() and TestAcceptGivenFolder() regression tests --- .../Inventory/Transfer/InventoryTransferModule.cs | 10 +- .../Transfer/Tests/InventoryTransferModuleTests.cs | 193 +++++++++++++++++++++ .../Tests/Common/Helpers/UserInventoryHelpers.cs | 41 ++++- .../Tests/Common/Mock/TestXInventoryDataPlugin.cs | 28 ++- 4 files changed, 262 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index c292700..1417a19 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -175,9 +175,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer { UUID folderID = new UUID(im.binaryBucket, 1); - m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+ - "into agent {1}'s inventory", - folderID, new UUID(im.toAgentID)); + m_log.DebugFormat( + "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory", + folderID, new UUID(im.toAgentID)); InventoryFolderBase folderCopy = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero); @@ -200,7 +200,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer user.ControllingClient.SendBulkUpdateInventory(folderCopy); // HACK!! - // Insert the ID of the copied item into the IM so that we know which item to move to trash if it + // Insert the ID of the copied folder into the IM so that we know which item to move to trash if it // is rejected. // XXX: This is probably a misuse of the session ID slot. im.imSessionID = copyID.Guid; @@ -396,7 +396,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer { folder = new InventoryFolderBase(inventoryID, client.AgentId); folder = invService.GetFolder(folder); - + if (folder != null & trashFolder != null) { previousParentFolderID = folder.ParentID; diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs index b07d38c..162a0c3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs @@ -252,5 +252,198 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests Assert.That(originalItemAfterDelete, Is.Not.Null); } + + [Test] + public void TestAcceptGivenFolder() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID folderId = TestHelpers.ParseTail(0x100); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + InventoryFolderBase originalFolder + = UserInventoryHelpers.CreateInventoryFolder( + m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); + + byte[] giveImBinaryBucket = new byte[17]; + giveImBinaryBucket[0] = (byte)AssetType.Folder; + byte[] itemIdBytes = folderId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + GridInstantMessage acceptIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryAccepted, + false, + "inventory accepted msg", + initialSessionId, + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(acceptIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryFolderBase originalFolderAfterGive + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterGive, Is.Not.Null); + Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); + + // Test for item successfully making it into the receiver's inventory + InventoryFolderBase receivedFolder + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1"); + + Assert.That(receivedFolder, Is.Not.Null); + Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List() { receivedFolder.ID }); + + InventoryFolderBase originalFolderAfterDelete + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterDelete, Is.Not.Null); + + // TODO: Test scenario where giver deletes their item first. + } + + /// + /// Test user rejection of a given item. + /// + /// + /// A rejected item still ends up in the user's trash folder. + /// + [Test] + public void TestRejectGivenFolder() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID initialSessionId = TestHelpers.ParseTail(0x10); + UUID folderId = TestHelpers.ParseTail(0x100); + + UserAccount ua1 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); + UserAccount ua2 + = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); + + ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); + TestClient giverClient = (TestClient)giverSp.ControllingClient; + + ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); + TestClient receiverClient = (TestClient)receiverSp.ControllingClient; + + // Create the folder to test give + InventoryFolderBase originalFolder + = UserInventoryHelpers.CreateInventoryFolder( + m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); + + GridInstantMessage receivedIm = null; + receiverClient.OnReceivedInstantMessage += im => receivedIm = im; + + byte[] giveImBinaryBucket = new byte[17]; + giveImBinaryBucket[0] = (byte)AssetType.Folder; + byte[] itemIdBytes = folderId.GetBytes(); + Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); + + GridInstantMessage giveIm + = new GridInstantMessage( + m_scene, + giverSp.UUID, + giverSp.Name, + receiverSp.UUID, + (byte)InstantMessageDialog.InventoryOffered, + false, + "inventory offered msg", + initialSessionId, + false, + Vector3.Zero, + giveImBinaryBucket, + true); + + giverClient.HandleImprovedInstantMessage(giveIm); + + // These details might not all be correct. + // Session ID is now the created item ID (!) + GridInstantMessage rejectIm + = new GridInstantMessage( + m_scene, + receiverSp.UUID, + receiverSp.Name, + giverSp.UUID, + (byte)InstantMessageDialog.InventoryDeclined, + false, + "inventory declined msg", + new UUID(receivedIm.imSessionID), + false, + Vector3.Zero, + null, + true); + + receiverClient.HandleImprovedInstantMessage(rejectIm); + + // Test for item remaining in the giver's inventory (here we assume a copy item) + // TODO: Test no-copy items. + InventoryFolderBase originalFolderAfterGive + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterGive, Is.Not.Null); + Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); + + // Test for folder successfully making it into the receiver's inventory + InventoryFolderBase receivedFolder + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1"); + + InventoryFolderBase trashFolder + = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder); + + Assert.That(receivedFolder, Is.Not.Null); + Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID)); + Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID)); + + // Test that on a delete, item still exists and is accessible for the giver. + m_scene.InventoryService.PurgeFolder(trashFolder); + + InventoryFolderBase originalFolderAfterDelete + = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); + + Assert.That(originalFolderAfterDelete, Is.Not.Null); + } } } \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs index a1794c9..b3b75af 100644 --- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs @@ -218,12 +218,37 @@ namespace OpenSim.Tests.Common public static InventoryFolderBase CreateInventoryFolder( IInventoryService inventoryService, UUID userId, string path, bool useExistingFolders) { + return CreateInventoryFolder(inventoryService, userId, UUID.Random(), path, useExistingFolders); + } + + /// + /// Create inventory folders starting from the user's root folder. + /// + /// + /// + /// + /// + /// The folders to create. Multiple folders can be specified on a path delimited by the PATH_DELIMITER + /// + /// + /// If true, then folders in the path which already the same name are + /// used. This applies to the terminal folder as well. + /// If false, then all folders in the path are created, even if there is already a folder at a particular + /// level with the same name. + /// + /// + /// The folder created. If the path contains multiple folders then the last one created is returned. + /// Will return null if the root folder could not be found. + /// + public static InventoryFolderBase CreateInventoryFolder( + IInventoryService inventoryService, UUID userId, UUID folderId, string path, bool useExistingFolders) + { InventoryFolderBase rootFolder = inventoryService.GetRootFolder(userId); if (null == rootFolder) return null; - return CreateInventoryFolder(inventoryService, rootFolder, path, useExistingFolders); + return CreateInventoryFolder(inventoryService, folderId, rootFolder, path, useExistingFolders); } /// @@ -235,6 +260,7 @@ namespace OpenSim.Tests.Common /// TODO: May need to make it an option to create duplicate folders. /// /// + /// ID of the folder to create /// /// /// The folder to create. @@ -249,7 +275,7 @@ namespace OpenSim.Tests.Common /// The folder created. If the path contains multiple folders then the last one created is returned. /// public static InventoryFolderBase CreateInventoryFolder( - IInventoryService inventoryService, InventoryFolderBase parentFolder, string path, bool useExistingFolders) + IInventoryService inventoryService, UUID folderId, InventoryFolderBase parentFolder, string path, bool useExistingFolders) { string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None); @@ -262,9 +288,16 @@ namespace OpenSim.Tests.Common { // Console.WriteLine("Creating folder {0} at {1}", components[0], parentFolder.Name); + UUID folderIdForCreate; + + if (components.Length > 1) + folderIdForCreate = UUID.Random(); + else + folderIdForCreate = folderId; + folder = new InventoryFolderBase( - UUID.Random(), components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); + folderIdForCreate, components[0], parentFolder.Owner, (short)AssetType.Unknown, parentFolder.ID, 0); inventoryService.AddFolder(folder); } @@ -274,7 +307,7 @@ namespace OpenSim.Tests.Common // } if (components.Length > 1) - return CreateInventoryFolder(inventoryService, folder, components[1], useExistingFolders); + return CreateInventoryFolder(inventoryService, folderId, folder, components[1], useExistingFolders); else return folder; } diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs index ccbdf81..30b1f38 100644 --- a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs @@ -53,6 +53,9 @@ namespace OpenSim.Tests.Common.Mock public XInventoryFolder[] GetFolders(string[] fields, string[] vals) { +// Console.WriteLine( +// "Requesting folders, fields {0}, vals {1}", string.Join(",", fields), string.Join(",", vals)); + List origFolders = Get(fields, vals, m_allFolders.Values.ToList()); @@ -104,7 +107,30 @@ namespace OpenSim.Tests.Common.Mock } public bool MoveItem(string id, string newParent) { throw new NotImplementedException(); } - public bool MoveFolder(string id, string newParent) { throw new NotImplementedException(); } + + public bool MoveFolder(string id, string newParent) + { + // Don't use GetFolders() here - it takes a clone! + XInventoryFolder folder = m_allFolders[new UUID(id)]; + + if (folder == null) + return false; + + folder.parentFolderID = new UUID(newParent); + + XInventoryFolder[] newParentFolders + = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() }); + +// Console.WriteLine( +// "Moved folder {0} {1}, to {2} {3}", +// folder.folderName, folder.folderID, newParentFolders[0].folderName, folder.parentFolderID); + + // TODO: Really need to implement folder version incrementing, though this should be common code anyway, + // not reimplemented in each db plugin. + + return true; + } + public XInventoryItem[] GetActiveGestures(UUID principalID) { throw new NotImplementedException(); } public int GetAssetPermissions(UUID principalID, UUID assetID) { throw new NotImplementedException(); } } -- cgit v1.1 From 537b243360a69f63210003371d1e6ef9f9c3716c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Apr 2013 22:18:11 +0100 Subject: minor: Eliminate warning in LLimageManagerTests by properly calling through to OpenSimTestCase.SetUp() --- OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 7d9f581..a0e0078 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs @@ -75,6 +75,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests [SetUp] public void SetUp() { + base.SetUp(); + UUID userId = TestHelpers.ParseTail(0x3); J2KDecoderModule j2kdm = new J2KDecoderModule(); -- cgit v1.1 From 3ce198165c3533d416148a9f4ffa056bf22c602d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Apr 2013 22:21:57 +0100 Subject: minor: remove some mono compiler warnings in ServicesServerBase --- OpenSim/Server/Base/ServicesServerBase.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index 7c8e6b7..b13c87d 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -171,11 +171,6 @@ namespace OpenSim.Server.Base m_console = MainConsole.Instance; - // Configure the appenders for log4net - // - OpenSimAppender consoleAppender = null; - FileAppender fileAppender = null; - if (logConfig != null) { FileInfo cfg = new FileInfo(logConfig); -- cgit v1.1 From 15a3f80e2eb82c5e4726d5cd93cfed32da5d6768 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 29 Apr 2013 17:30:38 -0700 Subject: BulletSim: LinksetCompound work to disable collision for root and child prims so compound shape can do all collisions. Don't try to build a compound linkset for non-physical linksets. Remove and replace root body when compound shape is added so collision cache is rebuilt. --- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 44 +++++++++++++++------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 1fd541f..e967dfc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -143,19 +143,18 @@ public sealed class BSLinksetCompound : BSLinkset // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. ScheduleRebuild(LinksetRoot); } - else - { - // The origional prims are removed from the world as the shape of the root compound - // shape takes over. - m_physicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - m_physicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); - // We don't want collisions from the old linkset children. - m_physicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - child.PhysBody.collisionType = CollisionType.LinksetChild; + // The origional prims are removed from the world as the shape of the root compound + // shape takes over. + m_physicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + m_physicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); + // We don't want collisions from the old linkset children. + m_physicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + + child.PhysBody.collisionType = CollisionType.LinksetChild; + + ret = true; - ret = true; - } return ret; } @@ -190,6 +189,13 @@ public sealed class BSLinksetCompound : BSLinkset // Called at taint-time. public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) { + if (!LinksetRoot.IsPhysicallyActive) + { + // No reason to do this physical stuff for static linksets. + DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); + return; + } + // The user moving a child around requires the rebuilding of the linkset compound shape // One problem is this happens when a border is crossed -- the simulator implementation // stores the position into the group which causes the move of the object @@ -392,6 +398,13 @@ public sealed class BSLinksetCompound : BSLinkset private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged private void RecomputeLinksetCompound() { + if (!LinksetRoot.IsPhysicallyActive) + { + // There is no reason to build all this physical stuff for a non-physical linkset + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); + return; + } + try { // This replaces the physical shape of the root prim with a compound shape made up of the root @@ -403,7 +416,8 @@ public sealed class BSLinksetCompound : BSLinkset // Free up any shape we'd previously built. LinksetShape.Dereference(m_physicsScene); - LinksetShape = BSShapeCompound.GetReference(m_physicsScene, LinksetRoot); + // Get a new compound shape to build the linkset shape in. + LinksetShape = BSShapeCompound.GetReference(m_physicsScene); // The center of mass for the linkset is the geometric center of the group. // Compute a displacement for each component so it is relative to the center-of-mass. @@ -431,8 +445,7 @@ public sealed class BSLinksetCompound : BSLinkset cPrim.LinksetChildIndex = memberIndex; } - BSShape childShape = cPrim.PhysShape; - childShape.IncrementReference(); + BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; m_physicsScene.PE.AddChildShapeToCompoundShape(LinksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); @@ -446,7 +459,10 @@ public sealed class BSLinksetCompound : BSLinkset // Sneak the built compound shape in as the shape of the root prim. // Note this doesn't touch the root prim's PhysShape so be sure the manage the difference. + // Object removed and added to world to get collision cache rebuilt for new shape. + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, LinksetShape.physShapeInfo); + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); // With all of the linkset packed into the root prim, it has the mass of everyone. LinksetMass = ComputeLinksetMass(); -- cgit v1.1 From d322625f9062d7748a1a896b6fd37c51f7f41435 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 29 Apr 2013 17:30:54 -0700 Subject: BulletSim: Add non-static BSShape.GetReference for getting another reference to an existing shape instance. BSShapeNative rebuilds shape for all references. BSShapeCompound returns another reference copy if the compound shape already exists (for linksets). --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 125 +++++++++++++++------ .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 9 ++ 2 files changed, 102 insertions(+), 32 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 5c58ad5..f0c9fd5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -47,26 +47,31 @@ public abstract class BSShape public BSShape() { - referenceCount = 0; + referenceCount = 1; lastReferenced = DateTime.Now; physShapeInfo = new BulletShape(); } public BSShape(BulletShape pShape) { - referenceCount = 0; + referenceCount = 1; lastReferenced = DateTime.Now; physShapeInfo = pShape; } + // Get another reference to this shape. + public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); + // Called when this shape is being used again. - public virtual void IncrementReference() + // Used internally. External callers should call instance.GetReference() to properly copy/reference + // the shape. + protected virtual void IncrementReference() { referenceCount++; lastReferenced = DateTime.Now; } // Called when this shape is being used again. - public virtual void DecrementReference() + protected virtual void DecrementReference() { referenceCount--; lastReferenced = DateTime.Now; @@ -99,12 +104,19 @@ public abstract class BSShape // Returns a string for debugging that uniquily identifies the memory used by this instance public virtual string AddrString { - get { return "unknown"; } + get + { + if (physShapeInfo != null) + return physShapeInfo.AddrString; + return "unknown"; + } } public override string ToString() { StringBuilder buff = new StringBuilder(); + buff.Append(" m_hulls; private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, @@ -520,7 +562,7 @@ public class BSShapeHull : BSShape physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } // Now done with the mesh shape. - meshShape.DecrementReference(); + meshShape.Dereference(physicsScene); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } if (!newShape.HasPhysicalShape) @@ -671,37 +713,52 @@ public class BSShapeCompound : BSShape public BSShapeCompound(BulletShape pShape) : base(pShape) { } - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + public static BSShape GetReference(BSScene physicsScene) + { + // Base compound shapes are not shared so this returns a raw shape. + // A built compound shape can be reused in linksets. + return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); + } + public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) { - // Compound shapes are not shared so a new one is created every time. - return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene, prim)); + // Calling this reference means we want another handle to an existing compound shape + // (usually linksets) so return this copy. + IncrementReference(); + return this; } // Dereferencing a compound shape releases the hold on all the child shapes. public override void Dereference(BSScene physicsScene) { - if (!physicsScene.PE.IsCompound(physShapeInfo)) + lock (physShapeInfo) { - // Failed the sanity check!! - physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", - LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", - BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); - return; - } + Dereference(physicsScene); + if (referenceCount <= 0) + { + if (!physicsScene.PE.IsCompound(physShapeInfo)) + { + // Failed the sanity check!! + physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", + LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", + BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); + return; + } - int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", - BSScene.DetailLogZero, physShapeInfo, numChildren); + int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", + BSScene.DetailLogZero, physShapeInfo, numChildren); - // Loop through all the children dereferencing each. - for (int ii = numChildren - 1; ii >= 0; ii--) - { - BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); - DereferenceAnonCollisionShape(physicsScene, childShape); + // Loop through all the children dereferencing each. + for (int ii = numChildren - 1; ii >= 0; ii--) + { + BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); + DereferenceAnonCollisionShape(physicsScene, childShape); + } + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } } - physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); } - private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene, BSPhysObject prim) + private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) { BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); return cShape; @@ -754,6 +811,10 @@ public class BSShapeAvatar : BSShape { return new BSShapeNull(); } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + return new BSShapeNull(); + } public override void Dereference(BSScene physicsScene) { } // From the front: diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index c67081a..559a73f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -1,3 +1,12 @@ +PROBLEMS TO LOOK INTO +================================================= +Nebadon vehicle ride, get up, ride again. Second time vehicle does not act correctly. + Have to rez new vehicle and delete the old to fix situation. +Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd + position state where it will not settle onto ground properly, etc +Two of Nebadon vehicles in a sim max the CPU. This is new. +A sitting, active vehicle bobs up and down a small amount. + CURRENT PRIORITIES ================================================= Use the HACD convex hull routine in Bullet rather than the C# version. -- cgit v1.1 From 7cdb07b386ffe88749fcc6cabadd9851f254699d Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 30 Apr 2013 11:42:11 -0700 Subject: BulletSim: improvements to LinksetCompound and PrimDisplaced. Not all working yet. --- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 37 ++++++++++++++++------ .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 3 +- .../Physics/BulletSPlugin/BSPrimDisplaced.cs | 22 ++++++++++--- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 2 +- .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 3 ++ 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e967dfc..e3ce7fb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -395,7 +395,8 @@ public sealed class BSLinksetCompound : BSLinkset // Constraint linksets are rebuilt every time. // Note that this works for rebuilding just the root after a linkset is taken apart. // Called at taint time!! - private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged + private bool UseBulletSimRootOffsetHack = false; + private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting private void RecomputeLinksetCompound() { if (!LinksetRoot.IsPhysicallyActive) @@ -428,11 +429,19 @@ public sealed class BSLinksetCompound : BSLinkset // 'centerDisplacement' is the value to subtract from children to give physical offset position OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; - LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); - - // TODO: add phantom root shape to be the center-of-mass + if (UseBulletSimRootOffsetHack || disableCOM) + { + centerDisplacement = OMV.Vector3.Zero; + LinksetRoot.ClearDisplacement(); + } + else + { + LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacement); + } + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", + LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacement); - // Add a shape for each of the other children in the linkset + // Add the shapes of all the components of the linkset int memberIndex = 1; ForEachMember(delegate(BSPrimLinkable cPrim) { @@ -449,8 +458,8 @@ public sealed class BSLinksetCompound : BSLinkset OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; m_physicsScene.PE.AddChildShapeToCompoundShape(LinksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", - LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1}cShape={2},offPos={3},offRot={4}", + LinksetRoot.LocalID, memberIndex, cPrim.PhysShape, offsetPos, offsetRot); memberIndex++; @@ -463,13 +472,21 @@ public sealed class BSLinksetCompound : BSLinkset m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, LinksetShape.physShapeInfo); m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", + LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetShape); // With all of the linkset packed into the root prim, it has the mass of everyone. LinksetMass = ComputeLinksetMass(); LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); - // Enable the physical position updator to return the position and rotation of the root shape - m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); + if (UseBulletSimRootOffsetHack) + { + // Enable the physical position updator to return the position and rotation of the root shape. + // This enables a feature in the C++ code to return the world coordinates of the first shape in the + // compound shape. This eleviates the need to offset the returned physical position by the + // center-of-mass offset. + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); + } } finally { @@ -477,7 +494,7 @@ public sealed class BSLinksetCompound : BSLinkset } // See that the Aabb surrounds the new shape - m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); + m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetShape.physShapeInfo); } } } \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 28d4bd7..7eba851 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -259,7 +259,8 @@ public abstract class BSPhysObject : PhysicsActor // The user can optionally set the center of mass. The user's setting will override any // computed center-of-mass (like in linksets). - public OMV.Vector3? UserSetCenterOfMass { get; set; } + // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. + public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index f1c3b5c..f5ee671 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs @@ -78,14 +78,16 @@ public class BSPrimDisplaced : BSPrim // Set this sets and computes the displacement from the passed prim to the center-of-mass. // A user set value for center-of-mass overrides whatever might be passed in here. // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). - public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) + public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) { Vector3 comDisp; - if (UserSetCenterOfMass.HasValue) - comDisp = (OMV.Vector3)UserSetCenterOfMass; + if (UserSetCenterOfMassDisplacement.HasValue) + comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; else comDisp = centerOfMassDisplacement; + DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", + LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); if (comDisp == Vector3.Zero) { // If there is no diplacement. Things get reset. @@ -107,9 +109,15 @@ public class BSPrimDisplaced : BSPrim set { if (PositionDisplacement != OMV.Vector3.Zero) - base.ForcePosition = value - (PositionDisplacement * RawOrientation); + { + OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation); + DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos); + base.ForcePosition = displacedPos; + } else + { base.ForcePosition = value; + } } } @@ -118,6 +126,7 @@ public class BSPrimDisplaced : BSPrim get { return base.ForceOrientation; } set { + // TODO: base.ForceOrientation = value; } } @@ -143,7 +152,10 @@ public class BSPrimDisplaced : BSPrim { // Correct for any rotation around the center-of-mass // TODO!!! - entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); + + OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); + DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos); + entprop.Position = displacedPos; // entprop.Rotation = something; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index f0c9fd5..3faa484 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -117,7 +117,7 @@ public abstract class BSShape StringBuilder buff = new StringBuilder(); buff.Append(" /// If true, then exclude the seed cap. - public Hashtable GetCapsDetails(bool excludeSeed) + public Hashtable GetCapsDetails(bool excludeSeed, List requestedCaps) { Hashtable caps = new Hashtable(); string protocol = "http://"; @@ -175,6 +175,9 @@ namespace OpenSim.Framework.Capabilities if (excludeSeed && "SEED" == capsName) continue; + if (requestedCaps != null && !requestedCaps.Contains(capsName)) + continue; + caps[capsName] = baseUrl + m_capsHandlers[capsName].Path; } } @@ -182,4 +185,4 @@ namespace OpenSim.Framework.Capabilities return caps; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 8752404..a46c24a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -273,11 +273,22 @@ namespace OpenSim.Region.ClientStack.Linden return string.Empty; } - Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true); + OSDArray capsRequested = (OSDArray)OSDParser.DeserializeLLSDXml(request); + List validCaps = new List(); + + foreach (OSD c in capsRequested) + validCaps.Add(c.AsString()); + + Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); // Add the external too foreach (KeyValuePair kvp in m_HostCapsObj.ExternalCapsHandlers) + { + if (!validCaps.Contains(kvp.Key)) + continue; + caps[kvp.Key] = kvp.Value; + } string result = LLSDHelpers.SerialiseLLSDReply(caps); diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 8329af0..6ae9448 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -240,7 +240,7 @@ namespace OpenSim.Region.CoreModules.Framework { caps.AppendFormat("** User {0}:\n", kvp.Key); - for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false).GetEnumerator(); kvp2.MoveNext(); ) + for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) { Uri uri = new Uri(kvp2.Value.ToString()); caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); -- cgit v1.1 From 206fb306a7820cf593570e35ddfa8e7c5a10e449 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 1 May 2013 19:01:43 +0100 Subject: Update SmartThreadPool to latest version 2.2.3 with a major and minor change. SmartThreadPool code comes from http://www.codeproject.com/Articles/7933/Smart-Thread-Pool This version implements thread abort (via WorkItem.Cancel(true)), threadpool naming, max thread stack, etc. so we no longer need to manually patch those. However, two changes have been made to stock 2.2.3. Major change: WorkItem.Cancel(bool abortExecution) in our version does not succeed if the work item was in progress and thread abort was not specified. This is to match previous behaviour where we handle co-operative termination via another mechanism rather than checking WorkItem.IsCanceled. Minor change: Did not add STP's StopWatch implementation as this is only used WinCE and Silverlight and causes a build clash with System.Diagnostics.StopWatch The reason for updating is to see if this improves http://opensimulator.org/mantis/view.php?id=6557 and http://opensimulator.org/mantis/view.php?id=6586 --- OpenSim/Framework/Util.cs | 20 +- .../ScriptEngine/Interfaces/IScriptInstance.cs | 2 +- .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 9 +- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 4 +- OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs | 6 +- ThirdParty/SmartThreadPool/AssemblyInfo.cs | 61 - ThirdParty/SmartThreadPool/CallerThreadContext.cs | 361 +-- .../SmartThreadPool/CanceledWorkItemsGroup.cs | 14 + ThirdParty/SmartThreadPool/EventWaitHandle.cs | 104 + .../SmartThreadPool/EventWaitHandleFactory.cs | 82 + ThirdParty/SmartThreadPool/Exceptions.cs | 192 +- ThirdParty/SmartThreadPool/Interfaces.cs | 899 ++++-- ThirdParty/SmartThreadPool/InternalInterfaces.cs | 27 + ThirdParty/SmartThreadPool/PriorityQueue.cs | 479 ++- .../SmartThreadPool/Properties/AssemblyInfo.cs | 23 + ThirdParty/SmartThreadPool/SLExt.cs | 16 + ThirdParty/SmartThreadPool/STPEventWaitHandle.cs | 62 + .../SmartThreadPool/STPPerformanceCounter.cs | 802 ++--- ThirdParty/SmartThreadPool/STPStartInfo.cs | 325 +- .../SmartThreadPool/SmartThreadPool.ThreadEntry.cs | 60 + ThirdParty/SmartThreadPool/SmartThreadPool.cs | 3180 +++++++++++--------- .../SmartThreadPool/SynchronizedDictionary.cs | 89 + ThirdParty/SmartThreadPool/WIGStartInfo.cs | 270 +- .../SmartThreadPool/WorkItem.WorkItemResult.cs | 190 ++ ThirdParty/SmartThreadPool/WorkItem.cs | 649 ++-- ThirdParty/SmartThreadPool/WorkItemFactory.cs | 676 +++-- ThirdParty/SmartThreadPool/WorkItemInfo.cs | 171 +- .../SmartThreadPool/WorkItemResultTWrapper.cs | 128 + ThirdParty/SmartThreadPool/WorkItemsGroup.cs | 873 +++--- ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs | 471 +++ ThirdParty/SmartThreadPool/WorkItemsQueue.cs | 1245 ++++---- 31 files changed, 6688 insertions(+), 4802 deletions(-) delete mode 100644 ThirdParty/SmartThreadPool/AssemblyInfo.cs create mode 100644 ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs create mode 100644 ThirdParty/SmartThreadPool/EventWaitHandle.cs create mode 100644 ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs create mode 100644 ThirdParty/SmartThreadPool/InternalInterfaces.cs create mode 100644 ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs create mode 100644 ThirdParty/SmartThreadPool/SLExt.cs create mode 100644 ThirdParty/SmartThreadPool/STPEventWaitHandle.cs create mode 100644 ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs create mode 100644 ThirdParty/SmartThreadPool/SynchronizedDictionary.cs create mode 100644 ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs create mode 100644 ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs create mode 100644 ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index bde4673..a3602e9 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1840,7 +1840,7 @@ namespace OpenSim.Framework case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) InitThreadPool(15); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); + m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); break; case FireAndForgetMethod.Thread: Thread thread = new Thread(delegate(object o) { realCallback(o); }); @@ -1910,15 +1910,15 @@ namespace OpenSim.Framework return sb.ToString(); } - private static object SmartThreadPoolCallback(object o) - { - object[] array = (object[])o; - WaitCallback callback = (WaitCallback)array[0]; - object obj = array[1]; - - callback(obj); - return null; - } +// private static object SmartThreadPoolCallback(object o) +// { +// object[] array = (object[])o; +// WaitCallback callback = (WaitCallback)array[0]; +// object obj = array[1]; +// +// callback(obj); +// return null; +// } #endregion FireAndForget Threading Pattern diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 35ae44c..b9a217b 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces public interface IScriptWorkItem { bool Cancel(); - void Abort(); + bool Abort(); /// /// Wait for the work item to complete. diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 1e6db43..f9d3afc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -564,9 +564,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public bool Stop(int timeout) { -// m_log.DebugFormat( -// "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", -// ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); + if (DebugLevel >= 1) + m_log.DebugFormat( + "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", + ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); IScriptWorkItem workItem; @@ -627,6 +628,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } } + Console.WriteLine("Here9"); + lock (EventQueue) { workItem = m_CurrentWorkItem; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 0d9babb..5804aa8 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -483,7 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine /// /// Basis on which to sort output. Can be null if no sort needs to take place private void HandleScriptsAction( - string[] cmdparams, Action action, Func keySelector) + string[] cmdparams, Action action, System.Func keySelector) { if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) return; @@ -1517,7 +1517,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine startInfo.MaxWorkerThreads = maxThreads; startInfo.MinWorkerThreads = minThreads; startInfo.ThreadPriority = threadPriority;; - startInfo.StackSize = stackSize; + startInfo.MaxStackSize = stackSize; startInfo.StartSuspended = true; m_ThreadPool = new SmartThreadPool(startInfo); diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs index 8dd7677..9d9dee1 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs @@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine return wr.Cancel(); } - public void Abort() + public bool Abort() { - wr.Abort(); + return wr.Cancel(true); } public bool Wait(int t) { // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an - // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 + // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8 // (or very likely other versions of Mono at least up until 3.0.3). return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); } diff --git a/ThirdParty/SmartThreadPool/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/AssemblyInfo.cs deleted file mode 100644 index e2465b0..0000000 --- a/ThirdParty/SmartThreadPool/AssemblyInfo.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -// -// 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("")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: CLSCompliant(true)] - -// -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly: AssemblyVersion("0.7.6.*")] - -// -// In order to sign your assembly you must specify a key to use. Refer to the -// Microsoft .NET Framework documentation for more information on assembly signing. -// -// Use the attributes below to control which key is used for signing. -// -// Notes: -// (*) If no key is specified, the assembly is not signed. -// (*) KeyName refers to a key that has been installed in the Crypto Service -// Provider (CSP) on your machine. KeyFile refers to a file which contains -// a key. -// (*) If the KeyFile and the KeyName values are both specified, the -// following processing occurs: -// (1) If the KeyName can be found in the CSP, that key is used. -// (2) If the KeyName does not exist and the KeyFile does exist, the key -// in the KeyFile is installed into the CSP and used. -// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. -// When specifying the KeyFile, the location of the KeyFile should be -// relative to the project output directory which is -// %Project Directory%\obj\. For example, if your KeyFile is -// located in the project directory, you would specify the AssemblyKeyFile -// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] -// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework -// documentation for more information on this. -// -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs index 6ea53f6..2177241 100644 --- a/ThirdParty/SmartThreadPool/CallerThreadContext.cs +++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs @@ -1,223 +1,138 @@ -using System; -using System.Diagnostics; -using System.Threading; -using System.Reflection; -using System.Web; -using System.Runtime.Remoting.Messaging; - - -namespace Amib.Threading -{ - #region CallerThreadContext class - - /// - /// This class stores the caller call context in order to restore - /// it when the work item is executed in the thread pool environment. - /// - internal class CallerThreadContext - { - #region Prepare reflection information - - // Cached type information. - private static MethodInfo getLogicalCallContextMethodInfo = - typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); - - private static MethodInfo setLogicalCallContextMethodInfo = - typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); - - private static string HttpContextSlotName = GetHttpContextSlotName(); - - private static string GetHttpContextSlotName() - { - FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); - - if( fi != null ) - return (string)fi.GetValue(null); - else // Use the default "HttpContext" slot name - return "HttpContext"; - } - - #endregion - - #region Private fields - - private HttpContext _httpContext = null; - private LogicalCallContext _callContext = null; - - #endregion - - /// - /// Constructor - /// - private CallerThreadContext() - { - } - - public bool CapturedCallContext - { - get - { - return (null != _callContext); - } - } - - public bool CapturedHttpContext - { - get - { - return (null != _httpContext); - } - } - - /// - /// Captures the current thread context - /// - /// - public static CallerThreadContext Capture( - bool captureCallContext, - bool captureHttpContext) - { - Debug.Assert(captureCallContext || captureHttpContext); - - CallerThreadContext callerThreadContext = new CallerThreadContext(); - - // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() - // Capture Call Context - if(captureCallContext && (getLogicalCallContextMethodInfo != null)) - { - callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); - if (callerThreadContext._callContext != null) - { - callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); - } - } - - // Capture httpContext - if (captureHttpContext && (null != HttpContext.Current)) - { - callerThreadContext._httpContext = HttpContext.Current; - } - - return callerThreadContext; - } - - /// - /// Applies the thread context stored earlier - /// - /// - public static void Apply(CallerThreadContext callerThreadContext) - { - if (null == callerThreadContext) - { - throw new ArgumentNullException("callerThreadContext"); - } - - // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() - // Restore call context - if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) - { - setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); - } - - // Restore HttpContext - if (callerThreadContext._httpContext != null) - { - CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); - } - } - } - - #endregion - -} - - -/* -// Ami Bar -// amibar@gmail.com - -using System; -using System.Threading; -using System.Globalization; -using System.Security.Principal; -using System.Reflection; -using System.Runtime.Remoting.Contexts; - -namespace Amib.Threading.Internal -{ - #region CallerThreadContext class - - /// - /// This class stores the caller thread context in order to restore - /// it when the work item is executed in the context of the thread - /// from the pool. - /// Note that we can't store the thread's CompressedStack, because - /// it throws a security exception - /// - public class CallerThreadContext - { - private CultureInfo _culture = null; - private CultureInfo _cultureUI = null; - private IPrincipal _principal; - private System.Runtime.Remoting.Contexts.Context _context; - - private static FieldInfo _fieldInfo = GetFieldInfo(); - - private static FieldInfo GetFieldInfo() - { - Type threadType = typeof(Thread); - return threadType.GetField( - "m_Context", - BindingFlags.Instance | BindingFlags.NonPublic); - } - - /// - /// Constructor - /// - private CallerThreadContext() - { - } - - /// - /// Captures the current thread context - /// - /// - public static CallerThreadContext Capture() - { - CallerThreadContext callerThreadContext = new CallerThreadContext(); - - Thread thread = Thread.CurrentThread; - callerThreadContext._culture = thread.CurrentCulture; - callerThreadContext._cultureUI = thread.CurrentUICulture; - callerThreadContext._principal = Thread.CurrentPrincipal; - callerThreadContext._context = Thread.CurrentContext; - return callerThreadContext; - } - - /// - /// Applies the thread context stored earlier - /// - /// - public static void Apply(CallerThreadContext callerThreadContext) - { - Thread thread = Thread.CurrentThread; - thread.CurrentCulture = callerThreadContext._culture; - thread.CurrentUICulture = callerThreadContext._cultureUI; - Thread.CurrentPrincipal = callerThreadContext._principal; - - // Uncomment the following block to enable the Thread.CurrentThread -/* - if (null != _fieldInfo) - { - _fieldInfo.SetValue( - Thread.CurrentThread, - callerThreadContext._context); - } -* / - } - } - - #endregion -} -*/ - + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + +using System; +using System.Diagnostics; +using System.Threading; +using System.Reflection; +using System.Web; +using System.Runtime.Remoting.Messaging; + + +namespace Amib.Threading.Internal +{ +#region CallerThreadContext class + + /// + /// This class stores the caller call context in order to restore + /// it when the work item is executed in the thread pool environment. + /// + internal class CallerThreadContext + { +#region Prepare reflection information + + // Cached type information. + private static readonly MethodInfo getLogicalCallContextMethodInfo = + typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); + + private static readonly MethodInfo setLogicalCallContextMethodInfo = + typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); + + private static string HttpContextSlotName = GetHttpContextSlotName(); + + private static string GetHttpContextSlotName() + { + FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); + + if (fi != null) + { + return (string) fi.GetValue(null); + } + + return "HttpContext"; + } + + #endregion + +#region Private fields + + private HttpContext _httpContext; + private LogicalCallContext _callContext; + + #endregion + + /// + /// Constructor + /// + private CallerThreadContext() + { + } + + public bool CapturedCallContext + { + get + { + return (null != _callContext); + } + } + + public bool CapturedHttpContext + { + get + { + return (null != _httpContext); + } + } + + /// + /// Captures the current thread context + /// + /// + public static CallerThreadContext Capture( + bool captureCallContext, + bool captureHttpContext) + { + Debug.Assert(captureCallContext || captureHttpContext); + + CallerThreadContext callerThreadContext = new CallerThreadContext(); + + // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() + // Capture Call Context + if(captureCallContext && (getLogicalCallContextMethodInfo != null)) + { + callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); + if (callerThreadContext._callContext != null) + { + callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); + } + } + + // Capture httpContext + if (captureHttpContext && (null != HttpContext.Current)) + { + callerThreadContext._httpContext = HttpContext.Current; + } + + return callerThreadContext; + } + + /// + /// Applies the thread context stored earlier + /// + /// + public static void Apply(CallerThreadContext callerThreadContext) + { + if (null == callerThreadContext) + { + throw new ArgumentNullException("callerThreadContext"); + } + + // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() + // Restore call context + if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) + { + setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); + } + + // Restore HttpContext + if (callerThreadContext._httpContext != null) + { + HttpContext.Current = callerThreadContext._httpContext; + //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); + } + } + } + + #endregion +} +#endif diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs new file mode 100644 index 0000000..4a2a3e7 --- /dev/null +++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs @@ -0,0 +1,14 @@ +namespace Amib.Threading.Internal +{ + internal class CanceledWorkItemsGroup + { + public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); + + public CanceledWorkItemsGroup() + { + IsCanceled = false; + } + + public bool IsCanceled { get; set; } + } +} \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs new file mode 100644 index 0000000..70a1a29 --- /dev/null +++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs @@ -0,0 +1,104 @@ +#if (_WINDOWS_CE) + +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Amib.Threading.Internal +{ + /// + /// EventWaitHandle class + /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation. + /// So I wrote this class to implement these two methods with some of their overloads. + /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny. + /// Note that this class doesn't even inherit from WaitHandle! + /// + public class STPEventWaitHandle + { + #region Public Constants + + public const int WaitTimeout = Timeout.Infinite; + + #endregion + + #region Private External Constants + + private const Int32 WAIT_FAILED = -1; + private const Int32 WAIT_TIMEOUT = 0x102; + private const UInt32 INFINITE = 0xFFFFFFFF; + + #endregion + + #region WaitAll and WaitAny + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout, exitContext); + } + + private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles) + { + IntPtr[] nativeHandles = new IntPtr[waitHandles.Length]; + for (int i = 0; i < waitHandles.Length; i++) + { + nativeHandles[i] = waitHandles[i].Handle; + } + return nativeHandles; + } + + public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; + + IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); + + int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout); + + if (result == WAIT_TIMEOUT || result == WAIT_FAILED) + { + return false; + } + + return true; + } + + + public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; + + IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); + + int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout); + + if (result >= 0 && result < waitHandles.Length) + { + return result; + } + + return -1; + } + + public static int WaitAny(WaitHandle[] waitHandles) + { + return WaitAny(waitHandles, Timeout.Infinite, false); + } + + public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) + { + int millisecondsTimeout = (int)timeout.TotalMilliseconds; + + return WaitAny(waitHandles, millisecondsTimeout, false); + } + + #endregion + + #region External methods + + [DllImport("coredll.dll", SetLastError = true)] + public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds); + + #endregion + } +} +#endif \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs new file mode 100644 index 0000000..2f8c55b --- /dev/null +++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs @@ -0,0 +1,82 @@ +using System.Threading; + +#if (_WINDOWS_CE) +using System; +using System.Runtime.InteropServices; +#endif + +namespace Amib.Threading.Internal +{ + /// + /// EventWaitHandleFactory class. + /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. + /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property + /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. + /// Consequently this class creates the needed XxxResetEvent and replaces the handle if + /// it's a WindowsCE OS. + /// + public static class EventWaitHandleFactory + { + /// + /// Create a new AutoResetEvent object + /// + /// Return a new AutoResetEvent object + public static AutoResetEvent CreateAutoResetEvent() + { + AutoResetEvent waitHandle = new AutoResetEvent(false); + +#if (_WINDOWS_CE) + ReplaceEventHandle(waitHandle, false, false); +#endif + + return waitHandle; + } + + /// + /// Create a new ManualResetEvent object + /// + /// Return a new ManualResetEvent object + public static ManualResetEvent CreateManualResetEvent(bool initialState) + { + ManualResetEvent waitHandle = new ManualResetEvent(initialState); + +#if (_WINDOWS_CE) + ReplaceEventHandle(waitHandle, true, initialState); +#endif + + return waitHandle; + } + +#if (_WINDOWS_CE) + + /// + /// Replace the event handle + /// + /// The WaitHandle object which its handle needs to be replaced. + /// Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false) + /// The initial state of the event + private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState) + { + // Store the old handle + IntPtr oldHandle = waitHandle.Handle; + + // Create a new event + IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null); + + // Replace the old event with the new event + waitHandle.Handle = newHandle; + + // Close the old event + CloseHandle (oldHandle); + } + + [DllImport("coredll.dll", SetLastError = true)] + public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); + + //Handle + [DllImport("coredll.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); +#endif + + } +} diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs index c454709..8e66ce9 100644 --- a/ThirdParty/SmartThreadPool/Exceptions.cs +++ b/ThirdParty/SmartThreadPool/Exceptions.cs @@ -1,81 +1,111 @@ -// Ami Bar -// amibar@gmail.com - -using System; -using System.Runtime.Serialization; - -namespace Amib.Threading -{ - #region Exceptions - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been canceled - /// - [Serializable] - public sealed class WorkItemCancelException : ApplicationException - { - public WorkItemCancelException() : base() - { - } - - public WorkItemCancelException(string message) : base(message) - { - } - - public WorkItemCancelException(string message, Exception e) : base(message, e) - { - } - - public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - [Serializable] - public sealed class WorkItemTimeoutException : ApplicationException - { - public WorkItemTimeoutException() : base() - { - } - - public WorkItemTimeoutException(string message) : base(message) - { - } - - public WorkItemTimeoutException(string message, Exception e) : base(message, e) - { - } - - public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - [Serializable] - public sealed class WorkItemResultException : ApplicationException - { - public WorkItemResultException() : base() - { - } - - public WorkItemResultException(string message) : base(message) - { - } - - public WorkItemResultException(string message, Exception e) : base(message, e) - { - } - - public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc) - { - } - } - - #endregion -} +using System; +#if !(_WINDOWS_CE) +using System.Runtime.Serialization; +#endif + +namespace Amib.Threading +{ + #region Exceptions + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been canceled + /// + public sealed partial class WorkItemCancelException : Exception + { + public WorkItemCancelException() + { + } + + public WorkItemCancelException(string message) + : base(message) + { + } + + public WorkItemCancelException(string message, Exception e) + : base(message, e) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + public sealed partial class WorkItemTimeoutException : Exception + { + public WorkItemTimeoutException() + { + } + + public WorkItemTimeoutException(string message) + : base(message) + { + } + + public WorkItemTimeoutException(string message, Exception e) + : base(message, e) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + public sealed partial class WorkItemResultException : Exception + { + public WorkItemResultException() + { + } + + public WorkItemResultException(string message) + : base(message) + { + } + + public WorkItemResultException(string message, Exception e) + : base(message, e) + { + } + } + + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + /// + /// Represents an exception in case IWorkItemResult.GetResult has been canceled + /// + [Serializable] + public sealed partial class WorkItemCancelException + { + public WorkItemCancelException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + [Serializable] + public sealed partial class WorkItemTimeoutException + { + public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + [Serializable] + public sealed partial class WorkItemResultException + { + public WorkItemResultException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + +#endif + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs index f1c1fcf..29c8a3e 100644 --- a/ThirdParty/SmartThreadPool/Interfaces.cs +++ b/ThirdParty/SmartThreadPool/Interfaces.cs @@ -1,271 +1,628 @@ -// Ami Bar -// amibar@gmail.com - -using System; -using System.Threading; - -namespace Amib.Threading -{ - #region Delegates - - /// - /// A delegate that represents the method to run as the work item - /// - /// A state object for the method to run - public delegate object WorkItemCallback(object state); - - /// - /// A delegate to call after the WorkItemCallback completed - /// - /// The work item result object - public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); - - /// - /// A delegate to call when a WorkItemsGroup becomes idle - /// - /// A reference to the WorkItemsGroup that became idle - public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); - - #endregion - - #region WorkItem Priority - - public enum WorkItemPriority - { - Lowest, - BelowNormal, - Normal, - AboveNormal, - Highest, - } - - #endregion - - #region IHasWorkItemPriority interface - - public interface IHasWorkItemPriority - { - WorkItemPriority WorkItemPriority { get; } - } - - #endregion - - #region IWorkItemsGroup interface - - /// - /// IWorkItemsGroup interface - /// - public interface IWorkItemsGroup - { - /// - /// Get/Set the name of the WorkItemsGroup - /// - string Name { get; set; } - - IWorkItemResult QueueWorkItem(WorkItemCallback callback); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); - - IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); - IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); - - void WaitForIdle(); - bool WaitForIdle(TimeSpan timeout); - bool WaitForIdle(int millisecondsTimeout); - - int WaitingCallbacks { get; } - event WorkItemsGroupIdleHandler OnIdle; - - void Cancel(); - void Start(); - } - - #endregion - - #region CallToPostExecute enumerator - - [Flags] - public enum CallToPostExecute - { - Never = 0x00, - WhenWorkItemCanceled = 0x01, - WhenWorkItemNotCanceled = 0x02, - Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, - } - - #endregion - - #region IWorkItemResult interface - - /// - /// IWorkItemResult interface - /// - public interface IWorkItemResult - { - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits. - /// - /// The result of the work item - object GetResult(); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - object GetResult( - int millisecondsTimeout, - bool exitContext); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - object GetResult( - TimeSpan timeout, - bool exitContext); - - void Abort(); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// Timeout in milliseconds, or -1 for infinite - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the blocking if needed - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - object GetResult( - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - object GetResult( - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits. - /// - /// Filled with the exception if one was thrown - /// The result of the work item - object GetResult(out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - object GetResult( - int millisecondsTimeout, - bool exitContext, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - object GetResult( - TimeSpan timeout, - bool exitContext, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// Timeout in milliseconds, or -1 for infinite - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the blocking if needed - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - object GetResult( - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// The result of the work item - /// Filled with the exception if one was thrown - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - object GetResult( - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle, - out Exception e); - - /// - /// Gets an indication whether the asynchronous operation has completed. - /// - bool IsCompleted { get; } - - /// - /// Gets an indication whether the asynchronous operation has been canceled. - /// - bool IsCanceled { get; } - - /// - /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. - /// - object State { get; } - - /// - /// Cancel the work item if it didn't start running yet. - /// - /// Returns true on success or false if the work item is in progress or already completed - bool Cancel(); - - /// - /// Get the work item's priority - /// - WorkItemPriority WorkItemPriority { get; } - - /// - /// Return the result, same as GetResult() - /// - object Result { get; } - - /// - /// Returns the exception if occured otherwise returns null. - /// - object Exception { get; } - } - - #endregion -} +using System; +using System.Threading; + +namespace Amib.Threading +{ + #region Delegates + + /// + /// A delegate that represents the method to run as the work item + /// + /// A state object for the method to run + public delegate object WorkItemCallback(object state); + + /// + /// A delegate to call after the WorkItemCallback completed + /// + /// The work item result object + public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); + + /// + /// A delegate to call after the WorkItemCallback completed + /// + /// The work item result object + public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); + + /// + /// A delegate to call when a WorkItemsGroup becomes idle + /// + /// A reference to the WorkItemsGroup that became idle + public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); + + /// + /// A delegate to call after a thread is created, but before + /// it's first use. + /// + public delegate void ThreadInitializationHandler(); + + /// + /// A delegate to call when a thread is about to exit, after + /// it is no longer belong to the pool. + /// + public delegate void ThreadTerminationHandler(); + + #endregion + + #region WorkItem Priority + + /// + /// Defines the availeable priorities of a work item. + /// The higher the priority a work item has, the sooner + /// it will be executed. + /// + public enum WorkItemPriority + { + Lowest, + BelowNormal, + Normal, + AboveNormal, + Highest, + } + + #endregion + + #region IWorkItemsGroup interface + + /// + /// IWorkItemsGroup interface + /// Created by SmartThreadPool.CreateWorkItemsGroup() + /// + public interface IWorkItemsGroup + { + /// + /// Get/Set the name of the WorkItemsGroup + /// + string Name { get; set; } + + /// + /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool + /// + int Concurrency { get; set; } + + /// + /// Get the number of work items waiting in the queue. + /// + int WaitingCallbacks { get; } + + /// + /// Get an array with all the state objects of the currently running items. + /// The array represents a snap shot and impact performance. + /// + object[] GetStates(); + + /// + /// Get the WorkItemsGroup start information + /// + WIGStartInfo WIGStartInfo { get; } + + /// + /// Starts to execute work items + /// + void Start(); + + /// + /// Cancel all the work items. + /// Same as Cancel(false) + /// + void Cancel(); + + /// + /// Cancel all work items using thread abortion + /// + /// True to stop work items by raising ThreadAbortException + void Cancel(bool abortExecution); + + /// + /// Wait for all work item to complete. + /// + void WaitForIdle(); + + /// + /// Wait for all work item to complete, until timeout expired + /// + /// How long to wait for the work items to complete + /// Returns true if work items completed within the timeout, otherwise false. + bool WaitForIdle(TimeSpan timeout); + + /// + /// Wait for all work item to complete, until timeout expired + /// + /// How long to wait for the work items to complete in milliseconds + /// Returns true if work items completed within the timeout, otherwise false. + bool WaitForIdle(int millisecondsTimeout); + + /// + /// IsIdle is true when there are no work items running or queued. + /// + bool IsIdle { get; } + + /// + /// This event is fired when all work items are completed. + /// (When IsIdle changes to true) + /// This event only work on WorkItemsGroup. On SmartThreadPool + /// it throws the NotImplementedException. + /// + event WorkItemsGroupIdleHandler OnIdle; + + #region QueueWorkItem + + /// + /// Queue a work item + /// + /// A callback to execute + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback); + + /// + /// Queue a work item + /// + /// A callback to execute + /// The priority of the work item + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// Work item info + /// A callback to execute + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); + + /// + /// Queue a work item + /// + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); + + #endregion + + #region QueueWorkItem(Action<...>) + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T arg); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority); + + #endregion + + #region QueueWorkItem(Func<...>) + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T arg); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + #endregion + } + + #endregion + + #region CallToPostExecute enumerator + + [Flags] + public enum CallToPostExecute + { + /// + /// Never call to the PostExecute call back + /// + Never = 0x00, + + /// + /// Call to the PostExecute only when the work item is cancelled + /// + WhenWorkItemCanceled = 0x01, + + /// + /// Call to the PostExecute only when the work item is not cancelled + /// + WhenWorkItemNotCanceled = 0x02, + + /// + /// Always call to the PostExecute + /// + Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, + } + + #endregion + + #region IWorkItemResult interface + + /// + /// The common interface of IWorkItemResult and IWorkItemResult<T> + /// + public interface IWaitableResult + { + /// + /// This method intent is for internal use. + /// + /// + IWorkItemResult GetWorkItemResult(); + + /// + /// This method intent is for internal use. + /// + /// + IWorkItemResult GetWorkItemResultT(); + } + + /// + /// IWorkItemResult interface. + /// Created when a WorkItemCallback work item is queued. + /// + public interface IWorkItemResult : IWorkItemResult + { + } + + /// + /// IWorkItemResult<TResult> interface. + /// Created when a Func<TResult> work item is queued. + /// + public interface IWorkItemResult : IWaitableResult + { + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits. + /// + /// The result of the work item + TResult GetResult(); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + int millisecondsTimeout, + bool exitContext); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + TimeSpan timeout, + bool exitContext); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// Timeout in milliseconds, or -1 for infinite + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the blocking if needed + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits. + /// + /// Filled with the exception if one was thrown + /// The result of the work item + TResult GetResult(out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// + /// + /// Filled with the exception if one was thrown + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// + /// Filled with the exception if one was thrown + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// Timeout in milliseconds, or -1 for infinite + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the blocking if needed + /// Filled with the exception if one was thrown + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// The result of the work item + /// + /// Filled with the exception if one was thrown + /// + /// + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle, + out Exception e); + + /// + /// Gets an indication whether the asynchronous operation has completed. + /// + bool IsCompleted { get; } + + /// + /// Gets an indication whether the asynchronous operation has been canceled. + /// + bool IsCanceled { get; } + + /// + /// Gets the user-defined object that contains context data + /// for the work item method. + /// + object State { get; } + + /// + /// Same as Cancel(false). + /// + bool Cancel(); + + /// + /// Cancel the work item execution. + /// If the work item is in the queue then it won't execute + /// If the work item is completed, it will remain completed + /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled + /// property to check if the work item has been cancelled. If the abortExecution is set to true then + /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution + /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException. + /// If the work item is already cancelled it will remain cancelled + /// + /// When true send an AbortException to the executing thread. + /// Returns true if the work item was not completed, otherwise false. + bool Cancel(bool abortExecution); + + /// + /// Get the work item's priority + /// + WorkItemPriority WorkItemPriority { get; } + + /// + /// Return the result, same as GetResult() + /// + TResult Result { get; } + + /// + /// Returns the exception if occured otherwise returns null. + /// + object Exception { get; } + } + + #endregion + + #region .NET 3.5 + + // All these delegate are built-in .NET 3.5 + // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity. + + public delegate void Action(); + public delegate void Action(T1 arg1, T2 arg2); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + public delegate TResult Func(); + public delegate TResult Func(T arg1); + public delegate TResult Func(T1 arg1, T2 arg2); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/InternalInterfaces.cs b/ThirdParty/SmartThreadPool/InternalInterfaces.cs new file mode 100644 index 0000000..8be7161 --- /dev/null +++ b/ThirdParty/SmartThreadPool/InternalInterfaces.cs @@ -0,0 +1,27 @@ + +namespace Amib.Threading.Internal +{ + /// + /// An internal delegate to call when the WorkItem starts or completes + /// + internal delegate void WorkItemStateCallback(WorkItem workItem); + + internal interface IInternalWorkItemResult + { + event WorkItemStateCallback OnWorkItemStarted; + event WorkItemStateCallback OnWorkItemCompleted; + } + + internal interface IInternalWaitableResult + { + /// + /// This method is intent for internal use. + /// + IWorkItemResult GetWorkItemResult(); + } + + public interface IHasWorkItemPriority + { + WorkItemPriority WorkItemPriority { get; } + } +} diff --git a/ThirdParty/SmartThreadPool/PriorityQueue.cs b/ThirdParty/SmartThreadPool/PriorityQueue.cs index 63d5e84..6245fd8 100644 --- a/ThirdParty/SmartThreadPool/PriorityQueue.cs +++ b/ThirdParty/SmartThreadPool/PriorityQueue.cs @@ -1,240 +1,239 @@ -// Ami Bar -// amibar@gmail.com - -using System; -using System.Collections; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - #region PriorityQueue class - - /// - /// PriorityQueue class - /// This class is not thread safe because we use external lock - /// - public sealed class PriorityQueue : IEnumerable - { - #region Private members - - /// - /// The number of queues, there is one for each type of priority - /// - private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; - - /// - /// Work items queues. There is one for each type of priority - /// - private Queue [] _queues = new Queue[_queuesCount]; - - /// - /// The total number of work items within the queues - /// - private int _workItemsCount = 0; - - /// - /// Use with IEnumerable interface - /// - private int _version = 0; - - #endregion - - #region Contructor - - public PriorityQueue() - { - for(int i = 0; i < _queues.Length; ++i) - { - _queues[i] = new Queue(); - } - } - - #endregion - - #region Methods - - /// - /// Enqueue a work item. - /// - /// A work item - public void Enqueue(IHasWorkItemPriority workItem) - { - Debug.Assert(null != workItem); - - int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; - Debug.Assert(queueIndex >= 0); - Debug.Assert(queueIndex < _queuesCount); - - _queues[queueIndex].Enqueue(workItem); - ++_workItemsCount; - ++_version; - } - - /// - /// Dequeque a work item. - /// - /// Returns the next work item - public IHasWorkItemPriority Dequeue() - { - IHasWorkItemPriority workItem = null; - - if(_workItemsCount > 0) - { - int queueIndex = GetNextNonEmptyQueue(-1); - Debug.Assert(queueIndex >= 0); - workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority; - Debug.Assert(null != workItem); - --_workItemsCount; - ++_version; - } - - return workItem; - } - - /// - /// Find the next non empty queue starting at queue queueIndex+1 - /// - /// The index-1 to start from - /// - /// The index of the next non empty queue or -1 if all the queues are empty - /// - private int GetNextNonEmptyQueue(int queueIndex) - { - for(int i = queueIndex+1; i < _queuesCount; ++i) - { - if(_queues[i].Count > 0) - { - return i; - } - } - return -1; - } - - /// - /// The number of work items - /// - public int Count - { - get - { - return _workItemsCount; - } - } - - /// - /// Clear all the work items - /// - public void Clear() - { - if (_workItemsCount > 0) - { - foreach(Queue queue in _queues) - { - queue.Clear(); - } - _workItemsCount = 0; - ++_version; - } - } - - #endregion - - #region IEnumerable Members - - /// - /// Returns an enumerator to iterate over the work items - /// - /// Returns an enumerator - public IEnumerator GetEnumerator() - { - return new PriorityQueueEnumerator(this); - } - - #endregion - - #region PriorityQueueEnumerator - - /// - /// The class the implements the enumerator - /// - private class PriorityQueueEnumerator : IEnumerator - { - private PriorityQueue _priorityQueue; - private int _version; - private int _queueIndex; - private IEnumerator _enumerator; - - public PriorityQueueEnumerator(PriorityQueue priorityQueue) - { - _priorityQueue = priorityQueue; - _version = _priorityQueue._version; - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); - if (_queueIndex >= 0) - { - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - } - else - { - _enumerator = null; - } - } - - #region IEnumerator Members - - public void Reset() - { - _version = _priorityQueue._version; - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); - if (_queueIndex >= 0) - { - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - } - else - { - _enumerator = null; - } - } - - public object Current - { - get - { - Debug.Assert(null != _enumerator); - return _enumerator.Current; - } - } - - public bool MoveNext() - { - if (null == _enumerator) - { - return false; - } - - if(_version != _priorityQueue._version) - { - throw new InvalidOperationException("The collection has been modified"); - - } - if (!_enumerator.MoveNext()) - { - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); - if(-1 == _queueIndex) - { - return false; - } - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - _enumerator.MoveNext(); - return true; - } - return true; - } - - #endregion - } - - #endregion - } - - #endregion -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Amib.Threading.Internal +{ + #region PriorityQueue class + + /// + /// PriorityQueue class + /// This class is not thread safe because we use external lock + /// + public sealed class PriorityQueue : IEnumerable + { + #region Private members + + /// + /// The number of queues, there is one for each type of priority + /// + private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; + + /// + /// Work items queues. There is one for each type of priority + /// + private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; + + /// + /// The total number of work items within the queues + /// + private int _workItemsCount; + + /// + /// Use with IEnumerable interface + /// + private int _version; + + #endregion + + #region Contructor + + public PriorityQueue() + { + for(int i = 0; i < _queues.Length; ++i) + { + _queues[i] = new LinkedList(); + } + } + + #endregion + + #region Methods + + /// + /// Enqueue a work item. + /// + /// A work item + public void Enqueue(IHasWorkItemPriority workItem) + { + Debug.Assert(null != workItem); + + int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; + Debug.Assert(queueIndex >= 0); + Debug.Assert(queueIndex < _queuesCount); + + _queues[queueIndex].AddLast(workItem); + ++_workItemsCount; + ++_version; + } + + /// + /// Dequeque a work item. + /// + /// Returns the next work item + public IHasWorkItemPriority Dequeue() + { + IHasWorkItemPriority workItem = null; + + if(_workItemsCount > 0) + { + int queueIndex = GetNextNonEmptyQueue(-1); + Debug.Assert(queueIndex >= 0); + workItem = _queues[queueIndex].First.Value; + _queues[queueIndex].RemoveFirst(); + Debug.Assert(null != workItem); + --_workItemsCount; + ++_version; + } + + return workItem; + } + + /// + /// Find the next non empty queue starting at queue queueIndex+1 + /// + /// The index-1 to start from + /// + /// The index of the next non empty queue or -1 if all the queues are empty + /// + private int GetNextNonEmptyQueue(int queueIndex) + { + for(int i = queueIndex+1; i < _queuesCount; ++i) + { + if(_queues[i].Count > 0) + { + return i; + } + } + return -1; + } + + /// + /// The number of work items + /// + public int Count + { + get + { + return _workItemsCount; + } + } + + /// + /// Clear all the work items + /// + public void Clear() + { + if (_workItemsCount > 0) + { + foreach(LinkedList queue in _queues) + { + queue.Clear(); + } + _workItemsCount = 0; + ++_version; + } + } + + #endregion + + #region IEnumerable Members + + /// + /// Returns an enumerator to iterate over the work items + /// + /// Returns an enumerator + public IEnumerator GetEnumerator() + { + return new PriorityQueueEnumerator(this); + } + + #endregion + + #region PriorityQueueEnumerator + + /// + /// The class the implements the enumerator + /// + private class PriorityQueueEnumerator : IEnumerator + { + private readonly PriorityQueue _priorityQueue; + private int _version; + private int _queueIndex; + private IEnumerator _enumerator; + + public PriorityQueueEnumerator(PriorityQueue priorityQueue) + { + _priorityQueue = priorityQueue; + _version = _priorityQueue._version; + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); + if (_queueIndex >= 0) + { + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + } + else + { + _enumerator = null; + } + } + + #region IEnumerator Members + + public void Reset() + { + _version = _priorityQueue._version; + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); + if (_queueIndex >= 0) + { + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + } + else + { + _enumerator = null; + } + } + + public object Current + { + get + { + Debug.Assert(null != _enumerator); + return _enumerator.Current; + } + } + + public bool MoveNext() + { + if (null == _enumerator) + { + return false; + } + + if(_version != _priorityQueue._version) + { + throw new InvalidOperationException("The collection has been modified"); + + } + if (!_enumerator.MoveNext()) + { + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); + if(-1 == _queueIndex) + { + return false; + } + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + _enumerator.MoveNext(); + return true; + } + return true; + } + + #endregion + } + + #endregion + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1651e78 --- /dev/null +++ b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Amib.Threading")] +[assembly: AssemblyDescription("Smart Thread Pool")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Amib.Threading")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")] +[assembly: AssemblyVersion("2.2.3.0")] + +#if (_PUBLISH) +[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")] +#else +[assembly: InternalsVisibleTo("STPTests")] +#endif + + diff --git a/ThirdParty/SmartThreadPool/SLExt.cs b/ThirdParty/SmartThreadPool/SLExt.cs new file mode 100644 index 0000000..fafff19 --- /dev/null +++ b/ThirdParty/SmartThreadPool/SLExt.cs @@ -0,0 +1,16 @@ +#if _SILVERLIGHT + +using System.Threading; + +namespace Amib.Threading +{ + public enum ThreadPriority + { + Lowest, + BelowNormal, + Normal, + AboveNormal, + Highest, + } +} +#endif diff --git a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs new file mode 100644 index 0000000..3b92645 --- /dev/null +++ b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs @@ -0,0 +1,62 @@ +#if !(_WINDOWS_CE) + +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ +#if _WINDOWS || WINDOWS_PHONE + internal static class STPEventWaitHandle + { + public const int WaitTimeout = Timeout.Infinite; + + internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAll(waitHandles, millisecondsTimeout); + } + + internal static int WaitAny(WaitHandle[] waitHandles) + { + return WaitHandle.WaitAny(waitHandles); + } + + internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAny(waitHandles, millisecondsTimeout); + } + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout); + } + } +#else + internal static class STPEventWaitHandle + { + public const int WaitTimeout = Timeout.Infinite; + + internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); + } + + internal static int WaitAny(WaitHandle[] waitHandles) + { + return WaitHandle.WaitAny(waitHandles); + } + + internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); + } + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout, exitContext); + } + } +#endif + +} + +#endif \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs index 077cf17..2508661 100644 --- a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs +++ b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs @@ -1,354 +1,448 @@ -using System; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - internal enum STPPerformanceCounterType - { - // Fields - ActiveThreads = 0, - InUseThreads = 1, - OverheadThreads = 2, - OverheadThreadsPercent = 3, - OverheadThreadsPercentBase = 4, - - WorkItems = 5, - WorkItemsInQueue = 6, - WorkItemsProcessed = 7, - - WorkItemsQueuedPerSecond = 8, - WorkItemsProcessedPerSecond = 9, - - AvgWorkItemWaitTime = 10, - AvgWorkItemWaitTimeBase = 11, - - AvgWorkItemProcessTime = 12, - AvgWorkItemProcessTimeBase = 13, - - WorkItemsGroups = 14, - - LastCounter = 14, - } - - - /// - /// Summary description for STPPerformanceCounter. - /// - internal class STPPerformanceCounter - { - // Fields - private PerformanceCounterType _pcType; - protected string _counterHelp; - protected string _counterName; - - // Methods - public STPPerformanceCounter( - string counterName, - string counterHelp, - PerformanceCounterType pcType) - { - this._counterName = counterName; - this._counterHelp = counterHelp; - this._pcType = pcType; - } - - public void AddCounterToCollection(CounterCreationDataCollection counterData) - { - CounterCreationData counterCreationData = new CounterCreationData( - _counterName, - _counterHelp, - _pcType); - - counterData.Add(counterCreationData); - } - - // Properties - public string Name - { - get - { - return _counterName; - } - } - } - - internal class STPPerformanceCounters - { - // Fields - internal STPPerformanceCounter[] _stpPerformanceCounters; - private static STPPerformanceCounters _instance; - internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; - internal const string _stpCategoryName = "SmartThreadPool"; - - // Methods - static STPPerformanceCounters() - { - _instance = new STPPerformanceCounters(); - } - - private STPPerformanceCounters() - { - STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] - { - new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), - new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), - - new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), - - new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), - new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), - - new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), - new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), - - new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), - new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), - - new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), - }; - - _stpPerformanceCounters = stpPerformanceCounters; - SetupCategory(); - } - - private void SetupCategory() - { - if (!PerformanceCounterCategory.Exists(_stpCategoryName)) - { - CounterCreationDataCollection counters = new CounterCreationDataCollection(); - - for (int i = 0; i < _stpPerformanceCounters.Length; i++) - { - _stpPerformanceCounters[i].AddCounterToCollection(counters); - } - - - // *********** Remark for .NET 2.0 *********** - // If you are here, it means you got the warning that this overload - // of the method is deprecated in .NET 2.0. To use the correct - // method overload, uncomment the third argument of - // the method. - #pragma warning disable 0618 - PerformanceCounterCategory.Create( - _stpCategoryName, - _stpCategoryHelp, - //PerformanceCounterCategoryType.MultiInstance, - counters); - #pragma warning restore 0618 - } - } - - // Properties - public static STPPerformanceCounters Instance - { - get - { - return _instance; - } - } - } - - internal class STPInstancePerformanceCounter : IDisposable - { - // Fields - private PerformanceCounter _pcs; - - // Methods - protected STPInstancePerformanceCounter() - { - } - - public STPInstancePerformanceCounter( - string instance, - STPPerformanceCounterType spcType) - { - STPPerformanceCounters counters = STPPerformanceCounters.Instance; - _pcs = new PerformanceCounter( - STPPerformanceCounters._stpCategoryName, - counters._stpPerformanceCounters[(int) spcType].Name, - instance, - false); - _pcs.RawValue = _pcs.RawValue; - } - - ~STPInstancePerformanceCounter() - { - Close(); - } - - public void Close() - { - if (_pcs != null) - { - _pcs.RemoveInstance(); - _pcs.Close(); - _pcs = null; - } - } - - public void Dispose() - { - Close(); - GC.SuppressFinalize(this); - } - - public virtual void Increment() - { - _pcs.Increment(); - } - - public virtual void IncrementBy(long val) - { - _pcs.IncrementBy(val); - } - - public virtual void Set(long val) - { - _pcs.RawValue = val; - } - } - - internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter - { - // Methods - public STPInstanceNullPerformanceCounter() {} - public override void Increment() {} - public override void IncrementBy(long value) {} - public override void Set(long val) {} - } - - internal interface ISTPInstancePerformanceCounters : IDisposable - { - void Close(); - void SampleThreads(long activeThreads, long inUseThreads); - void SampleWorkItems(long workItemsQueued, long workItemsProcessed); - void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); - void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); - } - - - internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable - { - // Fields - private STPInstancePerformanceCounter[] _pcs; - private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; - - // Methods - static STPInstancePerformanceCounters() - { - _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); - } - - public STPInstancePerformanceCounters(string instance) - { - _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; - // STPPerformanceCounters counters = STPPerformanceCounters.Instance; - for (int i = 0; i < _pcs.Length; i++) - { - if (instance != null) - { - _pcs[i] = new STPInstancePerformanceCounter( - instance, - (STPPerformanceCounterType) i); - } - else - { - _pcs[i] = _stpInstanceNullPerformanceCounter; - } - } - } - - - public void Close() - { - if (null != _pcs) - { - for (int i = 0; i < _pcs.Length; i++) - { - if (null != _pcs[i]) - { - _pcs[i].Close(); - } - } - _pcs = null; - } - } - - ~STPInstancePerformanceCounters() - { - Close(); - } - - public void Dispose() - { - Close(); - GC.SuppressFinalize(this); - } - - private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) - { - return _pcs[(int) spcType]; - } - - public void SampleThreads(long activeThreads, long inUseThreads) - { - GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); - GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); - GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); - - GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); - GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); - } - - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) - { - GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); - GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); - GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); - - GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); - GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); - } - - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) - { - GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); - GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); - } - - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) - { - GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); - GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); - } - } - - internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable - { - static NullSTPInstancePerformanceCounters() - { - } - - private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null); - - public static NullSTPInstancePerformanceCounters Instance - { - get { return _instance; } - } - - public NullSTPInstancePerformanceCounters(string instance) {} - public void Close() {} - public void Dispose() {} - - public void SampleThreads(long activeThreads, long inUseThreads) {} - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} - } - -} +using System; +using System.Diagnostics; +using System.Threading; + +namespace Amib.Threading +{ + public interface ISTPPerformanceCountersReader + { + long InUseThreads { get; } + long ActiveThreads { get; } + long WorkItemsQueued { get; } + long WorkItemsProcessed { get; } + } +} + +namespace Amib.Threading.Internal +{ + internal interface ISTPInstancePerformanceCounters : IDisposable + { + void Close(); + void SampleThreads(long activeThreads, long inUseThreads); + void SampleWorkItems(long workItemsQueued, long workItemsProcessed); + void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); + void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); + } +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + internal enum STPPerformanceCounterType + { + // Fields + ActiveThreads = 0, + InUseThreads = 1, + OverheadThreads = 2, + OverheadThreadsPercent = 3, + OverheadThreadsPercentBase = 4, + + WorkItems = 5, + WorkItemsInQueue = 6, + WorkItemsProcessed = 7, + + WorkItemsQueuedPerSecond = 8, + WorkItemsProcessedPerSecond = 9, + + AvgWorkItemWaitTime = 10, + AvgWorkItemWaitTimeBase = 11, + + AvgWorkItemProcessTime = 12, + AvgWorkItemProcessTimeBase = 13, + + WorkItemsGroups = 14, + + LastCounter = 14, + } + + + /// + /// Summary description for STPPerformanceCounter. + /// + internal class STPPerformanceCounter + { + // Fields + private readonly PerformanceCounterType _pcType; + protected string _counterHelp; + protected string _counterName; + + // Methods + public STPPerformanceCounter( + string counterName, + string counterHelp, + PerformanceCounterType pcType) + { + _counterName = counterName; + _counterHelp = counterHelp; + _pcType = pcType; + } + + public void AddCounterToCollection(CounterCreationDataCollection counterData) + { + CounterCreationData counterCreationData = new CounterCreationData( + _counterName, + _counterHelp, + _pcType); + + counterData.Add(counterCreationData); + } + + // Properties + public string Name + { + get + { + return _counterName; + } + } + } + + internal class STPPerformanceCounters + { + // Fields + internal STPPerformanceCounter[] _stpPerformanceCounters; + private static readonly STPPerformanceCounters _instance; + internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; + internal const string _stpCategoryName = "SmartThreadPool"; + + // Methods + static STPPerformanceCounters() + { + _instance = new STPPerformanceCounters(); + } + + private STPPerformanceCounters() + { + STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] + { + new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), + new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), + + new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), + + new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), + new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), + + new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), + new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), + + new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), + new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), + + new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), + }; + + _stpPerformanceCounters = stpPerformanceCounters; + SetupCategory(); + } + + private void SetupCategory() + { + if (!PerformanceCounterCategory.Exists(_stpCategoryName)) + { + CounterCreationDataCollection counters = new CounterCreationDataCollection(); + + for (int i = 0; i < _stpPerformanceCounters.Length; i++) + { + _stpPerformanceCounters[i].AddCounterToCollection(counters); + } + + PerformanceCounterCategory.Create( + _stpCategoryName, + _stpCategoryHelp, + PerformanceCounterCategoryType.MultiInstance, + counters); + + } + } + + // Properties + public static STPPerformanceCounters Instance + { + get + { + return _instance; + } + } + } + + internal class STPInstancePerformanceCounter : IDisposable + { + // Fields + private bool _isDisposed; + private PerformanceCounter _pcs; + + // Methods + protected STPInstancePerformanceCounter() + { + _isDisposed = false; + } + + public STPInstancePerformanceCounter( + string instance, + STPPerformanceCounterType spcType) : this() + { + STPPerformanceCounters counters = STPPerformanceCounters.Instance; + _pcs = new PerformanceCounter( + STPPerformanceCounters._stpCategoryName, + counters._stpPerformanceCounters[(int) spcType].Name, + instance, + false); + _pcs.RawValue = _pcs.RawValue; + } + + + public void Close() + { + if (_pcs != null) + { + _pcs.RemoveInstance(); + _pcs.Close(); + _pcs = null; + } + } + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + } + } + _isDisposed = true; + } + + public virtual void Increment() + { + _pcs.Increment(); + } + + public virtual void IncrementBy(long val) + { + _pcs.IncrementBy(val); + } + + public virtual void Set(long val) + { + _pcs.RawValue = val; + } + } + + internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter + { + // Methods + public override void Increment() {} + public override void IncrementBy(long value) {} + public override void Set(long val) {} + } + + + + internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters + { + private bool _isDisposed; + // Fields + private STPInstancePerformanceCounter[] _pcs; + private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; + + // Methods + static STPInstancePerformanceCounters() + { + _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); + } + + public STPInstancePerformanceCounters(string instance) + { + _isDisposed = false; + _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; + + // Call the STPPerformanceCounters.Instance so the static constructor will + // intialize the STPPerformanceCounters singleton. + STPPerformanceCounters.Instance.GetHashCode(); + + for (int i = 0; i < _pcs.Length; i++) + { + if (instance != null) + { + _pcs[i] = new STPInstancePerformanceCounter( + instance, + (STPPerformanceCounterType) i); + } + else + { + _pcs[i] = _stpInstanceNullPerformanceCounter; + } + } + } + + + public void Close() + { + if (null != _pcs) + { + for (int i = 0; i < _pcs.Length; i++) + { + if (null != _pcs[i]) + { + _pcs[i].Dispose(); + } + } + _pcs = null; + } + } + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + } + } + _isDisposed = true; + } + + private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) + { + return _pcs[(int) spcType]; + } + + public void SampleThreads(long activeThreads, long inUseThreads) + { + GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); + GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); + GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); + + GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); + GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); + } + + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) + { + GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); + GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); + GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); + + GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); + GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); + } + + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) + { + GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); + GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); + } + + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) + { + GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); + GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); + } + } +#endif + + internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader + { + private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(); + + public static NullSTPInstancePerformanceCounters Instance + { + get { return _instance; } + } + + public void Close() {} + public void Dispose() {} + + public void SampleThreads(long activeThreads, long inUseThreads) {} + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} + public long InUseThreads + { + get { return 0; } + } + + public long ActiveThreads + { + get { return 0; } + } + + public long WorkItemsQueued + { + get { return 0; } + } + + public long WorkItemsProcessed + { + get { return 0; } + } + } + + internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader + { + public void Close() { } + public void Dispose() { } + + private long _activeThreads; + private long _inUseThreads; + private long _workItemsQueued; + private long _workItemsProcessed; + + public long InUseThreads + { + get { return _inUseThreads; } + } + + public long ActiveThreads + { + get { return _activeThreads; } + } + + public long WorkItemsQueued + { + get { return _workItemsQueued; } + } + + public long WorkItemsProcessed + { + get { return _workItemsProcessed; } + } + + public void SampleThreads(long activeThreads, long inUseThreads) + { + _activeThreads = activeThreads; + _inUseThreads = inUseThreads; + } + + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) + { + _workItemsQueued = workItemsQueued; + _workItemsProcessed = workItemsProcessed; + } + + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) + { + // Not supported + } + + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) + { + // Not supported + } + } +} diff --git a/ThirdParty/SmartThreadPool/STPStartInfo.cs b/ThirdParty/SmartThreadPool/STPStartInfo.cs index fa9ceb4..2ec8dc6 100644 --- a/ThirdParty/SmartThreadPool/STPStartInfo.cs +++ b/ThirdParty/SmartThreadPool/STPStartInfo.cs @@ -1,113 +1,212 @@ -// Ami Bar -// amibar@gmail.com - -using System.Threading; - -namespace Amib.Threading -{ - /// - /// Summary description for STPStartInfo. - /// - public class STPStartInfo : WIGStartInfo - { - /// - /// Idle timeout in milliseconds. - /// If a thread is idle for _idleTimeout milliseconds then - /// it may quit. - /// - private int _idleTimeout; - - /// - /// The lower limit of threads in the pool. - /// - private int _minWorkerThreads; - - /// - /// The upper limit of threads in the pool. - /// - private int _maxWorkerThreads; - - /// - /// The priority of the threads in the pool - /// - private ThreadPriority _threadPriority; - - /// - /// The thread pool name. Threads will get names depending on this. - /// - private string _threadPoolName; - - /// - /// If this field is not null then the performance counters are enabled - /// and use the string as the name of the instance. - /// - private string _pcInstanceName; - - private int _stackSize; - - public STPStartInfo() : base() - { - _idleTimeout = SmartThreadPool.DefaultIdleTimeout; - _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; - _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; - _threadPriority = SmartThreadPool.DefaultThreadPriority; - _threadPoolName = SmartThreadPool.DefaultThreadPoolName; - _pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; - _stackSize = SmartThreadPool.DefaultStackSize; - } - - public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo) - { - _idleTimeout = stpStartInfo._idleTimeout; - _minWorkerThreads = stpStartInfo._minWorkerThreads; - _maxWorkerThreads = stpStartInfo._maxWorkerThreads; - _threadPriority = stpStartInfo._threadPriority; - _threadPoolName = stpStartInfo._threadPoolName; - _pcInstanceName = stpStartInfo._pcInstanceName; - _stackSize = stpStartInfo._stackSize; - } - - public int IdleTimeout - { - get { return _idleTimeout; } - set { _idleTimeout = value; } - } - - public int MinWorkerThreads - { - get { return _minWorkerThreads; } - set { _minWorkerThreads = value; } - } - - public int MaxWorkerThreads - { - get { return _maxWorkerThreads; } - set { _maxWorkerThreads = value; } - } - - public ThreadPriority ThreadPriority - { - get { return _threadPriority; } - set { _threadPriority = value; } - } - - public virtual string ThreadPoolName - { - get { return _threadPoolName; } - set { _threadPoolName = value; } - } - - - public string PerformanceCounterInstanceName - { - get { return _pcInstanceName; } - set { _pcInstanceName = value; } - } - - public int StackSize - { - get { return _stackSize; } - set { _stackSize = value; } - } - } -} +using System; +using System.Threading; + +namespace Amib.Threading +{ + /// + /// Summary description for STPStartInfo. + /// + public class STPStartInfo : WIGStartInfo + { + private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout; + private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; + private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; +#if !(WINDOWS_PHONE) + private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority; +#endif + private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; + private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground; + private bool _enableLocalPerformanceCounters; + private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName; + private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize; + + public STPStartInfo() + { + _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; +#if !(WINDOWS_PHONE) + _threadPriority = SmartThreadPool.DefaultThreadPriority; +#endif + _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; + _idleTimeout = SmartThreadPool.DefaultIdleTimeout; + _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; + } + + public STPStartInfo(STPStartInfo stpStartInfo) + : base(stpStartInfo) + { + _idleTimeout = stpStartInfo.IdleTimeout; + _minWorkerThreads = stpStartInfo.MinWorkerThreads; + _maxWorkerThreads = stpStartInfo.MaxWorkerThreads; +#if !(WINDOWS_PHONE) + _threadPriority = stpStartInfo.ThreadPriority; +#endif + _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName; + _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters; + _threadPoolName = stpStartInfo._threadPoolName; + _areThreadsBackground = stpStartInfo.AreThreadsBackground; +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + _apartmentState = stpStartInfo._apartmentState; +#endif + } + + /// + /// Get/Set the idle timeout in milliseconds. + /// If a thread is idle (starved) longer than IdleTimeout then it may quit. + /// + public virtual int IdleTimeout + { + get { return _idleTimeout; } + set + { + ThrowIfReadOnly(); + _idleTimeout = value; + } + } + + + /// + /// Get/Set the lower limit of threads in the pool. + /// + public virtual int MinWorkerThreads + { + get { return _minWorkerThreads; } + set + { + ThrowIfReadOnly(); + _minWorkerThreads = value; + } + } + + + /// + /// Get/Set the upper limit of threads in the pool. + /// + public virtual int MaxWorkerThreads + { + get { return _maxWorkerThreads; } + set + { + ThrowIfReadOnly(); + _maxWorkerThreads = value; + } + } + +#if !(WINDOWS_PHONE) + /// + /// Get/Set the scheduling priority of the threads in the pool. + /// The Os handles the scheduling. + /// + public virtual ThreadPriority ThreadPriority + { + get { return _threadPriority; } + set + { + ThrowIfReadOnly(); + _threadPriority = value; + } + } +#endif + /// + /// Get/Set the thread pool name. Threads will get names depending on this. + /// + public virtual string ThreadPoolName { + get { return _threadPoolName; } + set + { + ThrowIfReadOnly (); + _threadPoolName = value; + } + } + + /// + /// Get/Set the performance counter instance name of this SmartThreadPool + /// The default is null which indicate not to use performance counters at all. + /// + public virtual string PerformanceCounterInstanceName + { + get { return _performanceCounterInstanceName; } + set + { + ThrowIfReadOnly(); + _performanceCounterInstanceName = value; + } + } + + /// + /// Enable/Disable the local performance counter. + /// This enables the user to get some performance information about the SmartThreadPool + /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.) + /// The default is false. + /// + public virtual bool EnableLocalPerformanceCounters + { + get { return _enableLocalPerformanceCounters; } + set + { + ThrowIfReadOnly(); + _enableLocalPerformanceCounters = value; + } + } + + /// + /// Get/Set backgroundness of thread in thread pool. + /// + public virtual bool AreThreadsBackground + { + get { return _areThreadsBackground; } + set + { + ThrowIfReadOnly (); + _areThreadsBackground = value; + } + } + + /// + /// Get a readonly version of this STPStartInfo. + /// + /// Returns a readonly reference to this STPStartInfo + public new STPStartInfo AsReadOnly() + { + return new STPStartInfo(this) { _readOnly = true }; + } + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState; + + /// + /// Get/Set the apartment state of threads in the thread pool + /// + public ApartmentState ApartmentState + { + get { return _apartmentState; } + set + { + ThrowIfReadOnly(); + _apartmentState = value; + } + } + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + /// + /// Get/Set the max stack size of threads in the thread pool + /// + public int? MaxStackSize + { + get { return _maxStackSize; } + set + { + ThrowIfReadOnly(); + if (value.HasValue && value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", "Value must be greater than 0."); + } + _maxStackSize = value; + } + } +#endif + +#endif + } +} diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs new file mode 100644 index 0000000..ba7d73f --- /dev/null +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs @@ -0,0 +1,60 @@ + +using System; +using Amib.Threading.Internal; + +namespace Amib.Threading +{ + public partial class SmartThreadPool + { + #region ThreadEntry class + + internal class ThreadEntry + { + /// + /// The thread creation time + /// The value is stored as UTC value. + /// + private readonly DateTime _creationTime; + + /// + /// The last time this thread has been running + /// It is updated by IAmAlive() method + /// The value is stored as UTC value. + /// + private DateTime _lastAliveTime; + + /// + /// A reference from each thread in the thread pool to its SmartThreadPool + /// object container. + /// With this variable a thread can know whatever it belongs to a + /// SmartThreadPool. + /// + private readonly SmartThreadPool _associatedSmartThreadPool; + + /// + /// A reference to the current work item a thread from the thread pool + /// is executing. + /// + public WorkItem CurrentWorkItem { get; set; } + + public ThreadEntry(SmartThreadPool stp) + { + _associatedSmartThreadPool = stp; + _creationTime = DateTime.UtcNow; + _lastAliveTime = DateTime.MinValue; + } + + public SmartThreadPool AssociatedSmartThreadPool + { + get { return _associatedSmartThreadPool; } + } + + public void IAmAlive() + { + _lastAliveTime = DateTime.UtcNow; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs index 19a0007..9256777 100644 --- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs @@ -1,1448 +1,1732 @@ -// Ami Bar -// amibar@gmail.com -// -// Smart thread pool in C#. -// 7 Aug 2004 - Initial release -// 14 Sep 2004 - Bug fixes -// 15 Oct 2004 - Added new features -// - Work items return result. -// - Support waiting synchronization for multiple work items. -// - Work items can be cancelled. -// - Passage of the caller threads context to the thread in the pool. -// - Minimal usage of WIN32 handles. -// - Minor bug fixes. -// 26 Dec 2004 - Changes: -// - Removed static constructors. -// - Added finalizers. -// - Changed Exceptions so they are serializable. -// - Fixed the bug in one of the SmartThreadPool constructors. -// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. -// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. -// - Added PostExecute with options on which cases to call it. -// - Added option to dispose of the state objects. -// - Added a WaitForIdle() method that waits until the work items queue is empty. -// - Added an STPStartInfo class for the initialization of the thread pool. -// - Changed exception handling so if a work item throws an exception it -// is rethrown at GetResult(), rather then firing an UnhandledException event. -// Note that PostExecute exception are always ignored. -// 25 Mar 2005 - Changes: -// - Fixed lost of work items bug -// 3 Jul 2005: Changes. -// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. -// 16 Aug 2005: Changes. -// - Fixed bug where the InUseThreads becomes negative when canceling work items. -// -// 31 Jan 2006 - Changes: -// - Added work items priority -// - Removed support of chained delegates in callbacks and post executes (nobody really use this) -// - Added work items groups -// - Added work items groups idle event -// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array -// it returns true rather then throwing an exception. -// - Added option to start the STP and the WIG as suspended -// - Exception behavior changed, the real exception is returned by an -// inner exception -// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) -// - Added performance counters -// - Added priority to the threads in the pool -// -// 13 Feb 2006 - Changes: -// - Added a call to the dispose of the Performance Counter so -// their won't be a Performance Counter leak. -// - Added exception catch in case the Performance Counters cannot -// be created. - -using System; -using System.Security; -using System.Threading; -using System.Collections; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -using Amib.Threading.Internal; - -namespace Amib.Threading -{ - #region SmartThreadPool class - /// - /// Smart thread pool class. - /// - public class SmartThreadPool : IWorkItemsGroup, IDisposable - { - #region Default Constants - - /// - /// Default minimum number of threads the thread pool contains. (0) - /// - public const int DefaultMinWorkerThreads = 0; - - /// - /// Default maximum number of threads the thread pool contains. (25) - /// - public const int DefaultMaxWorkerThreads = 25; - - /// - /// Default idle timeout in milliseconds. (One minute) - /// - public const int DefaultIdleTimeout = 60*1000; // One minute - - /// - /// Indicate to copy the security context of the caller and then use it in the call. (false) - /// - public const bool DefaultUseCallerCallContext = false; - - /// - /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) - /// - public const bool DefaultUseCallerHttpContext = false; - - /// - /// Indicate to dispose of the state objects if they support the IDispose interface. (false) - /// - public const bool DefaultDisposeOfStateObjects = false; - - /// - /// The default option to run the post execute - /// - public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; - - /// - /// The default post execute method to run. - /// When null it means not to call it. - /// - public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback = null; - - /// - /// The default work item priority - /// - public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; - - /// - /// The default is to work on work items as soon as they arrive - /// and not to wait for the start. - /// - public const bool DefaultStartSuspended = false; - - /// - /// The default is not to use the performance counters - /// - public static readonly string DefaultPerformanceCounterInstanceName = null; - - public static readonly int DefaultStackSize = 0; - - /// - /// The default thread priority - /// - public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; - - /// - /// The default thread pool name - /// - public const string DefaultThreadPoolName = "SmartThreadPool"; - - #endregion - - #region Member Variables - - /// - /// Contains the name of this instance of SmartThreadPool. - /// Can be changed by the user. - /// - private string _name = DefaultThreadPoolName; - - /// - /// Hashtable of all the threads in the thread pool. - /// - private Hashtable _workerThreads = Hashtable.Synchronized(new Hashtable()); - - /// - /// Queue of work items. - /// - private WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); - - /// - /// Count the work items handled. - /// Used by the performance counter. - /// - private long _workItemsProcessed = 0; - - /// - /// Number of threads that currently work (not idle). - /// - private int _inUseWorkerThreads = 0; - - /// - /// Start information to use. - /// It is simpler than providing many constructors. - /// - private STPStartInfo _stpStartInfo = new STPStartInfo(); - - /// - /// Total number of work items that are stored in the work items queue - /// plus the work items that the threads in the pool are working on. - /// - private int _currentWorkItemsCount = 0; - - /// - /// Signaled when the thread pool is idle, i.e. no thread is busy - /// and the work items queue is empty - /// - private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); - - /// - /// An event to signal all the threads to quit immediately. - /// - private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); - - /// - /// A flag to indicate the threads to quit. - /// - private bool _shutdown = false; - - /// - /// Counts the threads created in the pool. - /// It is used to name the threads. - /// - private int _threadCounter = 0; - - /// - /// Indicate that the SmartThreadPool has been disposed - /// - private bool _isDisposed = false; - - /// - /// Event to send that the thread pool is idle - /// - private event EventHandler _stpIdle; - - /// - /// On idle event - /// - //private event WorkItemsGroupIdleHandler _onIdle; - - /// - /// Holds all the WorkItemsGroup instaces that have at least one - /// work item int the SmartThreadPool - /// This variable is used in case of Shutdown - /// - private Hashtable _workItemsGroups = Hashtable.Synchronized(new Hashtable()); - - /// - /// A reference from each thread in the thread pool to its SmartThreadPool - /// object container. - /// With this variable a thread can know whatever it belongs to a - /// SmartThreadPool. - /// - [ThreadStatic] - private static SmartThreadPool _smartThreadPool; - - /// - /// A reference to the current work item a thread from the thread pool - /// is executing. - /// - [ThreadStatic] - private static WorkItem _currentWorkItem; - - /// - /// STP performance counters - /// - private ISTPInstancePerformanceCounters _pcs = NullSTPInstancePerformanceCounters.Instance; - - #endregion - - #region Construction and Finalization - - /// - /// Constructor - /// - public SmartThreadPool() - { - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - public SmartThreadPool(int idleTimeout) - { - _stpStartInfo.IdleTimeout = idleTimeout; - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - /// Upper limit of threads in the pool - public SmartThreadPool( - int idleTimeout, - int maxWorkerThreads) - { - _stpStartInfo.IdleTimeout = idleTimeout; - _stpStartInfo.MaxWorkerThreads = maxWorkerThreads; - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - /// Upper limit of threads in the pool - /// Lower limit of threads in the pool - public SmartThreadPool( - int idleTimeout, - int maxWorkerThreads, - int minWorkerThreads) - { - _stpStartInfo.IdleTimeout = idleTimeout; - _stpStartInfo.MaxWorkerThreads = maxWorkerThreads; - _stpStartInfo.MinWorkerThreads = minWorkerThreads; - Initialize(); - } - - /// - /// Constructor - /// - public SmartThreadPool(STPStartInfo stpStartInfo) - { - _stpStartInfo = new STPStartInfo(stpStartInfo); - Initialize(); - } - - private void Initialize() - { - Name = _stpStartInfo.ThreadPoolName; - ValidateSTPStartInfo(); - - if (null != _stpStartInfo.PerformanceCounterInstanceName) - { - try - { - _pcs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); - } - catch(Exception e) - { - Debug.WriteLine("Unable to create Performance Counters: " + e.ToString()); - _pcs = NullSTPInstancePerformanceCounters.Instance; - } - } - - StartOptimalNumberOfThreads(); - } - - private void StartOptimalNumberOfThreads() - { - int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); - threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); - StartThreads(threadsCount); - } - - private void ValidateSTPStartInfo() - { - if (_stpStartInfo.MinWorkerThreads < 0) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads", "MinWorkerThreads cannot be negative"); - } - - if (_stpStartInfo.MaxWorkerThreads <= 0) - { - throw new ArgumentOutOfRangeException( - "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); - } - - if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads, maxWorkerThreads", - "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); - } - } - - private void ValidateCallback(Delegate callback) - { - if(callback.GetInvocationList().Length > 1) - { - throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); - } - } - - #endregion - - #region Thread Processing - - /// - /// Waits on the queue for a work item, shutdown, or timeout. - /// - /// - /// Returns the WaitingCallback or null in case of timeout or shutdown. - /// - private WorkItem Dequeue() - { - WorkItem workItem = - _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); - - return workItem; - } - - /// - /// Put a new work item in the queue - /// - /// A work item to queue - private void Enqueue(WorkItem workItem) - { - Enqueue(workItem, true); - } - - /// - /// Put a new work item in the queue - /// - /// A work item to queue - internal void Enqueue(WorkItem workItem, bool incrementWorkItems) - { - // Make sure the workItem is not null - Debug.Assert(null != workItem); - - if (incrementWorkItems) - { - IncrementWorkItemsCount(); - } - - _workItemsQueue.EnqueueWorkItem(workItem); - workItem.WorkItemIsQueued(); - - // If all the threads are busy then try to create a new one - if ((InUseThreads + WaitingCallbacks) > _workerThreads.Count) - { - StartThreads(1); - } - } - - private void IncrementWorkItemsCount() - { - _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - - int count = Interlocked.Increment(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 1) - { - //Trace.WriteLine("STP is NOT idle"); - _isIdleWaitHandle.Reset(); - } - } - - private void DecrementWorkItemsCount() - { - ++_workItemsProcessed; - - // The counter counts even if the work item was cancelled - _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - - int count = Interlocked.Decrement(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 0) - { - //Trace.WriteLine("STP is idle"); - _isIdleWaitHandle.Set(); - } - } - - internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) - { - _workItemsGroups[workItemsGroup] = workItemsGroup; - } - - internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) - { - if (_workItemsGroups.Contains(workItemsGroup)) - { - _workItemsGroups.Remove(workItemsGroup); - } - } - - /// - /// Inform that the current thread is about to quit or quiting. - /// The same thread may call this method more than once. - /// - private void InformCompleted() - { - // There is no need to lock the two methods together - // since only the current thread removes itself - // and the _workerThreads is a synchronized hashtable - if (_workerThreads.Contains(Thread.CurrentThread)) - { - _workerThreads.Remove(Thread.CurrentThread); - _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - - /// - /// Starts new threads - /// - /// The number of threads to start - private void StartThreads(int threadsCount) - { - if (_stpStartInfo.StartSuspended) - { - return; - } - - lock(_workerThreads.SyncRoot) - { - // Don't start threads on shut down - if (_shutdown) - { - return; - } - - for(int i = 0; i < threadsCount; ++i) - { - // Don't create more threads then the upper limit - if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) - { - return; - } - - // Create a new thread - Thread workerThread; - if (_stpStartInfo.StackSize > 0) - workerThread = new Thread(ProcessQueuedItems, _stpStartInfo.StackSize); - else - workerThread = new Thread(ProcessQueuedItems); - - // Configure the new thread and start it - workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; - workerThread.IsBackground = true; - workerThread.Priority = _stpStartInfo.ThreadPriority; - workerThread.Start(); - ++_threadCounter; - - // Add the new thread to the hashtable and update its creation - // time. - _workerThreads[workerThread] = DateTime.Now; - _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - } - - /// - /// A worker thread method that processes work items from the work items queue. - /// - private void ProcessQueuedItems() - { - // Initialize the _smartThreadPool variable - _smartThreadPool = this; - - try - { - bool bInUseWorkerThreadsWasIncremented = false; - - // Process until shutdown. - while(!_shutdown) - { - // Update the last time this thread was seen alive. - // It's good for debugging. - _workerThreads[Thread.CurrentThread] = DateTime.Now; - - // Wait for a work item, shutdown, or timeout - WorkItem workItem = Dequeue(); - - // Update the last time this thread was seen alive. - // It's good for debugging. - _workerThreads[Thread.CurrentThread] = DateTime.Now; - - // On timeout or shut down. - if (null == workItem) - { - // Double lock for quit. - if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - lock(_workerThreads.SyncRoot) - { - if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - // Inform that the thread is quiting and then quit. - // This method must be called within this lock or else - // more threads will quit and the thread pool will go - // below the lower limit. - InformCompleted(); - break; - } - } - } - } - - // If we didn't quit then skip to the next iteration. - if (null == workItem) - { - continue; - } - - try - { - // Initialize the value to false - bInUseWorkerThreadsWasIncremented = false; - - // Change the state of the work item to 'in progress' if possible. - // We do it here so if the work item has been canceled we won't - // increment the _inUseWorkerThreads. - // The cancel mechanism doesn't delete items from the queue, - // it marks the work item as canceled, and when the work item - // is dequeued, we just skip it. - // If the post execute of work item is set to always or to - // call when the work item is canceled then the StartingWorkItem() - // will return true, so the post execute can run. - if (!workItem.StartingWorkItem()) - { - continue; - } - - // Execute the callback. Make sure to accurately - // record how many callbacks are currently executing. - int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); - _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - - // Mark that the _inUseWorkerThreads incremented, so in the finally{} - // statement we will decrement it correctly. - bInUseWorkerThreadsWasIncremented = true; - - // Set the _currentWorkItem to the current work item - _currentWorkItem = workItem; - - lock(workItem) - { - workItem.currentThread = Thread.CurrentThread; - } - - ExecuteWorkItem(workItem); - - lock(workItem) - { - workItem.currentThread = null; - } - - } - catch(ThreadAbortException ex) - { - lock(workItem) - { - workItem.currentThread = null; - } - ex.GetHashCode(); - Thread.ResetAbort(); - } - catch(Exception ex) - { - ex.GetHashCode(); - // Do nothing - } - finally - { - lock(workItem) - { - workItem.currentThread = null; - } - - if (null != workItem) - { - workItem.DisposeOfState(); - } - - // Set the _currentWorkItem to null, since we - // no longer run user's code. - _currentWorkItem = null; - - // Decrement the _inUseWorkerThreads only if we had - // incremented it. Note the cancelled work items don't - // increment _inUseWorkerThreads. - if (bInUseWorkerThreadsWasIncremented) - { - int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); - _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - } - - // Notify that the work item has been completed. - // WorkItemsGroup may enqueue their next work item. - workItem.FireWorkItemCompleted(); - - // Decrement the number of work items here so the idle - // ManualResetEvent won't fluctuate. - DecrementWorkItemsCount(); - } - } - } - catch(ThreadAbortException tae) - { - tae.GetHashCode(); - // Handle the abort exception gracfully. - Thread.ResetAbort(); - } - catch(Exception e) - { - Debug.Assert(null != e); - } - finally - { - InformCompleted(); - } - } - - private void ExecuteWorkItem(WorkItem workItem) - { - _pcs.SampleWorkItemsWaitTime(workItem.WaitingTime); - try - { - workItem.Execute(); - } - catch - { - throw; - } - finally - { - _pcs.SampleWorkItemsProcessTime(workItem.ProcessTime); - } - } - - - #endregion - - #region Public Methods - - /// - /// Queue a work item - /// - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// The priority of the work item - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item info - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback, state); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - ValidateNotDisposed(); - ValidateCallback(callback); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Wait for the thread pool to be idle - /// - public void WaitForIdle() - { - WaitForIdle(Timeout.Infinite); - } - - /// - /// Wait for the thread pool to be idle - /// - public bool WaitForIdle(TimeSpan timeout) - { - return WaitForIdle((int)timeout.TotalMilliseconds); - } - - /// - /// Wait for the thread pool to be idle - /// - public bool WaitForIdle(int millisecondsTimeout) - { - ValidateWaitForIdle(); - return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false); - } - - private void ValidateWaitForIdle() - { - if(_smartThreadPool == this) - { - throw new NotSupportedException( - "WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); - } - } - - internal void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) - { - ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, SmartThreadPool._currentWorkItem); - if ((null != workItemsGroup) && - (null != SmartThreadPool._currentWorkItem) && - SmartThreadPool._currentWorkItem.WasQueuedBy(workItemsGroup)) - { - throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) - { - if ((null != workItemsGroup) && - (null != workItem) && - workItem.WasQueuedBy(workItemsGroup)) - { - throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock"); - } - } - - - - /// - /// Force the SmartThreadPool to shutdown - /// - public void Shutdown() - { - Shutdown(true, 0); - } - - public void Shutdown(bool forceAbort, TimeSpan timeout) - { - Shutdown(forceAbort, (int)timeout.TotalMilliseconds); - } - - /// - /// Empties the queue of work items and abort the threads in the pool. - /// - public void Shutdown(bool forceAbort, int millisecondsTimeout) - { - ValidateNotDisposed(); - - ISTPInstancePerformanceCounters pcs = _pcs; - - if (NullSTPInstancePerformanceCounters.Instance != _pcs) - { - _pcs.Dispose(); - // Set the _pcs to "null" to stop updating the performance - // counters - _pcs = NullSTPInstancePerformanceCounters.Instance; - } - - Thread [] threads = null; - lock(_workerThreads.SyncRoot) - { - // Shutdown the work items queue - _workItemsQueue.Dispose(); - - // Signal the threads to exit - _shutdown = true; - _shuttingDownEvent.Set(); - - // Make a copy of the threads' references in the pool - threads = new Thread [_workerThreads.Count]; - _workerThreads.Keys.CopyTo(threads, 0); - } - - int millisecondsLeft = millisecondsTimeout; - DateTime start = DateTime.Now; - bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); - bool timeout = false; - - // Each iteration we update the time left for the timeout. - foreach(Thread thread in threads) - { - // Join don't work with negative numbers - if (!waitInfinitely && (millisecondsLeft < 0)) - { - timeout = true; - break; - } - - // Wait for the thread to terminate - bool success = thread.Join(millisecondsLeft); - if(!success) - { - timeout = true; - break; - } - - if(!waitInfinitely) - { - // Update the time left to wait - TimeSpan ts = DateTime.Now - start; - millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds; - } - } - - if (timeout && forceAbort) - { - // Abort the threads in the pool - foreach(Thread thread in threads) - { - if ((thread != null) && thread.IsAlive) - { - try - { - thread.Abort("Shutdown"); - } - catch(SecurityException e) - { - e.GetHashCode(); - } - catch(ThreadStateException ex) - { - ex.GetHashCode(); - // In case the thread has been terminated - // after the check if it is alive. - } - } - } - } - - // Dispose of the performance counters - pcs.Dispose(); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWorkItemResult [] workItemResults) - { - return WaitAll(workItemResults, Timeout.Infinite, true); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWorkItemResult [] workItemResults, - TimeSpan timeout, - bool exitContext) - { - return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWorkItemResult [] workItemResults, - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWorkItemResult [] workItemResults, - int millisecondsTimeout, - bool exitContext) - { - return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, null); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWorkItemResult [] workItemResults, - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } - - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. - /// - public static int WaitAny( - IWorkItemResult [] workItemResults) - { - return WaitAny(workItemResults, Timeout.Infinite, true); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWorkItemResult [] workItemResults, - TimeSpan timeout, - bool exitContext) - { - return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWorkItemResult [] workItemResults, - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWorkItemResult [] workItemResults, - int millisecondsTimeout, - bool exitContext) - { - return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, null); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWorkItemResult [] workItemResults, - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } - - public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) - { - IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); - return workItemsGroup; - } - - public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) - { - IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); - return workItemsGroup; - } - - public event WorkItemsGroupIdleHandler OnIdle - { - add - { - throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); - //_onIdle += value; - } - remove - { - throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); - //_onIdle -= value; - } - } - - public void Cancel() - { - ICollection workItemsGroups = _workItemsGroups.Values; - foreach(WorkItemsGroup workItemsGroup in workItemsGroups) - { - workItemsGroup.Cancel(); - } - } - - public void Start() - { - lock (this) - { - if (!this._stpStartInfo.StartSuspended) - { - return; - } - _stpStartInfo.StartSuspended = false; - } - - ICollection workItemsGroups = _workItemsGroups.Values; - foreach(WorkItemsGroup workItemsGroup in workItemsGroups) - { - workItemsGroup.OnSTPIsStarting(); - } - - StartOptimalNumberOfThreads(); - } - - #endregion - - #region Properties - - /// - /// Get/Set the name of the SmartThreadPool instance - /// - public string Name - { - get - { - return _name; - } - - set - { - _name = value; - } - } - - /// - /// Get the lower limit of threads in the pool. - /// - public int MinThreads - { - get - { - ValidateNotDisposed(); - return _stpStartInfo.MinWorkerThreads; - } - } - - /// - /// Get the upper limit of threads in the pool. - /// - public int MaxThreads - { - get - { - ValidateNotDisposed(); - return _stpStartInfo.MaxWorkerThreads; - } - } - /// - /// Get the number of threads in the thread pool. - /// Should be between the lower and the upper limits. - /// - public int ActiveThreads - { - get - { - ValidateNotDisposed(); - return _workerThreads.Count; - } - } - - /// - /// Get the number of busy (not idle) threads in the thread pool. - /// - public int InUseThreads - { - get - { - ValidateNotDisposed(); - return _inUseWorkerThreads; - } - } - - /// - /// Get the number of work items in the queue. - /// - public int WaitingCallbacks - { - get - { - ValidateNotDisposed(); - return _workItemsQueue.Count; - } - } - - - public event EventHandler Idle - { - add - { - _stpIdle += value; - } - - remove - { - _stpIdle -= value; - } - } - - #endregion - - #region IDisposable Members - -// ~SmartThreadPool() -// { -// Dispose(); -// } - - public void Dispose() - { - if (!_isDisposed) - { - if (!_shutdown) - { - Shutdown(); - } - - if (null != _shuttingDownEvent) - { - _shuttingDownEvent.Close(); - _shuttingDownEvent = null; - } - _workerThreads.Clear(); - _isDisposed = true; - GC.SuppressFinalize(this); - } - } - - private void ValidateNotDisposed() - { - if(_isDisposed) - { - throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); - } - } - #endregion - } - #endregion -} +#region Release History + +// Smart Thread Pool +// 7 Aug 2004 - Initial release +// +// 14 Sep 2004 - Bug fixes +// +// 15 Oct 2004 - Added new features +// - Work items return result. +// - Support waiting synchronization for multiple work items. +// - Work items can be cancelled. +// - Passage of the caller thread’s context to the thread in the pool. +// - Minimal usage of WIN32 handles. +// - Minor bug fixes. +// +// 26 Dec 2004 - Changes: +// - Removed static constructors. +// - Added finalizers. +// - Changed Exceptions so they are serializable. +// - Fixed the bug in one of the SmartThreadPool constructors. +// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. +// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. +// - Added PostExecute with options on which cases to call it. +// - Added option to dispose of the state objects. +// - Added a WaitForIdle() method that waits until the work items queue is empty. +// - Added an STPStartInfo class for the initialization of the thread pool. +// - Changed exception handling so if a work item throws an exception it +// is rethrown at GetResult(), rather then firing an UnhandledException event. +// Note that PostExecute exception are always ignored. +// +// 25 Mar 2005 - Changes: +// - Fixed lost of work items bug +// +// 3 Jul 2005: Changes. +// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. +// +// 16 Aug 2005: Changes. +// - Fixed bug where the InUseThreads becomes negative when canceling work items. +// +// 31 Jan 2006 - Changes: +// - Added work items priority +// - Removed support of chained delegates in callbacks and post executes (nobody really use this) +// - Added work items groups +// - Added work items groups idle event +// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array +// it returns true rather then throwing an exception. +// - Added option to start the STP and the WIG as suspended +// - Exception behavior changed, the real exception is returned by an +// inner exception +// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) +// - Added performance counters +// - Added priority to the threads in the pool +// +// 13 Feb 2006 - Changes: +// - Added a call to the dispose of the Performance Counter so +// their won't be a Performance Counter leak. +// - Added exception catch in case the Performance Counters cannot +// be created. +// +// 17 May 2008 - Changes: +// - Changed the dispose behavior and removed the Finalizers. +// - Enabled the change of the MaxThreads and MinThreads at run time. +// - Enabled the change of the Concurrency of a IWorkItemsGroup at run +// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency +// refers to the MaxThreads. +// - Improved the cancel behavior. +// - Added events for thread creation and termination. +// - Fixed the HttpContext context capture. +// - Changed internal collections so they use generic collections +// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup +// - Added support for WinCE +// - Added support for Action and Func +// +// 07 April 2009 - Changes: +// - Added support for Silverlight and Mono +// - Added Join, Choice, and Pipe to SmartThreadPool. +// - Added local performance counters (for Mono, Silverlight, and WindowsCE) +// - Changed duration measures from DateTime.Now to Stopwatch. +// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList. +// +// 21 December 2009 - Changes: +// - Added work item timeout (passive) +// +// 20 August 2012 - Changes: +// - Added set name to threads +// - Fixed the WorkItemsQueue.Dequeue. +// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } +// - Fixed SmartThreadPool.Pipe +// - Added IsBackground option to threads +// - Added ApartmentState to threads +// - Fixed thread creation when queuing many work items at the same time. +// +// 24 August 2012 - Changes: +// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan +// - Added option to set MaxStackSize of threads + +#endregion + +using System; +using System.Security; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +using Amib.Threading.Internal; + +namespace Amib.Threading +{ + #region SmartThreadPool class + /// + /// Smart thread pool class. + /// + public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable + { + #region Public Default Constants + + /// + /// Default minimum number of threads the thread pool contains. (0) + /// + public const int DefaultMinWorkerThreads = 0; + + /// + /// Default maximum number of threads the thread pool contains. (25) + /// + public const int DefaultMaxWorkerThreads = 25; + + /// + /// Default idle timeout in milliseconds. (One minute) + /// + public const int DefaultIdleTimeout = 60*1000; // One minute + + /// + /// Indicate to copy the security context of the caller and then use it in the call. (false) + /// + public const bool DefaultUseCallerCallContext = false; + + /// + /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) + /// + public const bool DefaultUseCallerHttpContext = false; + + /// + /// Indicate to dispose of the state objects if they support the IDispose interface. (false) + /// + public const bool DefaultDisposeOfStateObjects = false; + + /// + /// The default option to run the post execute (CallToPostExecute.Always) + /// + public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; + + /// + /// The default post execute method to run. (None) + /// When null it means not to call it. + /// + public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; + + /// + /// The default work item priority (WorkItemPriority.Normal) + /// + public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; + + /// + /// The default is to work on work items as soon as they arrive + /// and not to wait for the start. (false) + /// + public const bool DefaultStartSuspended = false; + + /// + /// The default name to use for the performance counters instance. (null) + /// + public static readonly string DefaultPerformanceCounterInstanceName; + +#if !(WINDOWS_PHONE) + + /// + /// The default thread priority (ThreadPriority.Normal) + /// + public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; +#endif + /// + /// The default thread pool name. (SmartThreadPool) + /// + public const string DefaultThreadPoolName = "SmartThreadPool"; + + /// + /// The default Max Stack Size. (SmartThreadPool) + /// + public static readonly int? DefaultMaxStackSize = null; + + /// + /// The default fill state with params. (false) + /// It is relevant only to QueueWorkItem of Action<...>/Func<...> + /// + public const bool DefaultFillStateWithArgs = false; + + /// + /// The default thread backgroundness. (true) + /// + public const bool DefaultAreThreadsBackground = true; + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + /// + /// The default apartment state of a thread in the thread pool. + /// The default is ApartmentState.Unknown which means the STP will not + /// set the apartment of the thread. It will use the .NET default. + /// + public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; +#endif + + #endregion + + #region Member Variables + + /// + /// Dictionary of all the threads in the thread pool. + /// + private readonly SynchronizedDictionary _workerThreads = new SynchronizedDictionary(); + + /// + /// Queue of work items. + /// + private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); + + /// + /// Count the work items handled. + /// Used by the performance counter. + /// + private int _workItemsProcessed; + + /// + /// Number of threads that currently work (not idle). + /// + private int _inUseWorkerThreads; + + /// + /// Stores a copy of the original STPStartInfo. + /// It is used to change the MinThread and MaxThreads + /// + private STPStartInfo _stpStartInfo; + + /// + /// Total number of work items that are stored in the work items queue + /// plus the work items that the threads in the pool are working on. + /// + private int _currentWorkItemsCount; + + /// + /// Signaled when the thread pool is idle, i.e. no thread is busy + /// and the work items queue is empty + /// + //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); + private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); + + /// + /// An event to signal all the threads to quit immediately. + /// + //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); + private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); + + /// + /// A flag to indicate if the Smart Thread Pool is now suspended. + /// + private bool _isSuspended; + + /// + /// A flag to indicate the threads to quit. + /// + private bool _shutdown; + + /// + /// Counts the threads created in the pool. + /// It is used to name the threads. + /// + private int _threadCounter; + + /// + /// Indicate that the SmartThreadPool has been disposed + /// + private bool _isDisposed; + + /// + /// Holds all the WorkItemsGroup instaces that have at least one + /// work item int the SmartThreadPool + /// This variable is used in case of Shutdown + /// + private readonly SynchronizedDictionary _workItemsGroups = new SynchronizedDictionary(); + + /// + /// A common object for all the work items int the STP + /// so we can mark them to cancel in O(1) + /// + private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup(); + + /// + /// Windows STP performance counters + /// + private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + + /// + /// Local STP performance counters + /// + private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; + + +#if (WINDOWS_PHONE) + private static readonly Dictionary _threadEntries = new Dictionary(); +#elif (_WINDOWS_CE) + private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); +#else + [ThreadStatic] + private static ThreadEntry _threadEntry; + +#endif + + /// + /// An event to call after a thread is created, but before + /// it's first use. + /// + private event ThreadInitializationHandler _onThreadInitialization; + + /// + /// An event to call when a thread is about to exit, after + /// it is no longer belong to the pool. + /// + private event ThreadTerminationHandler _onThreadTermination; + + #endregion + + #region Per thread properties + + /// + /// A reference to the current work item a thread from the thread pool + /// is executing. + /// + internal static ThreadEntry CurrentThreadEntry + { +#if (WINDOWS_PHONE) + get + { + lock(_threadEntries) + { + ThreadEntry threadEntry; + if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry)) + { + return threadEntry; + } + } + return null; + } + set + { + lock(_threadEntries) + { + _threadEntries[Thread.CurrentThread.ManagedThreadId] = value; + } + } +#elif (_WINDOWS_CE) + get + { + //Thread.CurrentThread.ManagedThreadId + return Thread.GetData(_threadEntrySlot) as ThreadEntry; + } + set + { + Thread.SetData(_threadEntrySlot, value); + } +#else + get + { + return _threadEntry; + } + set + { + _threadEntry = value; + } +#endif + } + #endregion + + #region Construction and Finalization + + /// + /// Constructor + /// + public SmartThreadPool() + { + _stpStartInfo = new STPStartInfo(); + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + public SmartThreadPool(int idleTimeout) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + /// Upper limit of threads in the pool + public SmartThreadPool( + int idleTimeout, + int maxWorkerThreads) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + MaxWorkerThreads = maxWorkerThreads, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + /// Upper limit of threads in the pool + /// Lower limit of threads in the pool + public SmartThreadPool( + int idleTimeout, + int maxWorkerThreads, + int minWorkerThreads) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + MaxWorkerThreads = maxWorkerThreads, + MinWorkerThreads = minWorkerThreads, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// A SmartThreadPool configuration that overrides the default behavior + public SmartThreadPool(STPStartInfo stpStartInfo) + { + _stpStartInfo = new STPStartInfo(stpStartInfo); + Initialize(); + } + + private void Initialize() + { + Name = _stpStartInfo.ThreadPoolName; + ValidateSTPStartInfo(); + + // _stpStartInfoRW stores a read/write copy of the STPStartInfo. + // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten + + _isSuspended = _stpStartInfo.StartSuspended; + +#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { + throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); + } +#else + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { + try + { + _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); + } + catch (Exception e) + { + Debug.WriteLine("Unable to create Performance Counters: " + e); + _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + } + } +#endif + + if (_stpStartInfo.EnableLocalPerformanceCounters) + { + _localPCs = new LocalSTPInstancePerformanceCounters(); + } + + // If the STP is not started suspended then start the threads. + if (!_isSuspended) + { + StartOptimalNumberOfThreads(); + } + } + + private void StartOptimalNumberOfThreads() + { + int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); + threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); + threadsCount -= _workerThreads.Count; + if (threadsCount > 0) + { + StartThreads(threadsCount); + } + } + + private void ValidateSTPStartInfo() + { + if (_stpStartInfo.MinWorkerThreads < 0) + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads", "MinWorkerThreads cannot be negative"); + } + + if (_stpStartInfo.MaxWorkerThreads <= 0) + { + throw new ArgumentOutOfRangeException( + "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); + } + + if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads, maxWorkerThreads", + "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); + } + } + + private static void ValidateCallback(Delegate callback) + { + if(callback.GetInvocationList().Length > 1) + { + throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); + } + } + + #endregion + + #region Thread Processing + + /// + /// Waits on the queue for a work item, shutdown, or timeout. + /// + /// + /// Returns the WaitingCallback or null in case of timeout or shutdown. + /// + private WorkItem Dequeue() + { + WorkItem workItem = + _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); + + return workItem; + } + + /// + /// Put a new work item in the queue + /// + /// A work item to queue + internal override void Enqueue(WorkItem workItem) + { + // Make sure the workItem is not null + Debug.Assert(null != workItem); + + IncrementWorkItemsCount(); + + workItem.CanceledSmartThreadPool = _canceledSmartThreadPool; + _workItemsQueue.EnqueueWorkItem(workItem); + workItem.WorkItemIsQueued(); + + // If all the threads are busy then try to create a new one + if (_currentWorkItemsCount > _workerThreads.Count) + { + StartThreads(1); + } + } + + private void IncrementWorkItemsCount() + { + _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + + int count = Interlocked.Increment(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 1) + { + IsIdle = false; + _isIdleWaitHandle.Reset(); + } + } + + private void DecrementWorkItemsCount() + { + int count = Interlocked.Decrement(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 0) + { + IsIdle = true; + _isIdleWaitHandle.Set(); + } + + Interlocked.Increment(ref _workItemsProcessed); + + if (!_shutdown) + { + // The counter counts even if the work item was cancelled + _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + } + + } + + internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) + { + _workItemsGroups[workItemsGroup] = workItemsGroup; + } + + internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) + { + if (_workItemsGroups.Contains(workItemsGroup)) + { + _workItemsGroups.Remove(workItemsGroup); + } + } + + /// + /// Inform that the current thread is about to quit or quiting. + /// The same thread may call this method more than once. + /// + private void InformCompleted() + { + // There is no need to lock the two methods together + // since only the current thread removes itself + // and the _workerThreads is a synchronized dictionary + if (_workerThreads.Contains(Thread.CurrentThread)) + { + _workerThreads.Remove(Thread.CurrentThread); + _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + } + } + + /// + /// Starts new threads + /// + /// The number of threads to start + private void StartThreads(int threadsCount) + { + if (_isSuspended) + { + return; + } + + lock(_workerThreads.SyncRoot) + { + // Don't start threads on shut down + if (_shutdown) + { + return; + } + + for(int i = 0; i < threadsCount; ++i) + { + // Don't create more threads then the upper limit + if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) + { + return; + } + + // Create a new thread + +#if (_SILVERLIGHT) || (WINDOWS_PHONE) + Thread workerThread = new Thread(ProcessQueuedItems); +#else + Thread workerThread = + _stpStartInfo.MaxStackSize.HasValue + ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value) + : new Thread(ProcessQueuedItems); +#endif + // Configure the new thread and start it + workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; + workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; + +#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) + if (_stpStartInfo.ApartmentState != ApartmentState.Unknown) + { + workerThread.SetApartmentState(_stpStartInfo.ApartmentState); + } +#endif + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + workerThread.Priority = _stpStartInfo.ThreadPriority; +#endif + workerThread.Start(); + ++_threadCounter; + + // Add it to the dictionary and update its creation time. + _workerThreads[workerThread] = new ThreadEntry(this); + + _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + } + } + } + + /// + /// A worker thread method that processes work items from the work items queue. + /// + private void ProcessQueuedItems() + { + // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks + // of the dictionary. + CurrentThreadEntry = _workerThreads[Thread.CurrentThread]; + + FireOnThreadInitialization(); + + try + { + bool bInUseWorkerThreadsWasIncremented = false; + + // Process until shutdown. + while(!_shutdown) + { + // Update the last time this thread was seen alive. + // It's good for debugging. + CurrentThreadEntry.IAmAlive(); + + // The following block handles the when the MaxWorkerThreads has been + // incremented by the user at run-time. + // Double lock for quit. + if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) + { + lock (_workerThreads.SyncRoot) + { + if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) + { + // Inform that the thread is quiting and then quit. + // This method must be called within this lock or else + // more threads will quit and the thread pool will go + // below the lower limit. + InformCompleted(); + break; + } + } + } + + // Wait for a work item, shutdown, or timeout + WorkItem workItem = Dequeue(); + + // Update the last time this thread was seen alive. + // It's good for debugging. + CurrentThreadEntry.IAmAlive(); + + // On timeout or shut down. + if (null == workItem) + { + // Double lock for quit. + if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) + { + lock(_workerThreads.SyncRoot) + { + if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) + { + // Inform that the thread is quiting and then quit. + // This method must be called within this lock or else + // more threads will quit and the thread pool will go + // below the lower limit. + InformCompleted(); + break; + } + } + } + } + + // If we didn't quit then skip to the next iteration. + if (null == workItem) + { + continue; + } + + try + { + // Initialize the value to false + bInUseWorkerThreadsWasIncremented = false; + + // Set the Current Work Item of the thread. + // Store the Current Work Item before the workItem.StartingWorkItem() is called, + // so WorkItem.Cancel can work when the work item is between InQueue and InProgress + // states. + // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() + // (work item is in InQueue state) then workItem.StartingWorkItem() will return false. + // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then + // (work item is in InProgress state) then the thread will be aborted + CurrentThreadEntry.CurrentWorkItem = workItem; + + // Change the state of the work item to 'in progress' if possible. + // We do it here so if the work item has been canceled we won't + // increment the _inUseWorkerThreads. + // The cancel mechanism doesn't delete items from the queue, + // it marks the work item as canceled, and when the work item + // is dequeued, we just skip it. + // If the post execute of work item is set to always or to + // call when the work item is canceled then the StartingWorkItem() + // will return true, so the post execute can run. + if (!workItem.StartingWorkItem()) + { + continue; + } + + // Execute the callback. Make sure to accurately + // record how many callbacks are currently executing. + int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + + // Mark that the _inUseWorkerThreads incremented, so in the finally{} + // statement we will decrement it correctly. + bInUseWorkerThreadsWasIncremented = true; + + workItem.FireWorkItemStarted(); + + ExecuteWorkItem(workItem); + } + catch(Exception ex) + { + ex.GetHashCode(); + // Do nothing + } + finally + { + workItem.DisposeOfState(); + + // Set the CurrentWorkItem to null, since we + // no longer run user's code. + CurrentThreadEntry.CurrentWorkItem = null; + + // Decrement the _inUseWorkerThreads only if we had + // incremented it. Note the cancelled work items don't + // increment _inUseWorkerThreads. + if (bInUseWorkerThreadsWasIncremented) + { + int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + } + + // Notify that the work item has been completed. + // WorkItemsGroup may enqueue their next work item. + workItem.FireWorkItemCompleted(); + + // Decrement the number of work items here so the idle + // ManualResetEvent won't fluctuate. + DecrementWorkItemsCount(); + } + } + } + catch(ThreadAbortException tae) + { + tae.GetHashCode(); + // Handle the abort exception gracfully. +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + Thread.ResetAbort(); +#endif + } + catch(Exception e) + { + Debug.Assert(null != e); + } + finally + { + InformCompleted(); + FireOnThreadTermination(); + } + } + + private void ExecuteWorkItem(WorkItem workItem) + { + _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + try + { + workItem.Execute(); + } + finally + { + _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + } + } + + + #endregion + + #region Public Methods + + private void ValidateWaitForIdle() + { + if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this) + { + throw new NotSupportedException( + "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) + { + if (null == CurrentThreadEntry) + { + return; + } + + WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; + ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); + if ((null != workItemsGroup) && + (null != workItem) && + CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) + { + throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) + { + if ((null != workItemsGroup) && + (null != workItem) && + workItem.WasQueuedBy(workItemsGroup)) + { + throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + /// + /// Force the SmartThreadPool to shutdown + /// + public void Shutdown() + { + Shutdown(true, 0); + } + + /// + /// Force the SmartThreadPool to shutdown with timeout + /// + public void Shutdown(bool forceAbort, TimeSpan timeout) + { + Shutdown(forceAbort, (int)timeout.TotalMilliseconds); + } + + /// + /// Empties the queue of work items and abort the threads in the pool. + /// + public void Shutdown(bool forceAbort, int millisecondsTimeout) + { + ValidateNotDisposed(); + + ISTPInstancePerformanceCounters pcs = _windowsPCs; + + if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) + { + // Set the _pcs to "null" to stop updating the performance + // counters + _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + + pcs.Dispose(); + } + + Thread [] threads; + lock(_workerThreads.SyncRoot) + { + // Shutdown the work items queue + _workItemsQueue.Dispose(); + + // Signal the threads to exit + _shutdown = true; + _shuttingDownEvent.Set(); + + // Make a copy of the threads' references in the pool + threads = new Thread [_workerThreads.Count]; + _workerThreads.Keys.CopyTo(threads, 0); + } + + int millisecondsLeft = millisecondsTimeout; + Stopwatch stopwatch = Stopwatch.StartNew(); + //DateTime start = DateTime.UtcNow; + bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); + bool timeout = false; + + // Each iteration we update the time left for the timeout. + foreach(Thread thread in threads) + { + // Join don't work with negative numbers + if (!waitInfinitely && (millisecondsLeft < 0)) + { + timeout = true; + break; + } + + // Wait for the thread to terminate + bool success = thread.Join(millisecondsLeft); + if(!success) + { + timeout = true; + break; + } + + if(!waitInfinitely) + { + // Update the time left to wait + //TimeSpan ts = DateTime.UtcNow - start; + millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; + } + } + + if (timeout && forceAbort) + { + // Abort the threads in the pool + foreach(Thread thread in threads) + { + + if ((thread != null) +#if !(_WINDOWS_CE) + && thread.IsAlive +#endif + ) + { + try + { + thread.Abort(); // Shutdown + } + catch(SecurityException e) + { + e.GetHashCode(); + } + catch(ThreadStateException ex) + { + ex.GetHashCode(); + // In case the thread has been terminated + // after the check if it is alive. + } + } + } + } + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults) + { + return WaitAll(waitableResults, Timeout.Infinite, true); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults, + TimeSpan timeout, + bool exitContext) + { + return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult[] waitableResults, + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext) + { + return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult[] waitableResults, + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); + } + + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults) + { + return WaitAny(waitableResults, Timeout.Infinite, true); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult[] waitableResults, + TimeSpan timeout, + bool exitContext) + { + return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext) + { + return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); + } + + /// + /// Creates a new WorkItemsGroup. + /// + /// The number of work items that can be run concurrently + /// A reference to the WorkItemsGroup + public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) + { + IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); + return workItemsGroup; + } + + /// + /// Creates a new WorkItemsGroup. + /// + /// The number of work items that can be run concurrently + /// A WorkItemsGroup configuration that overrides the default behavior + /// A reference to the WorkItemsGroup + public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) + { + IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); + return workItemsGroup; + } + + #region Fire Thread's Events + + private void FireOnThreadInitialization() + { + if (null != _onThreadInitialization) + { + foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList()) + { + try + { + tih(); + } + catch (Exception e) + { + e.GetHashCode(); + Debug.Assert(false); + throw; + } + } + } + } + + private void FireOnThreadTermination() + { + if (null != _onThreadTermination) + { + foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList()) + { + try + { + tth(); + } + catch (Exception e) + { + e.GetHashCode(); + Debug.Assert(false); + throw; + } + } + } + } + + #endregion + + /// + /// This event is fired when a thread is created. + /// Use it to initialize a thread before the work items use it. + /// + public event ThreadInitializationHandler OnThreadInitialization + { + add { _onThreadInitialization += value; } + remove { _onThreadInitialization -= value; } + } + + /// + /// This event is fired when a thread is terminating. + /// Use it for cleanup. + /// + public event ThreadTerminationHandler OnThreadTermination + { + add { _onThreadTermination += value; } + remove { _onThreadTermination -= value; } + } + + + internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig) + { + foreach (ThreadEntry threadEntry in _workerThreads.Values) + { + WorkItem workItem = threadEntry.CurrentWorkItem; + if (null != workItem && + workItem.WasQueuedBy(wig) && + !workItem.IsCanceled) + { + threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); + } + } + } + + + + #endregion + + #region Properties + + /// + /// Get/Set the lower limit of threads in the pool. + /// + public int MinThreads + { + get + { + ValidateNotDisposed(); + return _stpStartInfo.MinWorkerThreads; + } + set + { + Debug.Assert(value >= 0); + Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads); + if (_stpStartInfo.MaxWorkerThreads < value) + { + _stpStartInfo.MaxWorkerThreads = value; + } + _stpStartInfo.MinWorkerThreads = value; + StartOptimalNumberOfThreads(); + } + } + + /// + /// Get/Set the upper limit of threads in the pool. + /// + public int MaxThreads + { + get + { + ValidateNotDisposed(); + return _stpStartInfo.MaxWorkerThreads; + } + + set + { + Debug.Assert(value > 0); + Debug.Assert(value >= _stpStartInfo.MinWorkerThreads); + if (_stpStartInfo.MinWorkerThreads > value) + { + _stpStartInfo.MinWorkerThreads = value; + } + _stpStartInfo.MaxWorkerThreads = value; + StartOptimalNumberOfThreads(); + } + } + /// + /// Get the number of threads in the thread pool. + /// Should be between the lower and the upper limits. + /// + public int ActiveThreads + { + get + { + ValidateNotDisposed(); + return _workerThreads.Count; + } + } + + /// + /// Get the number of busy (not idle) threads in the thread pool. + /// + public int InUseThreads + { + get + { + ValidateNotDisposed(); + return _inUseWorkerThreads; + } + } + + /// + /// Returns true if the current running work item has been cancelled. + /// Must be used within the work item's callback method. + /// The work item should sample this value in order to know if it + /// needs to quit before its completion. + /// + public static bool IsWorkItemCanceled + { + get + { + return CurrentThreadEntry.CurrentWorkItem.IsCanceled; + } + } + + /// + /// Checks if the work item has been cancelled, and if yes then abort the thread. + /// Can be used with Cancel and timeout + /// + public static void AbortOnWorkItemCancel() + { + if (IsWorkItemCanceled) + { + Thread.CurrentThread.Abort(); + } + } + + /// + /// Thread Pool start information (readonly) + /// + public STPStartInfo STPStartInfo + { + get + { + return _stpStartInfo.AsReadOnly(); + } + } + + public bool IsShuttingdown + { + get { return _shutdown; } + } + + /// + /// Return the local calculated performance counters + /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true. + /// + public ISTPPerformanceCountersReader PerformanceCountersReader + { + get { return (ISTPPerformanceCountersReader)_localPCs; } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!_isDisposed) + { + if (!_shutdown) + { + Shutdown(); + } + + if (null != _shuttingDownEvent) + { + _shuttingDownEvent.Close(); + _shuttingDownEvent = null; + } + _workerThreads.Clear(); + + if (null != _isIdleWaitHandle) + { + _isIdleWaitHandle.Close(); + _isIdleWaitHandle = null; + } + + _isDisposed = true; + } + } + + private void ValidateNotDisposed() + { + if(_isDisposed) + { + throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); + } + } + #endregion + + #region WorkItemsGroupBase Overrides + + /// + /// Get/Set the maximum number of work items that execute cocurrency on the thread pool + /// + public override int Concurrency + { + get { return MaxThreads; } + set { MaxThreads = value; } + } + + /// + /// Get the number of work items in the queue. + /// + public override int WaitingCallbacks + { + get + { + ValidateNotDisposed(); + return _workItemsQueue.Count; + } + } + + /// + /// Get an array with all the state objects of the currently running items. + /// The array represents a snap shot and impact performance. + /// + public override object[] GetStates() + { + object[] states = _workItemsQueue.GetStates(); + return states; + } + + /// + /// WorkItemsGroup start information (readonly) + /// + public override WIGStartInfo WIGStartInfo + { + get { return _stpStartInfo.AsReadOnly(); } + } + + /// + /// Start the thread pool if it was started suspended. + /// If it is already running, this method is ignored. + /// + public override void Start() + { + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + ICollection workItemsGroups = _workItemsGroups.Values; + foreach (WorkItemsGroup workItemsGroup in workItemsGroups) + { + workItemsGroup.OnSTPIsStarting(); + } + + StartOptimalNumberOfThreads(); + } + + /// + /// Cancel all work items using thread abortion + /// + /// True to stop work items by raising ThreadAbortException + public override void Cancel(bool abortExecution) + { + _canceledSmartThreadPool.IsCanceled = true; + _canceledSmartThreadPool = new CanceledWorkItemsGroup(); + + ICollection workItemsGroups = _workItemsGroups.Values; + foreach (WorkItemsGroup workItemsGroup in workItemsGroups) + { + workItemsGroup.Cancel(abortExecution); + } + + if (abortExecution) + { + foreach (ThreadEntry threadEntry in _workerThreads.Values) + { + WorkItem workItem = threadEntry.CurrentWorkItem; + if (null != workItem && + threadEntry.AssociatedSmartThreadPool == this && + !workItem.IsCanceled) + { + threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); + } + } + } + } + + /// + /// Wait for the thread pool to be idle + /// + public override bool WaitForIdle(int millisecondsTimeout) + { + ValidateWaitForIdle(); + return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); + } + + /// + /// This event is fired when all work items are completed. + /// (When IsIdle changes to true) + /// This event only work on WorkItemsGroup. On SmartThreadPool + /// it throws the NotImplementedException. + /// + public override event WorkItemsGroupIdleHandler OnIdle + { + add + { + throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); + //_onIdle += value; + } + remove + { + throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); + //_onIdle -= value; + } + } + + internal override void PreQueueWorkItem() + { + ValidateNotDisposed(); + } + + #endregion + + #region Join, Choice, Pipe, etc. + + /// + /// Executes all actions in parallel. + /// Returns when they all finish. + /// + /// Actions to execute + public void Join(IEnumerable actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); + foreach (Action action in actions) + { + workItemsGroup.QueueWorkItem(action); + } + workItemsGroup.Start(); + workItemsGroup.WaitForIdle(); + } + + /// + /// Executes all actions in parallel. + /// Returns when they all finish. + /// + /// Actions to execute + public void Join(params Action[] actions) + { + Join((IEnumerable)actions); + } + + private class ChoiceIndex + { + public int _index = -1; + } + + /// + /// Executes all actions in parallel + /// Returns when the first one completes + /// + /// Actions to execute + public int Choice(IEnumerable actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); + + ManualResetEvent anActionCompleted = new ManualResetEvent(false); + + ChoiceIndex choiceIndex = new ChoiceIndex(); + + int i = 0; + foreach (Action action in actions) + { + Action act = action; + int value = i; + workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); + ++i; + } + workItemsGroup.Start(); + anActionCompleted.WaitOne(); + + return choiceIndex._index; + } + + /// + /// Executes all actions in parallel + /// Returns when the first one completes + /// + /// Actions to execute + public int Choice(params Action[] actions) + { + return Choice((IEnumerable)actions); + } + + /// + /// Executes actions in sequence asynchronously. + /// Returns immediately. + /// + /// A state context that passes + /// Actions to execute in the order they should run + public void Pipe(T pipeState, IEnumerable> actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo); + foreach (Action action in actions) + { + Action act = action; + workItemsGroup.QueueWorkItem(() => act(pipeState)); + } + workItemsGroup.Start(); + workItemsGroup.WaitForIdle(); + } + + /// + /// Executes actions in sequence asynchronously. + /// Returns immediately. + /// + /// + /// Actions to execute in the order they should run + public void Pipe(T pipeState, params Action[] actions) + { + Pipe(pipeState, (IEnumerable>)actions); + } + #endregion + } + #endregion +} diff --git a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs new file mode 100644 index 0000000..3532cca --- /dev/null +++ b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; + +namespace Amib.Threading.Internal +{ + internal class SynchronizedDictionary + { + private readonly Dictionary _dictionary; + private readonly object _lock; + + public SynchronizedDictionary() + { + _lock = new object(); + _dictionary = new Dictionary(); + } + + public int Count + { + get { return _dictionary.Count; } + } + + public bool Contains(TKey key) + { + lock (_lock) + { + return _dictionary.ContainsKey(key); + } + } + + public void Remove(TKey key) + { + lock (_lock) + { + _dictionary.Remove(key); + } + } + + public object SyncRoot + { + get { return _lock; } + } + + public TValue this[TKey key] + { + get + { + lock (_lock) + { + return _dictionary[key]; + } + } + set + { + lock (_lock) + { + _dictionary[key] = value; + } + } + } + + public Dictionary.KeyCollection Keys + { + get + { + lock (_lock) + { + return _dictionary.Keys; + } + } + } + + public Dictionary.ValueCollection Values + { + get + { + lock (_lock) + { + return _dictionary.Values; + } + } + } + public void Clear() + { + lock (_lock) + { + _dictionary.Clear(); + } + } + } +} diff --git a/ThirdParty/SmartThreadPool/WIGStartInfo.cs b/ThirdParty/SmartThreadPool/WIGStartInfo.cs index 150317f..e5ff150 100644 --- a/ThirdParty/SmartThreadPool/WIGStartInfo.cs +++ b/ThirdParty/SmartThreadPool/WIGStartInfo.cs @@ -1,99 +1,171 @@ -// Ami Bar -// amibar@gmail.com - -namespace Amib.Threading -{ - /// - /// Summary description for WIGStartInfo. - /// - public class WIGStartInfo - { - /// - /// Use the caller's security context - /// - private bool _useCallerCallContext; - - /// - /// Use the caller's HTTP context - /// - private bool _useCallerHttpContext; - - /// - /// Dispose of the state object of a work item - /// - private bool _disposeOfStateObjects; - - /// - /// The option to run the post execute - /// - private CallToPostExecute _callToPostExecute; - - /// - /// A post execute callback to call when none is provided in - /// the QueueWorkItem method. - /// - private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; - - /// - /// Indicate the WorkItemsGroup to suspend the handling of the work items - /// until the Start() method is called. - /// - private bool _startSuspended; - - public WIGStartInfo() - { - _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; - _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; - _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; - _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; - _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; - _startSuspended = SmartThreadPool.DefaultStartSuspended; - } - - public WIGStartInfo(WIGStartInfo wigStartInfo) - { - _useCallerCallContext = wigStartInfo._useCallerCallContext; - _useCallerHttpContext = wigStartInfo._useCallerHttpContext; - _disposeOfStateObjects = wigStartInfo._disposeOfStateObjects; - _callToPostExecute = wigStartInfo._callToPostExecute; - _postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback; - _startSuspended = wigStartInfo._startSuspended; - } - - public bool UseCallerCallContext - { - get { return _useCallerCallContext; } - set { _useCallerCallContext = value; } - } - - public bool UseCallerHttpContext - { - get { return _useCallerHttpContext; } - set { _useCallerHttpContext = value; } - } - - public bool DisposeOfStateObjects - { - get { return _disposeOfStateObjects; } - set { _disposeOfStateObjects = value; } - } - - public CallToPostExecute CallToPostExecute - { - get { return _callToPostExecute; } - set { _callToPostExecute = value; } - } - - public PostExecuteWorkItemCallback PostExecuteWorkItemCallback - { - get { return _postExecuteWorkItemCallback; } - set { _postExecuteWorkItemCallback = value; } - } - - public bool StartSuspended - { - get { return _startSuspended; } - set { _startSuspended = value; } - } - } -} +using System; + +namespace Amib.Threading +{ + /// + /// Summary description for WIGStartInfo. + /// + public class WIGStartInfo + { + private bool _useCallerCallContext; + private bool _useCallerHttpContext; + private bool _disposeOfStateObjects; + private CallToPostExecute _callToPostExecute; + private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; + private bool _startSuspended; + private WorkItemPriority _workItemPriority; + private bool _fillStateWithArgs; + + protected bool _readOnly; + + public WIGStartInfo() + { + _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; + _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; + _startSuspended = SmartThreadPool.DefaultStartSuspended; + _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; + _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; + _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; + _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; + _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; + } + + public WIGStartInfo(WIGStartInfo wigStartInfo) + { + _useCallerCallContext = wigStartInfo.UseCallerCallContext; + _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; + _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + _callToPostExecute = wigStartInfo.CallToPostExecute; + _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + _workItemPriority = wigStartInfo.WorkItemPriority; + _startSuspended = wigStartInfo.StartSuspended; + _fillStateWithArgs = wigStartInfo.FillStateWithArgs; + } + + protected void ThrowIfReadOnly() + { + if (_readOnly) + { + throw new NotSupportedException("This is a readonly instance and set is not supported"); + } + } + + /// + /// Get/Set if to use the caller's security context + /// + public virtual bool UseCallerCallContext + { + get { return _useCallerCallContext; } + set + { + ThrowIfReadOnly(); + _useCallerCallContext = value; + } + } + + + /// + /// Get/Set if to use the caller's HTTP context + /// + public virtual bool UseCallerHttpContext + { + get { return _useCallerHttpContext; } + set + { + ThrowIfReadOnly(); + _useCallerHttpContext = value; + } + } + + + /// + /// Get/Set if to dispose of the state object of a work item + /// + public virtual bool DisposeOfStateObjects + { + get { return _disposeOfStateObjects; } + set + { + ThrowIfReadOnly(); + _disposeOfStateObjects = value; + } + } + + + /// + /// Get/Set the run the post execute options + /// + public virtual CallToPostExecute CallToPostExecute + { + get { return _callToPostExecute; } + set + { + ThrowIfReadOnly(); + _callToPostExecute = value; + } + } + + + /// + /// Get/Set the default post execute callback + /// + public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback + { + get { return _postExecuteWorkItemCallback; } + set + { + ThrowIfReadOnly(); + _postExecuteWorkItemCallback = value; + } + } + + + /// + /// Get/Set if the work items execution should be suspended until the Start() + /// method is called. + /// + public virtual bool StartSuspended + { + get { return _startSuspended; } + set + { + ThrowIfReadOnly(); + _startSuspended = value; + } + } + + + /// + /// Get/Set the default priority that a work item gets when it is enqueued + /// + public virtual WorkItemPriority WorkItemPriority + { + get { return _workItemPriority; } + set { _workItemPriority = value; } + } + + /// + /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the + /// arguments as an object array into the state of the work item. + /// The arguments can be access later by IWorkItemResult.State. + /// + public virtual bool FillStateWithArgs + { + get { return _fillStateWithArgs; } + set + { + ThrowIfReadOnly(); + _fillStateWithArgs = value; + } + } + + /// + /// Get a readonly version of this WIGStartInfo + /// + /// Returns a readonly reference to this WIGStartInfoRO + public WIGStartInfo AsReadOnly() + { + return new WIGStartInfo(this) { _readOnly = true }; + } + } +} diff --git a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs new file mode 100644 index 0000000..5745c15 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Amib.Threading.Internal +{ + public partial class WorkItem + { + #region WorkItemResult class + + private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult + { + /// + /// A back reference to the work item + /// + private readonly WorkItem _workItem; + + public WorkItemResult(WorkItem workItem) + { + _workItem = workItem; + } + + internal WorkItem GetWorkItem() + { + return _workItem; + } + + #region IWorkItemResult Members + + public bool IsCompleted + { + get + { + return _workItem.IsCompleted; + } + } + + public bool IsCanceled + { + get + { + return _workItem.IsCanceled; + } + } + + public object GetResult() + { + return _workItem.GetResult(Timeout.Infinite, true, null); + } + + public object GetResult(int millisecondsTimeout, bool exitContext) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, null); + } + + public object GetResult(TimeSpan timeout, bool exitContext) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); + } + + public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + public object GetResult(out Exception e) + { + return _workItem.GetResult(Timeout.Infinite, true, null, out e); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); + } + + public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); + } + + public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); + } + + public bool Cancel() + { + return Cancel(false); + } + + public bool Cancel(bool abortExecution) + { + return _workItem.Cancel(abortExecution); + } + + public object State + { + get + { + return _workItem._state; + } + } + + public WorkItemPriority WorkItemPriority + { + get + { + return _workItem._workItemInfo.WorkItemPriority; + } + } + + /// + /// Return the result, same as GetResult() + /// + public object Result + { + get { return GetResult(); } + } + + /// + /// Returns the exception if occured otherwise returns null. + /// This value is valid only after the work item completed, + /// before that it is always null. + /// + public object Exception + { + get { return _workItem._exception; } + } + + #endregion + + #region IInternalWorkItemResult Members + + public event WorkItemStateCallback OnWorkItemStarted + { + add + { + _workItem.OnWorkItemStarted += value; + } + remove + { + _workItem.OnWorkItemStarted -= value; + } + } + + + public event WorkItemStateCallback OnWorkItemCompleted + { + add + { + _workItem.OnWorkItemCompleted += value; + } + remove + { + _workItem.OnWorkItemCompleted -= value; + } + } + + #endregion + + #region IInternalWorkItemResult Members + + public IWorkItemResult GetWorkItemResult() + { + return this; + } + + public IWorkItemResult GetWorkItemResultT() + { + return new WorkItemResultTWrapper(this); + } + + #endregion + } + + #endregion + + } +} diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs index d0c0524..f229d1f 100644 --- a/ThirdParty/SmartThreadPool/WorkItem.cs +++ b/ThirdParty/SmartThreadPool/WorkItem.cs @@ -1,58 +1,13 @@ -// Ami Bar -// amibar@gmail.com - using System; using System.Threading; using System.Diagnostics; namespace Amib.Threading.Internal { - #region WorkItem Delegate - - /// - /// An internal delegate to call when the WorkItem starts or completes - /// - internal delegate void WorkItemStateCallback(WorkItem workItem); - - #endregion - - #region IInternalWorkItemResult interface - - public class CanceledWorkItemsGroup - { - public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); - - private bool _isCanceled = false; - public bool IsCanceled - { - get { return _isCanceled; } - set { _isCanceled = value; } - } - } - - internal interface IInternalWorkItemResult - { - event WorkItemStateCallback OnWorkItemStarted; - event WorkItemStateCallback OnWorkItemCompleted; - } - - #endregion - - #region IWorkItem interface - - public interface IWorkItem - { - - } - - #endregion - - #region WorkItem class - /// /// Holds a callback delegate and the state for that delegate. /// - public class WorkItem : IHasWorkItemPriority, IWorkItem + public partial class WorkItem : IHasWorkItemPriority { #region WorkItemState enum @@ -61,33 +16,57 @@ namespace Amib.Threading.Internal /// private enum WorkItemState { - InQueue, - InProgress, - Completed, - Canceled, + InQueue = 0, // Nexts: InProgress, Canceled + InProgress = 1, // Nexts: Completed, Canceled + Completed = 2, // Stays Completed + Canceled = 3, // Stays Canceled } - #endregion + private static bool IsValidStatesTransition(WorkItemState currentState, WorkItemState nextState) + { + bool valid = false; + + switch (currentState) + { + case WorkItemState.InQueue: + valid = (WorkItemState.InProgress == nextState) || (WorkItemState.Canceled == nextState); + break; + case WorkItemState.InProgress: + valid = (WorkItemState.Completed == nextState) || (WorkItemState.Canceled == nextState); + break; + case WorkItemState.Completed: + case WorkItemState.Canceled: + // Cannot be changed + break; + default: + // Unknown state + Debug.Assert(false); + break; + } - #region Member Variables + return valid; + } - public Thread currentThread; + #endregion + + #region Fields /// /// Callback delegate for the callback. /// - private WorkItemCallback _callback; + private readonly WorkItemCallback _callback; /// /// State with which to call the callback delegate. /// private object _state; +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) /// /// Stores the caller's context /// - private CallerThreadContext _callerContext; - + private readonly CallerThreadContext _callerContext; +#endif /// /// Holds the result of the mehtod /// @@ -117,12 +96,12 @@ namespace Amib.Threading.Internal /// /// Represents the result state of the work item /// - private WorkItemResult _workItemResult; + private readonly WorkItemResult _workItemResult; /// /// Work item info /// - private WorkItemInfo _workItemInfo; + private readonly WorkItemInfo _workItemInfo; /// /// Called when the WorkItem starts @@ -141,30 +120,41 @@ namespace Amib.Threading.Internal private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; /// + /// A reference to an object that indicates whatever the + /// SmartThreadPool has been canceled + /// + private CanceledWorkItemsGroup _canceledSmartThreadPool = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup; + + /// /// The work item group this work item belong to. - /// /// - private IWorkItemsGroup _workItemsGroup; + private readonly IWorkItemsGroup _workItemsGroup; - #region Performance Counter fields + /// + /// The thread that executes this workitem. + /// This field is available for the period when the work item is executed, before and after it is null. + /// + private Thread _executingThread; /// - /// The time when the work items is queued. - /// Used with the performance counter. + /// The absulote time when the work item will be timeout /// - private DateTime _queuedTime; + private long _expirationTime; + + #region Performance Counter fields + + + /// - /// The time when the work items starts its execution. - /// Used with the performance counter. + /// Stores how long the work item waited on the stp queue /// - private DateTime _beginProcessTime; + private Stopwatch _waitingOnQueueStopwatch; /// - /// The time when the work items ends its execution. - /// Used with the performance counter. + /// Stores how much time it took the work item to execute after it went out of the queue /// - private DateTime _endProcessTime; + private Stopwatch _processingStopwatch; #endregion @@ -174,17 +164,25 @@ namespace Amib.Threading.Internal public TimeSpan WaitingTime { - get + get { - return (_beginProcessTime - _queuedTime); + return _waitingOnQueueStopwatch.Elapsed; } } public TimeSpan ProcessTime { - get + get + { + return _processingStopwatch.Elapsed; + } + } + + internal WorkItemInfo WorkItemInfo + { + get { - return (_endProcessTime - _beginProcessTime); + return _workItemInfo; } } @@ -195,6 +193,8 @@ namespace Amib.Threading.Internal /// /// Initialize the callback holding object. /// + /// The workItemGroup of the workitem + /// The WorkItemInfo of te workitem /// Callback delegate for the callback. /// State with which to call the callback delegate. /// @@ -203,16 +203,18 @@ namespace Amib.Threading.Internal public WorkItem( IWorkItemsGroup workItemsGroup, WorkItemInfo workItemInfo, - WorkItemCallback callback, + WorkItemCallback callback, object state) { _workItemsGroup = workItemsGroup; _workItemInfo = workItemInfo; +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext) { _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext); } +#endif _callback = callback; _state = state; @@ -222,9 +224,18 @@ namespace Amib.Threading.Internal internal void Initialize() { + // The _workItemState is changed directly instead of using the SetWorkItemState + // method since we don't want to go throught IsValidStateTransition. _workItemState = WorkItemState.InQueue; + _workItemCompleted = null; _workItemCompletedRefCount = 0; + _waitingOnQueueStopwatch = new Stopwatch(); + _processingStopwatch = new Stopwatch(); + _expirationTime = + _workItemInfo.Timeout > 0 ? + DateTime.UtcNow.Ticks + _workItemInfo.Timeout * TimeSpan.TicksPerMillisecond : + long.MaxValue; } internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup) @@ -237,17 +248,16 @@ namespace Amib.Threading.Internal #region Methods - public CanceledWorkItemsGroup CanceledWorkItemsGroup + internal CanceledWorkItemsGroup CanceledWorkItemsGroup { - get - { - return _canceledWorkItemsGroup; - } + get { return _canceledWorkItemsGroup; } + set { _canceledWorkItemsGroup = value; } + } - set - { - _canceledWorkItemsGroup = value; - } + internal CanceledWorkItemsGroup CanceledSmartThreadPool + { + get { return _canceledSmartThreadPool; } + set { _canceledSmartThreadPool = value; } } /// @@ -259,9 +269,10 @@ namespace Amib.Threading.Internal /// public bool StartingWorkItem() { - _beginProcessTime = DateTime.Now; + _waitingOnQueueStopwatch.Stop(); + _processingStopwatch.Start(); - lock(this) + lock (this) { if (IsCanceled) { @@ -277,6 +288,9 @@ namespace Amib.Threading.Internal Debug.Assert(WorkItemState.InQueue == GetWorkItemState()); + // No need for a lock yet, only after the state has changed to InProgress + _executingThread = Thread.CurrentThread; + SetWorkItemState(WorkItemState.InProgress); } @@ -291,7 +305,7 @@ namespace Amib.Threading.Internal CallToPostExecute currentCallToPostExecute = 0; // Execute the work item if we are in the correct state - switch(GetWorkItemState()) + switch (GetWorkItemState()) { case WorkItemState.InProgress: currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled; @@ -311,7 +325,7 @@ namespace Amib.Threading.Internal PostExecute(); } - _endProcessTime = DateTime.Now; + _processingStopwatch.Stop(); } internal void FireWorkItemCompleted() @@ -323,8 +337,21 @@ namespace Amib.Threading.Internal _workItemCompletedEvent(this); } } - catch // Ignore exceptions - {} + catch // Suppress exceptions + { } + } + + internal void FireWorkItemStarted() + { + try + { + if (null != _workItemStartedEvent) + { + _workItemStartedEvent(this); + } + } + catch // Suppress exceptions + { } } /// @@ -332,32 +359,70 @@ namespace Amib.Threading.Internal /// private void ExecuteWorkItem() { + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) CallerThreadContext ctc = null; if (null != _callerContext) { ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext); CallerThreadContext.Apply(_callerContext); } +#endif Exception exception = null; object result = null; try { - result = _callback(_state); + try + { + result = _callback(_state); + } + catch (Exception e) + { + // Save the exception so we can rethrow it later + exception = e; + } + + // Remove the value of the execution thread, so it will be impossible to cancel the work item, + // since it is already completed. + // Cancelling a work item that already completed may cause the abortion of the next work item!!! + Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); + + if (null == executionThread) + { + // Oops! we are going to be aborted..., Wait here so we can catch the ThreadAbortException + Thread.Sleep(60 * 1000); + + // If after 1 minute this thread was not aborted then let it continue working. + } } - catch (Exception e) + // We must treat the ThreadAbortException or else it will be stored in the exception variable + catch (ThreadAbortException tae) { - // Save the exception so we can rethrow it later - exception = e; + tae.GetHashCode(); + // Check if the work item was cancelled + // If we got a ThreadAbortException and the STP is not shutting down, it means the + // work items was cancelled. + if (!SmartThreadPool.CurrentThreadEntry.AssociatedSmartThreadPool.IsShuttingdown) + { +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + Thread.ResetAbort(); +#endif + } } - + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) if (null != _callerContext) { CallerThreadContext.Apply(ctc); } +#endif - SetResult(result, exception); + if (!SmartThreadPool.IsWorkItemCanceled) + { + SetResult(result, exception); + } } /// @@ -369,9 +434,9 @@ namespace Amib.Threading.Internal { try { - _workItemInfo.PostExecuteWorkItemCallback(this._workItemResult); + _workItemInfo.PostExecuteWorkItemCallback(_workItemResult); } - catch (Exception e) + catch (Exception e) { Debug.Assert(null != e); } @@ -382,6 +447,8 @@ namespace Amib.Threading.Internal /// Set the result of the work item to return /// /// The result of the work item + /// The exception that was throw while the workitem executed, null + /// if there was no exception. internal void SetResult(object result, Exception exception) { _result = result; @@ -401,48 +468,48 @@ namespace Amib.Threading.Internal /// /// Wait for all work items to complete /// - /// Array of work item result objects + /// Array of work item result objects /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. /// /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. /// /// A cancel wait handle to interrupt the wait if needed /// - /// true when every work item in workItemResults has completed; otherwise false. + /// true when every work item in waitableResults has completed; otherwise false. /// internal static bool WaitAll( - IWorkItemResult [] workItemResults, + IWaitableResult[] waitableResults, int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) { - if (0 == workItemResults.Length) + if (0 == waitableResults.Length) { return true; } bool success; - WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];; - GetWaitHandles(workItemResults, waitHandles); + WaitHandle[] waitHandles = new WaitHandle[waitableResults.Length]; + GetWaitHandles(waitableResults, waitHandles); if ((null == cancelWaitHandle) && (waitHandles.Length <= 64)) { - success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); + success = STPEventWaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); } else { success = true; int millisecondsLeft = millisecondsTimeout; - DateTime start = DateTime.Now; + Stopwatch stopwatch = Stopwatch.StartNew(); - WaitHandle [] whs; + WaitHandle[] whs; if (null != cancelWaitHandle) { - whs = new WaitHandle [] { null, cancelWaitHandle }; + whs = new WaitHandle[] { null, cancelWaitHandle }; } else { - whs = new WaitHandle [] { null }; + whs = new WaitHandle[] { null }; } bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); @@ -450,7 +517,7 @@ namespace Amib.Threading.Internal // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle // won't affect it. // Each iteration we update the time left for the timeout. - for(int i = 0; i < workItemResults.Length; ++i) + for (int i = 0; i < waitableResults.Length; ++i) { // WaitAny don't work with negative numbers if (!waitInfinitely && (millisecondsLeft < 0)) @@ -460,23 +527,22 @@ namespace Amib.Threading.Internal } whs[0] = waitHandles[i]; - int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext); - if((result > 0) || (WaitHandle.WaitTimeout == result)) + int result = STPEventWaitHandle.WaitAny(whs, millisecondsLeft, exitContext); + if ((result > 0) || (STPEventWaitHandle.WaitTimeout == result)) { success = false; break; } - if(!waitInfinitely) + if (!waitInfinitely) { // Update the time left to wait - TimeSpan ts = DateTime.Now - start; - millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds; + millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; } } } // Release the wait handles - ReleaseWaitHandles(workItemResults); + ReleaseWaitHandles(waitableResults); return success; } @@ -484,7 +550,7 @@ namespace Amib.Threading.Internal /// /// Waits for any of the work items in the specified array to complete, cancel, or timeout /// - /// Array of work item result objects + /// Array of work item result objects /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. /// /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. @@ -493,38 +559,38 @@ namespace Amib.Threading.Internal /// /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. /// - internal static int WaitAny( - IWorkItemResult [] workItemResults, + internal static int WaitAny( + IWaitableResult[] waitableResults, int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) { - WaitHandle [] waitHandles = null; + WaitHandle[] waitHandles; if (null != cancelWaitHandle) { - waitHandles = new WaitHandle[workItemResults.Length+1]; - GetWaitHandles(workItemResults, waitHandles); - waitHandles[workItemResults.Length] = cancelWaitHandle; + waitHandles = new WaitHandle[waitableResults.Length + 1]; + GetWaitHandles(waitableResults, waitHandles); + waitHandles[waitableResults.Length] = cancelWaitHandle; } else { - waitHandles = new WaitHandle[workItemResults.Length]; - GetWaitHandles(workItemResults, waitHandles); + waitHandles = new WaitHandle[waitableResults.Length]; + GetWaitHandles(waitableResults, waitHandles); } - int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); + int result = STPEventWaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); // Treat cancel as timeout if (null != cancelWaitHandle) { - if (result == workItemResults.Length) + if (result == waitableResults.Length) { - result = WaitHandle.WaitTimeout; + result = STPEventWaitHandle.WaitTimeout; } } - ReleaseWaitHandles(workItemResults); + ReleaseWaitHandles(waitableResults); return result; } @@ -532,16 +598,16 @@ namespace Amib.Threading.Internal /// /// Fill an array of wait handles with the work items wait handles. /// - /// An array of work item results + /// An array of work item results /// An array of wait handles to fill private static void GetWaitHandles( - IWorkItemResult [] workItemResults, - WaitHandle [] waitHandles) + IWaitableResult[] waitableResults, + WaitHandle[] waitHandles) { - for(int i = 0; i < workItemResults.Length; ++i) + for (int i = 0; i < waitableResults.Length; ++i) { - WorkItemResult wir = workItemResults[i] as WorkItemResult; - Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects"); + WorkItemResult wir = waitableResults[i].GetWorkItemResult() as WorkItemResult; + Debug.Assert(null != wir, "All waitableResults must be WorkItemResult objects"); waitHandles[i] = wir.GetWorkItem().GetWaitHandle(); } @@ -550,40 +616,64 @@ namespace Amib.Threading.Internal /// /// Release the work items' wait handles /// - /// An array of work item results - private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults) + /// An array of work item results + private static void ReleaseWaitHandles(IWaitableResult[] waitableResults) { - for(int i = 0; i < workItemResults.Length; ++i) + for (int i = 0; i < waitableResults.Length; ++i) { - WorkItemResult wir = workItemResults[i] as WorkItemResult; + WorkItemResult wir = (WorkItemResult)waitableResults[i].GetWorkItemResult(); wir.GetWorkItem().ReleaseWaitHandle(); } } - #endregion - + #region Private Members private WorkItemState GetWorkItemState() { - if (_canceledWorkItemsGroup.IsCanceled) + lock (this) { - return WorkItemState.Canceled; - } - return _workItemState; + if (WorkItemState.Completed == _workItemState) + { + return _workItemState; + } + + long nowTicks = DateTime.UtcNow.Ticks; + if (WorkItemState.Canceled != _workItemState && nowTicks > _expirationTime) + { + _workItemState = WorkItemState.Canceled; + } + + if (WorkItemState.InProgress == _workItemState) + { + return _workItemState; + } + + if (CanceledSmartThreadPool.IsCanceled || CanceledWorkItemsGroup.IsCanceled) + { + return WorkItemState.Canceled; + } + + return _workItemState; + } } + + /// /// Sets the work item's state /// /// The state to set the work item to private void SetWorkItemState(WorkItemState workItemState) { - lock(this) + lock (this) { - _workItemState = workItemState; + if (IsValidStatesTransition(_workItemState, workItemState)) + { + _workItemState = workItemState; + } } } @@ -594,7 +684,7 @@ namespace Amib.Threading.Internal private void SignalComplete(bool canceled) { SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed); - lock(this) + lock (this) { // If someone is waiting then signal. if (null != _workItemCompleted) @@ -606,40 +696,83 @@ namespace Amib.Threading.Internal internal void WorkItemIsQueued() { - _queuedTime = DateTime.Now; + _waitingOnQueueStopwatch.Start(); } #endregion - + #region Members exposed by WorkItemResult /// /// Cancel the work item if it didn't start running yet. /// /// Returns true on success or false if the work item is in progress or already completed - private bool Cancel() + private bool Cancel(bool abortExecution) { - lock(this) +#if (_WINDOWS_CE) + if(abortExecution) + { + throw new ArgumentOutOfRangeException("abortExecution", "WindowsCE doesn't support this feature"); + } +#endif + bool success = false; + bool signalComplete = false; + + lock (this) { - switch(GetWorkItemState()) + switch (GetWorkItemState()) { case WorkItemState.Canceled: //Debug.WriteLine("Work item already canceled"); - return true; + if (abortExecution) + { + Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); + if (null != executionThread) + { + executionThread.Abort(); // "Cancel" + // No need to signalComplete, because we already cancelled this work item + // so it already signaled its completion. + //signalComplete = true; + } + } + success = true; + break; case WorkItemState.Completed: - case WorkItemState.InProgress: //Debug.WriteLine("Work item cannot be canceled"); - return false; + break; + case WorkItemState.InProgress: + if (abortExecution) + { + Thread executionThread = Interlocked.CompareExchange(ref _executingThread, null, _executingThread); + if (null != executionThread) + { + executionThread.Abort(); // "Cancel" + success = true; + signalComplete = true; + } + } + else + { + success = false; + signalComplete = false; + } + break; case WorkItemState.InQueue: // Signal to the wait for completion that the work // item has been completed (canceled). There is no // reason to wait for it to get out of the queue - SignalComplete(true); + signalComplete = true; //Debug.WriteLine("Work item canceled"); - return true; + success = true; + break; + } + + if (signalComplete) + { + SignalComplete(true); } } - return false; + return success; } /// @@ -653,7 +786,7 @@ namespace Amib.Threading.Internal bool exitContext, WaitHandle cancelWaitHandle) { - Exception e = null; + Exception e; object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); if (null != e) { @@ -694,7 +827,7 @@ namespace Amib.Threading.Internal { WaitHandle wh = GetWaitHandle(); - bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext); + bool timeout = !STPEventWaitHandle.WaitOne(wh, millisecondsTimeout, exitContext); ReleaseWaitHandle(); @@ -706,10 +839,10 @@ namespace Amib.Threading.Internal else { WaitHandle wh = GetWaitHandle(); - int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); + int result = STPEventWaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle }); ReleaseWaitHandle(); - switch(result) + switch (result) { case 0: // The work item signaled @@ -717,7 +850,7 @@ namespace Amib.Threading.Internal // work item (not the get result) break; case 1: - case WaitHandle.WaitTimeout: + case STPEventWaitHandle.WaitTimeout: throw new WorkItemTimeoutException("Work item timeout"); default: Debug.Assert(false); @@ -745,11 +878,11 @@ namespace Amib.Threading.Internal /// private WaitHandle GetWaitHandle() { - lock(this) + lock (this) { if (null == _workItemCompleted) { - _workItemCompleted = new ManualResetEvent(IsCompleted); + _workItemCompleted = EventWaitHandleFactory.CreateManualResetEvent(IsCompleted); } ++_workItemCompletedRefCount; } @@ -758,7 +891,7 @@ namespace Amib.Threading.Internal private void ReleaseWaitHandle() { - lock(this) + lock (this) { if (null != _workItemCompleted) { @@ -779,10 +912,10 @@ namespace Amib.Threading.Internal { get { - lock(this) + lock (this) { WorkItemState workItemState = GetWorkItemState(); - return ((workItemState == WorkItemState.Completed) || + return ((workItemState == WorkItemState.Completed) || (workItemState == WorkItemState.Canceled)); } } @@ -795,7 +928,7 @@ namespace Amib.Threading.Internal { get { - lock(this) + lock (this) { return (GetWorkItemState() == WorkItemState.Canceled); } @@ -843,172 +976,6 @@ namespace Amib.Threading.Internal } } - - #region WorkItemResult class - - private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult - { - /// - /// A back reference to the work item - /// - private WorkItem _workItem; - - public WorkItemResult(WorkItem workItem) - { - _workItem = workItem; - } - - internal WorkItem GetWorkItem() - { - return _workItem; - } - - #region IWorkItemResult Members - - public bool IsCompleted - { - get - { - return _workItem.IsCompleted; - } - } - - public void Abort() - { - _workItem.Abort(); - } - - public bool IsCanceled - { - get - { - return _workItem.IsCanceled; - } - } - - public object GetResult() - { - return _workItem.GetResult(Timeout.Infinite, true, null); - } - - public object GetResult(int millisecondsTimeout, bool exitContext) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, null); - } - - public object GetResult(TimeSpan timeout, bool exitContext) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); - } - - public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - public object GetResult(out Exception e) - { - return _workItem.GetResult(Timeout.Infinite, true, null, out e); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); - } - - public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); - } - - public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); - } - - public bool Cancel() - { - return _workItem.Cancel(); - } - - public object State - { - get - { - return _workItem._state; - } - } - - public WorkItemPriority WorkItemPriority - { - get - { - return _workItem._workItemInfo.WorkItemPriority; - } - } - - /// - /// Return the result, same as GetResult() - /// - public object Result - { - get { return GetResult(); } - } - - /// - /// Returns the exception if occured otherwise returns null. - /// This value is valid only after the work item completed, - /// before that it is always null. - /// - public object Exception - { - get { return _workItem._exception; } - } - - #endregion - - #region IInternalWorkItemResult Members - - public event WorkItemStateCallback OnWorkItemStarted - { - add - { - _workItem.OnWorkItemStarted += value; - } - remove - { - _workItem.OnWorkItemStarted -= value; - } - } - - - public event WorkItemStateCallback OnWorkItemCompleted - { - add - { - _workItem.OnWorkItemCompleted += value; - } - remove - { - _workItem.OnWorkItemCompleted -= value; - } - } - - #endregion - } - - #endregion - public void DisposeOfState() { if (_workItemInfo.DisposeOfStateObjects) @@ -1021,15 +988,5 @@ namespace Amib.Threading.Internal } } } - - public void Abort() - { - lock (this) - { - if(currentThread != null) - currentThread.Abort(); - } - } } - #endregion } diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs index dfcb54f..2d6601e 100644 --- a/ThirdParty/SmartThreadPool/WorkItemFactory.cs +++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs @@ -1,333 +1,343 @@ -// Ami Bar -// amibar@gmail.com - -using System; - -namespace Amib.Threading.Internal -{ - #region WorkItemFactory class - - public class WorkItemFactory - { - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback) - { - return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// The priority of the work item - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - WorkItemPriority workItemPriority) - { - return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// Work item info - /// A callback to execute - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemInfo workItemInfo, - WorkItemCallback callback) - { - return CreateWorkItem( - workItemsGroup, - wigStartInfo, - workItemInfo, - callback, - null); - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state) - { - ValidateCallback(callback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - return workItem; - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - WorkItemPriority workItemPriority) - { - ValidateCallback(callback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = workItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemInfo workItemInfo, - WorkItemCallback callback, - object state) - { - ValidateCallback(callback); - ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); - - WorkItem workItem = new WorkItem( - workItemsGroup, - new WorkItemInfo(workItemInfo), - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = workItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = callToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = callToPostExecute; - workItemInfo.WorkItemPriority = workItemPriority; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - private static void ValidateCallback(Delegate callback) - { - if(callback.GetInvocationList().Length > 1) - { - throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); - } - } - } - - #endregion -} +using System; + +namespace Amib.Threading.Internal +{ + #region WorkItemFactory class + + public class WorkItemFactory + { + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback) + { + return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// The priority of the work item + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + WorkItemPriority workItemPriority) + { + return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// Work item info + /// A callback to execute + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemInfo workItemInfo, + WorkItemCallback callback) + { + return CreateWorkItem( + workItemsGroup, + wigStartInfo, + workItemInfo, + callback, + null); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state) + { + ValidateCallback(callback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + WorkItemPriority workItemPriority) + { + ValidateCallback(callback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = workItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemInfo workItemInfo, + WorkItemCallback callback, + object state) + { + ValidateCallback(callback); + ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); + + WorkItem workItem = new WorkItem( + workItemsGroup, + new WorkItemInfo(workItemInfo), + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + WorkItemPriority workItemPriority) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = workItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = callToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute, + WorkItemPriority workItemPriority) + { + + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = callToPostExecute; + workItemInfo.WorkItemPriority = workItemPriority; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + private static void ValidateCallback(Delegate callback) + { + if (callback != null && callback.GetInvocationList().Length > 1) + { + throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); + } + } + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs index c259339..5fbceb8 100644 --- a/ThirdParty/SmartThreadPool/WorkItemInfo.cs +++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs @@ -1,102 +1,69 @@ -// Ami Bar -// amibar@gmail.com - -namespace Amib.Threading -{ - #region WorkItemInfo class - - /// - /// Summary description for WorkItemInfo. - /// - public class WorkItemInfo - { - /// - /// Use the caller's security context - /// - private bool _useCallerCallContext; - - /// - /// Use the caller's security context - /// - private bool _useCallerHttpContext; - - /// - /// Dispose of the state object of a work item - /// - private bool _disposeOfStateObjects; - - /// - /// The option to run the post execute - /// - private CallToPostExecute _callToPostExecute; - - /// - /// A post execute callback to call when none is provided in - /// the QueueWorkItem method. - /// - private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; - - /// - /// The priority of the work item - /// - private WorkItemPriority _workItemPriority; - - public WorkItemInfo() - { - _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; - _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; - _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; - _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; - _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; - _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; - } - - public WorkItemInfo(WorkItemInfo workItemInfo) - { - _useCallerCallContext = workItemInfo._useCallerCallContext; - _useCallerHttpContext = workItemInfo._useCallerHttpContext; - _disposeOfStateObjects = workItemInfo._disposeOfStateObjects; - _callToPostExecute = workItemInfo._callToPostExecute; - _postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback; - _workItemPriority = workItemInfo._workItemPriority; - } - - public bool UseCallerCallContext - { - get { return _useCallerCallContext; } - set { _useCallerCallContext = value; } - } - - public bool UseCallerHttpContext - { - get { return _useCallerHttpContext; } - set { _useCallerHttpContext = value; } - } - - public bool DisposeOfStateObjects - { - get { return _disposeOfStateObjects; } - set { _disposeOfStateObjects = value; } - } - - public CallToPostExecute CallToPostExecute - { - get { return _callToPostExecute; } - set { _callToPostExecute = value; } - } - - public PostExecuteWorkItemCallback PostExecuteWorkItemCallback - { - get { return _postExecuteWorkItemCallback; } - set { _postExecuteWorkItemCallback = value; } - } - - public WorkItemPriority WorkItemPriority - { - get { return _workItemPriority; } - set { _workItemPriority = value; } - } - } - - #endregion -} +namespace Amib.Threading +{ + #region WorkItemInfo class + + /// + /// Summary description for WorkItemInfo. + /// + public class WorkItemInfo + { + public WorkItemInfo() + { + UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; + UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; + DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; + CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; + PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; + WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; + } + + public WorkItemInfo(WorkItemInfo workItemInfo) + { + UseCallerCallContext = workItemInfo.UseCallerCallContext; + UseCallerHttpContext = workItemInfo.UseCallerHttpContext; + DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; + CallToPostExecute = workItemInfo.CallToPostExecute; + PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; + WorkItemPriority = workItemInfo.WorkItemPriority; + Timeout = workItemInfo.Timeout; + } + + /// + /// Get/Set if to use the caller's security context + /// + public bool UseCallerCallContext { get; set; } + + /// + /// Get/Set if to use the caller's HTTP context + /// + public bool UseCallerHttpContext { get; set; } + + /// + /// Get/Set if to dispose of the state object of a work item + /// + public bool DisposeOfStateObjects { get; set; } + + /// + /// Get/Set the run the post execute options + /// + public CallToPostExecute CallToPostExecute { get; set; } + + /// + /// Get/Set the post execute callback + /// + public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } + + /// + /// Get/Set the work item's priority + /// + public WorkItemPriority WorkItemPriority { get; set; } + + /// + /// Get/Set the work item's timout in milliseconds. + /// This is a passive timout. When the timout expires the work item won't be actively aborted! + /// + public long Timeout { get; set; } + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs new file mode 100644 index 0000000..a0bf8b8 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs @@ -0,0 +1,128 @@ +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ + #region WorkItemResultTWrapper class + + internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult + { + private readonly IWorkItemResult _workItemResult; + + public WorkItemResultTWrapper(IWorkItemResult workItemResult) + { + _workItemResult = workItemResult; + } + + #region IWorkItemResult Members + + public TResult GetResult() + { + return (TResult)_workItemResult.GetResult(); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); + } + + public TResult GetResult(out Exception e) + { + return (TResult)_workItemResult.GetResult(out e); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); + } + + public bool IsCompleted + { + get { return _workItemResult.IsCompleted; } + } + + public bool IsCanceled + { + get { return _workItemResult.IsCanceled; } + } + + public object State + { + get { return _workItemResult.State; } + } + + public bool Cancel() + { + return _workItemResult.Cancel(); + } + + public bool Cancel(bool abortExecution) + { + return _workItemResult.Cancel(abortExecution); + } + + public WorkItemPriority WorkItemPriority + { + get { return _workItemResult.WorkItemPriority; } + } + + public TResult Result + { + get { return (TResult)_workItemResult.Result; } + } + + public object Exception + { + get { return (TResult)_workItemResult.Exception; } + } + + #region IInternalWorkItemResult Members + + public IWorkItemResult GetWorkItemResult() + { + return _workItemResult.GetWorkItemResult(); + } + + public IWorkItemResult GetWorkItemResultT() + { + return (IWorkItemResult)this; + } + + #endregion + + #endregion + } + + #endregion + +} diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs index 01ac8dd..67dcbdd 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs @@ -1,512 +1,361 @@ -// Ami Bar -// amibar@gmail.com - -using System; -using System.Threading; -using System.Runtime.CompilerServices; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - #region WorkItemsGroup class - - /// - /// Summary description for WorkItemsGroup. - /// - public class WorkItemsGroup : IWorkItemsGroup - { - #region Private members - - private object _lock = new object(); - /// - /// Contains the name of this instance of SmartThreadPool. - /// Can be changed by the user. - /// - private string _name = "WorkItemsGroup"; - - /// - /// A reference to the SmartThreadPool instance that created this - /// WorkItemsGroup. - /// - private SmartThreadPool _stp; - - /// - /// The OnIdle event - /// - private event WorkItemsGroupIdleHandler _onIdle; - - /// - /// Defines how many work items of this WorkItemsGroup can run at once. - /// - private int _concurrency; - - /// - /// Priority queue to hold work items before they are passed - /// to the SmartThreadPool. - /// - private PriorityQueue _workItemsQueue; - - /// - /// Indicate how many work items are waiting in the SmartThreadPool - /// queue. - /// This value is used to apply the concurrency. - /// - private int _workItemsInStpQueue; - - /// - /// Indicate how many work items are currently running in the SmartThreadPool. - /// This value is used with the Cancel, to calculate if we can send new - /// work items to the STP. - /// - private int _workItemsExecutingInStp = 0; - - /// - /// WorkItemsGroup start information - /// - private WIGStartInfo _workItemsGroupStartInfo; - - /// - /// Signaled when all of the WorkItemsGroup's work item completed. - /// - private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); - - /// - /// A common object for all the work items that this work items group - /// generate so we can mark them to cancel in O(1) - /// - private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); - - #endregion - - #region Construction - - public WorkItemsGroup( - SmartThreadPool stp, - int concurrency, - WIGStartInfo wigStartInfo) - { - if (concurrency <= 0) - { - throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero"); - } - _stp = stp; - _concurrency = concurrency; - _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo); - _workItemsQueue = new PriorityQueue(); - - // The _workItemsInStpQueue gets the number of currently executing work items, - // because once a work item is executing, it cannot be cancelled. - _workItemsInStpQueue = _workItemsExecutingInStp; - } - - #endregion - - #region IWorkItemsGroup implementation - - /// - /// Get/Set the name of the SmartThreadPool instance - /// - public string Name - { - get - { - return _name; - } - - set - { - _name = value; - } - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// The priority of the work item - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item info - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); - EnqueueToSTPNextWorkItem(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Wait for the thread pool to be idle - /// - public void WaitForIdle() - { - WaitForIdle(Timeout.Infinite); - } - - /// - /// Wait for the thread pool to be idle - /// - public bool WaitForIdle(TimeSpan timeout) - { - return WaitForIdle((int)timeout.TotalMilliseconds); - } - - /// - /// Wait for the thread pool to be idle - /// - public bool WaitForIdle(int millisecondsTimeout) - { - _stp.ValidateWorkItemsGroupWaitForIdle(this); - return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false); - } - - public int WaitingCallbacks - { - get - { - return _workItemsQueue.Count; - } - } - - public event WorkItemsGroupIdleHandler OnIdle - { - add - { - _onIdle += value; - } - remove - { - _onIdle -= value; - } - } - - public void Cancel() - { - lock(_lock) - { - _canceledWorkItemsGroup.IsCanceled = true; - _workItemsQueue.Clear(); - _workItemsInStpQueue = 0; - _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); - } - } - - public void Start() - { - lock (this) - { - if (!_workItemsGroupStartInfo.StartSuspended) - { - return; - } - _workItemsGroupStartInfo.StartSuspended = false; - } - - for(int i = 0; i < _concurrency; ++i) - { - EnqueueToSTPNextWorkItem(null, false); - } - } - - #endregion - - #region Private methods - - private void RegisterToWorkItemCompletion(IWorkItemResult wir) - { - IInternalWorkItemResult iwir = wir as IInternalWorkItemResult; - iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback); - iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback); - } - - public void OnSTPIsStarting() - { - lock (this) - { - if (_workItemsGroupStartInfo.StartSuspended) - { - return; - } - } - - for(int i = 0; i < _concurrency; ++i) - { - EnqueueToSTPNextWorkItem(null, false); - } - } - - private object FireOnIdle(object state) - { - FireOnIdleImpl(_onIdle); - return null; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) - { - if(null == onIdle) - { - return; - } - - Delegate[] delegates = onIdle.GetInvocationList(); - foreach(WorkItemsGroupIdleHandler eh in delegates) - { - try - { - eh(this); - } - // Ignore exceptions - catch{} - } - } - - private void OnWorkItemStartedCallback(WorkItem workItem) - { - lock(_lock) - { - ++_workItemsExecutingInStp; - } - } - - private void OnWorkItemCompletedCallback(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(null, true); - } - - private void EnqueueToSTPNextWorkItem(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(workItem, false); - } - - private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) - { - lock(_lock) - { - // Got here from OnWorkItemCompletedCallback() - if (decrementWorkItemsInStpQueue) - { - --_workItemsInStpQueue; - - if(_workItemsInStpQueue < 0) - { - _workItemsInStpQueue = 0; - } - - --_workItemsExecutingInStp; - - if(_workItemsExecutingInStp < 0) - { - _workItemsExecutingInStp = 0; - } - } - - // If the work item is not null then enqueue it - if (null != workItem) - { - workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; - - RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); - _workItemsQueue.Enqueue(workItem); - //_stp.IncrementWorkItemsCount(); - - if ((1 == _workItemsQueue.Count) && - (0 == _workItemsInStpQueue)) - { - _stp.RegisterWorkItemsGroup(this); - Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle"); - _isIdleWaitHandle.Reset(); - } - } - - // If the work items queue of the group is empty than quit - if (0 == _workItemsQueue.Count) - { - if (0 == _workItemsInStpQueue) - { - _stp.UnregisterWorkItemsGroup(this); - Trace.WriteLine("WorkItemsGroup " + Name + " is idle"); - _isIdleWaitHandle.Set(); - _stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle)); - } - return; - } - - if (!_workItemsGroupStartInfo.StartSuspended) - { - if (_workItemsInStpQueue < _concurrency) - { - WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; - _stp.Enqueue(nextWorkItem, true); - ++_workItemsInStpQueue; - } - } - } - } - - #endregion - } - - #endregion -} +using System; +using System.Threading; +using System.Runtime.CompilerServices; +using System.Diagnostics; + +namespace Amib.Threading.Internal +{ + + #region WorkItemsGroup class + + /// + /// Summary description for WorkItemsGroup. + /// + public class WorkItemsGroup : WorkItemsGroupBase + { + #region Private members + + private readonly object _lock = new object(); + + /// + /// A reference to the SmartThreadPool instance that created this + /// WorkItemsGroup. + /// + private readonly SmartThreadPool _stp; + + /// + /// The OnIdle event + /// + private event WorkItemsGroupIdleHandler _onIdle; + + /// + /// A flag to indicate if the Work Items Group is now suspended. + /// + private bool _isSuspended; + + /// + /// Defines how many work items of this WorkItemsGroup can run at once. + /// + private int _concurrency; + + /// + /// Priority queue to hold work items before they are passed + /// to the SmartThreadPool. + /// + private readonly PriorityQueue _workItemsQueue; + + /// + /// Indicate how many work items are waiting in the SmartThreadPool + /// queue. + /// This value is used to apply the concurrency. + /// + private int _workItemsInStpQueue; + + /// + /// Indicate how many work items are currently running in the SmartThreadPool. + /// This value is used with the Cancel, to calculate if we can send new + /// work items to the STP. + /// + private int _workItemsExecutingInStp = 0; + + /// + /// WorkItemsGroup start information + /// + private readonly WIGStartInfo _workItemsGroupStartInfo; + + /// + /// Signaled when all of the WorkItemsGroup's work item completed. + /// + //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); + private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); + + /// + /// A common object for all the work items that this work items group + /// generate so we can mark them to cancel in O(1) + /// + private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); + + #endregion + + #region Construction + + public WorkItemsGroup( + SmartThreadPool stp, + int concurrency, + WIGStartInfo wigStartInfo) + { + if (concurrency <= 0) + { + throw new ArgumentOutOfRangeException( + "concurrency", +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + concurrency, +#endif + "concurrency must be greater than zero"); + } + _stp = stp; + _concurrency = concurrency; + _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly(); + _workItemsQueue = new PriorityQueue(); + Name = "WorkItemsGroup"; + + // The _workItemsInStpQueue gets the number of currently executing work items, + // because once a work item is executing, it cannot be cancelled. + _workItemsInStpQueue = _workItemsExecutingInStp; + + _isSuspended = _workItemsGroupStartInfo.StartSuspended; + } + + #endregion + + #region WorkItemsGroupBase Overrides + + public override int Concurrency + { + get { return _concurrency; } + set + { + Debug.Assert(value > 0); + + int diff = value - _concurrency; + _concurrency = value; + if (diff > 0) + { + EnqueueToSTPNextNWorkItem(diff); + } + } + } + + public override int WaitingCallbacks + { + get { return _workItemsQueue.Count; } + } + + public override object[] GetStates() + { + lock (_lock) + { + object[] states = new object[_workItemsQueue.Count]; + int i = 0; + foreach (WorkItem workItem in _workItemsQueue) + { + states[i] = workItem.GetWorkItemResult().State; + ++i; + } + return states; + } + } + + /// + /// WorkItemsGroup start information + /// + public override WIGStartInfo WIGStartInfo + { + get { return _workItemsGroupStartInfo; } + } + + /// + /// Start the Work Items Group if it was started suspended + /// + public override void Start() + { + // If the Work Items Group already started then quit + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); + } + + public override void Cancel(bool abortExecution) + { + lock (_lock) + { + _canceledWorkItemsGroup.IsCanceled = true; + _workItemsQueue.Clear(); + _workItemsInStpQueue = 0; + _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); + } + + if (abortExecution) + { + _stp.CancelAbortWorkItemsGroup(this); + } + } + + /// + /// Wait for the thread pool to be idle + /// + public override bool WaitForIdle(int millisecondsTimeout) + { + SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this); + return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); + } + + public override event WorkItemsGroupIdleHandler OnIdle + { + add { _onIdle += value; } + remove { _onIdle -= value; } + } + + #endregion + + #region Private methods + + private void RegisterToWorkItemCompletion(IWorkItemResult wir) + { + IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir; + iwir.OnWorkItemStarted += OnWorkItemStartedCallback; + iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback; + } + + public void OnSTPIsStarting() + { + if (_isSuspended) + { + return; + } + + EnqueueToSTPNextNWorkItem(_concurrency); + } + + public void EnqueueToSTPNextNWorkItem(int count) + { + for (int i = 0; i < count; ++i) + { + EnqueueToSTPNextWorkItem(null, false); + } + } + + private object FireOnIdle(object state) + { + FireOnIdleImpl(_onIdle); + return null; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) + { + if(null == onIdle) + { + return; + } + + Delegate[] delegates = onIdle.GetInvocationList(); + foreach(WorkItemsGroupIdleHandler eh in delegates) + { + try + { + eh(this); + } + catch { } // Suppress exceptions + } + } + + private void OnWorkItemStartedCallback(WorkItem workItem) + { + lock(_lock) + { + ++_workItemsExecutingInStp; + } + } + + private void OnWorkItemCompletedCallback(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(null, true); + } + + internal override void Enqueue(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(workItem); + } + + private void EnqueueToSTPNextWorkItem(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(workItem, false); + } + + private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) + { + lock(_lock) + { + // Got here from OnWorkItemCompletedCallback() + if (decrementWorkItemsInStpQueue) + { + --_workItemsInStpQueue; + + if(_workItemsInStpQueue < 0) + { + _workItemsInStpQueue = 0; + } + + --_workItemsExecutingInStp; + + if(_workItemsExecutingInStp < 0) + { + _workItemsExecutingInStp = 0; + } + } + + // If the work item is not null then enqueue it + if (null != workItem) + { + workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; + + RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); + _workItemsQueue.Enqueue(workItem); + //_stp.IncrementWorkItemsCount(); + + if ((1 == _workItemsQueue.Count) && + (0 == _workItemsInStpQueue)) + { + _stp.RegisterWorkItemsGroup(this); + IsIdle = false; + _isIdleWaitHandle.Reset(); + } + } + + // If the work items queue of the group is empty than quit + if (0 == _workItemsQueue.Count) + { + if (0 == _workItemsInStpQueue) + { + _stp.UnregisterWorkItemsGroup(this); + IsIdle = true; + _isIdleWaitHandle.Set(); + if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0) + { + _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle)); + } + } + return; + } + + if (!_isSuspended) + { + if (_workItemsInStpQueue < _concurrency) + { + WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; + try + { + _stp.Enqueue(nextWorkItem); + } + catch (ObjectDisposedException e) + { + e.GetHashCode(); + // The STP has been shutdown + } + + ++_workItemsInStpQueue; + } + } + } + } + + #endregion + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs new file mode 100644 index 0000000..429de12 --- /dev/null +++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs @@ -0,0 +1,471 @@ +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ + public abstract class WorkItemsGroupBase : IWorkItemsGroup + { + #region Private Fields + + /// + /// Contains the name of this instance of SmartThreadPool. + /// Can be changed by the user. + /// + private string _name = "WorkItemsGroupBase"; + + public WorkItemsGroupBase() + { + IsIdle = true; + } + + #endregion + + #region IWorkItemsGroup Members + + #region Public Methods + + /// + /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance + /// + public string Name + { + get { return _name; } + set { _name = value; } + } + + #endregion + + #region Abstract Methods + + public abstract int Concurrency { get; set; } + public abstract int WaitingCallbacks { get; } + public abstract object[] GetStates(); + public abstract WIGStartInfo WIGStartInfo { get; } + public abstract void Start(); + public abstract void Cancel(bool abortExecution); + public abstract bool WaitForIdle(int millisecondsTimeout); + public abstract event WorkItemsGroupIdleHandler OnIdle; + + internal abstract void Enqueue(WorkItem workItem); + internal virtual void PreQueueWorkItem() { } + + #endregion + + #region Common Base Methods + + /// + /// Cancel all the work items. + /// Same as Cancel(false) + /// + public virtual void Cancel() + { + Cancel(false); + } + + /// + /// Wait for the SmartThreadPool/WorkItemsGroup to be idle + /// + public void WaitForIdle() + { + WaitForIdle(Timeout.Infinite); + } + + /// + /// Wait for the SmartThreadPool/WorkItemsGroup to be idle + /// + public bool WaitForIdle(TimeSpan timeout) + { + return WaitForIdle((int)timeout.TotalMilliseconds); + } + + /// + /// IsIdle is true when there are no work items running or queued. + /// + public bool IsIdle { get; protected set; } + + #endregion + + #region QueueWorkItem + + /// + /// Queue a work item + /// + /// A callback to execute + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback) + { + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// The priority of the work item + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// Work item info + /// A callback to execute + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) + { + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute, + WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + #endregion + + #region QueueWorkItem(Action<...>) + + public IWorkItemResult QueueWorkItem(Action action) + { + return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + delegate + { + action.Invoke (); + return null; + }, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T arg) + { + return QueueWorkItem (action, arg, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2) + { + return QueueWorkItem (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3) + { + return QueueWorkItem (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority); + ; + } + + public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2, arg3); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem( + Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + return QueueWorkItem (action, arg1, arg2, arg3, arg4, + SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem ( + Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2, arg3, arg4); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + #endregion + + #region QueueWorkItem(Func<...>) + + public IWorkItemResult QueueWorkItem(Func func) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(); + }); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem(Func func, T arg) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem( + Func func, T1 arg1, T2 arg2, T3 arg3) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2, arg3); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem( + Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2, arg3, arg4); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + #endregion + + #endregion + } +} \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs index af5af07..156a131 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs @@ -1,600 +1,645 @@ -// Ami Bar -// amibar@gmail.com - -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ - #region WorkItemsQueue class - - /// - /// WorkItemsQueue class. - /// - public class WorkItemsQueue : IDisposable - { - #region Member variables - - /// - /// Waiters queue (implemented as stack). - /// - private WaiterEntry _headWaiterEntry = new WaiterEntry(); - - /// - /// Waiters count - /// - private int _waitersCount = 0; - - /// - /// Work items queue - /// - private PriorityQueue _workItems = new PriorityQueue(); - - /// - /// Indicate that work items are allowed to be queued - /// - private bool _isWorkItemsQueueActive = true; - - /// - /// Each thread in the thread pool keeps its own waiter entry. - /// - [ThreadStatic] - private static WaiterEntry _waiterEntry; - - /// - /// A flag that indicates if the WorkItemsQueue has been disposed. - /// - private bool _isDisposed = false; - - #endregion - - #region Public properties - - /// - /// Returns the current number of work items in the queue - /// - public int Count - { - get - { - lock(this) - { - ValidateNotDisposed(); - return _workItems.Count; - } - } - } - - /// - /// Returns the current number of waiters - /// - public int WaitersCount - { - get - { - lock(this) - { - ValidateNotDisposed(); - return _waitersCount; - } - } - } - - - #endregion - - #region Public methods - - /// - /// Enqueue a work item to the queue. - /// - public bool EnqueueWorkItem(WorkItem workItem) - { - // A work item cannot be null, since null is used in the - // WaitForWorkItem() method to indicate timeout or cancel - if (null == workItem) - { - throw new ArgumentNullException("workItem" , "workItem cannot be null"); - } - - bool enqueue = true; - - // First check if there is a waiter waiting for work item. During - // the check, timed out waiters are ignored. If there is no - // waiter then the work item is queued. - lock(this) - { - ValidateNotDisposed(); - - if (!_isWorkItemsQueueActive) - { - return false; - } - - while(_waitersCount > 0) - { - // Dequeue a waiter. - WaiterEntry waiterEntry = PopWaiter(); - - // Signal the waiter. On success break the loop - if (waiterEntry.Signal(workItem)) - { - enqueue = false; - break; - } - } - - if (enqueue) - { - // Enqueue the work item - _workItems.Enqueue(workItem); - } - } - return true; - } - - - /// - /// Waits for a work item or exits on timeout or cancel - /// - /// Timeout in milliseconds - /// Cancel wait handle - /// Returns true if the resource was granted - public WorkItem DequeueWorkItem( - int millisecondsTimeout, - WaitHandle cancelEvent) - { - /// This method cause the caller to wait for a work item. - /// If there is at least one waiting work item then the - /// method returns immidiately with true. - /// - /// If there are no waiting work items then the caller - /// is queued between other waiters for a work item to arrive. - /// - /// If a work item didn't come within millisecondsTimeout or - /// the user canceled the wait by signaling the cancelEvent - /// then the method returns false to indicate that the caller - /// didn't get a work item. - - WaiterEntry waiterEntry = null; - WorkItem workItem = null; - - lock(this) - { - ValidateNotDisposed(); - - // If there are waiting work items then take one and return. - if (_workItems.Count > 0) - { - workItem = _workItems.Dequeue() as WorkItem; - return workItem; - } - // No waiting work items ... - else - { - // Get the wait entry for the waiters queue - waiterEntry = GetThreadWaiterEntry(); - - // Put the waiter with the other waiters - PushWaiter(waiterEntry); - } - } - - // Prepare array of wait handle for the WaitHandle.WaitAny() - WaitHandle [] waitHandles = new WaitHandle [] { - waiterEntry.WaitHandle, - cancelEvent }; - - // Wait for an available resource, cancel event, or timeout. - - // During the wait we are supposes to exit the synchronization - // domain. (Placing true as the third argument of the WaitAny()) - // It just doesn't work, I don't know why, so I have lock(this) - // statments insted of one. - - int index = WaitHandle.WaitAny( - waitHandles, - millisecondsTimeout, - true); - - lock(this) - { - // success is true if it got a work item. - bool success = (0 == index); - - // The timeout variable is used only for readability. - // (We treat cancel as timeout) - bool timeout = !success; - - // On timeout update the waiterEntry that it is timed out - if (timeout) - { - // The Timeout() fails if the waiter has already been signaled - timeout = waiterEntry.Timeout(); - - // On timeout remove the waiter from the queue. - // Note that the complexity is O(1). - if(timeout) - { - RemoveWaiter(waiterEntry, false); - } - - // Again readability - success = !timeout; - } - - // On success return the work item - if (success) - { - workItem = waiterEntry.WorkItem; - - if (null == workItem) - { - workItem = _workItems.Dequeue() as WorkItem; - } - } - } - // On failure return null. - return workItem; - } - - /// - /// Cleanup the work items queue, hence no more work - /// items are allowed to be queue - /// - protected virtual void Cleanup() - { - lock(this) - { - // Deactivate only once - if (!_isWorkItemsQueueActive) - { - return; - } - - // Don't queue more work items - _isWorkItemsQueueActive = false; - - foreach(WorkItem workItem in _workItems) - { - workItem.DisposeOfState(); - } - - // Clear the work items that are already queued - _workItems.Clear(); - - // Note: - // I don't iterate over the queue and dispose of work items's states, - // since if a work item has a state object that is still in use in the - // application then I must not dispose it. - - // Tell the waiters that they were timed out. - // It won't signal them to exit, but to ignore their - // next work item. - while(_waitersCount > 0) - { - WaiterEntry waiterEntry = PopWaiter(); - waiterEntry.Timeout(); - } - } - } - - #endregion - - #region Private methods - - /// - /// Returns the WaiterEntry of the current thread - /// - /// - /// In order to avoid creation and destuction of WaiterEntry - /// objects each thread has its own WaiterEntry object. - private WaiterEntry GetThreadWaiterEntry() - { - if (null == _waiterEntry) - { - _waiterEntry = new WaiterEntry(); - } - _waiterEntry.Reset(); - return _waiterEntry; - } - - #region Waiters stack methods - - /// - /// Push a new waiter into the waiter's stack - /// - /// A waiter to put in the stack - public void PushWaiter(WaiterEntry newWaiterEntry) - { - // Remove the waiter if it is already in the stack and - // update waiter's count as needed - RemoveWaiter(newWaiterEntry, false); - - // If the stack is empty then newWaiterEntry is the new head of the stack - if (null == _headWaiterEntry._nextWaiterEntry) - { - _headWaiterEntry._nextWaiterEntry = newWaiterEntry; - newWaiterEntry._prevWaiterEntry = _headWaiterEntry; - - } - // If the stack is not empty then put newWaiterEntry as the new head - // of the stack. - else - { - // Save the old first waiter entry - WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; - - // Update the links - _headWaiterEntry._nextWaiterEntry = newWaiterEntry; - newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; - newWaiterEntry._prevWaiterEntry = _headWaiterEntry; - oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; - } - - // Increment the number of waiters - ++_waitersCount; - } - - /// - /// Pop a waiter from the waiter's stack - /// - /// Returns the first waiter in the stack - private WaiterEntry PopWaiter() - { - // Store the current stack head - WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; - - // Store the new stack head - WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; - - // Update the old stack head list links and decrement the number - // waiters. - RemoveWaiter(oldFirstWaiterEntry, true); - - // Update the new stack head - _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; - if (null != newHeadWaiterEntry) - { - newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; - } - - // Return the old stack head - return oldFirstWaiterEntry; - } - - /// - /// Remove a waiter from the stack - /// - /// A waiter entry to remove - /// If true the waiter count is always decremented - private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) - { - // Store the prev entry in the list - WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; - - // Store the next entry in the list - WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; - - // A flag to indicate if we need to decrement the waiters count. - // If we got here from PopWaiter then we must decrement. - // If we got here from PushWaiter then we decrement only if - // the waiter was already in the stack. - bool decrementCounter = popDecrement; - - // Null the waiter's entry links - waiterEntry._prevWaiterEntry = null; - waiterEntry._nextWaiterEntry = null; - - // If the waiter entry had a prev link then update it. - // It also means that the waiter is already in the list and we - // need to decrement the waiters count. - if (null != prevWaiterEntry) - { - prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; - decrementCounter = true; - } - - // If the waiter entry had a next link then update it. - // It also means that the waiter is already in the list and we - // need to decrement the waiters count. - if (null != nextWaiterEntry) - { - nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; - decrementCounter = true; - } - - // Decrement the waiters count if needed - if (decrementCounter) - { - --_waitersCount; - } - } - - #endregion - - #endregion - - #region WaiterEntry class - - // A waiter entry in the _waiters queue. - public class WaiterEntry : IDisposable - { - #region Member variables - - /// - /// Event to signal the waiter that it got the work item. - /// - private AutoResetEvent _waitHandle = new AutoResetEvent(false); - - /// - /// Flag to know if this waiter already quited from the queue - /// because of a timeout. - /// - private bool _isTimedout = false; - - /// - /// Flag to know if the waiter was signaled and got a work item. - /// - private bool _isSignaled = false; - - /// - /// A work item that passed directly to the waiter withou going - /// through the queue - /// - private WorkItem _workItem = null; - - private bool _isDisposed = false; - - // Linked list members - internal WaiterEntry _nextWaiterEntry = null; - internal WaiterEntry _prevWaiterEntry = null; - - #endregion - - #region Construction - - public WaiterEntry() - { - Reset(); - } - - #endregion - - #region Public methods - - public WaitHandle WaitHandle - { - get { return _waitHandle; } - } - - public WorkItem WorkItem - { - get - { - lock(this) - { - return _workItem; - } - } - } - - /// - /// Signal the waiter that it got a work item. - /// - /// Return true on success - /// The method fails if Timeout() preceded its call - public bool Signal(WorkItem workItem) - { - lock(this) - { - if (!_isTimedout) - { - _workItem = workItem; - _isSignaled = true; - _waitHandle.Set(); - return true; - } - } - return false; - } - - /// - /// Mark the wait entry that it has been timed out - /// - /// Return true on success - /// The method fails if Signal() preceded its call - public bool Timeout() - { - lock(this) - { - // Time out can happen only if the waiter wasn't marked as - // signaled - if (!_isSignaled) - { - // We don't remove the waiter from the queue, the DequeueWorkItem - // method skips _waiters that were timed out. - _isTimedout = true; - return true; - } - } - return false; - } - - /// - /// Reset the wait entry so it can be used again - /// - public void Reset() - { - _workItem = null; - _isTimedout = false; - _isSignaled = false; - _waitHandle.Reset(); - } - - /// - /// Free resources - /// - public void Close() - { - if (null != _waitHandle) - { - _waitHandle.Close(); - _waitHandle = null; - } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!_isDisposed) - { - Close(); - _isDisposed = true; - } - } - - ~WaiterEntry() - { - Dispose(); - } - - #endregion - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!_isDisposed) - { - Cleanup(); - _isDisposed = true; - GC.SuppressFinalize(this); - } - } - - ~WorkItemsQueue() - { - Cleanup(); - } - - private void ValidateNotDisposed() - { - if(_isDisposed) - { - throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); - } - } - - #endregion - } - - #endregion -} - +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Amib.Threading.Internal +{ + #region WorkItemsQueue class + + /// + /// WorkItemsQueue class. + /// + public class WorkItemsQueue : IDisposable + { + #region Member variables + + /// + /// Waiters queue (implemented as stack). + /// + private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); + + /// + /// Waiters count + /// + private int _waitersCount = 0; + + /// + /// Work items queue + /// + private readonly PriorityQueue _workItems = new PriorityQueue(); + + /// + /// Indicate that work items are allowed to be queued + /// + private bool _isWorkItemsQueueActive = true; + + +#if (WINDOWS_PHONE) + private static readonly Dictionary _waiterEntries = new Dictionary(); +#elif (_WINDOWS_CE) + private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); +#else + + [ThreadStatic] + private static WaiterEntry _waiterEntry; +#endif + + + /// + /// Each thread in the thread pool keeps its own waiter entry. + /// + private static WaiterEntry CurrentWaiterEntry + { +#if (WINDOWS_PHONE) + get + { + lock (_waiterEntries) + { + WaiterEntry waiterEntry; + if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry)) + { + return waiterEntry; + } + } + return null; + } + set + { + lock (_waiterEntries) + { + _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value; + } + } +#elif (_WINDOWS_CE) + get + { + return Thread.GetData(_waiterEntrySlot) as WaiterEntry; + } + set + { + Thread.SetData(_waiterEntrySlot, value); + } +#else + get + { + return _waiterEntry; + } + set + { + _waiterEntry = value; + } +#endif + } + + /// + /// A flag that indicates if the WorkItemsQueue has been disposed. + /// + private bool _isDisposed = false; + + #endregion + + #region Public properties + + /// + /// Returns the current number of work items in the queue + /// + public int Count + { + get + { + return _workItems.Count; + } + } + + /// + /// Returns the current number of waiters + /// + public int WaitersCount + { + get + { + return _waitersCount; + } + } + + + #endregion + + #region Public methods + + /// + /// Enqueue a work item to the queue. + /// + public bool EnqueueWorkItem(WorkItem workItem) + { + // A work item cannot be null, since null is used in the + // WaitForWorkItem() method to indicate timeout or cancel + if (null == workItem) + { + throw new ArgumentNullException("workItem" , "workItem cannot be null"); + } + + bool enqueue = true; + + // First check if there is a waiter waiting for work item. During + // the check, timed out waiters are ignored. If there is no + // waiter then the work item is queued. + lock(this) + { + ValidateNotDisposed(); + + if (!_isWorkItemsQueueActive) + { + return false; + } + + while(_waitersCount > 0) + { + // Dequeue a waiter. + WaiterEntry waiterEntry = PopWaiter(); + + // Signal the waiter. On success break the loop + if (waiterEntry.Signal(workItem)) + { + enqueue = false; + break; + } + } + + if (enqueue) + { + // Enqueue the work item + _workItems.Enqueue(workItem); + } + } + return true; + } + + + /// + /// Waits for a work item or exits on timeout or cancel + /// + /// Timeout in milliseconds + /// Cancel wait handle + /// Returns true if the resource was granted + public WorkItem DequeueWorkItem( + int millisecondsTimeout, + WaitHandle cancelEvent) + { + // This method cause the caller to wait for a work item. + // If there is at least one waiting work item then the + // method returns immidiately with it. + // + // If there are no waiting work items then the caller + // is queued between other waiters for a work item to arrive. + // + // If a work item didn't come within millisecondsTimeout or + // the user canceled the wait by signaling the cancelEvent + // then the method returns null to indicate that the caller + // didn't get a work item. + + WaiterEntry waiterEntry; + WorkItem workItem = null; + lock (this) + { + ValidateNotDisposed(); + + // If there are waiting work items then take one and return. + if (_workItems.Count > 0) + { + workItem = _workItems.Dequeue() as WorkItem; + return workItem; + } + + // No waiting work items ... + + // Get the waiter entry for the waiters queue + waiterEntry = GetThreadWaiterEntry(); + + // Put the waiter with the other waiters + PushWaiter(waiterEntry); + } + + // Prepare array of wait handle for the WaitHandle.WaitAny() + WaitHandle [] waitHandles = new WaitHandle[] { + waiterEntry.WaitHandle, + cancelEvent }; + + // Wait for an available resource, cancel event, or timeout. + + // During the wait we are supposes to exit the synchronization + // domain. (Placing true as the third argument of the WaitAny()) + // It just doesn't work, I don't know why, so I have two lock(this) + // statments instead of one. + + int index = STPEventWaitHandle.WaitAny( + waitHandles, + millisecondsTimeout, + true); + + lock(this) + { + // success is true if it got a work item. + bool success = (0 == index); + + // The timeout variable is used only for readability. + // (We treat cancel as timeout) + bool timeout = !success; + + // On timeout update the waiterEntry that it is timed out + if (timeout) + { + // The Timeout() fails if the waiter has already been signaled + timeout = waiterEntry.Timeout(); + + // On timeout remove the waiter from the queue. + // Note that the complexity is O(1). + if(timeout) + { + RemoveWaiter(waiterEntry, false); + } + + // Again readability + success = !timeout; + } + + // On success return the work item + if (success) + { + workItem = waiterEntry.WorkItem; + + if (null == workItem) + { + workItem = _workItems.Dequeue() as WorkItem; + } + } + } + // On failure return null. + return workItem; + } + + /// + /// Cleanup the work items queue, hence no more work + /// items are allowed to be queue + /// + private void Cleanup() + { + lock(this) + { + // Deactivate only once + if (!_isWorkItemsQueueActive) + { + return; + } + + // Don't queue more work items + _isWorkItemsQueueActive = false; + + foreach(WorkItem workItem in _workItems) + { + workItem.DisposeOfState(); + } + + // Clear the work items that are already queued + _workItems.Clear(); + + // Note: + // I don't iterate over the queue and dispose of work items's states, + // since if a work item has a state object that is still in use in the + // application then I must not dispose it. + + // Tell the waiters that they were timed out. + // It won't signal them to exit, but to ignore their + // next work item. + while(_waitersCount > 0) + { + WaiterEntry waiterEntry = PopWaiter(); + waiterEntry.Timeout(); + } + } + } + + public object[] GetStates() + { + lock (this) + { + object[] states = new object[_workItems.Count]; + int i = 0; + foreach (WorkItem workItem in _workItems) + { + states[i] = workItem.GetWorkItemResult().State; + ++i; + } + return states; + } + } + + #endregion + + #region Private methods + + /// + /// Returns the WaiterEntry of the current thread + /// + /// + /// In order to avoid creation and destuction of WaiterEntry + /// objects each thread has its own WaiterEntry object. + private static WaiterEntry GetThreadWaiterEntry() + { + if (null == CurrentWaiterEntry) + { + CurrentWaiterEntry = new WaiterEntry(); + } + CurrentWaiterEntry.Reset(); + return CurrentWaiterEntry; + } + + #region Waiters stack methods + + /// + /// Push a new waiter into the waiter's stack + /// + /// A waiter to put in the stack + public void PushWaiter(WaiterEntry newWaiterEntry) + { + // Remove the waiter if it is already in the stack and + // update waiter's count as needed + RemoveWaiter(newWaiterEntry, false); + + // If the stack is empty then newWaiterEntry is the new head of the stack + if (null == _headWaiterEntry._nextWaiterEntry) + { + _headWaiterEntry._nextWaiterEntry = newWaiterEntry; + newWaiterEntry._prevWaiterEntry = _headWaiterEntry; + + } + // If the stack is not empty then put newWaiterEntry as the new head + // of the stack. + else + { + // Save the old first waiter entry + WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; + + // Update the links + _headWaiterEntry._nextWaiterEntry = newWaiterEntry; + newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; + newWaiterEntry._prevWaiterEntry = _headWaiterEntry; + oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; + } + + // Increment the number of waiters + ++_waitersCount; + } + + /// + /// Pop a waiter from the waiter's stack + /// + /// Returns the first waiter in the stack + private WaiterEntry PopWaiter() + { + // Store the current stack head + WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; + + // Store the new stack head + WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; + + // Update the old stack head list links and decrement the number + // waiters. + RemoveWaiter(oldFirstWaiterEntry, true); + + // Update the new stack head + _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; + if (null != newHeadWaiterEntry) + { + newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; + } + + // Return the old stack head + return oldFirstWaiterEntry; + } + + /// + /// Remove a waiter from the stack + /// + /// A waiter entry to remove + /// If true the waiter count is always decremented + private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) + { + // Store the prev entry in the list + WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; + + // Store the next entry in the list + WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; + + // A flag to indicate if we need to decrement the waiters count. + // If we got here from PopWaiter then we must decrement. + // If we got here from PushWaiter then we decrement only if + // the waiter was already in the stack. + bool decrementCounter = popDecrement; + + // Null the waiter's entry links + waiterEntry._prevWaiterEntry = null; + waiterEntry._nextWaiterEntry = null; + + // If the waiter entry had a prev link then update it. + // It also means that the waiter is already in the list and we + // need to decrement the waiters count. + if (null != prevWaiterEntry) + { + prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; + decrementCounter = true; + } + + // If the waiter entry had a next link then update it. + // It also means that the waiter is already in the list and we + // need to decrement the waiters count. + if (null != nextWaiterEntry) + { + nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; + decrementCounter = true; + } + + // Decrement the waiters count if needed + if (decrementCounter) + { + --_waitersCount; + } + } + + #endregion + + #endregion + + #region WaiterEntry class + + // A waiter entry in the _waiters queue. + public sealed class WaiterEntry : IDisposable + { + #region Member variables + + /// + /// Event to signal the waiter that it got the work item. + /// + //private AutoResetEvent _waitHandle = new AutoResetEvent(false); + private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); + + /// + /// Flag to know if this waiter already quited from the queue + /// because of a timeout. + /// + private bool _isTimedout = false; + + /// + /// Flag to know if the waiter was signaled and got a work item. + /// + private bool _isSignaled = false; + + /// + /// A work item that passed directly to the waiter withou going + /// through the queue + /// + private WorkItem _workItem = null; + + private bool _isDisposed = false; + + // Linked list members + internal WaiterEntry _nextWaiterEntry = null; + internal WaiterEntry _prevWaiterEntry = null; + + #endregion + + #region Construction + + public WaiterEntry() + { + Reset(); + } + + #endregion + + #region Public methods + + public WaitHandle WaitHandle + { + get { return _waitHandle; } + } + + public WorkItem WorkItem + { + get + { + return _workItem; + } + } + + /// + /// Signal the waiter that it got a work item. + /// + /// Return true on success + /// The method fails if Timeout() preceded its call + public bool Signal(WorkItem workItem) + { + lock(this) + { + if (!_isTimedout) + { + _workItem = workItem; + _isSignaled = true; + _waitHandle.Set(); + return true; + } + } + return false; + } + + /// + /// Mark the wait entry that it has been timed out + /// + /// Return true on success + /// The method fails if Signal() preceded its call + public bool Timeout() + { + lock(this) + { + // Time out can happen only if the waiter wasn't marked as + // signaled + if (!_isSignaled) + { + // We don't remove the waiter from the queue, the DequeueWorkItem + // method skips _waiters that were timed out. + _isTimedout = true; + return true; + } + } + return false; + } + + /// + /// Reset the wait entry so it can be used again + /// + public void Reset() + { + _workItem = null; + _isTimedout = false; + _isSignaled = false; + _waitHandle.Reset(); + } + + /// + /// Free resources + /// + public void Close() + { + if (null != _waitHandle) + { + _waitHandle.Close(); + _waitHandle = null; + } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + lock (this) + { + if (!_isDisposed) + { + Close(); + } + _isDisposed = true; + } + } + + #endregion + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!_isDisposed) + { + Cleanup(); + } + _isDisposed = true; + } + + private void ValidateNotDisposed() + { + if(_isDisposed) + { + throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); + } + } + + #endregion + } + + #endregion +} + -- cgit v1.1 From 8d3250cee4d16113e955c42d3cce02b0024bea55 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 1 May 2013 19:15:05 +0100 Subject: Add information about creating a PID file for robust to the Robust.ini and Robust.HG.ini example files --- bin/Robust.HG.ini.example | 27 +++++++++++++++------------ bin/Robust.ini.example | 28 +++++++++++++++------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 581c31d..d74f205 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -21,18 +21,21 @@ ; * [[@]/][:] ; * [Startup] - - ; Plugin Registry Location - ; Set path to directory for plugin registry. Information - ; about the registered repositories and installed plugins - ; will be stored here - ; The Robust.exe process must have R/W access to the location - RegistryLocation = "." - - ; Modular configurations - ; Set path to directory for modular ini files... - ; The Robust.exe process must have R/W access to the location - ConfigDirectory = "/home/opensim/etc/Configs" + ; Place to create a PID file + ; If no path if specified then a PID file is not created. + ; PIDFile = "/tmp/my.pid" + + ; Plugin Registry Location + ; Set path to directory for plugin registry. Information + ; about the registered repositories and installed plugins + ; will be stored here + ; The Robust.exe process must have R/W access to the location + RegistryLocation = "." + + ; Modular configurations + ; Set path to directory for modular ini files... + ; The Robust.exe process must have R/W access to the location + ConfigDirectory = "/home/opensim/etc/Configs" [ServiceList] diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index b98132e..b7b2524 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -13,19 +13,21 @@ ; * [[@]/][:] ; * [Startup] - - ; Plugin Registry Location - ; Set path to directory for plugin registry. Information - ; about the registered repositories and installed plugins - ; will be stored here - ; The Robust.exe process must have R/W access to the location - RegistryLocation = "." - - - ; Modular configurations - ; Set path to directory for modular ini files... - ; The Robust.exe process must have R/W access to the location - ConfigDirectory = "/home/opensim/etc/Configs" + ; Place to create a PID file + ; If no path if specified then a PID file is not created. + ; PIDFile = "/tmp/my.pid" + + ; Plugin Registry Location + ; Set path to directory for plugin registry. Information + ; about the registered repositories and installed plugins + ; will be stored here + ; The Robust.exe process must have R/W access to the location + RegistryLocation = "." + + ; Modular configurations + ; Set path to directory for modular ini files... + ; The Robust.exe process must have R/W access to the location + ConfigDirectory = "/home/opensim/etc/Configs" [ServiceList] AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector" -- cgit v1.1 From 81a90e30c637f84e6ef5d1cf7c188c1f6db12eb3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 1 May 2013 19:29:46 +0100 Subject: Add in-code exaplanation for the change in cancellation signalling in STP 2.2.3. Remove left in Console.WriteLine accidentally inserted in recent 206fb306 --- OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 2 -- ThirdParty/SmartThreadPool/WorkItem.cs | 10 ++++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index f9d3afc..887a317 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -628,8 +628,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } } - Console.WriteLine("Here9"); - lock (EventQueue) { workItem = m_CurrentWorkItem; diff --git a/ThirdParty/SmartThreadPool/WorkItem.cs b/ThirdParty/SmartThreadPool/WorkItem.cs index f229d1f..185f10c 100644 --- a/ThirdParty/SmartThreadPool/WorkItem.cs +++ b/ThirdParty/SmartThreadPool/WorkItem.cs @@ -753,6 +753,16 @@ namespace Amib.Threading.Internal } else { + // ************************** + // Stock SmartThreadPool 2.2.3 sets these to true and relies on the thread to check the + // WorkItem cancellation status. However, OpenSimulator uses a different mechanism to notify + // scripts of co-operative termination and the abort code also relies on this method + // returning false in order to implement a small wait. + // + // Therefore, as was the case previously with STP, we will not signal successful cancellation + // here. It's possible that OpenSimulator code could be changed in the future to remove + // the need for this change. + // ************************** success = false; signalComplete = false; } -- cgit v1.1 From b26276c8c48a8cf4edb468b2fd428815034a6320 Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 1 May 2013 21:35:50 +0100 Subject: Fix the long standing bug of items being delivered to lost and found or trash when takig copy. This bug was recently aggravated through the perms changes required for the export permission. --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index e0009bb..eb37626 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -646,11 +646,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else { - if (remoteClient == null || so.OwnerID != remoteClient.AgentId) + if (remoteClient == null || so.RootPart.OwnerID != remoteClient.AgentId) { // Taking copy of another person's item. Take to // Objects folder. folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); + so.FromFolderID = UUID.Zero; } else { @@ -666,7 +667,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) { - if (so.FromFolderID != UUID.Zero && userID == remoteClient.AgentId) + if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId) { InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); folder = m_Scene.InventoryService.GetFolder(f); -- cgit v1.1 From 854dcd1abddc3eef33da953592deb61133e5e7ed Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 1 May 2013 23:00:46 +0100 Subject: Fix SmartThreadPool line endings in recent update from dos to unix --- ThirdParty/SmartThreadPool/CallerThreadContext.cs | 276 +- .../SmartThreadPool/CanceledWorkItemsGroup.cs | 26 +- ThirdParty/SmartThreadPool/EventWaitHandle.cs | 206 +- .../SmartThreadPool/EventWaitHandleFactory.cs | 164 +- ThirdParty/SmartThreadPool/Exceptions.cs | 222 +- ThirdParty/SmartThreadPool/Interfaces.cs | 1256 +++---- ThirdParty/SmartThreadPool/InternalInterfaces.cs | 54 +- ThirdParty/SmartThreadPool/PriorityQueue.cs | 478 +-- .../SmartThreadPool/Properties/AssemblyInfo.cs | 46 +- ThirdParty/SmartThreadPool/SLExt.cs | 32 +- ThirdParty/SmartThreadPool/STPEventWaitHandle.cs | 122 +- .../SmartThreadPool/STPPerformanceCounter.cs | 896 ++--- ThirdParty/SmartThreadPool/STPStartInfo.cs | 424 +-- .../SmartThreadPool/SmartThreadPool.ThreadEntry.cs | 118 +- ThirdParty/SmartThreadPool/SmartThreadPool.cs | 3464 ++++++++++---------- .../SmartThreadPool/SynchronizedDictionary.cs | 178 +- ThirdParty/SmartThreadPool/WIGStartInfo.cs | 342 +- .../SmartThreadPool/WorkItem.WorkItemResult.cs | 380 +-- ThirdParty/SmartThreadPool/WorkItemFactory.cs | 686 ++-- ThirdParty/SmartThreadPool/WorkItemInfo.cs | 138 +- .../SmartThreadPool/WorkItemResultTWrapper.cs | 256 +- ThirdParty/SmartThreadPool/WorkItemsGroup.cs | 722 ++-- ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs | 940 +++--- ThirdParty/SmartThreadPool/WorkItemsQueue.cs | 1290 ++++---- 24 files changed, 6358 insertions(+), 6358 deletions(-) diff --git a/ThirdParty/SmartThreadPool/CallerThreadContext.cs b/ThirdParty/SmartThreadPool/CallerThreadContext.cs index 2177241..e63add5 100644 --- a/ThirdParty/SmartThreadPool/CallerThreadContext.cs +++ b/ThirdParty/SmartThreadPool/CallerThreadContext.cs @@ -1,138 +1,138 @@ - -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - -using System; -using System.Diagnostics; -using System.Threading; -using System.Reflection; -using System.Web; -using System.Runtime.Remoting.Messaging; - - -namespace Amib.Threading.Internal -{ -#region CallerThreadContext class - - /// - /// This class stores the caller call context in order to restore - /// it when the work item is executed in the thread pool environment. - /// - internal class CallerThreadContext - { -#region Prepare reflection information - - // Cached type information. - private static readonly MethodInfo getLogicalCallContextMethodInfo = - typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); - - private static readonly MethodInfo setLogicalCallContextMethodInfo = - typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); - - private static string HttpContextSlotName = GetHttpContextSlotName(); - - private static string GetHttpContextSlotName() - { - FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); - - if (fi != null) - { - return (string) fi.GetValue(null); - } - - return "HttpContext"; - } - - #endregion - -#region Private fields - - private HttpContext _httpContext; - private LogicalCallContext _callContext; - - #endregion - - /// - /// Constructor - /// - private CallerThreadContext() - { - } - - public bool CapturedCallContext - { - get - { - return (null != _callContext); - } - } - - public bool CapturedHttpContext - { - get - { - return (null != _httpContext); - } - } - - /// - /// Captures the current thread context - /// - /// - public static CallerThreadContext Capture( - bool captureCallContext, - bool captureHttpContext) - { - Debug.Assert(captureCallContext || captureHttpContext); - - CallerThreadContext callerThreadContext = new CallerThreadContext(); - - // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() - // Capture Call Context - if(captureCallContext && (getLogicalCallContextMethodInfo != null)) - { - callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); - if (callerThreadContext._callContext != null) - { - callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); - } - } - - // Capture httpContext - if (captureHttpContext && (null != HttpContext.Current)) - { - callerThreadContext._httpContext = HttpContext.Current; - } - - return callerThreadContext; - } - - /// - /// Applies the thread context stored earlier - /// - /// - public static void Apply(CallerThreadContext callerThreadContext) - { - if (null == callerThreadContext) - { - throw new ArgumentNullException("callerThreadContext"); - } - - // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() - // Restore call context - if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) - { - setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); - } - - // Restore HttpContext - if (callerThreadContext._httpContext != null) - { - HttpContext.Current = callerThreadContext._httpContext; - //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); - } - } - } - - #endregion -} -#endif + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + +using System; +using System.Diagnostics; +using System.Threading; +using System.Reflection; +using System.Web; +using System.Runtime.Remoting.Messaging; + + +namespace Amib.Threading.Internal +{ +#region CallerThreadContext class + + /// + /// This class stores the caller call context in order to restore + /// it when the work item is executed in the thread pool environment. + /// + internal class CallerThreadContext + { +#region Prepare reflection information + + // Cached type information. + private static readonly MethodInfo getLogicalCallContextMethodInfo = + typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); + + private static readonly MethodInfo setLogicalCallContextMethodInfo = + typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic); + + private static string HttpContextSlotName = GetHttpContextSlotName(); + + private static string GetHttpContextSlotName() + { + FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic); + + if (fi != null) + { + return (string) fi.GetValue(null); + } + + return "HttpContext"; + } + + #endregion + +#region Private fields + + private HttpContext _httpContext; + private LogicalCallContext _callContext; + + #endregion + + /// + /// Constructor + /// + private CallerThreadContext() + { + } + + public bool CapturedCallContext + { + get + { + return (null != _callContext); + } + } + + public bool CapturedHttpContext + { + get + { + return (null != _httpContext); + } + } + + /// + /// Captures the current thread context + /// + /// + public static CallerThreadContext Capture( + bool captureCallContext, + bool captureHttpContext) + { + Debug.Assert(captureCallContext || captureHttpContext); + + CallerThreadContext callerThreadContext = new CallerThreadContext(); + + // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture() + // Capture Call Context + if(captureCallContext && (getLogicalCallContextMethodInfo != null)) + { + callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null); + if (callerThreadContext._callContext != null) + { + callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone(); + } + } + + // Capture httpContext + if (captureHttpContext && (null != HttpContext.Current)) + { + callerThreadContext._httpContext = HttpContext.Current; + } + + return callerThreadContext; + } + + /// + /// Applies the thread context stored earlier + /// + /// + public static void Apply(CallerThreadContext callerThreadContext) + { + if (null == callerThreadContext) + { + throw new ArgumentNullException("callerThreadContext"); + } + + // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run() + // Restore call context + if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null)) + { + setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext }); + } + + // Restore HttpContext + if (callerThreadContext._httpContext != null) + { + HttpContext.Current = callerThreadContext._httpContext; + //CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext); + } + } + } + + #endregion +} +#endif diff --git a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs index 4a2a3e7..5752957 100644 --- a/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs +++ b/ThirdParty/SmartThreadPool/CanceledWorkItemsGroup.cs @@ -1,14 +1,14 @@ -namespace Amib.Threading.Internal -{ - internal class CanceledWorkItemsGroup - { - public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); - - public CanceledWorkItemsGroup() - { - IsCanceled = false; - } - - public bool IsCanceled { get; set; } - } +namespace Amib.Threading.Internal +{ + internal class CanceledWorkItemsGroup + { + public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup(); + + public CanceledWorkItemsGroup() + { + IsCanceled = false; + } + + public bool IsCanceled { get; set; } + } } \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/EventWaitHandle.cs b/ThirdParty/SmartThreadPool/EventWaitHandle.cs index 70a1a29..25be07a 100644 --- a/ThirdParty/SmartThreadPool/EventWaitHandle.cs +++ b/ThirdParty/SmartThreadPool/EventWaitHandle.cs @@ -1,104 +1,104 @@ -#if (_WINDOWS_CE) - -using System; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Amib.Threading.Internal -{ - /// - /// EventWaitHandle class - /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation. - /// So I wrote this class to implement these two methods with some of their overloads. - /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny. - /// Note that this class doesn't even inherit from WaitHandle! - /// - public class STPEventWaitHandle - { - #region Public Constants - - public const int WaitTimeout = Timeout.Infinite; - - #endregion - - #region Private External Constants - - private const Int32 WAIT_FAILED = -1; - private const Int32 WAIT_TIMEOUT = 0x102; - private const UInt32 INFINITE = 0xFFFFFFFF; - - #endregion - - #region WaitAll and WaitAny - - internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) - { - return waitHandle.WaitOne(millisecondsTimeout, exitContext); - } - - private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles) - { - IntPtr[] nativeHandles = new IntPtr[waitHandles.Length]; - for (int i = 0; i < waitHandles.Length; i++) - { - nativeHandles[i] = waitHandles[i].Handle; - } - return nativeHandles; - } - - public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; - - IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); - - int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout); - - if (result == WAIT_TIMEOUT || result == WAIT_FAILED) - { - return false; - } - - return true; - } - - - public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; - - IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); - - int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout); - - if (result >= 0 && result < waitHandles.Length) - { - return result; - } - - return -1; - } - - public static int WaitAny(WaitHandle[] waitHandles) - { - return WaitAny(waitHandles, Timeout.Infinite, false); - } - - public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) - { - int millisecondsTimeout = (int)timeout.TotalMilliseconds; - - return WaitAny(waitHandles, millisecondsTimeout, false); - } - - #endregion - - #region External methods - - [DllImport("coredll.dll", SetLastError = true)] - public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds); - - #endregion - } -} +#if (_WINDOWS_CE) + +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Amib.Threading.Internal +{ + /// + /// EventWaitHandle class + /// In WindowsCE this class doesn't exist and I needed the WaitAll and WaitAny implementation. + /// So I wrote this class to implement these two methods with some of their overloads. + /// It uses the WaitForMultipleObjects API to do the WaitAll and WaitAny. + /// Note that this class doesn't even inherit from WaitHandle! + /// + public class STPEventWaitHandle + { + #region Public Constants + + public const int WaitTimeout = Timeout.Infinite; + + #endregion + + #region Private External Constants + + private const Int32 WAIT_FAILED = -1; + private const Int32 WAIT_TIMEOUT = 0x102; + private const UInt32 INFINITE = 0xFFFFFFFF; + + #endregion + + #region WaitAll and WaitAny + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout, exitContext); + } + + private static IntPtr[] PrepareNativeHandles(WaitHandle[] waitHandles) + { + IntPtr[] nativeHandles = new IntPtr[waitHandles.Length]; + for (int i = 0; i < waitHandles.Length; i++) + { + nativeHandles[i] = waitHandles[i].Handle; + } + return nativeHandles; + } + + public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; + + IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); + + int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, true, timeout); + + if (result == WAIT_TIMEOUT || result == WAIT_FAILED) + { + return false; + } + + return true; + } + + + public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + uint timeout = millisecondsTimeout < 0 ? INFINITE : (uint)millisecondsTimeout; + + IntPtr[] nativeHandles = PrepareNativeHandles(waitHandles); + + int result = WaitForMultipleObjects((uint)waitHandles.Length, nativeHandles, false, timeout); + + if (result >= 0 && result < waitHandles.Length) + { + return result; + } + + return -1; + } + + public static int WaitAny(WaitHandle[] waitHandles) + { + return WaitAny(waitHandles, Timeout.Infinite, false); + } + + public static int WaitAny(WaitHandle[] waitHandles, TimeSpan timeout, bool exitContext) + { + int millisecondsTimeout = (int)timeout.TotalMilliseconds; + + return WaitAny(waitHandles, millisecondsTimeout, false); + } + + #endregion + + #region External methods + + [DllImport("coredll.dll", SetLastError = true)] + public static extern int WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool fWaitAll, uint dwMilliseconds); + + #endregion + } +} #endif \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs index 2f8c55b..3c9c849 100644 --- a/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs +++ b/ThirdParty/SmartThreadPool/EventWaitHandleFactory.cs @@ -1,82 +1,82 @@ -using System.Threading; - -#if (_WINDOWS_CE) -using System; -using System.Runtime.InteropServices; -#endif - -namespace Amib.Threading.Internal -{ - /// - /// EventWaitHandleFactory class. - /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. - /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property - /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. - /// Consequently this class creates the needed XxxResetEvent and replaces the handle if - /// it's a WindowsCE OS. - /// - public static class EventWaitHandleFactory - { - /// - /// Create a new AutoResetEvent object - /// - /// Return a new AutoResetEvent object - public static AutoResetEvent CreateAutoResetEvent() - { - AutoResetEvent waitHandle = new AutoResetEvent(false); - -#if (_WINDOWS_CE) - ReplaceEventHandle(waitHandle, false, false); -#endif - - return waitHandle; - } - - /// - /// Create a new ManualResetEvent object - /// - /// Return a new ManualResetEvent object - public static ManualResetEvent CreateManualResetEvent(bool initialState) - { - ManualResetEvent waitHandle = new ManualResetEvent(initialState); - -#if (_WINDOWS_CE) - ReplaceEventHandle(waitHandle, true, initialState); -#endif - - return waitHandle; - } - -#if (_WINDOWS_CE) - - /// - /// Replace the event handle - /// - /// The WaitHandle object which its handle needs to be replaced. - /// Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false) - /// The initial state of the event - private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState) - { - // Store the old handle - IntPtr oldHandle = waitHandle.Handle; - - // Create a new event - IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null); - - // Replace the old event with the new event - waitHandle.Handle = newHandle; - - // Close the old event - CloseHandle (oldHandle); - } - - [DllImport("coredll.dll", SetLastError = true)] - public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); - - //Handle - [DllImport("coredll.dll", SetLastError = true)] - public static extern bool CloseHandle(IntPtr hObject); -#endif - - } -} +using System.Threading; + +#if (_WINDOWS_CE) +using System; +using System.Runtime.InteropServices; +#endif + +namespace Amib.Threading.Internal +{ + /// + /// EventWaitHandleFactory class. + /// This is a static class that creates AutoResetEvent and ManualResetEvent objects. + /// In WindowCE the WaitForMultipleObjects API fails to use the Handle property + /// of XxxResetEvent. It can use only handles that were created by the CreateEvent API. + /// Consequently this class creates the needed XxxResetEvent and replaces the handle if + /// it's a WindowsCE OS. + /// + public static class EventWaitHandleFactory + { + /// + /// Create a new AutoResetEvent object + /// + /// Return a new AutoResetEvent object + public static AutoResetEvent CreateAutoResetEvent() + { + AutoResetEvent waitHandle = new AutoResetEvent(false); + +#if (_WINDOWS_CE) + ReplaceEventHandle(waitHandle, false, false); +#endif + + return waitHandle; + } + + /// + /// Create a new ManualResetEvent object + /// + /// Return a new ManualResetEvent object + public static ManualResetEvent CreateManualResetEvent(bool initialState) + { + ManualResetEvent waitHandle = new ManualResetEvent(initialState); + +#if (_WINDOWS_CE) + ReplaceEventHandle(waitHandle, true, initialState); +#endif + + return waitHandle; + } + +#if (_WINDOWS_CE) + + /// + /// Replace the event handle + /// + /// The WaitHandle object which its handle needs to be replaced. + /// Indicates if the event is a ManualResetEvent (true) or an AutoResetEvent (false) + /// The initial state of the event + private static void ReplaceEventHandle(WaitHandle waitHandle, bool manualReset, bool initialState) + { + // Store the old handle + IntPtr oldHandle = waitHandle.Handle; + + // Create a new event + IntPtr newHandle = CreateEvent(IntPtr.Zero, manualReset, initialState, null); + + // Replace the old event with the new event + waitHandle.Handle = newHandle; + + // Close the old event + CloseHandle (oldHandle); + } + + [DllImport("coredll.dll", SetLastError = true)] + public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); + + //Handle + [DllImport("coredll.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); +#endif + + } +} diff --git a/ThirdParty/SmartThreadPool/Exceptions.cs b/ThirdParty/SmartThreadPool/Exceptions.cs index 8e66ce9..6c6a88b 100644 --- a/ThirdParty/SmartThreadPool/Exceptions.cs +++ b/ThirdParty/SmartThreadPool/Exceptions.cs @@ -1,111 +1,111 @@ -using System; -#if !(_WINDOWS_CE) -using System.Runtime.Serialization; -#endif - -namespace Amib.Threading -{ - #region Exceptions - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been canceled - /// - public sealed partial class WorkItemCancelException : Exception - { - public WorkItemCancelException() - { - } - - public WorkItemCancelException(string message) - : base(message) - { - } - - public WorkItemCancelException(string message, Exception e) - : base(message, e) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - public sealed partial class WorkItemTimeoutException : Exception - { - public WorkItemTimeoutException() - { - } - - public WorkItemTimeoutException(string message) - : base(message) - { - } - - public WorkItemTimeoutException(string message, Exception e) - : base(message, e) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - public sealed partial class WorkItemResultException : Exception - { - public WorkItemResultException() - { - } - - public WorkItemResultException(string message) - : base(message) - { - } - - public WorkItemResultException(string message, Exception e) - : base(message, e) - { - } - } - - -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - /// - /// Represents an exception in case IWorkItemResult.GetResult has been canceled - /// - [Serializable] - public sealed partial class WorkItemCancelException - { - public WorkItemCancelException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - [Serializable] - public sealed partial class WorkItemTimeoutException - { - public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } - } - - /// - /// Represents an exception in case IWorkItemResult.GetResult has been timed out - /// - [Serializable] - public sealed partial class WorkItemResultException - { - public WorkItemResultException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } - } - -#endif - - #endregion -} +using System; +#if !(_WINDOWS_CE) +using System.Runtime.Serialization; +#endif + +namespace Amib.Threading +{ + #region Exceptions + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been canceled + /// + public sealed partial class WorkItemCancelException : Exception + { + public WorkItemCancelException() + { + } + + public WorkItemCancelException(string message) + : base(message) + { + } + + public WorkItemCancelException(string message, Exception e) + : base(message, e) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + public sealed partial class WorkItemTimeoutException : Exception + { + public WorkItemTimeoutException() + { + } + + public WorkItemTimeoutException(string message) + : base(message) + { + } + + public WorkItemTimeoutException(string message, Exception e) + : base(message, e) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + public sealed partial class WorkItemResultException : Exception + { + public WorkItemResultException() + { + } + + public WorkItemResultException(string message) + : base(message) + { + } + + public WorkItemResultException(string message, Exception e) + : base(message, e) + { + } + } + + +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + /// + /// Represents an exception in case IWorkItemResult.GetResult has been canceled + /// + [Serializable] + public sealed partial class WorkItemCancelException + { + public WorkItemCancelException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + [Serializable] + public sealed partial class WorkItemTimeoutException + { + public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + + /// + /// Represents an exception in case IWorkItemResult.GetResult has been timed out + /// + [Serializable] + public sealed partial class WorkItemResultException + { + public WorkItemResultException(SerializationInfo si, StreamingContext sc) + : base(si, sc) + { + } + } + +#endif + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/Interfaces.cs b/ThirdParty/SmartThreadPool/Interfaces.cs index 29c8a3e..513422f 100644 --- a/ThirdParty/SmartThreadPool/Interfaces.cs +++ b/ThirdParty/SmartThreadPool/Interfaces.cs @@ -1,628 +1,628 @@ -using System; -using System.Threading; - -namespace Amib.Threading -{ - #region Delegates - - /// - /// A delegate that represents the method to run as the work item - /// - /// A state object for the method to run - public delegate object WorkItemCallback(object state); - - /// - /// A delegate to call after the WorkItemCallback completed - /// - /// The work item result object - public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); - - /// - /// A delegate to call after the WorkItemCallback completed - /// - /// The work item result object - public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); - - /// - /// A delegate to call when a WorkItemsGroup becomes idle - /// - /// A reference to the WorkItemsGroup that became idle - public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); - - /// - /// A delegate to call after a thread is created, but before - /// it's first use. - /// - public delegate void ThreadInitializationHandler(); - - /// - /// A delegate to call when a thread is about to exit, after - /// it is no longer belong to the pool. - /// - public delegate void ThreadTerminationHandler(); - - #endregion - - #region WorkItem Priority - - /// - /// Defines the availeable priorities of a work item. - /// The higher the priority a work item has, the sooner - /// it will be executed. - /// - public enum WorkItemPriority - { - Lowest, - BelowNormal, - Normal, - AboveNormal, - Highest, - } - - #endregion - - #region IWorkItemsGroup interface - - /// - /// IWorkItemsGroup interface - /// Created by SmartThreadPool.CreateWorkItemsGroup() - /// - public interface IWorkItemsGroup - { - /// - /// Get/Set the name of the WorkItemsGroup - /// - string Name { get; set; } - - /// - /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool - /// - int Concurrency { get; set; } - - /// - /// Get the number of work items waiting in the queue. - /// - int WaitingCallbacks { get; } - - /// - /// Get an array with all the state objects of the currently running items. - /// The array represents a snap shot and impact performance. - /// - object[] GetStates(); - - /// - /// Get the WorkItemsGroup start information - /// - WIGStartInfo WIGStartInfo { get; } - - /// - /// Starts to execute work items - /// - void Start(); - - /// - /// Cancel all the work items. - /// Same as Cancel(false) - /// - void Cancel(); - - /// - /// Cancel all work items using thread abortion - /// - /// True to stop work items by raising ThreadAbortException - void Cancel(bool abortExecution); - - /// - /// Wait for all work item to complete. - /// - void WaitForIdle(); - - /// - /// Wait for all work item to complete, until timeout expired - /// - /// How long to wait for the work items to complete - /// Returns true if work items completed within the timeout, otherwise false. - bool WaitForIdle(TimeSpan timeout); - - /// - /// Wait for all work item to complete, until timeout expired - /// - /// How long to wait for the work items to complete in milliseconds - /// Returns true if work items completed within the timeout, otherwise false. - bool WaitForIdle(int millisecondsTimeout); - - /// - /// IsIdle is true when there are no work items running or queued. - /// - bool IsIdle { get; } - - /// - /// This event is fired when all work items are completed. - /// (When IsIdle changes to true) - /// This event only work on WorkItemsGroup. On SmartThreadPool - /// it throws the NotImplementedException. - /// - event WorkItemsGroupIdleHandler OnIdle; - - #region QueueWorkItem - - /// - /// Queue a work item - /// - /// A callback to execute - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback); - - /// - /// Queue a work item - /// - /// A callback to execute - /// The priority of the work item - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); - - /// - /// Queue a work item - /// - /// Work item info - /// A callback to execute - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); - - /// - /// Queue a work item - /// - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); - - #endregion - - #region QueueWorkItem(Action<...>) - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T arg); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult object, but its GetResult() will always return null - IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority); - - #endregion - - #region QueueWorkItem(Func<...>) - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T arg); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3); - - /// - /// Queue a work item. - /// - /// Returns a IWorkItemResult<TResult> object. - /// its GetResult() returns a TResult object - IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - #endregion - } - - #endregion - - #region CallToPostExecute enumerator - - [Flags] - public enum CallToPostExecute - { - /// - /// Never call to the PostExecute call back - /// - Never = 0x00, - - /// - /// Call to the PostExecute only when the work item is cancelled - /// - WhenWorkItemCanceled = 0x01, - - /// - /// Call to the PostExecute only when the work item is not cancelled - /// - WhenWorkItemNotCanceled = 0x02, - - /// - /// Always call to the PostExecute - /// - Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, - } - - #endregion - - #region IWorkItemResult interface - - /// - /// The common interface of IWorkItemResult and IWorkItemResult<T> - /// - public interface IWaitableResult - { - /// - /// This method intent is for internal use. - /// - /// - IWorkItemResult GetWorkItemResult(); - - /// - /// This method intent is for internal use. - /// - /// - IWorkItemResult GetWorkItemResultT(); - } - - /// - /// IWorkItemResult interface. - /// Created when a WorkItemCallback work item is queued. - /// - public interface IWorkItemResult : IWorkItemResult - { - } - - /// - /// IWorkItemResult<TResult> interface. - /// Created when a Func<TResult> work item is queued. - /// - public interface IWorkItemResult : IWaitableResult - { - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits. - /// - /// The result of the work item - TResult GetResult(); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - int millisecondsTimeout, - bool exitContext); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - TimeSpan timeout, - bool exitContext); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// Timeout in milliseconds, or -1 for infinite - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the blocking if needed - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits. - /// - /// Filled with the exception if one was thrown - /// The result of the work item - TResult GetResult(out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// - /// - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - int millisecondsTimeout, - bool exitContext, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout. - /// - /// - /// Filled with the exception if one was thrown - /// - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - TResult GetResult( - TimeSpan timeout, - bool exitContext, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// Timeout in milliseconds, or -1 for infinite - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the blocking if needed - /// Filled with the exception if one was thrown - /// The result of the work item - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle, - out Exception e); - - /// - /// Get the result of the work item. - /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. - /// - /// The result of the work item - /// - /// Filled with the exception if one was thrown - /// - /// - /// On timeout throws WorkItemTimeoutException - /// On cancel throws WorkItemCancelException - TResult GetResult( - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle, - out Exception e); - - /// - /// Gets an indication whether the asynchronous operation has completed. - /// - bool IsCompleted { get; } - - /// - /// Gets an indication whether the asynchronous operation has been canceled. - /// - bool IsCanceled { get; } - - /// - /// Gets the user-defined object that contains context data - /// for the work item method. - /// - object State { get; } - - /// - /// Same as Cancel(false). - /// - bool Cancel(); - - /// - /// Cancel the work item execution. - /// If the work item is in the queue then it won't execute - /// If the work item is completed, it will remain completed - /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled - /// property to check if the work item has been cancelled. If the abortExecution is set to true then - /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution - /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException. - /// If the work item is already cancelled it will remain cancelled - /// - /// When true send an AbortException to the executing thread. - /// Returns true if the work item was not completed, otherwise false. - bool Cancel(bool abortExecution); - - /// - /// Get the work item's priority - /// - WorkItemPriority WorkItemPriority { get; } - - /// - /// Return the result, same as GetResult() - /// - TResult Result { get; } - - /// - /// Returns the exception if occured otherwise returns null. - /// - object Exception { get; } - } - - #endregion - - #region .NET 3.5 - - // All these delegate are built-in .NET 3.5 - // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity. - - public delegate void Action(); - public delegate void Action(T1 arg1, T2 arg2); - public delegate void Action(T1 arg1, T2 arg2, T3 arg3); - public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - public delegate TResult Func(); - public delegate TResult Func(T arg1); - public delegate TResult Func(T1 arg1, T2 arg2); - public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); - public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - - #endregion -} +using System; +using System.Threading; + +namespace Amib.Threading +{ + #region Delegates + + /// + /// A delegate that represents the method to run as the work item + /// + /// A state object for the method to run + public delegate object WorkItemCallback(object state); + + /// + /// A delegate to call after the WorkItemCallback completed + /// + /// The work item result object + public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); + + /// + /// A delegate to call after the WorkItemCallback completed + /// + /// The work item result object + public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir); + + /// + /// A delegate to call when a WorkItemsGroup becomes idle + /// + /// A reference to the WorkItemsGroup that became idle + public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup); + + /// + /// A delegate to call after a thread is created, but before + /// it's first use. + /// + public delegate void ThreadInitializationHandler(); + + /// + /// A delegate to call when a thread is about to exit, after + /// it is no longer belong to the pool. + /// + public delegate void ThreadTerminationHandler(); + + #endregion + + #region WorkItem Priority + + /// + /// Defines the availeable priorities of a work item. + /// The higher the priority a work item has, the sooner + /// it will be executed. + /// + public enum WorkItemPriority + { + Lowest, + BelowNormal, + Normal, + AboveNormal, + Highest, + } + + #endregion + + #region IWorkItemsGroup interface + + /// + /// IWorkItemsGroup interface + /// Created by SmartThreadPool.CreateWorkItemsGroup() + /// + public interface IWorkItemsGroup + { + /// + /// Get/Set the name of the WorkItemsGroup + /// + string Name { get; set; } + + /// + /// Get/Set the maximum number of workitem that execute cocurrency on the thread pool + /// + int Concurrency { get; set; } + + /// + /// Get the number of work items waiting in the queue. + /// + int WaitingCallbacks { get; } + + /// + /// Get an array with all the state objects of the currently running items. + /// The array represents a snap shot and impact performance. + /// + object[] GetStates(); + + /// + /// Get the WorkItemsGroup start information + /// + WIGStartInfo WIGStartInfo { get; } + + /// + /// Starts to execute work items + /// + void Start(); + + /// + /// Cancel all the work items. + /// Same as Cancel(false) + /// + void Cancel(); + + /// + /// Cancel all work items using thread abortion + /// + /// True to stop work items by raising ThreadAbortException + void Cancel(bool abortExecution); + + /// + /// Wait for all work item to complete. + /// + void WaitForIdle(); + + /// + /// Wait for all work item to complete, until timeout expired + /// + /// How long to wait for the work items to complete + /// Returns true if work items completed within the timeout, otherwise false. + bool WaitForIdle(TimeSpan timeout); + + /// + /// Wait for all work item to complete, until timeout expired + /// + /// How long to wait for the work items to complete in milliseconds + /// Returns true if work items completed within the timeout, otherwise false. + bool WaitForIdle(int millisecondsTimeout); + + /// + /// IsIdle is true when there are no work items running or queued. + /// + bool IsIdle { get; } + + /// + /// This event is fired when all work items are completed. + /// (When IsIdle changes to true) + /// This event only work on WorkItemsGroup. On SmartThreadPool + /// it throws the NotImplementedException. + /// + event WorkItemsGroupIdleHandler OnIdle; + + #region QueueWorkItem + + /// + /// Queue a work item + /// + /// A callback to execute + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback); + + /// + /// Queue a work item + /// + /// A callback to execute + /// The priority of the work item + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute); + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority); + + /// + /// Queue a work item + /// + /// Work item info + /// A callback to execute + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback); + + /// + /// Queue a work item + /// + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state); + + #endregion + + #region QueueWorkItem(Action<...>) + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T arg); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult object, but its GetResult() will always return null + IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority); + + #endregion + + #region QueueWorkItem(Func<...>) + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T arg); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3); + + /// + /// Queue a work item. + /// + /// Returns a IWorkItemResult<TResult> object. + /// its GetResult() returns a TResult object + IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + #endregion + } + + #endregion + + #region CallToPostExecute enumerator + + [Flags] + public enum CallToPostExecute + { + /// + /// Never call to the PostExecute call back + /// + Never = 0x00, + + /// + /// Call to the PostExecute only when the work item is cancelled + /// + WhenWorkItemCanceled = 0x01, + + /// + /// Call to the PostExecute only when the work item is not cancelled + /// + WhenWorkItemNotCanceled = 0x02, + + /// + /// Always call to the PostExecute + /// + Always = WhenWorkItemCanceled | WhenWorkItemNotCanceled, + } + + #endregion + + #region IWorkItemResult interface + + /// + /// The common interface of IWorkItemResult and IWorkItemResult<T> + /// + public interface IWaitableResult + { + /// + /// This method intent is for internal use. + /// + /// + IWorkItemResult GetWorkItemResult(); + + /// + /// This method intent is for internal use. + /// + /// + IWorkItemResult GetWorkItemResultT(); + } + + /// + /// IWorkItemResult interface. + /// Created when a WorkItemCallback work item is queued. + /// + public interface IWorkItemResult : IWorkItemResult + { + } + + /// + /// IWorkItemResult<TResult> interface. + /// Created when a Func<TResult> work item is queued. + /// + public interface IWorkItemResult : IWaitableResult + { + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits. + /// + /// The result of the work item + TResult GetResult(); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + int millisecondsTimeout, + bool exitContext); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + TimeSpan timeout, + bool exitContext); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// Timeout in milliseconds, or -1 for infinite + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the blocking if needed + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits. + /// + /// Filled with the exception if one was thrown + /// The result of the work item + TResult GetResult(out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// + /// + /// Filled with the exception if one was thrown + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout. + /// + /// + /// Filled with the exception if one was thrown + /// + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// Timeout in milliseconds, or -1 for infinite + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the blocking if needed + /// Filled with the exception if one was thrown + /// The result of the work item + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle, + out Exception e); + + /// + /// Get the result of the work item. + /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled. + /// + /// The result of the work item + /// + /// Filled with the exception if one was thrown + /// + /// + /// On timeout throws WorkItemTimeoutException + /// On cancel throws WorkItemCancelException + TResult GetResult( + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle, + out Exception e); + + /// + /// Gets an indication whether the asynchronous operation has completed. + /// + bool IsCompleted { get; } + + /// + /// Gets an indication whether the asynchronous operation has been canceled. + /// + bool IsCanceled { get; } + + /// + /// Gets the user-defined object that contains context data + /// for the work item method. + /// + object State { get; } + + /// + /// Same as Cancel(false). + /// + bool Cancel(); + + /// + /// Cancel the work item execution. + /// If the work item is in the queue then it won't execute + /// If the work item is completed, it will remain completed + /// If the work item is in progress then the user can check the SmartThreadPool.IsWorkItemCanceled + /// property to check if the work item has been cancelled. If the abortExecution is set to true then + /// the Smart Thread Pool will send an AbortException to the running thread to stop the execution + /// of the work item. When an in progress work item is canceled its GetResult will throw WorkItemCancelException. + /// If the work item is already cancelled it will remain cancelled + /// + /// When true send an AbortException to the executing thread. + /// Returns true if the work item was not completed, otherwise false. + bool Cancel(bool abortExecution); + + /// + /// Get the work item's priority + /// + WorkItemPriority WorkItemPriority { get; } + + /// + /// Return the result, same as GetResult() + /// + TResult Result { get; } + + /// + /// Returns the exception if occured otherwise returns null. + /// + object Exception { get; } + } + + #endregion + + #region .NET 3.5 + + // All these delegate are built-in .NET 3.5 + // Comment/Remove them when compiling to .NET 3.5 to avoid ambiguity. + + public delegate void Action(); + public delegate void Action(T1 arg1, T2 arg2); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + public delegate TResult Func(); + public delegate TResult Func(T arg1); + public delegate TResult Func(T1 arg1, T2 arg2); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/InternalInterfaces.cs b/ThirdParty/SmartThreadPool/InternalInterfaces.cs index 8be7161..0072e10 100644 --- a/ThirdParty/SmartThreadPool/InternalInterfaces.cs +++ b/ThirdParty/SmartThreadPool/InternalInterfaces.cs @@ -1,27 +1,27 @@ - -namespace Amib.Threading.Internal -{ - /// - /// An internal delegate to call when the WorkItem starts or completes - /// - internal delegate void WorkItemStateCallback(WorkItem workItem); - - internal interface IInternalWorkItemResult - { - event WorkItemStateCallback OnWorkItemStarted; - event WorkItemStateCallback OnWorkItemCompleted; - } - - internal interface IInternalWaitableResult - { - /// - /// This method is intent for internal use. - /// - IWorkItemResult GetWorkItemResult(); - } - - public interface IHasWorkItemPriority - { - WorkItemPriority WorkItemPriority { get; } - } -} + +namespace Amib.Threading.Internal +{ + /// + /// An internal delegate to call when the WorkItem starts or completes + /// + internal delegate void WorkItemStateCallback(WorkItem workItem); + + internal interface IInternalWorkItemResult + { + event WorkItemStateCallback OnWorkItemStarted; + event WorkItemStateCallback OnWorkItemCompleted; + } + + internal interface IInternalWaitableResult + { + /// + /// This method is intent for internal use. + /// + IWorkItemResult GetWorkItemResult(); + } + + public interface IHasWorkItemPriority + { + WorkItemPriority WorkItemPriority { get; } + } +} diff --git a/ThirdParty/SmartThreadPool/PriorityQueue.cs b/ThirdParty/SmartThreadPool/PriorityQueue.cs index 6245fd8..409c879 100644 --- a/ThirdParty/SmartThreadPool/PriorityQueue.cs +++ b/ThirdParty/SmartThreadPool/PriorityQueue.cs @@ -1,239 +1,239 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - #region PriorityQueue class - - /// - /// PriorityQueue class - /// This class is not thread safe because we use external lock - /// - public sealed class PriorityQueue : IEnumerable - { - #region Private members - - /// - /// The number of queues, there is one for each type of priority - /// - private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; - - /// - /// Work items queues. There is one for each type of priority - /// - private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; - - /// - /// The total number of work items within the queues - /// - private int _workItemsCount; - - /// - /// Use with IEnumerable interface - /// - private int _version; - - #endregion - - #region Contructor - - public PriorityQueue() - { - for(int i = 0; i < _queues.Length; ++i) - { - _queues[i] = new LinkedList(); - } - } - - #endregion - - #region Methods - - /// - /// Enqueue a work item. - /// - /// A work item - public void Enqueue(IHasWorkItemPriority workItem) - { - Debug.Assert(null != workItem); - - int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; - Debug.Assert(queueIndex >= 0); - Debug.Assert(queueIndex < _queuesCount); - - _queues[queueIndex].AddLast(workItem); - ++_workItemsCount; - ++_version; - } - - /// - /// Dequeque a work item. - /// - /// Returns the next work item - public IHasWorkItemPriority Dequeue() - { - IHasWorkItemPriority workItem = null; - - if(_workItemsCount > 0) - { - int queueIndex = GetNextNonEmptyQueue(-1); - Debug.Assert(queueIndex >= 0); - workItem = _queues[queueIndex].First.Value; - _queues[queueIndex].RemoveFirst(); - Debug.Assert(null != workItem); - --_workItemsCount; - ++_version; - } - - return workItem; - } - - /// - /// Find the next non empty queue starting at queue queueIndex+1 - /// - /// The index-1 to start from - /// - /// The index of the next non empty queue or -1 if all the queues are empty - /// - private int GetNextNonEmptyQueue(int queueIndex) - { - for(int i = queueIndex+1; i < _queuesCount; ++i) - { - if(_queues[i].Count > 0) - { - return i; - } - } - return -1; - } - - /// - /// The number of work items - /// - public int Count - { - get - { - return _workItemsCount; - } - } - - /// - /// Clear all the work items - /// - public void Clear() - { - if (_workItemsCount > 0) - { - foreach(LinkedList queue in _queues) - { - queue.Clear(); - } - _workItemsCount = 0; - ++_version; - } - } - - #endregion - - #region IEnumerable Members - - /// - /// Returns an enumerator to iterate over the work items - /// - /// Returns an enumerator - public IEnumerator GetEnumerator() - { - return new PriorityQueueEnumerator(this); - } - - #endregion - - #region PriorityQueueEnumerator - - /// - /// The class the implements the enumerator - /// - private class PriorityQueueEnumerator : IEnumerator - { - private readonly PriorityQueue _priorityQueue; - private int _version; - private int _queueIndex; - private IEnumerator _enumerator; - - public PriorityQueueEnumerator(PriorityQueue priorityQueue) - { - _priorityQueue = priorityQueue; - _version = _priorityQueue._version; - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); - if (_queueIndex >= 0) - { - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - } - else - { - _enumerator = null; - } - } - - #region IEnumerator Members - - public void Reset() - { - _version = _priorityQueue._version; - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); - if (_queueIndex >= 0) - { - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - } - else - { - _enumerator = null; - } - } - - public object Current - { - get - { - Debug.Assert(null != _enumerator); - return _enumerator.Current; - } - } - - public bool MoveNext() - { - if (null == _enumerator) - { - return false; - } - - if(_version != _priorityQueue._version) - { - throw new InvalidOperationException("The collection has been modified"); - - } - if (!_enumerator.MoveNext()) - { - _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); - if(-1 == _queueIndex) - { - return false; - } - _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); - _enumerator.MoveNext(); - return true; - } - return true; - } - - #endregion - } - - #endregion - } - - #endregion -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Amib.Threading.Internal +{ + #region PriorityQueue class + + /// + /// PriorityQueue class + /// This class is not thread safe because we use external lock + /// + public sealed class PriorityQueue : IEnumerable + { + #region Private members + + /// + /// The number of queues, there is one for each type of priority + /// + private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1; + + /// + /// Work items queues. There is one for each type of priority + /// + private readonly LinkedList[] _queues = new LinkedList[_queuesCount]; + + /// + /// The total number of work items within the queues + /// + private int _workItemsCount; + + /// + /// Use with IEnumerable interface + /// + private int _version; + + #endregion + + #region Contructor + + public PriorityQueue() + { + for(int i = 0; i < _queues.Length; ++i) + { + _queues[i] = new LinkedList(); + } + } + + #endregion + + #region Methods + + /// + /// Enqueue a work item. + /// + /// A work item + public void Enqueue(IHasWorkItemPriority workItem) + { + Debug.Assert(null != workItem); + + int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1; + Debug.Assert(queueIndex >= 0); + Debug.Assert(queueIndex < _queuesCount); + + _queues[queueIndex].AddLast(workItem); + ++_workItemsCount; + ++_version; + } + + /// + /// Dequeque a work item. + /// + /// Returns the next work item + public IHasWorkItemPriority Dequeue() + { + IHasWorkItemPriority workItem = null; + + if(_workItemsCount > 0) + { + int queueIndex = GetNextNonEmptyQueue(-1); + Debug.Assert(queueIndex >= 0); + workItem = _queues[queueIndex].First.Value; + _queues[queueIndex].RemoveFirst(); + Debug.Assert(null != workItem); + --_workItemsCount; + ++_version; + } + + return workItem; + } + + /// + /// Find the next non empty queue starting at queue queueIndex+1 + /// + /// The index-1 to start from + /// + /// The index of the next non empty queue or -1 if all the queues are empty + /// + private int GetNextNonEmptyQueue(int queueIndex) + { + for(int i = queueIndex+1; i < _queuesCount; ++i) + { + if(_queues[i].Count > 0) + { + return i; + } + } + return -1; + } + + /// + /// The number of work items + /// + public int Count + { + get + { + return _workItemsCount; + } + } + + /// + /// Clear all the work items + /// + public void Clear() + { + if (_workItemsCount > 0) + { + foreach(LinkedList queue in _queues) + { + queue.Clear(); + } + _workItemsCount = 0; + ++_version; + } + } + + #endregion + + #region IEnumerable Members + + /// + /// Returns an enumerator to iterate over the work items + /// + /// Returns an enumerator + public IEnumerator GetEnumerator() + { + return new PriorityQueueEnumerator(this); + } + + #endregion + + #region PriorityQueueEnumerator + + /// + /// The class the implements the enumerator + /// + private class PriorityQueueEnumerator : IEnumerator + { + private readonly PriorityQueue _priorityQueue; + private int _version; + private int _queueIndex; + private IEnumerator _enumerator; + + public PriorityQueueEnumerator(PriorityQueue priorityQueue) + { + _priorityQueue = priorityQueue; + _version = _priorityQueue._version; + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); + if (_queueIndex >= 0) + { + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + } + else + { + _enumerator = null; + } + } + + #region IEnumerator Members + + public void Reset() + { + _version = _priorityQueue._version; + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1); + if (_queueIndex >= 0) + { + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + } + else + { + _enumerator = null; + } + } + + public object Current + { + get + { + Debug.Assert(null != _enumerator); + return _enumerator.Current; + } + } + + public bool MoveNext() + { + if (null == _enumerator) + { + return false; + } + + if(_version != _priorityQueue._version) + { + throw new InvalidOperationException("The collection has been modified"); + + } + if (!_enumerator.MoveNext()) + { + _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex); + if(-1 == _queueIndex) + { + return false; + } + _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator(); + _enumerator.MoveNext(); + return true; + } + return true; + } + + #endregion + } + + #endregion + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs index 1651e78..4728c1f 100644 --- a/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs +++ b/ThirdParty/SmartThreadPool/Properties/AssemblyInfo.cs @@ -1,23 +1,23 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Amib.Threading")] -[assembly: AssemblyDescription("Smart Thread Pool")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Amib.Threading")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")] -[assembly: AssemblyVersion("2.2.3.0")] - -#if (_PUBLISH) -[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")] -#else -[assembly: InternalsVisibleTo("STPTests")] -#endif - - +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Amib.Threading")] +[assembly: AssemblyDescription("Smart Thread Pool")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Amib.Threading")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("c764a3de-c4f8-434d-85b5-a09830d1e44f")] +[assembly: AssemblyVersion("2.2.3.0")] + +#if (_PUBLISH) +[assembly: InternalsVisibleTo("STPTests,PublicKey=00240000048000009400000006020000002400005253413100040000010001004fe3d39add741ba7c8d52cd1eb0d94c7d79060ad956cbaff0e51c1dce94db10356b261778bc1ac3114b3218434da6fcd8416dd5507653809598f7d2afc422099ce4f6b7b0477f18e6c57c727ef2a7ab6ee56e6b4589fe44cb0e25f2875a3c65ab0383ee33c4dd93023f7ce1218bebc8b7a9a1dac878938f5c4f45ea74b6bd8ad")] +#else +[assembly: InternalsVisibleTo("STPTests")] +#endif + + diff --git a/ThirdParty/SmartThreadPool/SLExt.cs b/ThirdParty/SmartThreadPool/SLExt.cs index fafff19..23a60bc 100644 --- a/ThirdParty/SmartThreadPool/SLExt.cs +++ b/ThirdParty/SmartThreadPool/SLExt.cs @@ -1,16 +1,16 @@ -#if _SILVERLIGHT - -using System.Threading; - -namespace Amib.Threading -{ - public enum ThreadPriority - { - Lowest, - BelowNormal, - Normal, - AboveNormal, - Highest, - } -} -#endif +#if _SILVERLIGHT + +using System.Threading; + +namespace Amib.Threading +{ + public enum ThreadPriority + { + Lowest, + BelowNormal, + Normal, + AboveNormal, + Highest, + } +} +#endif diff --git a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs index 3b92645..9b17f69 100644 --- a/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs +++ b/ThirdParty/SmartThreadPool/STPEventWaitHandle.cs @@ -1,62 +1,62 @@ -#if !(_WINDOWS_CE) - -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ -#if _WINDOWS || WINDOWS_PHONE - internal static class STPEventWaitHandle - { - public const int WaitTimeout = Timeout.Infinite; - - internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAll(waitHandles, millisecondsTimeout); - } - - internal static int WaitAny(WaitHandle[] waitHandles) - { - return WaitHandle.WaitAny(waitHandles); - } - - internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAny(waitHandles, millisecondsTimeout); - } - - internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) - { - return waitHandle.WaitOne(millisecondsTimeout); - } - } -#else - internal static class STPEventWaitHandle - { - public const int WaitTimeout = Timeout.Infinite; - - internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); - } - - internal static int WaitAny(WaitHandle[] waitHandles) - { - return WaitHandle.WaitAny(waitHandles); - } - - internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) - { - return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); - } - - internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) - { - return waitHandle.WaitOne(millisecondsTimeout, exitContext); - } - } -#endif - -} - +#if !(_WINDOWS_CE) + +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ +#if _WINDOWS || WINDOWS_PHONE + internal static class STPEventWaitHandle + { + public const int WaitTimeout = Timeout.Infinite; + + internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAll(waitHandles, millisecondsTimeout); + } + + internal static int WaitAny(WaitHandle[] waitHandles) + { + return WaitHandle.WaitAny(waitHandles); + } + + internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAny(waitHandles, millisecondsTimeout); + } + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout); + } + } +#else + internal static class STPEventWaitHandle + { + public const int WaitTimeout = Timeout.Infinite; + + internal static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext); + } + + internal static int WaitAny(WaitHandle[] waitHandles) + { + return WaitHandle.WaitAny(waitHandles); + } + + internal static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) + { + return WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext); + } + + internal static bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout, bool exitContext) + { + return waitHandle.WaitOne(millisecondsTimeout, exitContext); + } + } +#endif + +} + #endif \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs index 2508661..0663d1d 100644 --- a/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs +++ b/ThirdParty/SmartThreadPool/STPPerformanceCounter.cs @@ -1,448 +1,448 @@ -using System; -using System.Diagnostics; -using System.Threading; - -namespace Amib.Threading -{ - public interface ISTPPerformanceCountersReader - { - long InUseThreads { get; } - long ActiveThreads { get; } - long WorkItemsQueued { get; } - long WorkItemsProcessed { get; } - } -} - -namespace Amib.Threading.Internal -{ - internal interface ISTPInstancePerformanceCounters : IDisposable - { - void Close(); - void SampleThreads(long activeThreads, long inUseThreads); - void SampleWorkItems(long workItemsQueued, long workItemsProcessed); - void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); - void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); - } -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - - internal enum STPPerformanceCounterType - { - // Fields - ActiveThreads = 0, - InUseThreads = 1, - OverheadThreads = 2, - OverheadThreadsPercent = 3, - OverheadThreadsPercentBase = 4, - - WorkItems = 5, - WorkItemsInQueue = 6, - WorkItemsProcessed = 7, - - WorkItemsQueuedPerSecond = 8, - WorkItemsProcessedPerSecond = 9, - - AvgWorkItemWaitTime = 10, - AvgWorkItemWaitTimeBase = 11, - - AvgWorkItemProcessTime = 12, - AvgWorkItemProcessTimeBase = 13, - - WorkItemsGroups = 14, - - LastCounter = 14, - } - - - /// - /// Summary description for STPPerformanceCounter. - /// - internal class STPPerformanceCounter - { - // Fields - private readonly PerformanceCounterType _pcType; - protected string _counterHelp; - protected string _counterName; - - // Methods - public STPPerformanceCounter( - string counterName, - string counterHelp, - PerformanceCounterType pcType) - { - _counterName = counterName; - _counterHelp = counterHelp; - _pcType = pcType; - } - - public void AddCounterToCollection(CounterCreationDataCollection counterData) - { - CounterCreationData counterCreationData = new CounterCreationData( - _counterName, - _counterHelp, - _pcType); - - counterData.Add(counterCreationData); - } - - // Properties - public string Name - { - get - { - return _counterName; - } - } - } - - internal class STPPerformanceCounters - { - // Fields - internal STPPerformanceCounter[] _stpPerformanceCounters; - private static readonly STPPerformanceCounters _instance; - internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; - internal const string _stpCategoryName = "SmartThreadPool"; - - // Methods - static STPPerformanceCounters() - { - _instance = new STPPerformanceCounters(); - } - - private STPPerformanceCounters() - { - STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] - { - new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), - new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), - - new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), - new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), - - new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), - new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), - - new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), - new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), - - new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), - new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), - - new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), - }; - - _stpPerformanceCounters = stpPerformanceCounters; - SetupCategory(); - } - - private void SetupCategory() - { - if (!PerformanceCounterCategory.Exists(_stpCategoryName)) - { - CounterCreationDataCollection counters = new CounterCreationDataCollection(); - - for (int i = 0; i < _stpPerformanceCounters.Length; i++) - { - _stpPerformanceCounters[i].AddCounterToCollection(counters); - } - - PerformanceCounterCategory.Create( - _stpCategoryName, - _stpCategoryHelp, - PerformanceCounterCategoryType.MultiInstance, - counters); - - } - } - - // Properties - public static STPPerformanceCounters Instance - { - get - { - return _instance; - } - } - } - - internal class STPInstancePerformanceCounter : IDisposable - { - // Fields - private bool _isDisposed; - private PerformanceCounter _pcs; - - // Methods - protected STPInstancePerformanceCounter() - { - _isDisposed = false; - } - - public STPInstancePerformanceCounter( - string instance, - STPPerformanceCounterType spcType) : this() - { - STPPerformanceCounters counters = STPPerformanceCounters.Instance; - _pcs = new PerformanceCounter( - STPPerformanceCounters._stpCategoryName, - counters._stpPerformanceCounters[(int) spcType].Name, - instance, - false); - _pcs.RawValue = _pcs.RawValue; - } - - - public void Close() - { - if (_pcs != null) - { - _pcs.RemoveInstance(); - _pcs.Close(); - _pcs = null; - } - } - - public void Dispose() - { - Dispose(true); - } - - public virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - Close(); - } - } - _isDisposed = true; - } - - public virtual void Increment() - { - _pcs.Increment(); - } - - public virtual void IncrementBy(long val) - { - _pcs.IncrementBy(val); - } - - public virtual void Set(long val) - { - _pcs.RawValue = val; - } - } - - internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter - { - // Methods - public override void Increment() {} - public override void IncrementBy(long value) {} - public override void Set(long val) {} - } - - - - internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters - { - private bool _isDisposed; - // Fields - private STPInstancePerformanceCounter[] _pcs; - private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; - - // Methods - static STPInstancePerformanceCounters() - { - _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); - } - - public STPInstancePerformanceCounters(string instance) - { - _isDisposed = false; - _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; - - // Call the STPPerformanceCounters.Instance so the static constructor will - // intialize the STPPerformanceCounters singleton. - STPPerformanceCounters.Instance.GetHashCode(); - - for (int i = 0; i < _pcs.Length; i++) - { - if (instance != null) - { - _pcs[i] = new STPInstancePerformanceCounter( - instance, - (STPPerformanceCounterType) i); - } - else - { - _pcs[i] = _stpInstanceNullPerformanceCounter; - } - } - } - - - public void Close() - { - if (null != _pcs) - { - for (int i = 0; i < _pcs.Length; i++) - { - if (null != _pcs[i]) - { - _pcs[i].Dispose(); - } - } - _pcs = null; - } - } - - public void Dispose() - { - Dispose(true); - } - - public virtual void Dispose(bool disposing) - { - if (!_isDisposed) - { - if (disposing) - { - Close(); - } - } - _isDisposed = true; - } - - private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) - { - return _pcs[(int) spcType]; - } - - public void SampleThreads(long activeThreads, long inUseThreads) - { - GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); - GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); - GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); - - GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); - GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); - } - - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) - { - GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); - GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); - GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); - - GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); - GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); - } - - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) - { - GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); - GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); - } - - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) - { - GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); - GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); - } - } -#endif - - internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader - { - private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(); - - public static NullSTPInstancePerformanceCounters Instance - { - get { return _instance; } - } - - public void Close() {} - public void Dispose() {} - - public void SampleThreads(long activeThreads, long inUseThreads) {} - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} - public long InUseThreads - { - get { return 0; } - } - - public long ActiveThreads - { - get { return 0; } - } - - public long WorkItemsQueued - { - get { return 0; } - } - - public long WorkItemsProcessed - { - get { return 0; } - } - } - - internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader - { - public void Close() { } - public void Dispose() { } - - private long _activeThreads; - private long _inUseThreads; - private long _workItemsQueued; - private long _workItemsProcessed; - - public long InUseThreads - { - get { return _inUseThreads; } - } - - public long ActiveThreads - { - get { return _activeThreads; } - } - - public long WorkItemsQueued - { - get { return _workItemsQueued; } - } - - public long WorkItemsProcessed - { - get { return _workItemsProcessed; } - } - - public void SampleThreads(long activeThreads, long inUseThreads) - { - _activeThreads = activeThreads; - _inUseThreads = inUseThreads; - } - - public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) - { - _workItemsQueued = workItemsQueued; - _workItemsProcessed = workItemsProcessed; - } - - public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) - { - // Not supported - } - - public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) - { - // Not supported - } - } -} +using System; +using System.Diagnostics; +using System.Threading; + +namespace Amib.Threading +{ + public interface ISTPPerformanceCountersReader + { + long InUseThreads { get; } + long ActiveThreads { get; } + long WorkItemsQueued { get; } + long WorkItemsProcessed { get; } + } +} + +namespace Amib.Threading.Internal +{ + internal interface ISTPInstancePerformanceCounters : IDisposable + { + void Close(); + void SampleThreads(long activeThreads, long inUseThreads); + void SampleWorkItems(long workItemsQueued, long workItemsProcessed); + void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime); + void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime); + } +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + internal enum STPPerformanceCounterType + { + // Fields + ActiveThreads = 0, + InUseThreads = 1, + OverheadThreads = 2, + OverheadThreadsPercent = 3, + OverheadThreadsPercentBase = 4, + + WorkItems = 5, + WorkItemsInQueue = 6, + WorkItemsProcessed = 7, + + WorkItemsQueuedPerSecond = 8, + WorkItemsProcessedPerSecond = 9, + + AvgWorkItemWaitTime = 10, + AvgWorkItemWaitTimeBase = 11, + + AvgWorkItemProcessTime = 12, + AvgWorkItemProcessTimeBase = 13, + + WorkItemsGroups = 14, + + LastCounter = 14, + } + + + /// + /// Summary description for STPPerformanceCounter. + /// + internal class STPPerformanceCounter + { + // Fields + private readonly PerformanceCounterType _pcType; + protected string _counterHelp; + protected string _counterName; + + // Methods + public STPPerformanceCounter( + string counterName, + string counterHelp, + PerformanceCounterType pcType) + { + _counterName = counterName; + _counterHelp = counterHelp; + _pcType = pcType; + } + + public void AddCounterToCollection(CounterCreationDataCollection counterData) + { + CounterCreationData counterCreationData = new CounterCreationData( + _counterName, + _counterHelp, + _pcType); + + counterData.Add(counterCreationData); + } + + // Properties + public string Name + { + get + { + return _counterName; + } + } + } + + internal class STPPerformanceCounters + { + // Fields + internal STPPerformanceCounter[] _stpPerformanceCounters; + private static readonly STPPerformanceCounters _instance; + internal const string _stpCategoryHelp = "SmartThreadPool performance counters"; + internal const string _stpCategoryName = "SmartThreadPool"; + + // Methods + static STPPerformanceCounters() + { + _instance = new STPPerformanceCounters(); + } + + private STPPerformanceCounters() + { + STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] + { + new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), + new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), + + new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), + new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), + + new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), + new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), + + new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), + new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), + + new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), + new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), + + new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), + }; + + _stpPerformanceCounters = stpPerformanceCounters; + SetupCategory(); + } + + private void SetupCategory() + { + if (!PerformanceCounterCategory.Exists(_stpCategoryName)) + { + CounterCreationDataCollection counters = new CounterCreationDataCollection(); + + for (int i = 0; i < _stpPerformanceCounters.Length; i++) + { + _stpPerformanceCounters[i].AddCounterToCollection(counters); + } + + PerformanceCounterCategory.Create( + _stpCategoryName, + _stpCategoryHelp, + PerformanceCounterCategoryType.MultiInstance, + counters); + + } + } + + // Properties + public static STPPerformanceCounters Instance + { + get + { + return _instance; + } + } + } + + internal class STPInstancePerformanceCounter : IDisposable + { + // Fields + private bool _isDisposed; + private PerformanceCounter _pcs; + + // Methods + protected STPInstancePerformanceCounter() + { + _isDisposed = false; + } + + public STPInstancePerformanceCounter( + string instance, + STPPerformanceCounterType spcType) : this() + { + STPPerformanceCounters counters = STPPerformanceCounters.Instance; + _pcs = new PerformanceCounter( + STPPerformanceCounters._stpCategoryName, + counters._stpPerformanceCounters[(int) spcType].Name, + instance, + false); + _pcs.RawValue = _pcs.RawValue; + } + + + public void Close() + { + if (_pcs != null) + { + _pcs.RemoveInstance(); + _pcs.Close(); + _pcs = null; + } + } + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + } + } + _isDisposed = true; + } + + public virtual void Increment() + { + _pcs.Increment(); + } + + public virtual void IncrementBy(long val) + { + _pcs.IncrementBy(val); + } + + public virtual void Set(long val) + { + _pcs.RawValue = val; + } + } + + internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter + { + // Methods + public override void Increment() {} + public override void IncrementBy(long value) {} + public override void Set(long val) {} + } + + + + internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters + { + private bool _isDisposed; + // Fields + private STPInstancePerformanceCounter[] _pcs; + private static readonly STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter; + + // Methods + static STPInstancePerformanceCounters() + { + _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter(); + } + + public STPInstancePerformanceCounters(string instance) + { + _isDisposed = false; + _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter]; + + // Call the STPPerformanceCounters.Instance so the static constructor will + // intialize the STPPerformanceCounters singleton. + STPPerformanceCounters.Instance.GetHashCode(); + + for (int i = 0; i < _pcs.Length; i++) + { + if (instance != null) + { + _pcs[i] = new STPInstancePerformanceCounter( + instance, + (STPPerformanceCounterType) i); + } + else + { + _pcs[i] = _stpInstanceNullPerformanceCounter; + } + } + } + + + public void Close() + { + if (null != _pcs) + { + for (int i = 0; i < _pcs.Length; i++) + { + if (null != _pcs[i]) + { + _pcs[i].Dispose(); + } + } + _pcs = null; + } + } + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + Close(); + } + } + _isDisposed = true; + } + + private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType) + { + return _pcs[(int) spcType]; + } + + public void SampleThreads(long activeThreads, long inUseThreads) + { + GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads); + GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads); + GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads); + + GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads); + GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads); + } + + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) + { + GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed); + GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued); + GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed); + + GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued); + GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed); + } + + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) + { + GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds); + GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment(); + } + + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) + { + GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds); + GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment(); + } + } +#endif + + internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader + { + private static readonly NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(); + + public static NullSTPInstancePerformanceCounters Instance + { + get { return _instance; } + } + + public void Close() {} + public void Dispose() {} + + public void SampleThreads(long activeThreads, long inUseThreads) {} + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {} + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {} + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {} + public long InUseThreads + { + get { return 0; } + } + + public long ActiveThreads + { + get { return 0; } + } + + public long WorkItemsQueued + { + get { return 0; } + } + + public long WorkItemsProcessed + { + get { return 0; } + } + } + + internal class LocalSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, ISTPPerformanceCountersReader + { + public void Close() { } + public void Dispose() { } + + private long _activeThreads; + private long _inUseThreads; + private long _workItemsQueued; + private long _workItemsProcessed; + + public long InUseThreads + { + get { return _inUseThreads; } + } + + public long ActiveThreads + { + get { return _activeThreads; } + } + + public long WorkItemsQueued + { + get { return _workItemsQueued; } + } + + public long WorkItemsProcessed + { + get { return _workItemsProcessed; } + } + + public void SampleThreads(long activeThreads, long inUseThreads) + { + _activeThreads = activeThreads; + _inUseThreads = inUseThreads; + } + + public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) + { + _workItemsQueued = workItemsQueued; + _workItemsProcessed = workItemsProcessed; + } + + public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) + { + // Not supported + } + + public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) + { + // Not supported + } + } +} diff --git a/ThirdParty/SmartThreadPool/STPStartInfo.cs b/ThirdParty/SmartThreadPool/STPStartInfo.cs index 2ec8dc6..96fa094 100644 --- a/ThirdParty/SmartThreadPool/STPStartInfo.cs +++ b/ThirdParty/SmartThreadPool/STPStartInfo.cs @@ -1,212 +1,212 @@ -using System; -using System.Threading; - -namespace Amib.Threading -{ - /// - /// Summary description for STPStartInfo. - /// - public class STPStartInfo : WIGStartInfo - { - private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout; - private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; - private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; -#if !(WINDOWS_PHONE) - private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority; -#endif - private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; - private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground; - private bool _enableLocalPerformanceCounters; - private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName; - private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize; - - public STPStartInfo() - { - _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; -#if !(WINDOWS_PHONE) - _threadPriority = SmartThreadPool.DefaultThreadPriority; -#endif - _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; - _idleTimeout = SmartThreadPool.DefaultIdleTimeout; - _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; - } - - public STPStartInfo(STPStartInfo stpStartInfo) - : base(stpStartInfo) - { - _idleTimeout = stpStartInfo.IdleTimeout; - _minWorkerThreads = stpStartInfo.MinWorkerThreads; - _maxWorkerThreads = stpStartInfo.MaxWorkerThreads; -#if !(WINDOWS_PHONE) - _threadPriority = stpStartInfo.ThreadPriority; -#endif - _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName; - _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters; - _threadPoolName = stpStartInfo._threadPoolName; - _areThreadsBackground = stpStartInfo.AreThreadsBackground; -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - _apartmentState = stpStartInfo._apartmentState; -#endif - } - - /// - /// Get/Set the idle timeout in milliseconds. - /// If a thread is idle (starved) longer than IdleTimeout then it may quit. - /// - public virtual int IdleTimeout - { - get { return _idleTimeout; } - set - { - ThrowIfReadOnly(); - _idleTimeout = value; - } - } - - - /// - /// Get/Set the lower limit of threads in the pool. - /// - public virtual int MinWorkerThreads - { - get { return _minWorkerThreads; } - set - { - ThrowIfReadOnly(); - _minWorkerThreads = value; - } - } - - - /// - /// Get/Set the upper limit of threads in the pool. - /// - public virtual int MaxWorkerThreads - { - get { return _maxWorkerThreads; } - set - { - ThrowIfReadOnly(); - _maxWorkerThreads = value; - } - } - -#if !(WINDOWS_PHONE) - /// - /// Get/Set the scheduling priority of the threads in the pool. - /// The Os handles the scheduling. - /// - public virtual ThreadPriority ThreadPriority - { - get { return _threadPriority; } - set - { - ThrowIfReadOnly(); - _threadPriority = value; - } - } -#endif - /// - /// Get/Set the thread pool name. Threads will get names depending on this. - /// - public virtual string ThreadPoolName { - get { return _threadPoolName; } - set - { - ThrowIfReadOnly (); - _threadPoolName = value; - } - } - - /// - /// Get/Set the performance counter instance name of this SmartThreadPool - /// The default is null which indicate not to use performance counters at all. - /// - public virtual string PerformanceCounterInstanceName - { - get { return _performanceCounterInstanceName; } - set - { - ThrowIfReadOnly(); - _performanceCounterInstanceName = value; - } - } - - /// - /// Enable/Disable the local performance counter. - /// This enables the user to get some performance information about the SmartThreadPool - /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.) - /// The default is false. - /// - public virtual bool EnableLocalPerformanceCounters - { - get { return _enableLocalPerformanceCounters; } - set - { - ThrowIfReadOnly(); - _enableLocalPerformanceCounters = value; - } - } - - /// - /// Get/Set backgroundness of thread in thread pool. - /// - public virtual bool AreThreadsBackground - { - get { return _areThreadsBackground; } - set - { - ThrowIfReadOnly (); - _areThreadsBackground = value; - } - } - - /// - /// Get a readonly version of this STPStartInfo. - /// - /// Returns a readonly reference to this STPStartInfo - public new STPStartInfo AsReadOnly() - { - return new STPStartInfo(this) { _readOnly = true }; - } - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - - private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState; - - /// - /// Get/Set the apartment state of threads in the thread pool - /// - public ApartmentState ApartmentState - { - get { return _apartmentState; } - set - { - ThrowIfReadOnly(); - _apartmentState = value; - } - } - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - - /// - /// Get/Set the max stack size of threads in the thread pool - /// - public int? MaxStackSize - { - get { return _maxStackSize; } - set - { - ThrowIfReadOnly(); - if (value.HasValue && value.Value < 0) - { - throw new ArgumentOutOfRangeException("value", "Value must be greater than 0."); - } - _maxStackSize = value; - } - } -#endif - -#endif - } -} +using System; +using System.Threading; + +namespace Amib.Threading +{ + /// + /// Summary description for STPStartInfo. + /// + public class STPStartInfo : WIGStartInfo + { + private int _idleTimeout = SmartThreadPool.DefaultIdleTimeout; + private int _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; + private int _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; +#if !(WINDOWS_PHONE) + private ThreadPriority _threadPriority = SmartThreadPool.DefaultThreadPriority; +#endif + private string _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; + private bool _areThreadsBackground = SmartThreadPool.DefaultAreThreadsBackground; + private bool _enableLocalPerformanceCounters; + private string _threadPoolName = SmartThreadPool.DefaultThreadPoolName; + private int? _maxStackSize = SmartThreadPool.DefaultMaxStackSize; + + public STPStartInfo() + { + _performanceCounterInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName; +#if !(WINDOWS_PHONE) + _threadPriority = SmartThreadPool.DefaultThreadPriority; +#endif + _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads; + _idleTimeout = SmartThreadPool.DefaultIdleTimeout; + _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads; + } + + public STPStartInfo(STPStartInfo stpStartInfo) + : base(stpStartInfo) + { + _idleTimeout = stpStartInfo.IdleTimeout; + _minWorkerThreads = stpStartInfo.MinWorkerThreads; + _maxWorkerThreads = stpStartInfo.MaxWorkerThreads; +#if !(WINDOWS_PHONE) + _threadPriority = stpStartInfo.ThreadPriority; +#endif + _performanceCounterInstanceName = stpStartInfo.PerformanceCounterInstanceName; + _enableLocalPerformanceCounters = stpStartInfo._enableLocalPerformanceCounters; + _threadPoolName = stpStartInfo._threadPoolName; + _areThreadsBackground = stpStartInfo.AreThreadsBackground; +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + _apartmentState = stpStartInfo._apartmentState; +#endif + } + + /// + /// Get/Set the idle timeout in milliseconds. + /// If a thread is idle (starved) longer than IdleTimeout then it may quit. + /// + public virtual int IdleTimeout + { + get { return _idleTimeout; } + set + { + ThrowIfReadOnly(); + _idleTimeout = value; + } + } + + + /// + /// Get/Set the lower limit of threads in the pool. + /// + public virtual int MinWorkerThreads + { + get { return _minWorkerThreads; } + set + { + ThrowIfReadOnly(); + _minWorkerThreads = value; + } + } + + + /// + /// Get/Set the upper limit of threads in the pool. + /// + public virtual int MaxWorkerThreads + { + get { return _maxWorkerThreads; } + set + { + ThrowIfReadOnly(); + _maxWorkerThreads = value; + } + } + +#if !(WINDOWS_PHONE) + /// + /// Get/Set the scheduling priority of the threads in the pool. + /// The Os handles the scheduling. + /// + public virtual ThreadPriority ThreadPriority + { + get { return _threadPriority; } + set + { + ThrowIfReadOnly(); + _threadPriority = value; + } + } +#endif + /// + /// Get/Set the thread pool name. Threads will get names depending on this. + /// + public virtual string ThreadPoolName { + get { return _threadPoolName; } + set + { + ThrowIfReadOnly (); + _threadPoolName = value; + } + } + + /// + /// Get/Set the performance counter instance name of this SmartThreadPool + /// The default is null which indicate not to use performance counters at all. + /// + public virtual string PerformanceCounterInstanceName + { + get { return _performanceCounterInstanceName; } + set + { + ThrowIfReadOnly(); + _performanceCounterInstanceName = value; + } + } + + /// + /// Enable/Disable the local performance counter. + /// This enables the user to get some performance information about the SmartThreadPool + /// without using Windows performance counters. (Useful on WindowsCE, Silverlight, etc.) + /// The default is false. + /// + public virtual bool EnableLocalPerformanceCounters + { + get { return _enableLocalPerformanceCounters; } + set + { + ThrowIfReadOnly(); + _enableLocalPerformanceCounters = value; + } + } + + /// + /// Get/Set backgroundness of thread in thread pool. + /// + public virtual bool AreThreadsBackground + { + get { return _areThreadsBackground; } + set + { + ThrowIfReadOnly (); + _areThreadsBackground = value; + } + } + + /// + /// Get a readonly version of this STPStartInfo. + /// + /// Returns a readonly reference to this STPStartInfo + public new STPStartInfo AsReadOnly() + { + return new STPStartInfo(this) { _readOnly = true }; + } + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + private ApartmentState _apartmentState = SmartThreadPool.DefaultApartmentState; + + /// + /// Get/Set the apartment state of threads in the thread pool + /// + public ApartmentState ApartmentState + { + get { return _apartmentState; } + set + { + ThrowIfReadOnly(); + _apartmentState = value; + } + } + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + + /// + /// Get/Set the max stack size of threads in the thread pool + /// + public int? MaxStackSize + { + get { return _maxStackSize; } + set + { + ThrowIfReadOnly(); + if (value.HasValue && value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", "Value must be greater than 0."); + } + _maxStackSize = value; + } + } +#endif + +#endif + } +} diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs index ba7d73f..d9502bb 100644 --- a/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.ThreadEntry.cs @@ -1,60 +1,60 @@ - -using System; -using Amib.Threading.Internal; - -namespace Amib.Threading -{ - public partial class SmartThreadPool - { - #region ThreadEntry class - - internal class ThreadEntry - { - /// - /// The thread creation time - /// The value is stored as UTC value. - /// - private readonly DateTime _creationTime; - - /// - /// The last time this thread has been running - /// It is updated by IAmAlive() method - /// The value is stored as UTC value. - /// - private DateTime _lastAliveTime; - - /// - /// A reference from each thread in the thread pool to its SmartThreadPool - /// object container. - /// With this variable a thread can know whatever it belongs to a - /// SmartThreadPool. - /// - private readonly SmartThreadPool _associatedSmartThreadPool; - - /// - /// A reference to the current work item a thread from the thread pool - /// is executing. - /// - public WorkItem CurrentWorkItem { get; set; } - - public ThreadEntry(SmartThreadPool stp) - { - _associatedSmartThreadPool = stp; - _creationTime = DateTime.UtcNow; - _lastAliveTime = DateTime.MinValue; - } - - public SmartThreadPool AssociatedSmartThreadPool - { - get { return _associatedSmartThreadPool; } - } - - public void IAmAlive() - { - _lastAliveTime = DateTime.UtcNow; - } - } - - #endregion - } + +using System; +using Amib.Threading.Internal; + +namespace Amib.Threading +{ + public partial class SmartThreadPool + { + #region ThreadEntry class + + internal class ThreadEntry + { + /// + /// The thread creation time + /// The value is stored as UTC value. + /// + private readonly DateTime _creationTime; + + /// + /// The last time this thread has been running + /// It is updated by IAmAlive() method + /// The value is stored as UTC value. + /// + private DateTime _lastAliveTime; + + /// + /// A reference from each thread in the thread pool to its SmartThreadPool + /// object container. + /// With this variable a thread can know whatever it belongs to a + /// SmartThreadPool. + /// + private readonly SmartThreadPool _associatedSmartThreadPool; + + /// + /// A reference to the current work item a thread from the thread pool + /// is executing. + /// + public WorkItem CurrentWorkItem { get; set; } + + public ThreadEntry(SmartThreadPool stp) + { + _associatedSmartThreadPool = stp; + _creationTime = DateTime.UtcNow; + _lastAliveTime = DateTime.MinValue; + } + + public SmartThreadPool AssociatedSmartThreadPool + { + get { return _associatedSmartThreadPool; } + } + + public void IAmAlive() + { + _lastAliveTime = DateTime.UtcNow; + } + } + + #endregion + } } \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/SmartThreadPool.cs b/ThirdParty/SmartThreadPool/SmartThreadPool.cs index 9256777..a4f4ce5 100644 --- a/ThirdParty/SmartThreadPool/SmartThreadPool.cs +++ b/ThirdParty/SmartThreadPool/SmartThreadPool.cs @@ -1,1732 +1,1732 @@ -#region Release History - -// Smart Thread Pool -// 7 Aug 2004 - Initial release -// -// 14 Sep 2004 - Bug fixes -// -// 15 Oct 2004 - Added new features -// - Work items return result. -// - Support waiting synchronization for multiple work items. -// - Work items can be cancelled. -// - Passage of the caller thread’s context to the thread in the pool. -// - Minimal usage of WIN32 handles. -// - Minor bug fixes. -// -// 26 Dec 2004 - Changes: -// - Removed static constructors. -// - Added finalizers. -// - Changed Exceptions so they are serializable. -// - Fixed the bug in one of the SmartThreadPool constructors. -// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. -// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. -// - Added PostExecute with options on which cases to call it. -// - Added option to dispose of the state objects. -// - Added a WaitForIdle() method that waits until the work items queue is empty. -// - Added an STPStartInfo class for the initialization of the thread pool. -// - Changed exception handling so if a work item throws an exception it -// is rethrown at GetResult(), rather then firing an UnhandledException event. -// Note that PostExecute exception are always ignored. -// -// 25 Mar 2005 - Changes: -// - Fixed lost of work items bug -// -// 3 Jul 2005: Changes. -// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. -// -// 16 Aug 2005: Changes. -// - Fixed bug where the InUseThreads becomes negative when canceling work items. -// -// 31 Jan 2006 - Changes: -// - Added work items priority -// - Removed support of chained delegates in callbacks and post executes (nobody really use this) -// - Added work items groups -// - Added work items groups idle event -// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array -// it returns true rather then throwing an exception. -// - Added option to start the STP and the WIG as suspended -// - Exception behavior changed, the real exception is returned by an -// inner exception -// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) -// - Added performance counters -// - Added priority to the threads in the pool -// -// 13 Feb 2006 - Changes: -// - Added a call to the dispose of the Performance Counter so -// their won't be a Performance Counter leak. -// - Added exception catch in case the Performance Counters cannot -// be created. -// -// 17 May 2008 - Changes: -// - Changed the dispose behavior and removed the Finalizers. -// - Enabled the change of the MaxThreads and MinThreads at run time. -// - Enabled the change of the Concurrency of a IWorkItemsGroup at run -// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency -// refers to the MaxThreads. -// - Improved the cancel behavior. -// - Added events for thread creation and termination. -// - Fixed the HttpContext context capture. -// - Changed internal collections so they use generic collections -// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup -// - Added support for WinCE -// - Added support for Action and Func -// -// 07 April 2009 - Changes: -// - Added support for Silverlight and Mono -// - Added Join, Choice, and Pipe to SmartThreadPool. -// - Added local performance counters (for Mono, Silverlight, and WindowsCE) -// - Changed duration measures from DateTime.Now to Stopwatch. -// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList. -// -// 21 December 2009 - Changes: -// - Added work item timeout (passive) -// -// 20 August 2012 - Changes: -// - Added set name to threads -// - Fixed the WorkItemsQueue.Dequeue. -// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } -// - Fixed SmartThreadPool.Pipe -// - Added IsBackground option to threads -// - Added ApartmentState to threads -// - Fixed thread creation when queuing many work items at the same time. -// -// 24 August 2012 - Changes: -// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan -// - Added option to set MaxStackSize of threads - -#endregion - -using System; -using System.Security; -using System.Threading; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -using Amib.Threading.Internal; - -namespace Amib.Threading -{ - #region SmartThreadPool class - /// - /// Smart thread pool class. - /// - public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable - { - #region Public Default Constants - - /// - /// Default minimum number of threads the thread pool contains. (0) - /// - public const int DefaultMinWorkerThreads = 0; - - /// - /// Default maximum number of threads the thread pool contains. (25) - /// - public const int DefaultMaxWorkerThreads = 25; - - /// - /// Default idle timeout in milliseconds. (One minute) - /// - public const int DefaultIdleTimeout = 60*1000; // One minute - - /// - /// Indicate to copy the security context of the caller and then use it in the call. (false) - /// - public const bool DefaultUseCallerCallContext = false; - - /// - /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) - /// - public const bool DefaultUseCallerHttpContext = false; - - /// - /// Indicate to dispose of the state objects if they support the IDispose interface. (false) - /// - public const bool DefaultDisposeOfStateObjects = false; - - /// - /// The default option to run the post execute (CallToPostExecute.Always) - /// - public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; - - /// - /// The default post execute method to run. (None) - /// When null it means not to call it. - /// - public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; - - /// - /// The default work item priority (WorkItemPriority.Normal) - /// - public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; - - /// - /// The default is to work on work items as soon as they arrive - /// and not to wait for the start. (false) - /// - public const bool DefaultStartSuspended = false; - - /// - /// The default name to use for the performance counters instance. (null) - /// - public static readonly string DefaultPerformanceCounterInstanceName; - -#if !(WINDOWS_PHONE) - - /// - /// The default thread priority (ThreadPriority.Normal) - /// - public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; -#endif - /// - /// The default thread pool name. (SmartThreadPool) - /// - public const string DefaultThreadPoolName = "SmartThreadPool"; - - /// - /// The default Max Stack Size. (SmartThreadPool) - /// - public static readonly int? DefaultMaxStackSize = null; - - /// - /// The default fill state with params. (false) - /// It is relevant only to QueueWorkItem of Action<...>/Func<...> - /// - public const bool DefaultFillStateWithArgs = false; - - /// - /// The default thread backgroundness. (true) - /// - public const bool DefaultAreThreadsBackground = true; - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - /// - /// The default apartment state of a thread in the thread pool. - /// The default is ApartmentState.Unknown which means the STP will not - /// set the apartment of the thread. It will use the .NET default. - /// - public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; -#endif - - #endregion - - #region Member Variables - - /// - /// Dictionary of all the threads in the thread pool. - /// - private readonly SynchronizedDictionary _workerThreads = new SynchronizedDictionary(); - - /// - /// Queue of work items. - /// - private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); - - /// - /// Count the work items handled. - /// Used by the performance counter. - /// - private int _workItemsProcessed; - - /// - /// Number of threads that currently work (not idle). - /// - private int _inUseWorkerThreads; - - /// - /// Stores a copy of the original STPStartInfo. - /// It is used to change the MinThread and MaxThreads - /// - private STPStartInfo _stpStartInfo; - - /// - /// Total number of work items that are stored in the work items queue - /// plus the work items that the threads in the pool are working on. - /// - private int _currentWorkItemsCount; - - /// - /// Signaled when the thread pool is idle, i.e. no thread is busy - /// and the work items queue is empty - /// - //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); - private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); - - /// - /// An event to signal all the threads to quit immediately. - /// - //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); - private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); - - /// - /// A flag to indicate if the Smart Thread Pool is now suspended. - /// - private bool _isSuspended; - - /// - /// A flag to indicate the threads to quit. - /// - private bool _shutdown; - - /// - /// Counts the threads created in the pool. - /// It is used to name the threads. - /// - private int _threadCounter; - - /// - /// Indicate that the SmartThreadPool has been disposed - /// - private bool _isDisposed; - - /// - /// Holds all the WorkItemsGroup instaces that have at least one - /// work item int the SmartThreadPool - /// This variable is used in case of Shutdown - /// - private readonly SynchronizedDictionary _workItemsGroups = new SynchronizedDictionary(); - - /// - /// A common object for all the work items int the STP - /// so we can mark them to cancel in O(1) - /// - private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup(); - - /// - /// Windows STP performance counters - /// - private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance; - - /// - /// Local STP performance counters - /// - private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; - - -#if (WINDOWS_PHONE) - private static readonly Dictionary _threadEntries = new Dictionary(); -#elif (_WINDOWS_CE) - private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); -#else - [ThreadStatic] - private static ThreadEntry _threadEntry; - -#endif - - /// - /// An event to call after a thread is created, but before - /// it's first use. - /// - private event ThreadInitializationHandler _onThreadInitialization; - - /// - /// An event to call when a thread is about to exit, after - /// it is no longer belong to the pool. - /// - private event ThreadTerminationHandler _onThreadTermination; - - #endregion - - #region Per thread properties - - /// - /// A reference to the current work item a thread from the thread pool - /// is executing. - /// - internal static ThreadEntry CurrentThreadEntry - { -#if (WINDOWS_PHONE) - get - { - lock(_threadEntries) - { - ThreadEntry threadEntry; - if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry)) - { - return threadEntry; - } - } - return null; - } - set - { - lock(_threadEntries) - { - _threadEntries[Thread.CurrentThread.ManagedThreadId] = value; - } - } -#elif (_WINDOWS_CE) - get - { - //Thread.CurrentThread.ManagedThreadId - return Thread.GetData(_threadEntrySlot) as ThreadEntry; - } - set - { - Thread.SetData(_threadEntrySlot, value); - } -#else - get - { - return _threadEntry; - } - set - { - _threadEntry = value; - } -#endif - } - #endregion - - #region Construction and Finalization - - /// - /// Constructor - /// - public SmartThreadPool() - { - _stpStartInfo = new STPStartInfo(); - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - public SmartThreadPool(int idleTimeout) - { - _stpStartInfo = new STPStartInfo - { - IdleTimeout = idleTimeout, - }; - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - /// Upper limit of threads in the pool - public SmartThreadPool( - int idleTimeout, - int maxWorkerThreads) - { - _stpStartInfo = new STPStartInfo - { - IdleTimeout = idleTimeout, - MaxWorkerThreads = maxWorkerThreads, - }; - Initialize(); - } - - /// - /// Constructor - /// - /// Idle timeout in milliseconds - /// Upper limit of threads in the pool - /// Lower limit of threads in the pool - public SmartThreadPool( - int idleTimeout, - int maxWorkerThreads, - int minWorkerThreads) - { - _stpStartInfo = new STPStartInfo - { - IdleTimeout = idleTimeout, - MaxWorkerThreads = maxWorkerThreads, - MinWorkerThreads = minWorkerThreads, - }; - Initialize(); - } - - /// - /// Constructor - /// - /// A SmartThreadPool configuration that overrides the default behavior - public SmartThreadPool(STPStartInfo stpStartInfo) - { - _stpStartInfo = new STPStartInfo(stpStartInfo); - Initialize(); - } - - private void Initialize() - { - Name = _stpStartInfo.ThreadPoolName; - ValidateSTPStartInfo(); - - // _stpStartInfoRW stores a read/write copy of the STPStartInfo. - // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten - - _isSuspended = _stpStartInfo.StartSuspended; - -#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) - if (null != _stpStartInfo.PerformanceCounterInstanceName) - { - throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); - } -#else - if (null != _stpStartInfo.PerformanceCounterInstanceName) - { - try - { - _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); - } - catch (Exception e) - { - Debug.WriteLine("Unable to create Performance Counters: " + e); - _windowsPCs = NullSTPInstancePerformanceCounters.Instance; - } - } -#endif - - if (_stpStartInfo.EnableLocalPerformanceCounters) - { - _localPCs = new LocalSTPInstancePerformanceCounters(); - } - - // If the STP is not started suspended then start the threads. - if (!_isSuspended) - { - StartOptimalNumberOfThreads(); - } - } - - private void StartOptimalNumberOfThreads() - { - int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); - threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); - threadsCount -= _workerThreads.Count; - if (threadsCount > 0) - { - StartThreads(threadsCount); - } - } - - private void ValidateSTPStartInfo() - { - if (_stpStartInfo.MinWorkerThreads < 0) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads", "MinWorkerThreads cannot be negative"); - } - - if (_stpStartInfo.MaxWorkerThreads <= 0) - { - throw new ArgumentOutOfRangeException( - "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); - } - - if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) - { - throw new ArgumentOutOfRangeException( - "MinWorkerThreads, maxWorkerThreads", - "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); - } - } - - private static void ValidateCallback(Delegate callback) - { - if(callback.GetInvocationList().Length > 1) - { - throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); - } - } - - #endregion - - #region Thread Processing - - /// - /// Waits on the queue for a work item, shutdown, or timeout. - /// - /// - /// Returns the WaitingCallback or null in case of timeout or shutdown. - /// - private WorkItem Dequeue() - { - WorkItem workItem = - _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); - - return workItem; - } - - /// - /// Put a new work item in the queue - /// - /// A work item to queue - internal override void Enqueue(WorkItem workItem) - { - // Make sure the workItem is not null - Debug.Assert(null != workItem); - - IncrementWorkItemsCount(); - - workItem.CanceledSmartThreadPool = _canceledSmartThreadPool; - _workItemsQueue.EnqueueWorkItem(workItem); - workItem.WorkItemIsQueued(); - - // If all the threads are busy then try to create a new one - if (_currentWorkItemsCount > _workerThreads.Count) - { - StartThreads(1); - } - } - - private void IncrementWorkItemsCount() - { - _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - - int count = Interlocked.Increment(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 1) - { - IsIdle = false; - _isIdleWaitHandle.Reset(); - } - } - - private void DecrementWorkItemsCount() - { - int count = Interlocked.Decrement(ref _currentWorkItemsCount); - //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); - if (count == 0) - { - IsIdle = true; - _isIdleWaitHandle.Set(); - } - - Interlocked.Increment(ref _workItemsProcessed); - - if (!_shutdown) - { - // The counter counts even if the work item was cancelled - _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); - } - - } - - internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) - { - _workItemsGroups[workItemsGroup] = workItemsGroup; - } - - internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) - { - if (_workItemsGroups.Contains(workItemsGroup)) - { - _workItemsGroups.Remove(workItemsGroup); - } - } - - /// - /// Inform that the current thread is about to quit or quiting. - /// The same thread may call this method more than once. - /// - private void InformCompleted() - { - // There is no need to lock the two methods together - // since only the current thread removes itself - // and the _workerThreads is a synchronized dictionary - if (_workerThreads.Contains(Thread.CurrentThread)) - { - _workerThreads.Remove(Thread.CurrentThread); - _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - - /// - /// Starts new threads - /// - /// The number of threads to start - private void StartThreads(int threadsCount) - { - if (_isSuspended) - { - return; - } - - lock(_workerThreads.SyncRoot) - { - // Don't start threads on shut down - if (_shutdown) - { - return; - } - - for(int i = 0; i < threadsCount; ++i) - { - // Don't create more threads then the upper limit - if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) - { - return; - } - - // Create a new thread - -#if (_SILVERLIGHT) || (WINDOWS_PHONE) - Thread workerThread = new Thread(ProcessQueuedItems); -#else - Thread workerThread = - _stpStartInfo.MaxStackSize.HasValue - ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value) - : new Thread(ProcessQueuedItems); -#endif - // Configure the new thread and start it - workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; - workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; - -#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) - if (_stpStartInfo.ApartmentState != ApartmentState.Unknown) - { - workerThread.SetApartmentState(_stpStartInfo.ApartmentState); - } -#endif - -#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) - workerThread.Priority = _stpStartInfo.ThreadPriority; -#endif - workerThread.Start(); - ++_threadCounter; - - // Add it to the dictionary and update its creation time. - _workerThreads[workerThread] = new ThreadEntry(this); - - _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); - } - } - } - - /// - /// A worker thread method that processes work items from the work items queue. - /// - private void ProcessQueuedItems() - { - // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks - // of the dictionary. - CurrentThreadEntry = _workerThreads[Thread.CurrentThread]; - - FireOnThreadInitialization(); - - try - { - bool bInUseWorkerThreadsWasIncremented = false; - - // Process until shutdown. - while(!_shutdown) - { - // Update the last time this thread was seen alive. - // It's good for debugging. - CurrentThreadEntry.IAmAlive(); - - // The following block handles the when the MaxWorkerThreads has been - // incremented by the user at run-time. - // Double lock for quit. - if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) - { - lock (_workerThreads.SyncRoot) - { - if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) - { - // Inform that the thread is quiting and then quit. - // This method must be called within this lock or else - // more threads will quit and the thread pool will go - // below the lower limit. - InformCompleted(); - break; - } - } - } - - // Wait for a work item, shutdown, or timeout - WorkItem workItem = Dequeue(); - - // Update the last time this thread was seen alive. - // It's good for debugging. - CurrentThreadEntry.IAmAlive(); - - // On timeout or shut down. - if (null == workItem) - { - // Double lock for quit. - if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - lock(_workerThreads.SyncRoot) - { - if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) - { - // Inform that the thread is quiting and then quit. - // This method must be called within this lock or else - // more threads will quit and the thread pool will go - // below the lower limit. - InformCompleted(); - break; - } - } - } - } - - // If we didn't quit then skip to the next iteration. - if (null == workItem) - { - continue; - } - - try - { - // Initialize the value to false - bInUseWorkerThreadsWasIncremented = false; - - // Set the Current Work Item of the thread. - // Store the Current Work Item before the workItem.StartingWorkItem() is called, - // so WorkItem.Cancel can work when the work item is between InQueue and InProgress - // states. - // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() - // (work item is in InQueue state) then workItem.StartingWorkItem() will return false. - // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then - // (work item is in InProgress state) then the thread will be aborted - CurrentThreadEntry.CurrentWorkItem = workItem; - - // Change the state of the work item to 'in progress' if possible. - // We do it here so if the work item has been canceled we won't - // increment the _inUseWorkerThreads. - // The cancel mechanism doesn't delete items from the queue, - // it marks the work item as canceled, and when the work item - // is dequeued, we just skip it. - // If the post execute of work item is set to always or to - // call when the work item is canceled then the StartingWorkItem() - // will return true, so the post execute can run. - if (!workItem.StartingWorkItem()) - { - continue; - } - - // Execute the callback. Make sure to accurately - // record how many callbacks are currently executing. - int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); - _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - - // Mark that the _inUseWorkerThreads incremented, so in the finally{} - // statement we will decrement it correctly. - bInUseWorkerThreadsWasIncremented = true; - - workItem.FireWorkItemStarted(); - - ExecuteWorkItem(workItem); - } - catch(Exception ex) - { - ex.GetHashCode(); - // Do nothing - } - finally - { - workItem.DisposeOfState(); - - // Set the CurrentWorkItem to null, since we - // no longer run user's code. - CurrentThreadEntry.CurrentWorkItem = null; - - // Decrement the _inUseWorkerThreads only if we had - // incremented it. Note the cancelled work items don't - // increment _inUseWorkerThreads. - if (bInUseWorkerThreadsWasIncremented) - { - int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); - _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); - } - - // Notify that the work item has been completed. - // WorkItemsGroup may enqueue their next work item. - workItem.FireWorkItemCompleted(); - - // Decrement the number of work items here so the idle - // ManualResetEvent won't fluctuate. - DecrementWorkItemsCount(); - } - } - } - catch(ThreadAbortException tae) - { - tae.GetHashCode(); - // Handle the abort exception gracfully. -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - Thread.ResetAbort(); -#endif - } - catch(Exception e) - { - Debug.Assert(null != e); - } - finally - { - InformCompleted(); - FireOnThreadTermination(); - } - } - - private void ExecuteWorkItem(WorkItem workItem) - { - _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); - _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); - try - { - workItem.Execute(); - } - finally - { - _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); - _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); - } - } - - - #endregion - - #region Public Methods - - private void ValidateWaitForIdle() - { - if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this) - { - throw new NotSupportedException( - "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); - } - } - - internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) - { - if (null == CurrentThreadEntry) - { - return; - } - - WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; - ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); - if ((null != workItemsGroup) && - (null != workItem) && - CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) - { - throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) - { - if ((null != workItemsGroup) && - (null != workItem) && - workItem.WasQueuedBy(workItemsGroup)) - { - throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); - } - } - - /// - /// Force the SmartThreadPool to shutdown - /// - public void Shutdown() - { - Shutdown(true, 0); - } - - /// - /// Force the SmartThreadPool to shutdown with timeout - /// - public void Shutdown(bool forceAbort, TimeSpan timeout) - { - Shutdown(forceAbort, (int)timeout.TotalMilliseconds); - } - - /// - /// Empties the queue of work items and abort the threads in the pool. - /// - public void Shutdown(bool forceAbort, int millisecondsTimeout) - { - ValidateNotDisposed(); - - ISTPInstancePerformanceCounters pcs = _windowsPCs; - - if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) - { - // Set the _pcs to "null" to stop updating the performance - // counters - _windowsPCs = NullSTPInstancePerformanceCounters.Instance; - - pcs.Dispose(); - } - - Thread [] threads; - lock(_workerThreads.SyncRoot) - { - // Shutdown the work items queue - _workItemsQueue.Dispose(); - - // Signal the threads to exit - _shutdown = true; - _shuttingDownEvent.Set(); - - // Make a copy of the threads' references in the pool - threads = new Thread [_workerThreads.Count]; - _workerThreads.Keys.CopyTo(threads, 0); - } - - int millisecondsLeft = millisecondsTimeout; - Stopwatch stopwatch = Stopwatch.StartNew(); - //DateTime start = DateTime.UtcNow; - bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); - bool timeout = false; - - // Each iteration we update the time left for the timeout. - foreach(Thread thread in threads) - { - // Join don't work with negative numbers - if (!waitInfinitely && (millisecondsLeft < 0)) - { - timeout = true; - break; - } - - // Wait for the thread to terminate - bool success = thread.Join(millisecondsLeft); - if(!success) - { - timeout = true; - break; - } - - if(!waitInfinitely) - { - // Update the time left to wait - //TimeSpan ts = DateTime.UtcNow - start; - millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; - } - } - - if (timeout && forceAbort) - { - // Abort the threads in the pool - foreach(Thread thread in threads) - { - - if ((thread != null) -#if !(_WINDOWS_CE) - && thread.IsAlive -#endif - ) - { - try - { - thread.Abort(); // Shutdown - } - catch(SecurityException e) - { - e.GetHashCode(); - } - catch(ThreadStateException ex) - { - ex.GetHashCode(); - // In case the thread has been terminated - // after the check if it is alive. - } - } - } - } - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult [] waitableResults) - { - return WaitAll(waitableResults, Timeout.Infinite, true); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult [] waitableResults, - TimeSpan timeout, - bool exitContext) - { - return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult[] waitableResults, - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult [] waitableResults, - int millisecondsTimeout, - bool exitContext) - { - return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); - } - - /// - /// Wait for all work items to complete - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// true when every work item in workItemResults has completed; otherwise false. - /// - public static bool WaitAll( - IWaitableResult[] waitableResults, - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } - - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. - /// - public static int WaitAny( - IWaitableResult [] waitableResults) - { - return WaitAny(waitableResults, Timeout.Infinite, true); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWaitableResult[] waitableResults, - TimeSpan timeout, - bool exitContext) - { - return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWaitableResult [] waitableResults, - TimeSpan timeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWaitableResult [] waitableResults, - int millisecondsTimeout, - bool exitContext) - { - return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); - } - - /// - /// Waits for any of the work items in the specified array to complete, cancel, or timeout - /// - /// Array of work item result objects - /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. - /// - /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. - /// - /// A cancel wait handle to interrupt the wait if needed - /// - /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. - /// - public static int WaitAny( - IWaitableResult [] waitableResults, - int millisecondsTimeout, - bool exitContext, - WaitHandle cancelWaitHandle) - { - return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); - } - - /// - /// Creates a new WorkItemsGroup. - /// - /// The number of work items that can be run concurrently - /// A reference to the WorkItemsGroup - public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) - { - IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); - return workItemsGroup; - } - - /// - /// Creates a new WorkItemsGroup. - /// - /// The number of work items that can be run concurrently - /// A WorkItemsGroup configuration that overrides the default behavior - /// A reference to the WorkItemsGroup - public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) - { - IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); - return workItemsGroup; - } - - #region Fire Thread's Events - - private void FireOnThreadInitialization() - { - if (null != _onThreadInitialization) - { - foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList()) - { - try - { - tih(); - } - catch (Exception e) - { - e.GetHashCode(); - Debug.Assert(false); - throw; - } - } - } - } - - private void FireOnThreadTermination() - { - if (null != _onThreadTermination) - { - foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList()) - { - try - { - tth(); - } - catch (Exception e) - { - e.GetHashCode(); - Debug.Assert(false); - throw; - } - } - } - } - - #endregion - - /// - /// This event is fired when a thread is created. - /// Use it to initialize a thread before the work items use it. - /// - public event ThreadInitializationHandler OnThreadInitialization - { - add { _onThreadInitialization += value; } - remove { _onThreadInitialization -= value; } - } - - /// - /// This event is fired when a thread is terminating. - /// Use it for cleanup. - /// - public event ThreadTerminationHandler OnThreadTermination - { - add { _onThreadTermination += value; } - remove { _onThreadTermination -= value; } - } - - - internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig) - { - foreach (ThreadEntry threadEntry in _workerThreads.Values) - { - WorkItem workItem = threadEntry.CurrentWorkItem; - if (null != workItem && - workItem.WasQueuedBy(wig) && - !workItem.IsCanceled) - { - threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); - } - } - } - - - - #endregion - - #region Properties - - /// - /// Get/Set the lower limit of threads in the pool. - /// - public int MinThreads - { - get - { - ValidateNotDisposed(); - return _stpStartInfo.MinWorkerThreads; - } - set - { - Debug.Assert(value >= 0); - Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads); - if (_stpStartInfo.MaxWorkerThreads < value) - { - _stpStartInfo.MaxWorkerThreads = value; - } - _stpStartInfo.MinWorkerThreads = value; - StartOptimalNumberOfThreads(); - } - } - - /// - /// Get/Set the upper limit of threads in the pool. - /// - public int MaxThreads - { - get - { - ValidateNotDisposed(); - return _stpStartInfo.MaxWorkerThreads; - } - - set - { - Debug.Assert(value > 0); - Debug.Assert(value >= _stpStartInfo.MinWorkerThreads); - if (_stpStartInfo.MinWorkerThreads > value) - { - _stpStartInfo.MinWorkerThreads = value; - } - _stpStartInfo.MaxWorkerThreads = value; - StartOptimalNumberOfThreads(); - } - } - /// - /// Get the number of threads in the thread pool. - /// Should be between the lower and the upper limits. - /// - public int ActiveThreads - { - get - { - ValidateNotDisposed(); - return _workerThreads.Count; - } - } - - /// - /// Get the number of busy (not idle) threads in the thread pool. - /// - public int InUseThreads - { - get - { - ValidateNotDisposed(); - return _inUseWorkerThreads; - } - } - - /// - /// Returns true if the current running work item has been cancelled. - /// Must be used within the work item's callback method. - /// The work item should sample this value in order to know if it - /// needs to quit before its completion. - /// - public static bool IsWorkItemCanceled - { - get - { - return CurrentThreadEntry.CurrentWorkItem.IsCanceled; - } - } - - /// - /// Checks if the work item has been cancelled, and if yes then abort the thread. - /// Can be used with Cancel and timeout - /// - public static void AbortOnWorkItemCancel() - { - if (IsWorkItemCanceled) - { - Thread.CurrentThread.Abort(); - } - } - - /// - /// Thread Pool start information (readonly) - /// - public STPStartInfo STPStartInfo - { - get - { - return _stpStartInfo.AsReadOnly(); - } - } - - public bool IsShuttingdown - { - get { return _shutdown; } - } - - /// - /// Return the local calculated performance counters - /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true. - /// - public ISTPPerformanceCountersReader PerformanceCountersReader - { - get { return (ISTPPerformanceCountersReader)_localPCs; } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!_isDisposed) - { - if (!_shutdown) - { - Shutdown(); - } - - if (null != _shuttingDownEvent) - { - _shuttingDownEvent.Close(); - _shuttingDownEvent = null; - } - _workerThreads.Clear(); - - if (null != _isIdleWaitHandle) - { - _isIdleWaitHandle.Close(); - _isIdleWaitHandle = null; - } - - _isDisposed = true; - } - } - - private void ValidateNotDisposed() - { - if(_isDisposed) - { - throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); - } - } - #endregion - - #region WorkItemsGroupBase Overrides - - /// - /// Get/Set the maximum number of work items that execute cocurrency on the thread pool - /// - public override int Concurrency - { - get { return MaxThreads; } - set { MaxThreads = value; } - } - - /// - /// Get the number of work items in the queue. - /// - public override int WaitingCallbacks - { - get - { - ValidateNotDisposed(); - return _workItemsQueue.Count; - } - } - - /// - /// Get an array with all the state objects of the currently running items. - /// The array represents a snap shot and impact performance. - /// - public override object[] GetStates() - { - object[] states = _workItemsQueue.GetStates(); - return states; - } - - /// - /// WorkItemsGroup start information (readonly) - /// - public override WIGStartInfo WIGStartInfo - { - get { return _stpStartInfo.AsReadOnly(); } - } - - /// - /// Start the thread pool if it was started suspended. - /// If it is already running, this method is ignored. - /// - public override void Start() - { - if (!_isSuspended) - { - return; - } - _isSuspended = false; - - ICollection workItemsGroups = _workItemsGroups.Values; - foreach (WorkItemsGroup workItemsGroup in workItemsGroups) - { - workItemsGroup.OnSTPIsStarting(); - } - - StartOptimalNumberOfThreads(); - } - - /// - /// Cancel all work items using thread abortion - /// - /// True to stop work items by raising ThreadAbortException - public override void Cancel(bool abortExecution) - { - _canceledSmartThreadPool.IsCanceled = true; - _canceledSmartThreadPool = new CanceledWorkItemsGroup(); - - ICollection workItemsGroups = _workItemsGroups.Values; - foreach (WorkItemsGroup workItemsGroup in workItemsGroups) - { - workItemsGroup.Cancel(abortExecution); - } - - if (abortExecution) - { - foreach (ThreadEntry threadEntry in _workerThreads.Values) - { - WorkItem workItem = threadEntry.CurrentWorkItem; - if (null != workItem && - threadEntry.AssociatedSmartThreadPool == this && - !workItem.IsCanceled) - { - threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); - } - } - } - } - - /// - /// Wait for the thread pool to be idle - /// - public override bool WaitForIdle(int millisecondsTimeout) - { - ValidateWaitForIdle(); - return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); - } - - /// - /// This event is fired when all work items are completed. - /// (When IsIdle changes to true) - /// This event only work on WorkItemsGroup. On SmartThreadPool - /// it throws the NotImplementedException. - /// - public override event WorkItemsGroupIdleHandler OnIdle - { - add - { - throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); - //_onIdle += value; - } - remove - { - throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); - //_onIdle -= value; - } - } - - internal override void PreQueueWorkItem() - { - ValidateNotDisposed(); - } - - #endregion - - #region Join, Choice, Pipe, etc. - - /// - /// Executes all actions in parallel. - /// Returns when they all finish. - /// - /// Actions to execute - public void Join(IEnumerable actions) - { - WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; - IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); - foreach (Action action in actions) - { - workItemsGroup.QueueWorkItem(action); - } - workItemsGroup.Start(); - workItemsGroup.WaitForIdle(); - } - - /// - /// Executes all actions in parallel. - /// Returns when they all finish. - /// - /// Actions to execute - public void Join(params Action[] actions) - { - Join((IEnumerable)actions); - } - - private class ChoiceIndex - { - public int _index = -1; - } - - /// - /// Executes all actions in parallel - /// Returns when the first one completes - /// - /// Actions to execute - public int Choice(IEnumerable actions) - { - WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; - IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); - - ManualResetEvent anActionCompleted = new ManualResetEvent(false); - - ChoiceIndex choiceIndex = new ChoiceIndex(); - - int i = 0; - foreach (Action action in actions) - { - Action act = action; - int value = i; - workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); - ++i; - } - workItemsGroup.Start(); - anActionCompleted.WaitOne(); - - return choiceIndex._index; - } - - /// - /// Executes all actions in parallel - /// Returns when the first one completes - /// - /// Actions to execute - public int Choice(params Action[] actions) - { - return Choice((IEnumerable)actions); - } - - /// - /// Executes actions in sequence asynchronously. - /// Returns immediately. - /// - /// A state context that passes - /// Actions to execute in the order they should run - public void Pipe(T pipeState, IEnumerable> actions) - { - WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; - IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo); - foreach (Action action in actions) - { - Action act = action; - workItemsGroup.QueueWorkItem(() => act(pipeState)); - } - workItemsGroup.Start(); - workItemsGroup.WaitForIdle(); - } - - /// - /// Executes actions in sequence asynchronously. - /// Returns immediately. - /// - /// - /// Actions to execute in the order they should run - public void Pipe(T pipeState, params Action[] actions) - { - Pipe(pipeState, (IEnumerable>)actions); - } - #endregion - } - #endregion -} +#region Release History + +// Smart Thread Pool +// 7 Aug 2004 - Initial release +// +// 14 Sep 2004 - Bug fixes +// +// 15 Oct 2004 - Added new features +// - Work items return result. +// - Support waiting synchronization for multiple work items. +// - Work items can be cancelled. +// - Passage of the caller thread’s context to the thread in the pool. +// - Minimal usage of WIN32 handles. +// - Minor bug fixes. +// +// 26 Dec 2004 - Changes: +// - Removed static constructors. +// - Added finalizers. +// - Changed Exceptions so they are serializable. +// - Fixed the bug in one of the SmartThreadPool constructors. +// - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. +// The SmartThreadPool.WaitAny() is still limited by the .NET Framework. +// - Added PostExecute with options on which cases to call it. +// - Added option to dispose of the state objects. +// - Added a WaitForIdle() method that waits until the work items queue is empty. +// - Added an STPStartInfo class for the initialization of the thread pool. +// - Changed exception handling so if a work item throws an exception it +// is rethrown at GetResult(), rather then firing an UnhandledException event. +// Note that PostExecute exception are always ignored. +// +// 25 Mar 2005 - Changes: +// - Fixed lost of work items bug +// +// 3 Jul 2005: Changes. +// - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. +// +// 16 Aug 2005: Changes. +// - Fixed bug where the InUseThreads becomes negative when canceling work items. +// +// 31 Jan 2006 - Changes: +// - Added work items priority +// - Removed support of chained delegates in callbacks and post executes (nobody really use this) +// - Added work items groups +// - Added work items groups idle event +// - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array +// it returns true rather then throwing an exception. +// - Added option to start the STP and the WIG as suspended +// - Exception behavior changed, the real exception is returned by an +// inner exception +// - Added option to keep the Http context of the caller thread. (Thanks to Steven T.) +// - Added performance counters +// - Added priority to the threads in the pool +// +// 13 Feb 2006 - Changes: +// - Added a call to the dispose of the Performance Counter so +// their won't be a Performance Counter leak. +// - Added exception catch in case the Performance Counters cannot +// be created. +// +// 17 May 2008 - Changes: +// - Changed the dispose behavior and removed the Finalizers. +// - Enabled the change of the MaxThreads and MinThreads at run time. +// - Enabled the change of the Concurrency of a IWorkItemsGroup at run +// time If the IWorkItemsGroup is a SmartThreadPool then the Concurrency +// refers to the MaxThreads. +// - Improved the cancel behavior. +// - Added events for thread creation and termination. +// - Fixed the HttpContext context capture. +// - Changed internal collections so they use generic collections +// - Added IsIdle flag to the SmartThreadPool and IWorkItemsGroup +// - Added support for WinCE +// - Added support for Action and Func +// +// 07 April 2009 - Changes: +// - Added support for Silverlight and Mono +// - Added Join, Choice, and Pipe to SmartThreadPool. +// - Added local performance counters (for Mono, Silverlight, and WindowsCE) +// - Changed duration measures from DateTime.Now to Stopwatch. +// - Queues changed from System.Collections.Queue to System.Collections.Generic.LinkedList. +// +// 21 December 2009 - Changes: +// - Added work item timeout (passive) +// +// 20 August 2012 - Changes: +// - Added set name to threads +// - Fixed the WorkItemsQueue.Dequeue. +// Replaced while (!Monitor.TryEnter(this)); with lock(this) { ... } +// - Fixed SmartThreadPool.Pipe +// - Added IsBackground option to threads +// - Added ApartmentState to threads +// - Fixed thread creation when queuing many work items at the same time. +// +// 24 August 2012 - Changes: +// - Enabled cancel abort after cancel. See: http://smartthreadpool.codeplex.com/discussions/345937 by alecswan +// - Added option to set MaxStackSize of threads + +#endregion + +using System; +using System.Security; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +using Amib.Threading.Internal; + +namespace Amib.Threading +{ + #region SmartThreadPool class + /// + /// Smart thread pool class. + /// + public partial class SmartThreadPool : WorkItemsGroupBase, IDisposable + { + #region Public Default Constants + + /// + /// Default minimum number of threads the thread pool contains. (0) + /// + public const int DefaultMinWorkerThreads = 0; + + /// + /// Default maximum number of threads the thread pool contains. (25) + /// + public const int DefaultMaxWorkerThreads = 25; + + /// + /// Default idle timeout in milliseconds. (One minute) + /// + public const int DefaultIdleTimeout = 60*1000; // One minute + + /// + /// Indicate to copy the security context of the caller and then use it in the call. (false) + /// + public const bool DefaultUseCallerCallContext = false; + + /// + /// Indicate to copy the HTTP context of the caller and then use it in the call. (false) + /// + public const bool DefaultUseCallerHttpContext = false; + + /// + /// Indicate to dispose of the state objects if they support the IDispose interface. (false) + /// + public const bool DefaultDisposeOfStateObjects = false; + + /// + /// The default option to run the post execute (CallToPostExecute.Always) + /// + public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always; + + /// + /// The default post execute method to run. (None) + /// When null it means not to call it. + /// + public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback; + + /// + /// The default work item priority (WorkItemPriority.Normal) + /// + public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal; + + /// + /// The default is to work on work items as soon as they arrive + /// and not to wait for the start. (false) + /// + public const bool DefaultStartSuspended = false; + + /// + /// The default name to use for the performance counters instance. (null) + /// + public static readonly string DefaultPerformanceCounterInstanceName; + +#if !(WINDOWS_PHONE) + + /// + /// The default thread priority (ThreadPriority.Normal) + /// + public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal; +#endif + /// + /// The default thread pool name. (SmartThreadPool) + /// + public const string DefaultThreadPoolName = "SmartThreadPool"; + + /// + /// The default Max Stack Size. (SmartThreadPool) + /// + public static readonly int? DefaultMaxStackSize = null; + + /// + /// The default fill state with params. (false) + /// It is relevant only to QueueWorkItem of Action<...>/Func<...> + /// + public const bool DefaultFillStateWithArgs = false; + + /// + /// The default thread backgroundness. (true) + /// + public const bool DefaultAreThreadsBackground = true; + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + /// + /// The default apartment state of a thread in the thread pool. + /// The default is ApartmentState.Unknown which means the STP will not + /// set the apartment of the thread. It will use the .NET default. + /// + public const ApartmentState DefaultApartmentState = ApartmentState.Unknown; +#endif + + #endregion + + #region Member Variables + + /// + /// Dictionary of all the threads in the thread pool. + /// + private readonly SynchronizedDictionary _workerThreads = new SynchronizedDictionary(); + + /// + /// Queue of work items. + /// + private readonly WorkItemsQueue _workItemsQueue = new WorkItemsQueue(); + + /// + /// Count the work items handled. + /// Used by the performance counter. + /// + private int _workItemsProcessed; + + /// + /// Number of threads that currently work (not idle). + /// + private int _inUseWorkerThreads; + + /// + /// Stores a copy of the original STPStartInfo. + /// It is used to change the MinThread and MaxThreads + /// + private STPStartInfo _stpStartInfo; + + /// + /// Total number of work items that are stored in the work items queue + /// plus the work items that the threads in the pool are working on. + /// + private int _currentWorkItemsCount; + + /// + /// Signaled when the thread pool is idle, i.e. no thread is busy + /// and the work items queue is empty + /// + //private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); + private ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); + + /// + /// An event to signal all the threads to quit immediately. + /// + //private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false); + private ManualResetEvent _shuttingDownEvent = EventWaitHandleFactory.CreateManualResetEvent(false); + + /// + /// A flag to indicate if the Smart Thread Pool is now suspended. + /// + private bool _isSuspended; + + /// + /// A flag to indicate the threads to quit. + /// + private bool _shutdown; + + /// + /// Counts the threads created in the pool. + /// It is used to name the threads. + /// + private int _threadCounter; + + /// + /// Indicate that the SmartThreadPool has been disposed + /// + private bool _isDisposed; + + /// + /// Holds all the WorkItemsGroup instaces that have at least one + /// work item int the SmartThreadPool + /// This variable is used in case of Shutdown + /// + private readonly SynchronizedDictionary _workItemsGroups = new SynchronizedDictionary(); + + /// + /// A common object for all the work items int the STP + /// so we can mark them to cancel in O(1) + /// + private CanceledWorkItemsGroup _canceledSmartThreadPool = new CanceledWorkItemsGroup(); + + /// + /// Windows STP performance counters + /// + private ISTPInstancePerformanceCounters _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + + /// + /// Local STP performance counters + /// + private ISTPInstancePerformanceCounters _localPCs = NullSTPInstancePerformanceCounters.Instance; + + +#if (WINDOWS_PHONE) + private static readonly Dictionary _threadEntries = new Dictionary(); +#elif (_WINDOWS_CE) + private static LocalDataStoreSlot _threadEntrySlot = Thread.AllocateDataSlot(); +#else + [ThreadStatic] + private static ThreadEntry _threadEntry; + +#endif + + /// + /// An event to call after a thread is created, but before + /// it's first use. + /// + private event ThreadInitializationHandler _onThreadInitialization; + + /// + /// An event to call when a thread is about to exit, after + /// it is no longer belong to the pool. + /// + private event ThreadTerminationHandler _onThreadTermination; + + #endregion + + #region Per thread properties + + /// + /// A reference to the current work item a thread from the thread pool + /// is executing. + /// + internal static ThreadEntry CurrentThreadEntry + { +#if (WINDOWS_PHONE) + get + { + lock(_threadEntries) + { + ThreadEntry threadEntry; + if (_threadEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadEntry)) + { + return threadEntry; + } + } + return null; + } + set + { + lock(_threadEntries) + { + _threadEntries[Thread.CurrentThread.ManagedThreadId] = value; + } + } +#elif (_WINDOWS_CE) + get + { + //Thread.CurrentThread.ManagedThreadId + return Thread.GetData(_threadEntrySlot) as ThreadEntry; + } + set + { + Thread.SetData(_threadEntrySlot, value); + } +#else + get + { + return _threadEntry; + } + set + { + _threadEntry = value; + } +#endif + } + #endregion + + #region Construction and Finalization + + /// + /// Constructor + /// + public SmartThreadPool() + { + _stpStartInfo = new STPStartInfo(); + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + public SmartThreadPool(int idleTimeout) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + /// Upper limit of threads in the pool + public SmartThreadPool( + int idleTimeout, + int maxWorkerThreads) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + MaxWorkerThreads = maxWorkerThreads, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// Idle timeout in milliseconds + /// Upper limit of threads in the pool + /// Lower limit of threads in the pool + public SmartThreadPool( + int idleTimeout, + int maxWorkerThreads, + int minWorkerThreads) + { + _stpStartInfo = new STPStartInfo + { + IdleTimeout = idleTimeout, + MaxWorkerThreads = maxWorkerThreads, + MinWorkerThreads = minWorkerThreads, + }; + Initialize(); + } + + /// + /// Constructor + /// + /// A SmartThreadPool configuration that overrides the default behavior + public SmartThreadPool(STPStartInfo stpStartInfo) + { + _stpStartInfo = new STPStartInfo(stpStartInfo); + Initialize(); + } + + private void Initialize() + { + Name = _stpStartInfo.ThreadPoolName; + ValidateSTPStartInfo(); + + // _stpStartInfoRW stores a read/write copy of the STPStartInfo. + // Actually only MaxWorkerThreads and MinWorkerThreads are overwritten + + _isSuspended = _stpStartInfo.StartSuspended; + +#if (_WINDOWS_CE) || (_SILVERLIGHT) || (_MONO) || (WINDOWS_PHONE) + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { + throw new NotSupportedException("Performance counters are not implemented for Compact Framework/Silverlight/Mono, instead use StpStartInfo.EnableLocalPerformanceCounters"); + } +#else + if (null != _stpStartInfo.PerformanceCounterInstanceName) + { + try + { + _windowsPCs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName); + } + catch (Exception e) + { + Debug.WriteLine("Unable to create Performance Counters: " + e); + _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + } + } +#endif + + if (_stpStartInfo.EnableLocalPerformanceCounters) + { + _localPCs = new LocalSTPInstancePerformanceCounters(); + } + + // If the STP is not started suspended then start the threads. + if (!_isSuspended) + { + StartOptimalNumberOfThreads(); + } + } + + private void StartOptimalNumberOfThreads() + { + int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads); + threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads); + threadsCount -= _workerThreads.Count; + if (threadsCount > 0) + { + StartThreads(threadsCount); + } + } + + private void ValidateSTPStartInfo() + { + if (_stpStartInfo.MinWorkerThreads < 0) + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads", "MinWorkerThreads cannot be negative"); + } + + if (_stpStartInfo.MaxWorkerThreads <= 0) + { + throw new ArgumentOutOfRangeException( + "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero"); + } + + if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads) + { + throw new ArgumentOutOfRangeException( + "MinWorkerThreads, maxWorkerThreads", + "MaxWorkerThreads must be greater or equal to MinWorkerThreads"); + } + } + + private static void ValidateCallback(Delegate callback) + { + if(callback.GetInvocationList().Length > 1) + { + throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); + } + } + + #endregion + + #region Thread Processing + + /// + /// Waits on the queue for a work item, shutdown, or timeout. + /// + /// + /// Returns the WaitingCallback or null in case of timeout or shutdown. + /// + private WorkItem Dequeue() + { + WorkItem workItem = + _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent); + + return workItem; + } + + /// + /// Put a new work item in the queue + /// + /// A work item to queue + internal override void Enqueue(WorkItem workItem) + { + // Make sure the workItem is not null + Debug.Assert(null != workItem); + + IncrementWorkItemsCount(); + + workItem.CanceledSmartThreadPool = _canceledSmartThreadPool; + _workItemsQueue.EnqueueWorkItem(workItem); + workItem.WorkItemIsQueued(); + + // If all the threads are busy then try to create a new one + if (_currentWorkItemsCount > _workerThreads.Count) + { + StartThreads(1); + } + } + + private void IncrementWorkItemsCount() + { + _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + + int count = Interlocked.Increment(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 1) + { + IsIdle = false; + _isIdleWaitHandle.Reset(); + } + } + + private void DecrementWorkItemsCount() + { + int count = Interlocked.Decrement(ref _currentWorkItemsCount); + //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString()); + if (count == 0) + { + IsIdle = true; + _isIdleWaitHandle.Set(); + } + + Interlocked.Increment(ref _workItemsProcessed); + + if (!_shutdown) + { + // The counter counts even if the work item was cancelled + _windowsPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + _localPCs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed); + } + + } + + internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) + { + _workItemsGroups[workItemsGroup] = workItemsGroup; + } + + internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup) + { + if (_workItemsGroups.Contains(workItemsGroup)) + { + _workItemsGroups.Remove(workItemsGroup); + } + } + + /// + /// Inform that the current thread is about to quit or quiting. + /// The same thread may call this method more than once. + /// + private void InformCompleted() + { + // There is no need to lock the two methods together + // since only the current thread removes itself + // and the _workerThreads is a synchronized dictionary + if (_workerThreads.Contains(Thread.CurrentThread)) + { + _workerThreads.Remove(Thread.CurrentThread); + _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + } + } + + /// + /// Starts new threads + /// + /// The number of threads to start + private void StartThreads(int threadsCount) + { + if (_isSuspended) + { + return; + } + + lock(_workerThreads.SyncRoot) + { + // Don't start threads on shut down + if (_shutdown) + { + return; + } + + for(int i = 0; i < threadsCount; ++i) + { + // Don't create more threads then the upper limit + if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads) + { + return; + } + + // Create a new thread + +#if (_SILVERLIGHT) || (WINDOWS_PHONE) + Thread workerThread = new Thread(ProcessQueuedItems); +#else + Thread workerThread = + _stpStartInfo.MaxStackSize.HasValue + ? new Thread(ProcessQueuedItems, _stpStartInfo.MaxStackSize.Value) + : new Thread(ProcessQueuedItems); +#endif + // Configure the new thread and start it + workerThread.Name = "STP " + Name + " Thread #" + _threadCounter; + workerThread.IsBackground = _stpStartInfo.AreThreadsBackground; + +#if !(_SILVERLIGHT) && !(_WINDOWS_CE) && !(WINDOWS_PHONE) + if (_stpStartInfo.ApartmentState != ApartmentState.Unknown) + { + workerThread.SetApartmentState(_stpStartInfo.ApartmentState); + } +#endif + +#if !(_SILVERLIGHT) && !(WINDOWS_PHONE) + workerThread.Priority = _stpStartInfo.ThreadPriority; +#endif + workerThread.Start(); + ++_threadCounter; + + // Add it to the dictionary and update its creation time. + _workerThreads[workerThread] = new ThreadEntry(this); + + _windowsPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads); + } + } + } + + /// + /// A worker thread method that processes work items from the work items queue. + /// + private void ProcessQueuedItems() + { + // Keep the entry of the dictionary as thread's variable to avoid the synchronization locks + // of the dictionary. + CurrentThreadEntry = _workerThreads[Thread.CurrentThread]; + + FireOnThreadInitialization(); + + try + { + bool bInUseWorkerThreadsWasIncremented = false; + + // Process until shutdown. + while(!_shutdown) + { + // Update the last time this thread was seen alive. + // It's good for debugging. + CurrentThreadEntry.IAmAlive(); + + // The following block handles the when the MaxWorkerThreads has been + // incremented by the user at run-time. + // Double lock for quit. + if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) + { + lock (_workerThreads.SyncRoot) + { + if (_workerThreads.Count > _stpStartInfo.MaxWorkerThreads) + { + // Inform that the thread is quiting and then quit. + // This method must be called within this lock or else + // more threads will quit and the thread pool will go + // below the lower limit. + InformCompleted(); + break; + } + } + } + + // Wait for a work item, shutdown, or timeout + WorkItem workItem = Dequeue(); + + // Update the last time this thread was seen alive. + // It's good for debugging. + CurrentThreadEntry.IAmAlive(); + + // On timeout or shut down. + if (null == workItem) + { + // Double lock for quit. + if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) + { + lock(_workerThreads.SyncRoot) + { + if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads) + { + // Inform that the thread is quiting and then quit. + // This method must be called within this lock or else + // more threads will quit and the thread pool will go + // below the lower limit. + InformCompleted(); + break; + } + } + } + } + + // If we didn't quit then skip to the next iteration. + if (null == workItem) + { + continue; + } + + try + { + // Initialize the value to false + bInUseWorkerThreadsWasIncremented = false; + + // Set the Current Work Item of the thread. + // Store the Current Work Item before the workItem.StartingWorkItem() is called, + // so WorkItem.Cancel can work when the work item is between InQueue and InProgress + // states. + // If the work item has been cancelled BEFORE the workItem.StartingWorkItem() + // (work item is in InQueue state) then workItem.StartingWorkItem() will return false. + // If the work item has been cancelled AFTER the workItem.StartingWorkItem() then + // (work item is in InProgress state) then the thread will be aborted + CurrentThreadEntry.CurrentWorkItem = workItem; + + // Change the state of the work item to 'in progress' if possible. + // We do it here so if the work item has been canceled we won't + // increment the _inUseWorkerThreads. + // The cancel mechanism doesn't delete items from the queue, + // it marks the work item as canceled, and when the work item + // is dequeued, we just skip it. + // If the post execute of work item is set to always or to + // call when the work item is canceled then the StartingWorkItem() + // will return true, so the post execute can run. + if (!workItem.StartingWorkItem()) + { + continue; + } + + // Execute the callback. Make sure to accurately + // record how many callbacks are currently executing. + int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + + // Mark that the _inUseWorkerThreads incremented, so in the finally{} + // statement we will decrement it correctly. + bInUseWorkerThreadsWasIncremented = true; + + workItem.FireWorkItemStarted(); + + ExecuteWorkItem(workItem); + } + catch(Exception ex) + { + ex.GetHashCode(); + // Do nothing + } + finally + { + workItem.DisposeOfState(); + + // Set the CurrentWorkItem to null, since we + // no longer run user's code. + CurrentThreadEntry.CurrentWorkItem = null; + + // Decrement the _inUseWorkerThreads only if we had + // incremented it. Note the cancelled work items don't + // increment _inUseWorkerThreads. + if (bInUseWorkerThreadsWasIncremented) + { + int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads); + _windowsPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + _localPCs.SampleThreads(_workerThreads.Count, inUseWorkerThreads); + } + + // Notify that the work item has been completed. + // WorkItemsGroup may enqueue their next work item. + workItem.FireWorkItemCompleted(); + + // Decrement the number of work items here so the idle + // ManualResetEvent won't fluctuate. + DecrementWorkItemsCount(); + } + } + } + catch(ThreadAbortException tae) + { + tae.GetHashCode(); + // Handle the abort exception gracfully. +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + Thread.ResetAbort(); +#endif + } + catch(Exception e) + { + Debug.Assert(null != e); + } + finally + { + InformCompleted(); + FireOnThreadTermination(); + } + } + + private void ExecuteWorkItem(WorkItem workItem) + { + _windowsPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + _localPCs.SampleWorkItemsWaitTime(workItem.WaitingTime); + try + { + workItem.Execute(); + } + finally + { + _windowsPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + _localPCs.SampleWorkItemsProcessTime(workItem.ProcessTime); + } + } + + + #endregion + + #region Public Methods + + private void ValidateWaitForIdle() + { + if (null != CurrentThreadEntry && CurrentThreadEntry.AssociatedSmartThreadPool == this) + { + throw new NotSupportedException( + "WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup) + { + if (null == CurrentThreadEntry) + { + return; + } + + WorkItem workItem = CurrentThreadEntry.CurrentWorkItem; + ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); + if ((null != workItemsGroup) && + (null != workItem) && + CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) + { + throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem) + { + if ((null != workItemsGroup) && + (null != workItem) && + workItem.WasQueuedBy(workItemsGroup)) + { + throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); + } + } + + /// + /// Force the SmartThreadPool to shutdown + /// + public void Shutdown() + { + Shutdown(true, 0); + } + + /// + /// Force the SmartThreadPool to shutdown with timeout + /// + public void Shutdown(bool forceAbort, TimeSpan timeout) + { + Shutdown(forceAbort, (int)timeout.TotalMilliseconds); + } + + /// + /// Empties the queue of work items and abort the threads in the pool. + /// + public void Shutdown(bool forceAbort, int millisecondsTimeout) + { + ValidateNotDisposed(); + + ISTPInstancePerformanceCounters pcs = _windowsPCs; + + if (NullSTPInstancePerformanceCounters.Instance != _windowsPCs) + { + // Set the _pcs to "null" to stop updating the performance + // counters + _windowsPCs = NullSTPInstancePerformanceCounters.Instance; + + pcs.Dispose(); + } + + Thread [] threads; + lock(_workerThreads.SyncRoot) + { + // Shutdown the work items queue + _workItemsQueue.Dispose(); + + // Signal the threads to exit + _shutdown = true; + _shuttingDownEvent.Set(); + + // Make a copy of the threads' references in the pool + threads = new Thread [_workerThreads.Count]; + _workerThreads.Keys.CopyTo(threads, 0); + } + + int millisecondsLeft = millisecondsTimeout; + Stopwatch stopwatch = Stopwatch.StartNew(); + //DateTime start = DateTime.UtcNow; + bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout); + bool timeout = false; + + // Each iteration we update the time left for the timeout. + foreach(Thread thread in threads) + { + // Join don't work with negative numbers + if (!waitInfinitely && (millisecondsLeft < 0)) + { + timeout = true; + break; + } + + // Wait for the thread to terminate + bool success = thread.Join(millisecondsLeft); + if(!success) + { + timeout = true; + break; + } + + if(!waitInfinitely) + { + // Update the time left to wait + //TimeSpan ts = DateTime.UtcNow - start; + millisecondsLeft = millisecondsTimeout - (int)stopwatch.ElapsedMilliseconds; + } + } + + if (timeout && forceAbort) + { + // Abort the threads in the pool + foreach(Thread thread in threads) + { + + if ((thread != null) +#if !(_WINDOWS_CE) + && thread.IsAlive +#endif + ) + { + try + { + thread.Abort(); // Shutdown + } + catch(SecurityException e) + { + e.GetHashCode(); + } + catch(ThreadStateException ex) + { + ex.GetHashCode(); + // In case the thread has been terminated + // after the check if it is alive. + } + } + } + } + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults) + { + return WaitAll(waitableResults, Timeout.Infinite, true); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults, + TimeSpan timeout, + bool exitContext) + { + return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult[] waitableResults, + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WaitAll(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext) + { + return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, null); + } + + /// + /// Wait for all work items to complete + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// true when every work item in workItemResults has completed; otherwise false. + /// + public static bool WaitAll( + IWaitableResult[] waitableResults, + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WorkItem.WaitAll(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); + } + + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults) + { + return WaitAny(waitableResults, Timeout.Infinite, true); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult[] waitableResults, + TimeSpan timeout, + bool exitContext) + { + return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + TimeSpan timeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WaitAny(waitableResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext) + { + return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, null); + } + + /// + /// Waits for any of the work items in the specified array to complete, cancel, or timeout + /// + /// Array of work item result objects + /// The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely. + /// + /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. + /// + /// A cancel wait handle to interrupt the wait if needed + /// + /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled. + /// + public static int WaitAny( + IWaitableResult [] waitableResults, + int millisecondsTimeout, + bool exitContext, + WaitHandle cancelWaitHandle) + { + return WorkItem.WaitAny(waitableResults, millisecondsTimeout, exitContext, cancelWaitHandle); + } + + /// + /// Creates a new WorkItemsGroup. + /// + /// The number of work items that can be run concurrently + /// A reference to the WorkItemsGroup + public IWorkItemsGroup CreateWorkItemsGroup(int concurrency) + { + IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo); + return workItemsGroup; + } + + /// + /// Creates a new WorkItemsGroup. + /// + /// The number of work items that can be run concurrently + /// A WorkItemsGroup configuration that overrides the default behavior + /// A reference to the WorkItemsGroup + public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo) + { + IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo); + return workItemsGroup; + } + + #region Fire Thread's Events + + private void FireOnThreadInitialization() + { + if (null != _onThreadInitialization) + { + foreach (ThreadInitializationHandler tih in _onThreadInitialization.GetInvocationList()) + { + try + { + tih(); + } + catch (Exception e) + { + e.GetHashCode(); + Debug.Assert(false); + throw; + } + } + } + } + + private void FireOnThreadTermination() + { + if (null != _onThreadTermination) + { + foreach (ThreadTerminationHandler tth in _onThreadTermination.GetInvocationList()) + { + try + { + tth(); + } + catch (Exception e) + { + e.GetHashCode(); + Debug.Assert(false); + throw; + } + } + } + } + + #endregion + + /// + /// This event is fired when a thread is created. + /// Use it to initialize a thread before the work items use it. + /// + public event ThreadInitializationHandler OnThreadInitialization + { + add { _onThreadInitialization += value; } + remove { _onThreadInitialization -= value; } + } + + /// + /// This event is fired when a thread is terminating. + /// Use it for cleanup. + /// + public event ThreadTerminationHandler OnThreadTermination + { + add { _onThreadTermination += value; } + remove { _onThreadTermination -= value; } + } + + + internal void CancelAbortWorkItemsGroup(WorkItemsGroup wig) + { + foreach (ThreadEntry threadEntry in _workerThreads.Values) + { + WorkItem workItem = threadEntry.CurrentWorkItem; + if (null != workItem && + workItem.WasQueuedBy(wig) && + !workItem.IsCanceled) + { + threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); + } + } + } + + + + #endregion + + #region Properties + + /// + /// Get/Set the lower limit of threads in the pool. + /// + public int MinThreads + { + get + { + ValidateNotDisposed(); + return _stpStartInfo.MinWorkerThreads; + } + set + { + Debug.Assert(value >= 0); + Debug.Assert(value <= _stpStartInfo.MaxWorkerThreads); + if (_stpStartInfo.MaxWorkerThreads < value) + { + _stpStartInfo.MaxWorkerThreads = value; + } + _stpStartInfo.MinWorkerThreads = value; + StartOptimalNumberOfThreads(); + } + } + + /// + /// Get/Set the upper limit of threads in the pool. + /// + public int MaxThreads + { + get + { + ValidateNotDisposed(); + return _stpStartInfo.MaxWorkerThreads; + } + + set + { + Debug.Assert(value > 0); + Debug.Assert(value >= _stpStartInfo.MinWorkerThreads); + if (_stpStartInfo.MinWorkerThreads > value) + { + _stpStartInfo.MinWorkerThreads = value; + } + _stpStartInfo.MaxWorkerThreads = value; + StartOptimalNumberOfThreads(); + } + } + /// + /// Get the number of threads in the thread pool. + /// Should be between the lower and the upper limits. + /// + public int ActiveThreads + { + get + { + ValidateNotDisposed(); + return _workerThreads.Count; + } + } + + /// + /// Get the number of busy (not idle) threads in the thread pool. + /// + public int InUseThreads + { + get + { + ValidateNotDisposed(); + return _inUseWorkerThreads; + } + } + + /// + /// Returns true if the current running work item has been cancelled. + /// Must be used within the work item's callback method. + /// The work item should sample this value in order to know if it + /// needs to quit before its completion. + /// + public static bool IsWorkItemCanceled + { + get + { + return CurrentThreadEntry.CurrentWorkItem.IsCanceled; + } + } + + /// + /// Checks if the work item has been cancelled, and if yes then abort the thread. + /// Can be used with Cancel and timeout + /// + public static void AbortOnWorkItemCancel() + { + if (IsWorkItemCanceled) + { + Thread.CurrentThread.Abort(); + } + } + + /// + /// Thread Pool start information (readonly) + /// + public STPStartInfo STPStartInfo + { + get + { + return _stpStartInfo.AsReadOnly(); + } + } + + public bool IsShuttingdown + { + get { return _shutdown; } + } + + /// + /// Return the local calculated performance counters + /// Available only if STPStartInfo.EnableLocalPerformanceCounters is true. + /// + public ISTPPerformanceCountersReader PerformanceCountersReader + { + get { return (ISTPPerformanceCountersReader)_localPCs; } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!_isDisposed) + { + if (!_shutdown) + { + Shutdown(); + } + + if (null != _shuttingDownEvent) + { + _shuttingDownEvent.Close(); + _shuttingDownEvent = null; + } + _workerThreads.Clear(); + + if (null != _isIdleWaitHandle) + { + _isIdleWaitHandle.Close(); + _isIdleWaitHandle = null; + } + + _isDisposed = true; + } + } + + private void ValidateNotDisposed() + { + if(_isDisposed) + { + throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); + } + } + #endregion + + #region WorkItemsGroupBase Overrides + + /// + /// Get/Set the maximum number of work items that execute cocurrency on the thread pool + /// + public override int Concurrency + { + get { return MaxThreads; } + set { MaxThreads = value; } + } + + /// + /// Get the number of work items in the queue. + /// + public override int WaitingCallbacks + { + get + { + ValidateNotDisposed(); + return _workItemsQueue.Count; + } + } + + /// + /// Get an array with all the state objects of the currently running items. + /// The array represents a snap shot and impact performance. + /// + public override object[] GetStates() + { + object[] states = _workItemsQueue.GetStates(); + return states; + } + + /// + /// WorkItemsGroup start information (readonly) + /// + public override WIGStartInfo WIGStartInfo + { + get { return _stpStartInfo.AsReadOnly(); } + } + + /// + /// Start the thread pool if it was started suspended. + /// If it is already running, this method is ignored. + /// + public override void Start() + { + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + ICollection workItemsGroups = _workItemsGroups.Values; + foreach (WorkItemsGroup workItemsGroup in workItemsGroups) + { + workItemsGroup.OnSTPIsStarting(); + } + + StartOptimalNumberOfThreads(); + } + + /// + /// Cancel all work items using thread abortion + /// + /// True to stop work items by raising ThreadAbortException + public override void Cancel(bool abortExecution) + { + _canceledSmartThreadPool.IsCanceled = true; + _canceledSmartThreadPool = new CanceledWorkItemsGroup(); + + ICollection workItemsGroups = _workItemsGroups.Values; + foreach (WorkItemsGroup workItemsGroup in workItemsGroups) + { + workItemsGroup.Cancel(abortExecution); + } + + if (abortExecution) + { + foreach (ThreadEntry threadEntry in _workerThreads.Values) + { + WorkItem workItem = threadEntry.CurrentWorkItem; + if (null != workItem && + threadEntry.AssociatedSmartThreadPool == this && + !workItem.IsCanceled) + { + threadEntry.CurrentWorkItem.GetWorkItemResult().Cancel(true); + } + } + } + } + + /// + /// Wait for the thread pool to be idle + /// + public override bool WaitForIdle(int millisecondsTimeout) + { + ValidateWaitForIdle(); + return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); + } + + /// + /// This event is fired when all work items are completed. + /// (When IsIdle changes to true) + /// This event only work on WorkItemsGroup. On SmartThreadPool + /// it throws the NotImplementedException. + /// + public override event WorkItemsGroupIdleHandler OnIdle + { + add + { + throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); + //_onIdle += value; + } + remove + { + throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature."); + //_onIdle -= value; + } + } + + internal override void PreQueueWorkItem() + { + ValidateNotDisposed(); + } + + #endregion + + #region Join, Choice, Pipe, etc. + + /// + /// Executes all actions in parallel. + /// Returns when they all finish. + /// + /// Actions to execute + public void Join(IEnumerable actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); + foreach (Action action in actions) + { + workItemsGroup.QueueWorkItem(action); + } + workItemsGroup.Start(); + workItemsGroup.WaitForIdle(); + } + + /// + /// Executes all actions in parallel. + /// Returns when they all finish. + /// + /// Actions to execute + public void Join(params Action[] actions) + { + Join((IEnumerable)actions); + } + + private class ChoiceIndex + { + public int _index = -1; + } + + /// + /// Executes all actions in parallel + /// Returns when the first one completes + /// + /// Actions to execute + public int Choice(IEnumerable actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(int.MaxValue, wigStartInfo); + + ManualResetEvent anActionCompleted = new ManualResetEvent(false); + + ChoiceIndex choiceIndex = new ChoiceIndex(); + + int i = 0; + foreach (Action action in actions) + { + Action act = action; + int value = i; + workItemsGroup.QueueWorkItem(() => { act(); Interlocked.CompareExchange(ref choiceIndex._index, value, -1); anActionCompleted.Set(); }); + ++i; + } + workItemsGroup.Start(); + anActionCompleted.WaitOne(); + + return choiceIndex._index; + } + + /// + /// Executes all actions in parallel + /// Returns when the first one completes + /// + /// Actions to execute + public int Choice(params Action[] actions) + { + return Choice((IEnumerable)actions); + } + + /// + /// Executes actions in sequence asynchronously. + /// Returns immediately. + /// + /// A state context that passes + /// Actions to execute in the order they should run + public void Pipe(T pipeState, IEnumerable> actions) + { + WIGStartInfo wigStartInfo = new WIGStartInfo { StartSuspended = true }; + IWorkItemsGroup workItemsGroup = CreateWorkItemsGroup(1, wigStartInfo); + foreach (Action action in actions) + { + Action act = action; + workItemsGroup.QueueWorkItem(() => act(pipeState)); + } + workItemsGroup.Start(); + workItemsGroup.WaitForIdle(); + } + + /// + /// Executes actions in sequence asynchronously. + /// Returns immediately. + /// + /// + /// Actions to execute in the order they should run + public void Pipe(T pipeState, params Action[] actions) + { + Pipe(pipeState, (IEnumerable>)actions); + } + #endregion + } + #endregion +} diff --git a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs index 3532cca..0cce19f 100644 --- a/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs +++ b/ThirdParty/SmartThreadPool/SynchronizedDictionary.cs @@ -1,89 +1,89 @@ -using System.Collections.Generic; - -namespace Amib.Threading.Internal -{ - internal class SynchronizedDictionary - { - private readonly Dictionary _dictionary; - private readonly object _lock; - - public SynchronizedDictionary() - { - _lock = new object(); - _dictionary = new Dictionary(); - } - - public int Count - { - get { return _dictionary.Count; } - } - - public bool Contains(TKey key) - { - lock (_lock) - { - return _dictionary.ContainsKey(key); - } - } - - public void Remove(TKey key) - { - lock (_lock) - { - _dictionary.Remove(key); - } - } - - public object SyncRoot - { - get { return _lock; } - } - - public TValue this[TKey key] - { - get - { - lock (_lock) - { - return _dictionary[key]; - } - } - set - { - lock (_lock) - { - _dictionary[key] = value; - } - } - } - - public Dictionary.KeyCollection Keys - { - get - { - lock (_lock) - { - return _dictionary.Keys; - } - } - } - - public Dictionary.ValueCollection Values - { - get - { - lock (_lock) - { - return _dictionary.Values; - } - } - } - public void Clear() - { - lock (_lock) - { - _dictionary.Clear(); - } - } - } -} +using System.Collections.Generic; + +namespace Amib.Threading.Internal +{ + internal class SynchronizedDictionary + { + private readonly Dictionary _dictionary; + private readonly object _lock; + + public SynchronizedDictionary() + { + _lock = new object(); + _dictionary = new Dictionary(); + } + + public int Count + { + get { return _dictionary.Count; } + } + + public bool Contains(TKey key) + { + lock (_lock) + { + return _dictionary.ContainsKey(key); + } + } + + public void Remove(TKey key) + { + lock (_lock) + { + _dictionary.Remove(key); + } + } + + public object SyncRoot + { + get { return _lock; } + } + + public TValue this[TKey key] + { + get + { + lock (_lock) + { + return _dictionary[key]; + } + } + set + { + lock (_lock) + { + _dictionary[key] = value; + } + } + } + + public Dictionary.KeyCollection Keys + { + get + { + lock (_lock) + { + return _dictionary.Keys; + } + } + } + + public Dictionary.ValueCollection Values + { + get + { + lock (_lock) + { + return _dictionary.Values; + } + } + } + public void Clear() + { + lock (_lock) + { + _dictionary.Clear(); + } + } + } +} diff --git a/ThirdParty/SmartThreadPool/WIGStartInfo.cs b/ThirdParty/SmartThreadPool/WIGStartInfo.cs index e5ff150..8af195b 100644 --- a/ThirdParty/SmartThreadPool/WIGStartInfo.cs +++ b/ThirdParty/SmartThreadPool/WIGStartInfo.cs @@ -1,171 +1,171 @@ -using System; - -namespace Amib.Threading -{ - /// - /// Summary description for WIGStartInfo. - /// - public class WIGStartInfo - { - private bool _useCallerCallContext; - private bool _useCallerHttpContext; - private bool _disposeOfStateObjects; - private CallToPostExecute _callToPostExecute; - private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; - private bool _startSuspended; - private WorkItemPriority _workItemPriority; - private bool _fillStateWithArgs; - - protected bool _readOnly; - - public WIGStartInfo() - { - _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; - _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; - _startSuspended = SmartThreadPool.DefaultStartSuspended; - _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; - _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; - _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; - _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; - _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; - } - - public WIGStartInfo(WIGStartInfo wigStartInfo) - { - _useCallerCallContext = wigStartInfo.UseCallerCallContext; - _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; - _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - _callToPostExecute = wigStartInfo.CallToPostExecute; - _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - _workItemPriority = wigStartInfo.WorkItemPriority; - _startSuspended = wigStartInfo.StartSuspended; - _fillStateWithArgs = wigStartInfo.FillStateWithArgs; - } - - protected void ThrowIfReadOnly() - { - if (_readOnly) - { - throw new NotSupportedException("This is a readonly instance and set is not supported"); - } - } - - /// - /// Get/Set if to use the caller's security context - /// - public virtual bool UseCallerCallContext - { - get { return _useCallerCallContext; } - set - { - ThrowIfReadOnly(); - _useCallerCallContext = value; - } - } - - - /// - /// Get/Set if to use the caller's HTTP context - /// - public virtual bool UseCallerHttpContext - { - get { return _useCallerHttpContext; } - set - { - ThrowIfReadOnly(); - _useCallerHttpContext = value; - } - } - - - /// - /// Get/Set if to dispose of the state object of a work item - /// - public virtual bool DisposeOfStateObjects - { - get { return _disposeOfStateObjects; } - set - { - ThrowIfReadOnly(); - _disposeOfStateObjects = value; - } - } - - - /// - /// Get/Set the run the post execute options - /// - public virtual CallToPostExecute CallToPostExecute - { - get { return _callToPostExecute; } - set - { - ThrowIfReadOnly(); - _callToPostExecute = value; - } - } - - - /// - /// Get/Set the default post execute callback - /// - public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback - { - get { return _postExecuteWorkItemCallback; } - set - { - ThrowIfReadOnly(); - _postExecuteWorkItemCallback = value; - } - } - - - /// - /// Get/Set if the work items execution should be suspended until the Start() - /// method is called. - /// - public virtual bool StartSuspended - { - get { return _startSuspended; } - set - { - ThrowIfReadOnly(); - _startSuspended = value; - } - } - - - /// - /// Get/Set the default priority that a work item gets when it is enqueued - /// - public virtual WorkItemPriority WorkItemPriority - { - get { return _workItemPriority; } - set { _workItemPriority = value; } - } - - /// - /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the - /// arguments as an object array into the state of the work item. - /// The arguments can be access later by IWorkItemResult.State. - /// - public virtual bool FillStateWithArgs - { - get { return _fillStateWithArgs; } - set - { - ThrowIfReadOnly(); - _fillStateWithArgs = value; - } - } - - /// - /// Get a readonly version of this WIGStartInfo - /// - /// Returns a readonly reference to this WIGStartInfoRO - public WIGStartInfo AsReadOnly() - { - return new WIGStartInfo(this) { _readOnly = true }; - } - } -} +using System; + +namespace Amib.Threading +{ + /// + /// Summary description for WIGStartInfo. + /// + public class WIGStartInfo + { + private bool _useCallerCallContext; + private bool _useCallerHttpContext; + private bool _disposeOfStateObjects; + private CallToPostExecute _callToPostExecute; + private PostExecuteWorkItemCallback _postExecuteWorkItemCallback; + private bool _startSuspended; + private WorkItemPriority _workItemPriority; + private bool _fillStateWithArgs; + + protected bool _readOnly; + + public WIGStartInfo() + { + _fillStateWithArgs = SmartThreadPool.DefaultFillStateWithArgs; + _workItemPriority = SmartThreadPool.DefaultWorkItemPriority; + _startSuspended = SmartThreadPool.DefaultStartSuspended; + _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; + _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute; + _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; + _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; + _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; + } + + public WIGStartInfo(WIGStartInfo wigStartInfo) + { + _useCallerCallContext = wigStartInfo.UseCallerCallContext; + _useCallerHttpContext = wigStartInfo.UseCallerHttpContext; + _disposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + _callToPostExecute = wigStartInfo.CallToPostExecute; + _postExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + _workItemPriority = wigStartInfo.WorkItemPriority; + _startSuspended = wigStartInfo.StartSuspended; + _fillStateWithArgs = wigStartInfo.FillStateWithArgs; + } + + protected void ThrowIfReadOnly() + { + if (_readOnly) + { + throw new NotSupportedException("This is a readonly instance and set is not supported"); + } + } + + /// + /// Get/Set if to use the caller's security context + /// + public virtual bool UseCallerCallContext + { + get { return _useCallerCallContext; } + set + { + ThrowIfReadOnly(); + _useCallerCallContext = value; + } + } + + + /// + /// Get/Set if to use the caller's HTTP context + /// + public virtual bool UseCallerHttpContext + { + get { return _useCallerHttpContext; } + set + { + ThrowIfReadOnly(); + _useCallerHttpContext = value; + } + } + + + /// + /// Get/Set if to dispose of the state object of a work item + /// + public virtual bool DisposeOfStateObjects + { + get { return _disposeOfStateObjects; } + set + { + ThrowIfReadOnly(); + _disposeOfStateObjects = value; + } + } + + + /// + /// Get/Set the run the post execute options + /// + public virtual CallToPostExecute CallToPostExecute + { + get { return _callToPostExecute; } + set + { + ThrowIfReadOnly(); + _callToPostExecute = value; + } + } + + + /// + /// Get/Set the default post execute callback + /// + public virtual PostExecuteWorkItemCallback PostExecuteWorkItemCallback + { + get { return _postExecuteWorkItemCallback; } + set + { + ThrowIfReadOnly(); + _postExecuteWorkItemCallback = value; + } + } + + + /// + /// Get/Set if the work items execution should be suspended until the Start() + /// method is called. + /// + public virtual bool StartSuspended + { + get { return _startSuspended; } + set + { + ThrowIfReadOnly(); + _startSuspended = value; + } + } + + + /// + /// Get/Set the default priority that a work item gets when it is enqueued + /// + public virtual WorkItemPriority WorkItemPriority + { + get { return _workItemPriority; } + set { _workItemPriority = value; } + } + + /// + /// Get/Set the if QueueWorkItem of Action<...>/Func<...> fill the + /// arguments as an object array into the state of the work item. + /// The arguments can be access later by IWorkItemResult.State. + /// + public virtual bool FillStateWithArgs + { + get { return _fillStateWithArgs; } + set + { + ThrowIfReadOnly(); + _fillStateWithArgs = value; + } + } + + /// + /// Get a readonly version of this WIGStartInfo + /// + /// Returns a readonly reference to this WIGStartInfoRO + public WIGStartInfo AsReadOnly() + { + return new WIGStartInfo(this) { _readOnly = true }; + } + } +} diff --git a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs index 5745c15..435a14b 100644 --- a/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs +++ b/ThirdParty/SmartThreadPool/WorkItem.WorkItemResult.cs @@ -1,190 +1,190 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace Amib.Threading.Internal -{ - public partial class WorkItem - { - #region WorkItemResult class - - private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult - { - /// - /// A back reference to the work item - /// - private readonly WorkItem _workItem; - - public WorkItemResult(WorkItem workItem) - { - _workItem = workItem; - } - - internal WorkItem GetWorkItem() - { - return _workItem; - } - - #region IWorkItemResult Members - - public bool IsCompleted - { - get - { - return _workItem.IsCompleted; - } - } - - public bool IsCanceled - { - get - { - return _workItem.IsCanceled; - } - } - - public object GetResult() - { - return _workItem.GetResult(Timeout.Infinite, true, null); - } - - public object GetResult(int millisecondsTimeout, bool exitContext) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, null); - } - - public object GetResult(TimeSpan timeout, bool exitContext) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); - } - - public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); - } - - public object GetResult(out Exception e) - { - return _workItem.GetResult(Timeout.Infinite, true, null, out e); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); - } - - public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); - } - - public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); - } - - public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); - } - - public bool Cancel() - { - return Cancel(false); - } - - public bool Cancel(bool abortExecution) - { - return _workItem.Cancel(abortExecution); - } - - public object State - { - get - { - return _workItem._state; - } - } - - public WorkItemPriority WorkItemPriority - { - get - { - return _workItem._workItemInfo.WorkItemPriority; - } - } - - /// - /// Return the result, same as GetResult() - /// - public object Result - { - get { return GetResult(); } - } - - /// - /// Returns the exception if occured otherwise returns null. - /// This value is valid only after the work item completed, - /// before that it is always null. - /// - public object Exception - { - get { return _workItem._exception; } - } - - #endregion - - #region IInternalWorkItemResult Members - - public event WorkItemStateCallback OnWorkItemStarted - { - add - { - _workItem.OnWorkItemStarted += value; - } - remove - { - _workItem.OnWorkItemStarted -= value; - } - } - - - public event WorkItemStateCallback OnWorkItemCompleted - { - add - { - _workItem.OnWorkItemCompleted += value; - } - remove - { - _workItem.OnWorkItemCompleted -= value; - } - } - - #endregion - - #region IInternalWorkItemResult Members - - public IWorkItemResult GetWorkItemResult() - { - return this; - } - - public IWorkItemResult GetWorkItemResultT() - { - return new WorkItemResultTWrapper(this); - } - - #endregion - } - - #endregion - - } -} +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Amib.Threading.Internal +{ + public partial class WorkItem + { + #region WorkItemResult class + + private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult, IInternalWaitableResult + { + /// + /// A back reference to the work item + /// + private readonly WorkItem _workItem; + + public WorkItemResult(WorkItem workItem) + { + _workItem = workItem; + } + + internal WorkItem GetWorkItem() + { + return _workItem; + } + + #region IWorkItemResult Members + + public bool IsCompleted + { + get + { + return _workItem.IsCompleted; + } + } + + public bool IsCanceled + { + get + { + return _workItem.IsCanceled; + } + } + + public object GetResult() + { + return _workItem.GetResult(Timeout.Infinite, true, null); + } + + public object GetResult(int millisecondsTimeout, bool exitContext) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, null); + } + + public object GetResult(TimeSpan timeout, bool exitContext) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); + } + + public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle); + } + + public object GetResult(out Exception e) + { + return _workItem.GetResult(Timeout.Infinite, true, null, out e); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e); + } + + public object GetResult(TimeSpan timeout, bool exitContext, out Exception e) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e); + } + + public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); + } + + public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e); + } + + public bool Cancel() + { + return Cancel(false); + } + + public bool Cancel(bool abortExecution) + { + return _workItem.Cancel(abortExecution); + } + + public object State + { + get + { + return _workItem._state; + } + } + + public WorkItemPriority WorkItemPriority + { + get + { + return _workItem._workItemInfo.WorkItemPriority; + } + } + + /// + /// Return the result, same as GetResult() + /// + public object Result + { + get { return GetResult(); } + } + + /// + /// Returns the exception if occured otherwise returns null. + /// This value is valid only after the work item completed, + /// before that it is always null. + /// + public object Exception + { + get { return _workItem._exception; } + } + + #endregion + + #region IInternalWorkItemResult Members + + public event WorkItemStateCallback OnWorkItemStarted + { + add + { + _workItem.OnWorkItemStarted += value; + } + remove + { + _workItem.OnWorkItemStarted -= value; + } + } + + + public event WorkItemStateCallback OnWorkItemCompleted + { + add + { + _workItem.OnWorkItemCompleted += value; + } + remove + { + _workItem.OnWorkItemCompleted -= value; + } + } + + #endregion + + #region IInternalWorkItemResult Members + + public IWorkItemResult GetWorkItemResult() + { + return this; + } + + public IWorkItemResult GetWorkItemResultT() + { + return new WorkItemResultTWrapper(this); + } + + #endregion + } + + #endregion + + } +} diff --git a/ThirdParty/SmartThreadPool/WorkItemFactory.cs b/ThirdParty/SmartThreadPool/WorkItemFactory.cs index 2d6601e..16ccd81 100644 --- a/ThirdParty/SmartThreadPool/WorkItemFactory.cs +++ b/ThirdParty/SmartThreadPool/WorkItemFactory.cs @@ -1,343 +1,343 @@ -using System; - -namespace Amib.Threading.Internal -{ - #region WorkItemFactory class - - public class WorkItemFactory - { - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// A callback to execute - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback) - { - return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); - } - - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// A callback to execute - /// The priority of the work item - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - WorkItemPriority workItemPriority) - { - return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); - } - - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// Work item info - /// A callback to execute - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemInfo workItemInfo, - WorkItemCallback callback) - { - return CreateWorkItem( - workItemsGroup, - wigStartInfo, - workItemInfo, - callback, - null); - } - - /// - /// Create a new work item - /// - /// The WorkItemsGroup of this workitem - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state) - { - ValidateCallback(callback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - WorkItemPriority workItemPriority) - { - ValidateCallback(callback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = workItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemInfo workItemInfo, - WorkItemCallback callback, - object state) - { - ValidateCallback(callback); - ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); - - WorkItem workItem = new WorkItem( - workItemsGroup, - new WorkItemInfo(workItemInfo), - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = workItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = callToPostExecute; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - /// - /// Create a new work item - /// - /// The work items group - /// Work item group start information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item - public static WorkItem CreateWorkItem( - IWorkItemsGroup workItemsGroup, - WIGStartInfo wigStartInfo, - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - - ValidateCallback(callback); - ValidateCallback(postExecuteWorkItemCallback); - - WorkItemInfo workItemInfo = new WorkItemInfo(); - workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; - workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; - workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; - workItemInfo.CallToPostExecute = callToPostExecute; - workItemInfo.WorkItemPriority = workItemPriority; - workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; - - WorkItem workItem = new WorkItem( - workItemsGroup, - workItemInfo, - callback, - state); - - return workItem; - } - - private static void ValidateCallback(Delegate callback) - { - if (callback != null && callback.GetInvocationList().Length > 1) - { - throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); - } - } - } - - #endregion -} +using System; + +namespace Amib.Threading.Internal +{ + #region WorkItemFactory class + + public class WorkItemFactory + { + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback) + { + return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// The priority of the work item + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + WorkItemPriority workItemPriority) + { + return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// Work item info + /// A callback to execute + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemInfo workItemInfo, + WorkItemCallback callback) + { + return CreateWorkItem( + workItemsGroup, + wigStartInfo, + workItemInfo, + callback, + null); + } + + /// + /// Create a new work item + /// + /// The WorkItemsGroup of this workitem + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state) + { + ValidateCallback(callback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + WorkItemPriority workItemPriority) + { + ValidateCallback(callback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = workItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemInfo workItemInfo, + WorkItemCallback callback, + object state) + { + ValidateCallback(callback); + ValidateCallback(workItemInfo.PostExecuteWorkItemCallback); + + WorkItem workItem = new WorkItem( + workItemsGroup, + new WorkItemInfo(workItemInfo), + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + WorkItemPriority workItemPriority) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = workItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute) + { + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = callToPostExecute; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + workItemInfo.WorkItemPriority = wigStartInfo.WorkItemPriority; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + /// + /// Create a new work item + /// + /// The work items group + /// Work item group start information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item + public static WorkItem CreateWorkItem( + IWorkItemsGroup workItemsGroup, + WIGStartInfo wigStartInfo, + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute, + WorkItemPriority workItemPriority) + { + + ValidateCallback(callback); + ValidateCallback(postExecuteWorkItemCallback); + + WorkItemInfo workItemInfo = new WorkItemInfo(); + workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext; + workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext; + workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback; + workItemInfo.CallToPostExecute = callToPostExecute; + workItemInfo.WorkItemPriority = workItemPriority; + workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects; + + WorkItem workItem = new WorkItem( + workItemsGroup, + workItemInfo, + callback, + state); + + return workItem; + } + + private static void ValidateCallback(Delegate callback) + { + if (callback != null && callback.GetInvocationList().Length > 1) + { + throw new NotSupportedException("SmartThreadPool doesn't support delegates chains"); + } + } + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemInfo.cs b/ThirdParty/SmartThreadPool/WorkItemInfo.cs index 5fbceb8..0d7fc85 100644 --- a/ThirdParty/SmartThreadPool/WorkItemInfo.cs +++ b/ThirdParty/SmartThreadPool/WorkItemInfo.cs @@ -1,69 +1,69 @@ -namespace Amib.Threading -{ - #region WorkItemInfo class - - /// - /// Summary description for WorkItemInfo. - /// - public class WorkItemInfo - { - public WorkItemInfo() - { - UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; - UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; - DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; - CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; - PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; - WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; - } - - public WorkItemInfo(WorkItemInfo workItemInfo) - { - UseCallerCallContext = workItemInfo.UseCallerCallContext; - UseCallerHttpContext = workItemInfo.UseCallerHttpContext; - DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; - CallToPostExecute = workItemInfo.CallToPostExecute; - PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; - WorkItemPriority = workItemInfo.WorkItemPriority; - Timeout = workItemInfo.Timeout; - } - - /// - /// Get/Set if to use the caller's security context - /// - public bool UseCallerCallContext { get; set; } - - /// - /// Get/Set if to use the caller's HTTP context - /// - public bool UseCallerHttpContext { get; set; } - - /// - /// Get/Set if to dispose of the state object of a work item - /// - public bool DisposeOfStateObjects { get; set; } - - /// - /// Get/Set the run the post execute options - /// - public CallToPostExecute CallToPostExecute { get; set; } - - /// - /// Get/Set the post execute callback - /// - public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } - - /// - /// Get/Set the work item's priority - /// - public WorkItemPriority WorkItemPriority { get; set; } - - /// - /// Get/Set the work item's timout in milliseconds. - /// This is a passive timout. When the timout expires the work item won't be actively aborted! - /// - public long Timeout { get; set; } - } - - #endregion -} +namespace Amib.Threading +{ + #region WorkItemInfo class + + /// + /// Summary description for WorkItemInfo. + /// + public class WorkItemInfo + { + public WorkItemInfo() + { + UseCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext; + UseCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext; + DisposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects; + CallToPostExecute = SmartThreadPool.DefaultCallToPostExecute; + PostExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback; + WorkItemPriority = SmartThreadPool.DefaultWorkItemPriority; + } + + public WorkItemInfo(WorkItemInfo workItemInfo) + { + UseCallerCallContext = workItemInfo.UseCallerCallContext; + UseCallerHttpContext = workItemInfo.UseCallerHttpContext; + DisposeOfStateObjects = workItemInfo.DisposeOfStateObjects; + CallToPostExecute = workItemInfo.CallToPostExecute; + PostExecuteWorkItemCallback = workItemInfo.PostExecuteWorkItemCallback; + WorkItemPriority = workItemInfo.WorkItemPriority; + Timeout = workItemInfo.Timeout; + } + + /// + /// Get/Set if to use the caller's security context + /// + public bool UseCallerCallContext { get; set; } + + /// + /// Get/Set if to use the caller's HTTP context + /// + public bool UseCallerHttpContext { get; set; } + + /// + /// Get/Set if to dispose of the state object of a work item + /// + public bool DisposeOfStateObjects { get; set; } + + /// + /// Get/Set the run the post execute options + /// + public CallToPostExecute CallToPostExecute { get; set; } + + /// + /// Get/Set the post execute callback + /// + public PostExecuteWorkItemCallback PostExecuteWorkItemCallback { get; set; } + + /// + /// Get/Set the work item's priority + /// + public WorkItemPriority WorkItemPriority { get; set; } + + /// + /// Get/Set the work item's timout in milliseconds. + /// This is a passive timout. When the timout expires the work item won't be actively aborted! + /// + public long Timeout { get; set; } + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs index a0bf8b8..d1eff95 100644 --- a/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs +++ b/ThirdParty/SmartThreadPool/WorkItemResultTWrapper.cs @@ -1,128 +1,128 @@ -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ - #region WorkItemResultTWrapper class - - internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult - { - private readonly IWorkItemResult _workItemResult; - - public WorkItemResultTWrapper(IWorkItemResult workItemResult) - { - _workItemResult = workItemResult; - } - - #region IWorkItemResult Members - - public TResult GetResult() - { - return (TResult)_workItemResult.GetResult(); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); - } - - public TResult GetResult(out Exception e) - { - return (TResult)_workItemResult.GetResult(out e); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); - } - - public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); - } - - public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) - { - return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); - } - - public bool IsCompleted - { - get { return _workItemResult.IsCompleted; } - } - - public bool IsCanceled - { - get { return _workItemResult.IsCanceled; } - } - - public object State - { - get { return _workItemResult.State; } - } - - public bool Cancel() - { - return _workItemResult.Cancel(); - } - - public bool Cancel(bool abortExecution) - { - return _workItemResult.Cancel(abortExecution); - } - - public WorkItemPriority WorkItemPriority - { - get { return _workItemResult.WorkItemPriority; } - } - - public TResult Result - { - get { return (TResult)_workItemResult.Result; } - } - - public object Exception - { - get { return (TResult)_workItemResult.Exception; } - } - - #region IInternalWorkItemResult Members - - public IWorkItemResult GetWorkItemResult() - { - return _workItemResult.GetWorkItemResult(); - } - - public IWorkItemResult GetWorkItemResultT() - { - return (IWorkItemResult)this; - } - - #endregion - - #endregion - } - - #endregion - -} +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ + #region WorkItemResultTWrapper class + + internal class WorkItemResultTWrapper : IWorkItemResult, IInternalWaitableResult + { + private readonly IWorkItemResult _workItemResult; + + public WorkItemResultTWrapper(IWorkItemResult workItemResult) + { + _workItemResult = workItemResult; + } + + #region IWorkItemResult Members + + public TResult GetResult() + { + return (TResult)_workItemResult.GetResult(); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle); + } + + public TResult GetResult(out Exception e) + { + return (TResult)_workItemResult.GetResult(out e); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, out Exception e) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, out e); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, out Exception e) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, out e); + } + + public TResult GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return (TResult)_workItemResult.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e); + } + + public TResult GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e) + { + return (TResult)_workItemResult.GetResult(timeout, exitContext, cancelWaitHandle, out e); + } + + public bool IsCompleted + { + get { return _workItemResult.IsCompleted; } + } + + public bool IsCanceled + { + get { return _workItemResult.IsCanceled; } + } + + public object State + { + get { return _workItemResult.State; } + } + + public bool Cancel() + { + return _workItemResult.Cancel(); + } + + public bool Cancel(bool abortExecution) + { + return _workItemResult.Cancel(abortExecution); + } + + public WorkItemPriority WorkItemPriority + { + get { return _workItemResult.WorkItemPriority; } + } + + public TResult Result + { + get { return (TResult)_workItemResult.Result; } + } + + public object Exception + { + get { return (TResult)_workItemResult.Exception; } + } + + #region IInternalWorkItemResult Members + + public IWorkItemResult GetWorkItemResult() + { + return _workItemResult.GetWorkItemResult(); + } + + public IWorkItemResult GetWorkItemResultT() + { + return (IWorkItemResult)this; + } + + #endregion + + #endregion + } + + #endregion + +} diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs index 67dcbdd..d9d34ac 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsGroup.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsGroup.cs @@ -1,361 +1,361 @@ -using System; -using System.Threading; -using System.Runtime.CompilerServices; -using System.Diagnostics; - -namespace Amib.Threading.Internal -{ - - #region WorkItemsGroup class - - /// - /// Summary description for WorkItemsGroup. - /// - public class WorkItemsGroup : WorkItemsGroupBase - { - #region Private members - - private readonly object _lock = new object(); - - /// - /// A reference to the SmartThreadPool instance that created this - /// WorkItemsGroup. - /// - private readonly SmartThreadPool _stp; - - /// - /// The OnIdle event - /// - private event WorkItemsGroupIdleHandler _onIdle; - - /// - /// A flag to indicate if the Work Items Group is now suspended. - /// - private bool _isSuspended; - - /// - /// Defines how many work items of this WorkItemsGroup can run at once. - /// - private int _concurrency; - - /// - /// Priority queue to hold work items before they are passed - /// to the SmartThreadPool. - /// - private readonly PriorityQueue _workItemsQueue; - - /// - /// Indicate how many work items are waiting in the SmartThreadPool - /// queue. - /// This value is used to apply the concurrency. - /// - private int _workItemsInStpQueue; - - /// - /// Indicate how many work items are currently running in the SmartThreadPool. - /// This value is used with the Cancel, to calculate if we can send new - /// work items to the STP. - /// - private int _workItemsExecutingInStp = 0; - - /// - /// WorkItemsGroup start information - /// - private readonly WIGStartInfo _workItemsGroupStartInfo; - - /// - /// Signaled when all of the WorkItemsGroup's work item completed. - /// - //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); - private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); - - /// - /// A common object for all the work items that this work items group - /// generate so we can mark them to cancel in O(1) - /// - private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); - - #endregion - - #region Construction - - public WorkItemsGroup( - SmartThreadPool stp, - int concurrency, - WIGStartInfo wigStartInfo) - { - if (concurrency <= 0) - { - throw new ArgumentOutOfRangeException( - "concurrency", -#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) - concurrency, -#endif - "concurrency must be greater than zero"); - } - _stp = stp; - _concurrency = concurrency; - _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly(); - _workItemsQueue = new PriorityQueue(); - Name = "WorkItemsGroup"; - - // The _workItemsInStpQueue gets the number of currently executing work items, - // because once a work item is executing, it cannot be cancelled. - _workItemsInStpQueue = _workItemsExecutingInStp; - - _isSuspended = _workItemsGroupStartInfo.StartSuspended; - } - - #endregion - - #region WorkItemsGroupBase Overrides - - public override int Concurrency - { - get { return _concurrency; } - set - { - Debug.Assert(value > 0); - - int diff = value - _concurrency; - _concurrency = value; - if (diff > 0) - { - EnqueueToSTPNextNWorkItem(diff); - } - } - } - - public override int WaitingCallbacks - { - get { return _workItemsQueue.Count; } - } - - public override object[] GetStates() - { - lock (_lock) - { - object[] states = new object[_workItemsQueue.Count]; - int i = 0; - foreach (WorkItem workItem in _workItemsQueue) - { - states[i] = workItem.GetWorkItemResult().State; - ++i; - } - return states; - } - } - - /// - /// WorkItemsGroup start information - /// - public override WIGStartInfo WIGStartInfo - { - get { return _workItemsGroupStartInfo; } - } - - /// - /// Start the Work Items Group if it was started suspended - /// - public override void Start() - { - // If the Work Items Group already started then quit - if (!_isSuspended) - { - return; - } - _isSuspended = false; - - EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); - } - - public override void Cancel(bool abortExecution) - { - lock (_lock) - { - _canceledWorkItemsGroup.IsCanceled = true; - _workItemsQueue.Clear(); - _workItemsInStpQueue = 0; - _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); - } - - if (abortExecution) - { - _stp.CancelAbortWorkItemsGroup(this); - } - } - - /// - /// Wait for the thread pool to be idle - /// - public override bool WaitForIdle(int millisecondsTimeout) - { - SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this); - return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); - } - - public override event WorkItemsGroupIdleHandler OnIdle - { - add { _onIdle += value; } - remove { _onIdle -= value; } - } - - #endregion - - #region Private methods - - private void RegisterToWorkItemCompletion(IWorkItemResult wir) - { - IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir; - iwir.OnWorkItemStarted += OnWorkItemStartedCallback; - iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback; - } - - public void OnSTPIsStarting() - { - if (_isSuspended) - { - return; - } - - EnqueueToSTPNextNWorkItem(_concurrency); - } - - public void EnqueueToSTPNextNWorkItem(int count) - { - for (int i = 0; i < count; ++i) - { - EnqueueToSTPNextWorkItem(null, false); - } - } - - private object FireOnIdle(object state) - { - FireOnIdleImpl(_onIdle); - return null; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) - { - if(null == onIdle) - { - return; - } - - Delegate[] delegates = onIdle.GetInvocationList(); - foreach(WorkItemsGroupIdleHandler eh in delegates) - { - try - { - eh(this); - } - catch { } // Suppress exceptions - } - } - - private void OnWorkItemStartedCallback(WorkItem workItem) - { - lock(_lock) - { - ++_workItemsExecutingInStp; - } - } - - private void OnWorkItemCompletedCallback(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(null, true); - } - - internal override void Enqueue(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(workItem); - } - - private void EnqueueToSTPNextWorkItem(WorkItem workItem) - { - EnqueueToSTPNextWorkItem(workItem, false); - } - - private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) - { - lock(_lock) - { - // Got here from OnWorkItemCompletedCallback() - if (decrementWorkItemsInStpQueue) - { - --_workItemsInStpQueue; - - if(_workItemsInStpQueue < 0) - { - _workItemsInStpQueue = 0; - } - - --_workItemsExecutingInStp; - - if(_workItemsExecutingInStp < 0) - { - _workItemsExecutingInStp = 0; - } - } - - // If the work item is not null then enqueue it - if (null != workItem) - { - workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; - - RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); - _workItemsQueue.Enqueue(workItem); - //_stp.IncrementWorkItemsCount(); - - if ((1 == _workItemsQueue.Count) && - (0 == _workItemsInStpQueue)) - { - _stp.RegisterWorkItemsGroup(this); - IsIdle = false; - _isIdleWaitHandle.Reset(); - } - } - - // If the work items queue of the group is empty than quit - if (0 == _workItemsQueue.Count) - { - if (0 == _workItemsInStpQueue) - { - _stp.UnregisterWorkItemsGroup(this); - IsIdle = true; - _isIdleWaitHandle.Set(); - if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0) - { - _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle)); - } - } - return; - } - - if (!_isSuspended) - { - if (_workItemsInStpQueue < _concurrency) - { - WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; - try - { - _stp.Enqueue(nextWorkItem); - } - catch (ObjectDisposedException e) - { - e.GetHashCode(); - // The STP has been shutdown - } - - ++_workItemsInStpQueue; - } - } - } - } - - #endregion - } - - #endregion -} +using System; +using System.Threading; +using System.Runtime.CompilerServices; +using System.Diagnostics; + +namespace Amib.Threading.Internal +{ + + #region WorkItemsGroup class + + /// + /// Summary description for WorkItemsGroup. + /// + public class WorkItemsGroup : WorkItemsGroupBase + { + #region Private members + + private readonly object _lock = new object(); + + /// + /// A reference to the SmartThreadPool instance that created this + /// WorkItemsGroup. + /// + private readonly SmartThreadPool _stp; + + /// + /// The OnIdle event + /// + private event WorkItemsGroupIdleHandler _onIdle; + + /// + /// A flag to indicate if the Work Items Group is now suspended. + /// + private bool _isSuspended; + + /// + /// Defines how many work items of this WorkItemsGroup can run at once. + /// + private int _concurrency; + + /// + /// Priority queue to hold work items before they are passed + /// to the SmartThreadPool. + /// + private readonly PriorityQueue _workItemsQueue; + + /// + /// Indicate how many work items are waiting in the SmartThreadPool + /// queue. + /// This value is used to apply the concurrency. + /// + private int _workItemsInStpQueue; + + /// + /// Indicate how many work items are currently running in the SmartThreadPool. + /// This value is used with the Cancel, to calculate if we can send new + /// work items to the STP. + /// + private int _workItemsExecutingInStp = 0; + + /// + /// WorkItemsGroup start information + /// + private readonly WIGStartInfo _workItemsGroupStartInfo; + + /// + /// Signaled when all of the WorkItemsGroup's work item completed. + /// + //private readonly ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true); + private readonly ManualResetEvent _isIdleWaitHandle = EventWaitHandleFactory.CreateManualResetEvent(true); + + /// + /// A common object for all the work items that this work items group + /// generate so we can mark them to cancel in O(1) + /// + private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); + + #endregion + + #region Construction + + public WorkItemsGroup( + SmartThreadPool stp, + int concurrency, + WIGStartInfo wigStartInfo) + { + if (concurrency <= 0) + { + throw new ArgumentOutOfRangeException( + "concurrency", +#if !(_WINDOWS_CE) && !(_SILVERLIGHT) && !(WINDOWS_PHONE) + concurrency, +#endif + "concurrency must be greater than zero"); + } + _stp = stp; + _concurrency = concurrency; + _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo).AsReadOnly(); + _workItemsQueue = new PriorityQueue(); + Name = "WorkItemsGroup"; + + // The _workItemsInStpQueue gets the number of currently executing work items, + // because once a work item is executing, it cannot be cancelled. + _workItemsInStpQueue = _workItemsExecutingInStp; + + _isSuspended = _workItemsGroupStartInfo.StartSuspended; + } + + #endregion + + #region WorkItemsGroupBase Overrides + + public override int Concurrency + { + get { return _concurrency; } + set + { + Debug.Assert(value > 0); + + int diff = value - _concurrency; + _concurrency = value; + if (diff > 0) + { + EnqueueToSTPNextNWorkItem(diff); + } + } + } + + public override int WaitingCallbacks + { + get { return _workItemsQueue.Count; } + } + + public override object[] GetStates() + { + lock (_lock) + { + object[] states = new object[_workItemsQueue.Count]; + int i = 0; + foreach (WorkItem workItem in _workItemsQueue) + { + states[i] = workItem.GetWorkItemResult().State; + ++i; + } + return states; + } + } + + /// + /// WorkItemsGroup start information + /// + public override WIGStartInfo WIGStartInfo + { + get { return _workItemsGroupStartInfo; } + } + + /// + /// Start the Work Items Group if it was started suspended + /// + public override void Start() + { + // If the Work Items Group already started then quit + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); + } + + public override void Cancel(bool abortExecution) + { + lock (_lock) + { + _canceledWorkItemsGroup.IsCanceled = true; + _workItemsQueue.Clear(); + _workItemsInStpQueue = 0; + _canceledWorkItemsGroup = new CanceledWorkItemsGroup(); + } + + if (abortExecution) + { + _stp.CancelAbortWorkItemsGroup(this); + } + } + + /// + /// Wait for the thread pool to be idle + /// + public override bool WaitForIdle(int millisecondsTimeout) + { + SmartThreadPool.ValidateWorkItemsGroupWaitForIdle(this); + return STPEventWaitHandle.WaitOne(_isIdleWaitHandle, millisecondsTimeout, false); + } + + public override event WorkItemsGroupIdleHandler OnIdle + { + add { _onIdle += value; } + remove { _onIdle -= value; } + } + + #endregion + + #region Private methods + + private void RegisterToWorkItemCompletion(IWorkItemResult wir) + { + IInternalWorkItemResult iwir = (IInternalWorkItemResult)wir; + iwir.OnWorkItemStarted += OnWorkItemStartedCallback; + iwir.OnWorkItemCompleted += OnWorkItemCompletedCallback; + } + + public void OnSTPIsStarting() + { + if (_isSuspended) + { + return; + } + + EnqueueToSTPNextNWorkItem(_concurrency); + } + + public void EnqueueToSTPNextNWorkItem(int count) + { + for (int i = 0; i < count; ++i) + { + EnqueueToSTPNextWorkItem(null, false); + } + } + + private object FireOnIdle(object state) + { + FireOnIdleImpl(_onIdle); + return null; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle) + { + if(null == onIdle) + { + return; + } + + Delegate[] delegates = onIdle.GetInvocationList(); + foreach(WorkItemsGroupIdleHandler eh in delegates) + { + try + { + eh(this); + } + catch { } // Suppress exceptions + } + } + + private void OnWorkItemStartedCallback(WorkItem workItem) + { + lock(_lock) + { + ++_workItemsExecutingInStp; + } + } + + private void OnWorkItemCompletedCallback(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(null, true); + } + + internal override void Enqueue(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(workItem); + } + + private void EnqueueToSTPNextWorkItem(WorkItem workItem) + { + EnqueueToSTPNextWorkItem(workItem, false); + } + + private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue) + { + lock(_lock) + { + // Got here from OnWorkItemCompletedCallback() + if (decrementWorkItemsInStpQueue) + { + --_workItemsInStpQueue; + + if(_workItemsInStpQueue < 0) + { + _workItemsInStpQueue = 0; + } + + --_workItemsExecutingInStp; + + if(_workItemsExecutingInStp < 0) + { + _workItemsExecutingInStp = 0; + } + } + + // If the work item is not null then enqueue it + if (null != workItem) + { + workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup; + + RegisterToWorkItemCompletion(workItem.GetWorkItemResult()); + _workItemsQueue.Enqueue(workItem); + //_stp.IncrementWorkItemsCount(); + + if ((1 == _workItemsQueue.Count) && + (0 == _workItemsInStpQueue)) + { + _stp.RegisterWorkItemsGroup(this); + IsIdle = false; + _isIdleWaitHandle.Reset(); + } + } + + // If the work items queue of the group is empty than quit + if (0 == _workItemsQueue.Count) + { + if (0 == _workItemsInStpQueue) + { + _stp.UnregisterWorkItemsGroup(this); + IsIdle = true; + _isIdleWaitHandle.Set(); + if (decrementWorkItemsInStpQueue && _onIdle != null && _onIdle.GetInvocationList().Length > 0) + { + _stp.QueueWorkItem(new WorkItemCallback(FireOnIdle)); + } + } + return; + } + + if (!_isSuspended) + { + if (_workItemsInStpQueue < _concurrency) + { + WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem; + try + { + _stp.Enqueue(nextWorkItem); + } + catch (ObjectDisposedException e) + { + e.GetHashCode(); + // The STP has been shutdown + } + + ++_workItemsInStpQueue; + } + } + } + } + + #endregion + } + + #endregion +} diff --git a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs index 429de12..27fae5e 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsGroupBase.cs @@ -1,471 +1,471 @@ -using System; -using System.Threading; - -namespace Amib.Threading.Internal -{ - public abstract class WorkItemsGroupBase : IWorkItemsGroup - { - #region Private Fields - - /// - /// Contains the name of this instance of SmartThreadPool. - /// Can be changed by the user. - /// - private string _name = "WorkItemsGroupBase"; - - public WorkItemsGroupBase() - { - IsIdle = true; - } - - #endregion - - #region IWorkItemsGroup Members - - #region Public Methods - - /// - /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance - /// - public string Name - { - get { return _name; } - set { _name = value; } - } - - #endregion - - #region Abstract Methods - - public abstract int Concurrency { get; set; } - public abstract int WaitingCallbacks { get; } - public abstract object[] GetStates(); - public abstract WIGStartInfo WIGStartInfo { get; } - public abstract void Start(); - public abstract void Cancel(bool abortExecution); - public abstract bool WaitForIdle(int millisecondsTimeout); - public abstract event WorkItemsGroupIdleHandler OnIdle; - - internal abstract void Enqueue(WorkItem workItem); - internal virtual void PreQueueWorkItem() { } - - #endregion - - #region Common Base Methods - - /// - /// Cancel all the work items. - /// Same as Cancel(false) - /// - public virtual void Cancel() - { - Cancel(false); - } - - /// - /// Wait for the SmartThreadPool/WorkItemsGroup to be idle - /// - public void WaitForIdle() - { - WaitForIdle(Timeout.Infinite); - } - - /// - /// Wait for the SmartThreadPool/WorkItemsGroup to be idle - /// - public bool WaitForIdle(TimeSpan timeout) - { - return WaitForIdle((int)timeout.TotalMilliseconds); - } - - /// - /// IsIdle is true when there are no work items running or queued. - /// - public bool IsIdle { get; protected set; } - - #endregion - - #region QueueWorkItem - - /// - /// Queue a work item - /// - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// The priority of the work item - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item info - /// A callback to execute - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) - { - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// Work item information - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - /// - /// Queue a work item - /// - /// A callback to execute - /// - /// The context object of the work item. Used for passing arguments to the work item. - /// - /// - /// A delegate to call after the callback completion - /// - /// Indicates on which cases to call to the post execute callback - /// The work item priority - /// Returns a work item result - public IWorkItemResult QueueWorkItem( - WorkItemCallback callback, - object state, - PostExecuteWorkItemCallback postExecuteWorkItemCallback, - CallToPostExecute callToPostExecute, - WorkItemPriority workItemPriority) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); - Enqueue(workItem); - return workItem.GetWorkItemResult(); - } - - #endregion - - #region QueueWorkItem(Action<...>) - - public IWorkItemResult QueueWorkItem(Action action) - { - return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - delegate - { - action.Invoke (); - return null; - }, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem(Action action, T arg) - { - return QueueWorkItem (action, arg, SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2) - { - return QueueWorkItem (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg1, arg2); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3) - { - return QueueWorkItem (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority); - ; - } - - public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg1, arg2, arg3); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - public IWorkItemResult QueueWorkItem( - Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - return QueueWorkItem (action, arg1, arg2, arg3, arg4, - SmartThreadPool.DefaultWorkItemPriority); - } - - public IWorkItemResult QueueWorkItem ( - Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority) - { - PreQueueWorkItem (); - WorkItem workItem = WorkItemFactory.CreateWorkItem ( - this, - WIGStartInfo, - state => - { - action.Invoke (arg1, arg2, arg3, arg4); - return null; - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority); - Enqueue (workItem); - return workItem.GetWorkItemResult (); - } - - #endregion - - #region QueueWorkItem(Func<...>) - - public IWorkItemResult QueueWorkItem(Func func) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(); - }); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem(Func func, T arg) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg1, arg2); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem( - Func func, T1 arg1, T2 arg2, T3 arg3) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg1, arg2, arg3); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - public IWorkItemResult QueueWorkItem( - Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) - { - PreQueueWorkItem(); - WorkItem workItem = WorkItemFactory.CreateWorkItem( - this, - WIGStartInfo, - state => - { - return func.Invoke(arg1, arg2, arg3, arg4); - }, - WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null); - Enqueue(workItem); - return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); - } - - #endregion - - #endregion - } +using System; +using System.Threading; + +namespace Amib.Threading.Internal +{ + public abstract class WorkItemsGroupBase : IWorkItemsGroup + { + #region Private Fields + + /// + /// Contains the name of this instance of SmartThreadPool. + /// Can be changed by the user. + /// + private string _name = "WorkItemsGroupBase"; + + public WorkItemsGroupBase() + { + IsIdle = true; + } + + #endregion + + #region IWorkItemsGroup Members + + #region Public Methods + + /// + /// Get/Set the name of the SmartThreadPool/WorkItemsGroup instance + /// + public string Name + { + get { return _name; } + set { _name = value; } + } + + #endregion + + #region Abstract Methods + + public abstract int Concurrency { get; set; } + public abstract int WaitingCallbacks { get; } + public abstract object[] GetStates(); + public abstract WIGStartInfo WIGStartInfo { get; } + public abstract void Start(); + public abstract void Cancel(bool abortExecution); + public abstract bool WaitForIdle(int millisecondsTimeout); + public abstract event WorkItemsGroupIdleHandler OnIdle; + + internal abstract void Enqueue(WorkItem workItem); + internal virtual void PreQueueWorkItem() { } + + #endregion + + #region Common Base Methods + + /// + /// Cancel all the work items. + /// Same as Cancel(false) + /// + public virtual void Cancel() + { + Cancel(false); + } + + /// + /// Wait for the SmartThreadPool/WorkItemsGroup to be idle + /// + public void WaitForIdle() + { + WaitForIdle(Timeout.Infinite); + } + + /// + /// Wait for the SmartThreadPool/WorkItemsGroup to be idle + /// + public bool WaitForIdle(TimeSpan timeout) + { + return WaitForIdle((int)timeout.TotalMilliseconds); + } + + /// + /// IsIdle is true when there are no work items running or queued. + /// + public bool IsIdle { get; protected set; } + + #endregion + + #region QueueWorkItem + + /// + /// Queue a work item + /// + /// A callback to execute + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback) + { + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// The priority of the work item + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// Work item info + /// A callback to execute + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state) + { + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// Work item information + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, workItemInfo, callback, state); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + /// + /// Queue a work item + /// + /// A callback to execute + /// + /// The context object of the work item. Used for passing arguments to the work item. + /// + /// + /// A delegate to call after the callback completion + /// + /// Indicates on which cases to call to the post execute callback + /// The work item priority + /// Returns a work item result + public IWorkItemResult QueueWorkItem( + WorkItemCallback callback, + object state, + PostExecuteWorkItemCallback postExecuteWorkItemCallback, + CallToPostExecute callToPostExecute, + WorkItemPriority workItemPriority) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem(this, WIGStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority); + Enqueue(workItem); + return workItem.GetWorkItemResult(); + } + + #endregion + + #region QueueWorkItem(Action<...>) + + public IWorkItemResult QueueWorkItem(Action action) + { + return QueueWorkItem (action, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + delegate + { + action.Invoke (); + return null; + }, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T arg) + { + return QueueWorkItem (action, arg, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, T arg, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2) + { + return QueueWorkItem (action, arg1, arg2, SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem(Action action, T1 arg1, T2 arg2, T3 arg3) + { + return QueueWorkItem (action, arg1, arg2, arg3, SmartThreadPool.DefaultWorkItemPriority); + ; + } + + public IWorkItemResult QueueWorkItem (Action action, T1 arg1, T2 arg2, T3 arg3, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2, arg3); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + public IWorkItemResult QueueWorkItem( + Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + return QueueWorkItem (action, arg1, arg2, arg3, arg4, + SmartThreadPool.DefaultWorkItemPriority); + } + + public IWorkItemResult QueueWorkItem ( + Action action, T1 arg1, T2 arg2, T3 arg3, T4 arg4, WorkItemPriority priority) + { + PreQueueWorkItem (); + WorkItem workItem = WorkItemFactory.CreateWorkItem ( + this, + WIGStartInfo, + state => + { + action.Invoke (arg1, arg2, arg3, arg4); + return null; + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null, priority); + Enqueue (workItem); + return workItem.GetWorkItemResult (); + } + + #endregion + + #region QueueWorkItem(Func<...>) + + public IWorkItemResult QueueWorkItem(Func func) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(); + }); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem(Func func, T arg) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem(Func func, T1 arg1, T2 arg2) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem( + Func func, T1 arg1, T2 arg2, T3 arg3) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2, arg3); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + public IWorkItemResult QueueWorkItem( + Func func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) + { + PreQueueWorkItem(); + WorkItem workItem = WorkItemFactory.CreateWorkItem( + this, + WIGStartInfo, + state => + { + return func.Invoke(arg1, arg2, arg3, arg4); + }, + WIGStartInfo.FillStateWithArgs ? new object[] { arg1, arg2, arg3, arg4 } : null); + Enqueue(workItem); + return new WorkItemResultTWrapper(workItem.GetWorkItemResult()); + } + + #endregion + + #endregion + } } \ No newline at end of file diff --git a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs index 156a131..e0bc916 100644 --- a/ThirdParty/SmartThreadPool/WorkItemsQueue.cs +++ b/ThirdParty/SmartThreadPool/WorkItemsQueue.cs @@ -1,645 +1,645 @@ -using System; -using System.Collections.Generic; -using System.Threading; - -namespace Amib.Threading.Internal -{ - #region WorkItemsQueue class - - /// - /// WorkItemsQueue class. - /// - public class WorkItemsQueue : IDisposable - { - #region Member variables - - /// - /// Waiters queue (implemented as stack). - /// - private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); - - /// - /// Waiters count - /// - private int _waitersCount = 0; - - /// - /// Work items queue - /// - private readonly PriorityQueue _workItems = new PriorityQueue(); - - /// - /// Indicate that work items are allowed to be queued - /// - private bool _isWorkItemsQueueActive = true; - - -#if (WINDOWS_PHONE) - private static readonly Dictionary _waiterEntries = new Dictionary(); -#elif (_WINDOWS_CE) - private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); -#else - - [ThreadStatic] - private static WaiterEntry _waiterEntry; -#endif - - - /// - /// Each thread in the thread pool keeps its own waiter entry. - /// - private static WaiterEntry CurrentWaiterEntry - { -#if (WINDOWS_PHONE) - get - { - lock (_waiterEntries) - { - WaiterEntry waiterEntry; - if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry)) - { - return waiterEntry; - } - } - return null; - } - set - { - lock (_waiterEntries) - { - _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value; - } - } -#elif (_WINDOWS_CE) - get - { - return Thread.GetData(_waiterEntrySlot) as WaiterEntry; - } - set - { - Thread.SetData(_waiterEntrySlot, value); - } -#else - get - { - return _waiterEntry; - } - set - { - _waiterEntry = value; - } -#endif - } - - /// - /// A flag that indicates if the WorkItemsQueue has been disposed. - /// - private bool _isDisposed = false; - - #endregion - - #region Public properties - - /// - /// Returns the current number of work items in the queue - /// - public int Count - { - get - { - return _workItems.Count; - } - } - - /// - /// Returns the current number of waiters - /// - public int WaitersCount - { - get - { - return _waitersCount; - } - } - - - #endregion - - #region Public methods - - /// - /// Enqueue a work item to the queue. - /// - public bool EnqueueWorkItem(WorkItem workItem) - { - // A work item cannot be null, since null is used in the - // WaitForWorkItem() method to indicate timeout or cancel - if (null == workItem) - { - throw new ArgumentNullException("workItem" , "workItem cannot be null"); - } - - bool enqueue = true; - - // First check if there is a waiter waiting for work item. During - // the check, timed out waiters are ignored. If there is no - // waiter then the work item is queued. - lock(this) - { - ValidateNotDisposed(); - - if (!_isWorkItemsQueueActive) - { - return false; - } - - while(_waitersCount > 0) - { - // Dequeue a waiter. - WaiterEntry waiterEntry = PopWaiter(); - - // Signal the waiter. On success break the loop - if (waiterEntry.Signal(workItem)) - { - enqueue = false; - break; - } - } - - if (enqueue) - { - // Enqueue the work item - _workItems.Enqueue(workItem); - } - } - return true; - } - - - /// - /// Waits for a work item or exits on timeout or cancel - /// - /// Timeout in milliseconds - /// Cancel wait handle - /// Returns true if the resource was granted - public WorkItem DequeueWorkItem( - int millisecondsTimeout, - WaitHandle cancelEvent) - { - // This method cause the caller to wait for a work item. - // If there is at least one waiting work item then the - // method returns immidiately with it. - // - // If there are no waiting work items then the caller - // is queued between other waiters for a work item to arrive. - // - // If a work item didn't come within millisecondsTimeout or - // the user canceled the wait by signaling the cancelEvent - // then the method returns null to indicate that the caller - // didn't get a work item. - - WaiterEntry waiterEntry; - WorkItem workItem = null; - lock (this) - { - ValidateNotDisposed(); - - // If there are waiting work items then take one and return. - if (_workItems.Count > 0) - { - workItem = _workItems.Dequeue() as WorkItem; - return workItem; - } - - // No waiting work items ... - - // Get the waiter entry for the waiters queue - waiterEntry = GetThreadWaiterEntry(); - - // Put the waiter with the other waiters - PushWaiter(waiterEntry); - } - - // Prepare array of wait handle for the WaitHandle.WaitAny() - WaitHandle [] waitHandles = new WaitHandle[] { - waiterEntry.WaitHandle, - cancelEvent }; - - // Wait for an available resource, cancel event, or timeout. - - // During the wait we are supposes to exit the synchronization - // domain. (Placing true as the third argument of the WaitAny()) - // It just doesn't work, I don't know why, so I have two lock(this) - // statments instead of one. - - int index = STPEventWaitHandle.WaitAny( - waitHandles, - millisecondsTimeout, - true); - - lock(this) - { - // success is true if it got a work item. - bool success = (0 == index); - - // The timeout variable is used only for readability. - // (We treat cancel as timeout) - bool timeout = !success; - - // On timeout update the waiterEntry that it is timed out - if (timeout) - { - // The Timeout() fails if the waiter has already been signaled - timeout = waiterEntry.Timeout(); - - // On timeout remove the waiter from the queue. - // Note that the complexity is O(1). - if(timeout) - { - RemoveWaiter(waiterEntry, false); - } - - // Again readability - success = !timeout; - } - - // On success return the work item - if (success) - { - workItem = waiterEntry.WorkItem; - - if (null == workItem) - { - workItem = _workItems.Dequeue() as WorkItem; - } - } - } - // On failure return null. - return workItem; - } - - /// - /// Cleanup the work items queue, hence no more work - /// items are allowed to be queue - /// - private void Cleanup() - { - lock(this) - { - // Deactivate only once - if (!_isWorkItemsQueueActive) - { - return; - } - - // Don't queue more work items - _isWorkItemsQueueActive = false; - - foreach(WorkItem workItem in _workItems) - { - workItem.DisposeOfState(); - } - - // Clear the work items that are already queued - _workItems.Clear(); - - // Note: - // I don't iterate over the queue and dispose of work items's states, - // since if a work item has a state object that is still in use in the - // application then I must not dispose it. - - // Tell the waiters that they were timed out. - // It won't signal them to exit, but to ignore their - // next work item. - while(_waitersCount > 0) - { - WaiterEntry waiterEntry = PopWaiter(); - waiterEntry.Timeout(); - } - } - } - - public object[] GetStates() - { - lock (this) - { - object[] states = new object[_workItems.Count]; - int i = 0; - foreach (WorkItem workItem in _workItems) - { - states[i] = workItem.GetWorkItemResult().State; - ++i; - } - return states; - } - } - - #endregion - - #region Private methods - - /// - /// Returns the WaiterEntry of the current thread - /// - /// - /// In order to avoid creation and destuction of WaiterEntry - /// objects each thread has its own WaiterEntry object. - private static WaiterEntry GetThreadWaiterEntry() - { - if (null == CurrentWaiterEntry) - { - CurrentWaiterEntry = new WaiterEntry(); - } - CurrentWaiterEntry.Reset(); - return CurrentWaiterEntry; - } - - #region Waiters stack methods - - /// - /// Push a new waiter into the waiter's stack - /// - /// A waiter to put in the stack - public void PushWaiter(WaiterEntry newWaiterEntry) - { - // Remove the waiter if it is already in the stack and - // update waiter's count as needed - RemoveWaiter(newWaiterEntry, false); - - // If the stack is empty then newWaiterEntry is the new head of the stack - if (null == _headWaiterEntry._nextWaiterEntry) - { - _headWaiterEntry._nextWaiterEntry = newWaiterEntry; - newWaiterEntry._prevWaiterEntry = _headWaiterEntry; - - } - // If the stack is not empty then put newWaiterEntry as the new head - // of the stack. - else - { - // Save the old first waiter entry - WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; - - // Update the links - _headWaiterEntry._nextWaiterEntry = newWaiterEntry; - newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; - newWaiterEntry._prevWaiterEntry = _headWaiterEntry; - oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; - } - - // Increment the number of waiters - ++_waitersCount; - } - - /// - /// Pop a waiter from the waiter's stack - /// - /// Returns the first waiter in the stack - private WaiterEntry PopWaiter() - { - // Store the current stack head - WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; - - // Store the new stack head - WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; - - // Update the old stack head list links and decrement the number - // waiters. - RemoveWaiter(oldFirstWaiterEntry, true); - - // Update the new stack head - _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; - if (null != newHeadWaiterEntry) - { - newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; - } - - // Return the old stack head - return oldFirstWaiterEntry; - } - - /// - /// Remove a waiter from the stack - /// - /// A waiter entry to remove - /// If true the waiter count is always decremented - private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) - { - // Store the prev entry in the list - WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; - - // Store the next entry in the list - WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; - - // A flag to indicate if we need to decrement the waiters count. - // If we got here from PopWaiter then we must decrement. - // If we got here from PushWaiter then we decrement only if - // the waiter was already in the stack. - bool decrementCounter = popDecrement; - - // Null the waiter's entry links - waiterEntry._prevWaiterEntry = null; - waiterEntry._nextWaiterEntry = null; - - // If the waiter entry had a prev link then update it. - // It also means that the waiter is already in the list and we - // need to decrement the waiters count. - if (null != prevWaiterEntry) - { - prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; - decrementCounter = true; - } - - // If the waiter entry had a next link then update it. - // It also means that the waiter is already in the list and we - // need to decrement the waiters count. - if (null != nextWaiterEntry) - { - nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; - decrementCounter = true; - } - - // Decrement the waiters count if needed - if (decrementCounter) - { - --_waitersCount; - } - } - - #endregion - - #endregion - - #region WaiterEntry class - - // A waiter entry in the _waiters queue. - public sealed class WaiterEntry : IDisposable - { - #region Member variables - - /// - /// Event to signal the waiter that it got the work item. - /// - //private AutoResetEvent _waitHandle = new AutoResetEvent(false); - private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); - - /// - /// Flag to know if this waiter already quited from the queue - /// because of a timeout. - /// - private bool _isTimedout = false; - - /// - /// Flag to know if the waiter was signaled and got a work item. - /// - private bool _isSignaled = false; - - /// - /// A work item that passed directly to the waiter withou going - /// through the queue - /// - private WorkItem _workItem = null; - - private bool _isDisposed = false; - - // Linked list members - internal WaiterEntry _nextWaiterEntry = null; - internal WaiterEntry _prevWaiterEntry = null; - - #endregion - - #region Construction - - public WaiterEntry() - { - Reset(); - } - - #endregion - - #region Public methods - - public WaitHandle WaitHandle - { - get { return _waitHandle; } - } - - public WorkItem WorkItem - { - get - { - return _workItem; - } - } - - /// - /// Signal the waiter that it got a work item. - /// - /// Return true on success - /// The method fails if Timeout() preceded its call - public bool Signal(WorkItem workItem) - { - lock(this) - { - if (!_isTimedout) - { - _workItem = workItem; - _isSignaled = true; - _waitHandle.Set(); - return true; - } - } - return false; - } - - /// - /// Mark the wait entry that it has been timed out - /// - /// Return true on success - /// The method fails if Signal() preceded its call - public bool Timeout() - { - lock(this) - { - // Time out can happen only if the waiter wasn't marked as - // signaled - if (!_isSignaled) - { - // We don't remove the waiter from the queue, the DequeueWorkItem - // method skips _waiters that were timed out. - _isTimedout = true; - return true; - } - } - return false; - } - - /// - /// Reset the wait entry so it can be used again - /// - public void Reset() - { - _workItem = null; - _isTimedout = false; - _isSignaled = false; - _waitHandle.Reset(); - } - - /// - /// Free resources - /// - public void Close() - { - if (null != _waitHandle) - { - _waitHandle.Close(); - _waitHandle = null; - } - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - lock (this) - { - if (!_isDisposed) - { - Close(); - } - _isDisposed = true; - } - } - - #endregion - } - - #endregion - - #region IDisposable Members - - public void Dispose() - { - if (!_isDisposed) - { - Cleanup(); - } - _isDisposed = true; - } - - private void ValidateNotDisposed() - { - if(_isDisposed) - { - throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); - } - } - - #endregion - } - - #endregion -} - +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Amib.Threading.Internal +{ + #region WorkItemsQueue class + + /// + /// WorkItemsQueue class. + /// + public class WorkItemsQueue : IDisposable + { + #region Member variables + + /// + /// Waiters queue (implemented as stack). + /// + private readonly WaiterEntry _headWaiterEntry = new WaiterEntry(); + + /// + /// Waiters count + /// + private int _waitersCount = 0; + + /// + /// Work items queue + /// + private readonly PriorityQueue _workItems = new PriorityQueue(); + + /// + /// Indicate that work items are allowed to be queued + /// + private bool _isWorkItemsQueueActive = true; + + +#if (WINDOWS_PHONE) + private static readonly Dictionary _waiterEntries = new Dictionary(); +#elif (_WINDOWS_CE) + private static LocalDataStoreSlot _waiterEntrySlot = Thread.AllocateDataSlot(); +#else + + [ThreadStatic] + private static WaiterEntry _waiterEntry; +#endif + + + /// + /// Each thread in the thread pool keeps its own waiter entry. + /// + private static WaiterEntry CurrentWaiterEntry + { +#if (WINDOWS_PHONE) + get + { + lock (_waiterEntries) + { + WaiterEntry waiterEntry; + if (_waiterEntries.TryGetValue(Thread.CurrentThread.ManagedThreadId, out waiterEntry)) + { + return waiterEntry; + } + } + return null; + } + set + { + lock (_waiterEntries) + { + _waiterEntries[Thread.CurrentThread.ManagedThreadId] = value; + } + } +#elif (_WINDOWS_CE) + get + { + return Thread.GetData(_waiterEntrySlot) as WaiterEntry; + } + set + { + Thread.SetData(_waiterEntrySlot, value); + } +#else + get + { + return _waiterEntry; + } + set + { + _waiterEntry = value; + } +#endif + } + + /// + /// A flag that indicates if the WorkItemsQueue has been disposed. + /// + private bool _isDisposed = false; + + #endregion + + #region Public properties + + /// + /// Returns the current number of work items in the queue + /// + public int Count + { + get + { + return _workItems.Count; + } + } + + /// + /// Returns the current number of waiters + /// + public int WaitersCount + { + get + { + return _waitersCount; + } + } + + + #endregion + + #region Public methods + + /// + /// Enqueue a work item to the queue. + /// + public bool EnqueueWorkItem(WorkItem workItem) + { + // A work item cannot be null, since null is used in the + // WaitForWorkItem() method to indicate timeout or cancel + if (null == workItem) + { + throw new ArgumentNullException("workItem" , "workItem cannot be null"); + } + + bool enqueue = true; + + // First check if there is a waiter waiting for work item. During + // the check, timed out waiters are ignored. If there is no + // waiter then the work item is queued. + lock(this) + { + ValidateNotDisposed(); + + if (!_isWorkItemsQueueActive) + { + return false; + } + + while(_waitersCount > 0) + { + // Dequeue a waiter. + WaiterEntry waiterEntry = PopWaiter(); + + // Signal the waiter. On success break the loop + if (waiterEntry.Signal(workItem)) + { + enqueue = false; + break; + } + } + + if (enqueue) + { + // Enqueue the work item + _workItems.Enqueue(workItem); + } + } + return true; + } + + + /// + /// Waits for a work item or exits on timeout or cancel + /// + /// Timeout in milliseconds + /// Cancel wait handle + /// Returns true if the resource was granted + public WorkItem DequeueWorkItem( + int millisecondsTimeout, + WaitHandle cancelEvent) + { + // This method cause the caller to wait for a work item. + // If there is at least one waiting work item then the + // method returns immidiately with it. + // + // If there are no waiting work items then the caller + // is queued between other waiters for a work item to arrive. + // + // If a work item didn't come within millisecondsTimeout or + // the user canceled the wait by signaling the cancelEvent + // then the method returns null to indicate that the caller + // didn't get a work item. + + WaiterEntry waiterEntry; + WorkItem workItem = null; + lock (this) + { + ValidateNotDisposed(); + + // If there are waiting work items then take one and return. + if (_workItems.Count > 0) + { + workItem = _workItems.Dequeue() as WorkItem; + return workItem; + } + + // No waiting work items ... + + // Get the waiter entry for the waiters queue + waiterEntry = GetThreadWaiterEntry(); + + // Put the waiter with the other waiters + PushWaiter(waiterEntry); + } + + // Prepare array of wait handle for the WaitHandle.WaitAny() + WaitHandle [] waitHandles = new WaitHandle[] { + waiterEntry.WaitHandle, + cancelEvent }; + + // Wait for an available resource, cancel event, or timeout. + + // During the wait we are supposes to exit the synchronization + // domain. (Placing true as the third argument of the WaitAny()) + // It just doesn't work, I don't know why, so I have two lock(this) + // statments instead of one. + + int index = STPEventWaitHandle.WaitAny( + waitHandles, + millisecondsTimeout, + true); + + lock(this) + { + // success is true if it got a work item. + bool success = (0 == index); + + // The timeout variable is used only for readability. + // (We treat cancel as timeout) + bool timeout = !success; + + // On timeout update the waiterEntry that it is timed out + if (timeout) + { + // The Timeout() fails if the waiter has already been signaled + timeout = waiterEntry.Timeout(); + + // On timeout remove the waiter from the queue. + // Note that the complexity is O(1). + if(timeout) + { + RemoveWaiter(waiterEntry, false); + } + + // Again readability + success = !timeout; + } + + // On success return the work item + if (success) + { + workItem = waiterEntry.WorkItem; + + if (null == workItem) + { + workItem = _workItems.Dequeue() as WorkItem; + } + } + } + // On failure return null. + return workItem; + } + + /// + /// Cleanup the work items queue, hence no more work + /// items are allowed to be queue + /// + private void Cleanup() + { + lock(this) + { + // Deactivate only once + if (!_isWorkItemsQueueActive) + { + return; + } + + // Don't queue more work items + _isWorkItemsQueueActive = false; + + foreach(WorkItem workItem in _workItems) + { + workItem.DisposeOfState(); + } + + // Clear the work items that are already queued + _workItems.Clear(); + + // Note: + // I don't iterate over the queue and dispose of work items's states, + // since if a work item has a state object that is still in use in the + // application then I must not dispose it. + + // Tell the waiters that they were timed out. + // It won't signal them to exit, but to ignore their + // next work item. + while(_waitersCount > 0) + { + WaiterEntry waiterEntry = PopWaiter(); + waiterEntry.Timeout(); + } + } + } + + public object[] GetStates() + { + lock (this) + { + object[] states = new object[_workItems.Count]; + int i = 0; + foreach (WorkItem workItem in _workItems) + { + states[i] = workItem.GetWorkItemResult().State; + ++i; + } + return states; + } + } + + #endregion + + #region Private methods + + /// + /// Returns the WaiterEntry of the current thread + /// + /// + /// In order to avoid creation and destuction of WaiterEntry + /// objects each thread has its own WaiterEntry object. + private static WaiterEntry GetThreadWaiterEntry() + { + if (null == CurrentWaiterEntry) + { + CurrentWaiterEntry = new WaiterEntry(); + } + CurrentWaiterEntry.Reset(); + return CurrentWaiterEntry; + } + + #region Waiters stack methods + + /// + /// Push a new waiter into the waiter's stack + /// + /// A waiter to put in the stack + public void PushWaiter(WaiterEntry newWaiterEntry) + { + // Remove the waiter if it is already in the stack and + // update waiter's count as needed + RemoveWaiter(newWaiterEntry, false); + + // If the stack is empty then newWaiterEntry is the new head of the stack + if (null == _headWaiterEntry._nextWaiterEntry) + { + _headWaiterEntry._nextWaiterEntry = newWaiterEntry; + newWaiterEntry._prevWaiterEntry = _headWaiterEntry; + + } + // If the stack is not empty then put newWaiterEntry as the new head + // of the stack. + else + { + // Save the old first waiter entry + WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; + + // Update the links + _headWaiterEntry._nextWaiterEntry = newWaiterEntry; + newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry; + newWaiterEntry._prevWaiterEntry = _headWaiterEntry; + oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry; + } + + // Increment the number of waiters + ++_waitersCount; + } + + /// + /// Pop a waiter from the waiter's stack + /// + /// Returns the first waiter in the stack + private WaiterEntry PopWaiter() + { + // Store the current stack head + WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry; + + // Store the new stack head + WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry; + + // Update the old stack head list links and decrement the number + // waiters. + RemoveWaiter(oldFirstWaiterEntry, true); + + // Update the new stack head + _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry; + if (null != newHeadWaiterEntry) + { + newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry; + } + + // Return the old stack head + return oldFirstWaiterEntry; + } + + /// + /// Remove a waiter from the stack + /// + /// A waiter entry to remove + /// If true the waiter count is always decremented + private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement) + { + // Store the prev entry in the list + WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry; + + // Store the next entry in the list + WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry; + + // A flag to indicate if we need to decrement the waiters count. + // If we got here from PopWaiter then we must decrement. + // If we got here from PushWaiter then we decrement only if + // the waiter was already in the stack. + bool decrementCounter = popDecrement; + + // Null the waiter's entry links + waiterEntry._prevWaiterEntry = null; + waiterEntry._nextWaiterEntry = null; + + // If the waiter entry had a prev link then update it. + // It also means that the waiter is already in the list and we + // need to decrement the waiters count. + if (null != prevWaiterEntry) + { + prevWaiterEntry._nextWaiterEntry = nextWaiterEntry; + decrementCounter = true; + } + + // If the waiter entry had a next link then update it. + // It also means that the waiter is already in the list and we + // need to decrement the waiters count. + if (null != nextWaiterEntry) + { + nextWaiterEntry._prevWaiterEntry = prevWaiterEntry; + decrementCounter = true; + } + + // Decrement the waiters count if needed + if (decrementCounter) + { + --_waitersCount; + } + } + + #endregion + + #endregion + + #region WaiterEntry class + + // A waiter entry in the _waiters queue. + public sealed class WaiterEntry : IDisposable + { + #region Member variables + + /// + /// Event to signal the waiter that it got the work item. + /// + //private AutoResetEvent _waitHandle = new AutoResetEvent(false); + private AutoResetEvent _waitHandle = EventWaitHandleFactory.CreateAutoResetEvent(); + + /// + /// Flag to know if this waiter already quited from the queue + /// because of a timeout. + /// + private bool _isTimedout = false; + + /// + /// Flag to know if the waiter was signaled and got a work item. + /// + private bool _isSignaled = false; + + /// + /// A work item that passed directly to the waiter withou going + /// through the queue + /// + private WorkItem _workItem = null; + + private bool _isDisposed = false; + + // Linked list members + internal WaiterEntry _nextWaiterEntry = null; + internal WaiterEntry _prevWaiterEntry = null; + + #endregion + + #region Construction + + public WaiterEntry() + { + Reset(); + } + + #endregion + + #region Public methods + + public WaitHandle WaitHandle + { + get { return _waitHandle; } + } + + public WorkItem WorkItem + { + get + { + return _workItem; + } + } + + /// + /// Signal the waiter that it got a work item. + /// + /// Return true on success + /// The method fails if Timeout() preceded its call + public bool Signal(WorkItem workItem) + { + lock(this) + { + if (!_isTimedout) + { + _workItem = workItem; + _isSignaled = true; + _waitHandle.Set(); + return true; + } + } + return false; + } + + /// + /// Mark the wait entry that it has been timed out + /// + /// Return true on success + /// The method fails if Signal() preceded its call + public bool Timeout() + { + lock(this) + { + // Time out can happen only if the waiter wasn't marked as + // signaled + if (!_isSignaled) + { + // We don't remove the waiter from the queue, the DequeueWorkItem + // method skips _waiters that were timed out. + _isTimedout = true; + return true; + } + } + return false; + } + + /// + /// Reset the wait entry so it can be used again + /// + public void Reset() + { + _workItem = null; + _isTimedout = false; + _isSignaled = false; + _waitHandle.Reset(); + } + + /// + /// Free resources + /// + public void Close() + { + if (null != _waitHandle) + { + _waitHandle.Close(); + _waitHandle = null; + } + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + lock (this) + { + if (!_isDisposed) + { + Close(); + } + _isDisposed = true; + } + } + + #endregion + } + + #endregion + + #region IDisposable Members + + public void Dispose() + { + if (!_isDisposed) + { + Cleanup(); + } + _isDisposed = true; + } + + private void ValidateNotDisposed() + { + if(_isDisposed) + { + throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown"); + } + } + + #endregion + } + + #endregion +} + -- cgit v1.1 From e3d9d5566a799fdbb4261010b97b8b04dbd7da1e Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 1 May 2013 18:46:57 -0400 Subject: Fix inventory issue Fix issue where objects rezzed from Trash or Lost And Found then be placed back in the respective folder when taking the object or a copy back into inventory. --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index eb37626..e6d6cbf 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -671,6 +671,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); folder = m_Scene.InventoryService.GetFolder(f); + + if(folder.Type == 14 || folder.Type == 16) + { + // folder.Type = 6; + folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); + } } } -- cgit v1.1 From 0378baed350b846132b2f501c74bd39a2675e41d Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 1 May 2013 17:15:54 -0700 Subject: BulletSim: rework LinksetCompound to work with new BSShape system. Not all working yet. --- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 146 ++++++--------------- 1 file changed, 40 insertions(+), 106 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e3ce7fb..20eb871 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -35,6 +35,7 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { + /* // When a child is linked, the relationship position of the child to the parent // is remembered so the child's world position can be recomputed when it is // removed from the linkset. @@ -88,17 +89,15 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo return buff.ToString(); } }; + */ public sealed class BSLinksetCompound : BSLinkset { private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; - private BSShape LinksetShape; - public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) : base(scene, parent) { - LinksetShape = new BSShapeNull(); } // When physical properties are changed the linkset needs to recalculate @@ -143,25 +142,11 @@ public sealed class BSLinksetCompound : BSLinkset // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. ScheduleRebuild(LinksetRoot); } - - // The origional prims are removed from the world as the shape of the root compound - // shape takes over. - m_physicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - m_physicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); - // We don't want collisions from the old linkset children. - m_physicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - - child.PhysBody.collisionType = CollisionType.LinksetChild; - - ret = true; - return ret; } - // The object is going static (non-physical). Do any setup necessary for a static linkset. + // The object is going static (non-physical). We do not do anything for static linksets. // Return 'true' if any properties updated on the passed object. - // This doesn't normally happen -- OpenSim removes the objects from the physical - // world if it is a static linkset. // Called at taint-time! public override bool MakeStatic(BSPrimLinkable child) { @@ -169,19 +154,9 @@ public sealed class BSLinksetCompound : BSLinkset DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); if (IsRoot(child)) { + // Schedule a rebuild to verify that the root shape is set to the real shape. ScheduleRebuild(LinksetRoot); } - else - { - // The non-physical children can come back to life. - m_physicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - - child.PhysBody.collisionType = CollisionType.LinksetChild; - - // Don't force activation so setting of DISABLE_SIMULATION can stay if used. - m_physicsScene.PE.Activate(child.PhysBody, false); - ret = true; - } return ret; } @@ -283,9 +258,6 @@ public sealed class BSLinksetCompound : BSLinkset if (!IsRoot(child)) { - // Because it is a convenient time, recompute child world position and rotation based on - // its position in the linkset. - RecomputeChildWorldPosition(child, true /* inTaintTime */); child.LinksetInfo = null; } @@ -296,50 +268,6 @@ public sealed class BSLinksetCompound : BSLinkset return ret; } - // When the linkset is built, the child shape is added to the compound shape relative to the - // root shape. The linkset then moves around but this does not move the actual child - // prim. The child prim's location must be recomputed based on the location of the root shape. - private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime) - { - // For the moment (20130201), disable this computation (converting the child physical addr back to - // a region address) until we have a good handle on center-of-mass offsets and what the physics - // engine moving a child actually means. - // The simulator keeps track of where children should be as the linkset moves. Setting - // the pos/rot here does not effect that knowledge as there is no good way for the - // physics engine to send the simulator an update for a child. - - /* - BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; - if (lci != null) - { - if (inTaintTime) - { - OMV.Vector3 oldPos = child.RawPosition; - child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot; - child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; - DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", - child.LocalID, oldPos, lci, child.RawPosition); - } - else - { - // TaintedObject is not used here so the raw position is set now and not at taint-time. - child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot; - child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; - } - } - else - { - // This happens when children have been added to the linkset but the linkset - // has not been constructed yet. So like, at taint time, adding children to a linkset - // and then changing properties of the children (makePhysical, for instance) - // but the post-print action of actually rebuilding the linkset has not yet happened. - // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", - // LogHeader, child.LocalID); - DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); - } - */ - } - // ================================================================ // Add a new child to the linkset. @@ -372,7 +300,6 @@ public sealed class BSLinksetCompound : BSLinkset child.LocalID, child.PhysBody.AddrString); // Cause the child's body to be rebuilt and thus restored to normal operation - RecomputeChildWorldPosition(child, false); child.LinksetInfo = null; child.ForceBodyShapeRebuild(false); @@ -399,26 +326,27 @@ public sealed class BSLinksetCompound : BSLinkset private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting private void RecomputeLinksetCompound() { - if (!LinksetRoot.IsPhysicallyActive) - { - // There is no reason to build all this physical stuff for a non-physical linkset - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); - return; - } - try { - // This replaces the physical shape of the root prim with a compound shape made up of the root - // shape and all the children. + Rebuilding = true; + + // No matter what is being done, force the root prim's PhysBody and PhysShape to get set + // to what they should be as if the root was not in a linkset. + // Not that bad since we only get into this routine if there are children in the linkset and + // something has been updated/changed. + LinksetRoot.ForceBodyShapeRebuild(true); - // RootPrim.PhysShape is the shape of the root prim. - // Here we build the compound shape made up of all the children. + // There is no reason to build all this physical stuff for a non-physical linkset. + if (!LinksetRoot.IsPhysicallyActive) + { + // Clean up any old linkset shape and make sure the root shape is set to the root object. + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); - // Free up any shape we'd previously built. - LinksetShape.Dereference(m_physicsScene); + return; // Note the 'finally' clause at the botton which will get executed. + } // Get a new compound shape to build the linkset shape in. - LinksetShape = BSShapeCompound.GetReference(m_physicsScene); + BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); // The center of mass for the linkset is the geometric center of the group. // Compute a displacement for each component so it is relative to the center-of-mass. @@ -445,35 +373,41 @@ public sealed class BSLinksetCompound : BSLinkset int memberIndex = 1; ForEachMember(delegate(BSPrimLinkable cPrim) { - if (IsRoot(cPrim)) - { - cPrim.LinksetChildIndex = 0; - } - else - { - cPrim.LinksetChildIndex = memberIndex; - } + // Root shape is always index zero. + cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex; + // Get a reference to the shape of the child and add that shape to the linkset compound shape BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; - m_physicsScene.PE.AddChildShapeToCompoundShape(LinksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1}cShape={2},offPos={3},offRot={4}", + m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", LinksetRoot.LocalID, memberIndex, cPrim.PhysShape, offsetPos, offsetRot); + // Since we are borrowing the shape of the child, disable the origional child body + if (!IsRoot(cPrim)) + { + m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); + // We don't want collisions from the old linkset children. + m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + cPrim.PhysBody.collisionType = CollisionType.LinksetChild; + } + memberIndex++; return false; // 'false' says to move onto the next child in the list }); - // Sneak the built compound shape in as the shape of the root prim. - // Note this doesn't touch the root prim's PhysShape so be sure the manage the difference. + // Replace the root shape with the built compound shape. // Object removed and added to world to get collision cache rebuilt for new shape. + LinksetRoot.PhysShape.Dereference(m_physicsScene); + LinksetRoot.PhysShape = linksetShape; m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); - m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, LinksetShape.physShapeInfo); + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", - LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetShape); + LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); // With all of the linkset packed into the root prim, it has the mass of everyone. LinksetMass = ComputeLinksetMass(); @@ -494,7 +428,7 @@ public sealed class BSLinksetCompound : BSLinkset } // See that the Aabb surrounds the new shape - m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetShape.physShapeInfo); + m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); } } } \ No newline at end of file -- cgit v1.1 From ed46b42feae4659653ba54a9290dddede6f24f2e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 1 May 2013 17:16:46 -0700 Subject: BulletSim: fix crash when mesh asset wasn't available when meshing the first time. Debugging added for mesh/hull asset fetch. --- .../Physics/BulletSPlugin/BSShapeCollection.cs | 1 + OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 28 ++++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 19855da..a4250be 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -132,6 +132,7 @@ public sealed class BSShapeCollection : IDisposable PrimitiveBaseShape pbs = prim.BaseShape; // Kludge to create the capsule for the avatar. + // TDOD: Remove/redo this when BSShapeAvatar is working!! BSCharacter theChar = prim as BSCharacter; if (theChar != null) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 3faa484..2962249 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -164,6 +164,8 @@ public abstract class BSShape prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); } else { @@ -174,29 +176,33 @@ public abstract class BSShape && prim.BaseShape.SculptTexture != OMV.UUID.Zero ) { - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset", prim.LocalID); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); // Multiple requestors will know we're waiting for this asset prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; BSPhysObject xprim = prim; Util.FireAndForget(delegate { + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID); RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; if (assetProvider != null) { BSPhysObject yprim = xprim; // probably not necessary, but, just in case. assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) { + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); bool assetFound = false; string mismatchIDs = String.Empty; // DEBUG DEBUG if (asset != null && yprim.BaseShape.SculptEntry) { if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) { - yprim.BaseShape.SculptData = asset.Data; + yprim.BaseShape.SculptData = (byte[])asset.Data.Clone(); // This will cause the prim to see that the filler shape is not the right // one and try again to build the object. // No race condition with the normal shape setting since the rebuild is at taint time. + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; yprim.ForceBodyShapeRebuild(false /* inTaintTime */); assetFound = true; } @@ -205,11 +211,11 @@ public abstract class BSShape mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; } } - if (assetFound) - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; - else + if (!assetFound) + { yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; - physicsScene.DetailLog("{0},BSShape,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + } + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); }); } @@ -227,6 +233,8 @@ public abstract class BSShape { physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); } } } @@ -359,7 +367,7 @@ public class BSShapeMesh : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (newShape.shapeType == BSPhysicsShapeType.SHAPE_MESH) + if (!newShape.isNativeShape) { // If a mesh was what was created, remember the built shape for later sharing. Meshes.Add(newMeshKey, retMesh); @@ -408,7 +416,7 @@ public class BSShapeMesh : BSShape private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { - BulletShape newShape = null; + BulletShape newShape = new BulletShape(); IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, false, // say it is not physical so a bounding box is not built @@ -507,7 +515,7 @@ public class BSShapeHull : BSShape // Check to see if hull was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (newShape.shapeType == BSPhysicsShapeType.SHAPE_HULL) + if (!newShape.isNativeShape) { // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); @@ -731,7 +739,7 @@ public class BSShapeCompound : BSShape { lock (physShapeInfo) { - Dereference(physicsScene); + this.DecrementReference(); if (referenceCount <= 0) { if (!physicsScene.PE.IsCompound(physShapeInfo)) -- cgit v1.1 From 4cb73192a78f0c8d15c2eb052c7c632bb678ce5f Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 1 May 2013 23:01:33 -0400 Subject: Make default config directory "." --- bin/Robust.HG.ini.example | 2 +- bin/Robust.ini.example | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index d74f205..fee2a87 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -35,7 +35,7 @@ ; Modular configurations ; Set path to directory for modular ini files... ; The Robust.exe process must have R/W access to the location - ConfigDirectory = "/home/opensim/etc/Configs" + ConfigDirectory = "." [ServiceList] diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index b7b2524..2d5aa8c 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -27,7 +27,7 @@ ; Modular configurations ; Set path to directory for modular ini files... ; The Robust.exe process must have R/W access to the location - ConfigDirectory = "/home/opensim/etc/Configs" + ConfigDirectory = "." [ServiceList] AssetServiceConnector = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector" -- cgit v1.1 From d9c3947824feccd3522c70a72b75c72a84bab3e0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 2 May 2013 10:06:12 -0700 Subject: BulletSim: Rebuild physical body if physical shape changes for mesh and hull. Properly rebuilds collision caches. Release asset data fetched when building mesh or hulls. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 1 + OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 2 +- .../Physics/BulletSPlugin/BSShapeCollection.cs | 35 +++++++++++-- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 59 +++++++++++++++------- 4 files changed, 73 insertions(+), 24 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index f535e50..b9bd909 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -596,6 +596,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin public override void Refresh() { // If asking for a refresh, reset the physical parameters before the next simulation step. + // Called whether active or not since the active state may be updated before the next step. m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() { SetPhysicalParameters(); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 7e2af78..3d68d7f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -767,7 +767,7 @@ public class BSPrim : BSPhysObject if (!PhysBody.HasPhysicalBody) { // This would only happen if updates are called for during initialization when the body is not set up yet. - DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); + // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); return; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index a4250be..809435d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -227,16 +227,41 @@ public sealed class BSShapeCollection : IDisposable if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) { // Update prim.BSShape to reference a hull of this shape. - DereferenceExistingShape(prim, shapeCallback); - prim.PhysShape = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + BSShape potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + // If the current shape is not what is on the prim at the moment, time to change. + if (!prim.PhysShape.HasPhysicalShape + || potentialHull.ShapeType != prim.PhysShape.ShapeType + || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = potentialHull; + ret = true; + } + else + { + potentialHull.Dereference(m_physicsScene); + } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X")); } else { // Update prim.BSShape to reference a mesh of this shape. - DereferenceExistingShape(prim, shapeCallback); - prim.PhysShape = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + // If the current shape is not what is on the prim at the moment, time to change. + if (!prim.PhysShape.HasPhysicalShape + || potentialMesh.ShapeType != prim.PhysShape.ShapeType + || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = potentialMesh; + ret = true; + } + else + { + // We don't need this reference to the mesh that is already being using. + potentialMesh.Dereference(m_physicsScene); + } if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X")); } @@ -320,7 +345,7 @@ public sealed class BSShapeCollection : IDisposable if (prim.IsSolid) { aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); } else { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 2962249..3346626 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -115,10 +115,15 @@ public abstract class BSShape public override string ToString() { StringBuilder buff = new StringBuilder(); - buff.Append(""); @@ -184,21 +189,21 @@ public abstract class BSShape BSPhysObject xprim = prim; Util.FireAndForget(delegate { - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID); + // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID); RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; if (assetProvider != null) { BSPhysObject yprim = xprim; // probably not necessary, but, just in case. assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) { - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); + // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); bool assetFound = false; string mismatchIDs = String.Empty; // DEBUG DEBUG if (asset != null && yprim.BaseShape.SculptEntry) { if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) { - yprim.BaseShape.SculptData = (byte[])asset.Data.Clone(); + yprim.BaseShape.SculptData = asset.Data; // This will cause the prim to see that the filler shape is not the right // one and try again to build the object. // No race condition with the normal shape setting since the rebuild is at taint time. @@ -290,7 +295,7 @@ public class BSShapeNative : BSShape { if (physShapeInfo.HasPhysicalShape) { - physicsScene.DetailLog("{0},BSShapeNative.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); + physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); } physShapeInfo.Clear(); @@ -347,9 +352,8 @@ public class BSShapeMesh : BSShape float lod; System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - physicsScene.DetailLog("{0},BSShapeMesh,getReference,oldKey={1},newKey={2},size={3},lod={4}", - prim.LocalID, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"), - newMeshKey.ToString("X"), prim.Size, lod); + physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); BSShapeMesh retMesh = null; lock (Meshes) @@ -389,6 +393,7 @@ public class BSShapeMesh : BSShape lock (Meshes) { this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); // TODO: schedule aging and destruction of unused meshes. } } @@ -425,6 +430,12 @@ public class BSShapeMesh : BSShape if (meshData != null) { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + // Release the fetched asset data once it has been used. + pbs.SculptData = new byte[0]; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } int[] indices = meshData.getIndexListAsInt(); int realIndicesIndex = indices.Length; @@ -462,8 +473,8 @@ public class BSShapeMesh : BSShape } } } - physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", - BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); + physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", + BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); if (realIndicesIndex != 0) { @@ -496,8 +507,8 @@ public class BSShapeHull : BSShape float lod; System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - physicsScene.DetailLog("{0},BSShapeHull,getReference,oldKey={1},newKey={2},size={3},lod={4}", - prim.LocalID, prim.PhysShape.physShapeInfo.shapeKey.ToString("X"), newHullKey.ToString("X"), prim.Size, lod); + physicsScene.DetailLog("{0},BSShapeHull,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newHullKey.ToString("X"), prim.Size, lod); BSShapeHull retHull = null; lock (Hulls) @@ -537,6 +548,7 @@ public class BSShapeHull : BSShape lock (Hulls) { this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); // TODO: schedule aging and destruction of unused meshes. } } @@ -549,6 +561,8 @@ public class BSShapeHull : BSShape if (BSParam.ShouldUseBulletHACD) { + // Build the hull shape from an existing mesh shape. + // The mesh should have already been created in Bullet. physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); @@ -568,18 +582,26 @@ public class BSShapeHull : BSShape physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + + // Now done with the mesh shape. + meshShape.Dereference(physicsScene); } - // Now done with the mesh shape. - meshShape.Dereference(physicsScene); physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } if (!newShape.HasPhysicalShape) { - // Build a new hull in the physical world. + // Build a new hull in the physical world using the C# HACD algorigthm. // Pass true for physicalness as this prevents the creation of bounding box which is not needed IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); if (meshData != null) { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + // Release the fetched asset data once it has been used. + pbs.SculptData = new byte[0]; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } + int[] indices = meshData.getIndexListAsInt(); List vertices = meshData.getVertexList(); @@ -740,6 +762,7 @@ public class BSShapeCompound : BSShape lock (physShapeInfo) { this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); if (referenceCount <= 0) { if (!physicsScene.PE.IsCompound(physShapeInfo)) -- cgit v1.1 From 4042c82a7293c40955a14d04d9e5ae05d35ef7cf Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 2 May 2013 12:27:30 -0700 Subject: BulletSim: prims with no cuts created with single convex hull shape. Parameter added to enable/disable this feature. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 5 ++ OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 3 + .../Physics/BulletSPlugin/BSShapeCollection.cs | 19 +++++- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 74 ++++++++++++++++++++++ 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 5ebeace..2ac68e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -87,6 +87,7 @@ public static class BSParam public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects public static bool ShouldRemoveZeroWidthTriangles { get; private set; } public static bool ShouldUseBulletHACD { get; set; } + public static bool ShouldUseSingleConvexHullForPrims { get; set; } public static float TerrainImplementation { get; private set; } public static int TerrainMeshMagnification { get; private set; } @@ -342,6 +343,10 @@ public static class BSParam false, (s) => { return ShouldUseBulletHACD; }, (s,v) => { ShouldUseBulletHACD = v; } ), + new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", + true, + (s) => { return ShouldUseSingleConvexHullForPrims; }, + (s,v) => { ShouldUseSingleConvexHullForPrims = v; } ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 8e05b58..a4a8794 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -316,7 +316,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters break; case "bulletxna": ret = new BSAPIXNA(engineName, this); + // Disable some features that are not implemented in BulletXNA + m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); BSParam.ShouldUseBulletHACD = false; + BSParam.ShouldUseSingleConvexHullForPrims = false; break; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 809435d..794857c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -226,8 +226,23 @@ public sealed class BSShapeCollection : IDisposable // made. Native shapes work in either case. if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) { - // Update prim.BSShape to reference a hull of this shape. - BSShape potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + // Use a simple, single mesh convex hull shape if the object is simple enough + BSShape potentialHull = null; + + PrimitiveBaseShape pbs = prim.BaseShape; + if (BSParam.ShouldUseSingleConvexHullForPrims + && pbs != null + && !pbs.SculptEntry + && PrimHasNoCuts(pbs) + ) + { + potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); + } + else + { + potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + } + // If the current shape is not what is on the prim at the moment, time to change. if (!prim.PhysShape.HasPhysicalShape || potentialHull.ShapeType != prim.PhysShape.ShapeType diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 3346626..9ef2923 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -832,6 +832,80 @@ public class BSShapeCompound : BSShape } // ============================================================================================================ +public class BSShapeConvexHull : BSShape +{ + private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; + public static Dictionary ConvexHulls = new Dictionary(); + + public BSShapeConvexHull(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeConvexHull retConvexHull = null; + lock (ConvexHulls) + { + if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) + { + // The mesh has already been created. Return a new reference to same. + retConvexHull.IncrementReference(); + } + else + { + retConvexHull = new BSShapeConvexHull(new BulletShape()); + BulletShape convexShape = null; + + // Get a handle to a mesh to build the hull from + BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); + if (baseMesh.physShapeInfo.isNativeShape) + { + // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. + // In the short term, we return the native shape and a later ForceBodyShapeRebuild should + // get back to this code with a buildable mesh. + // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? + convexShape = baseMesh.physShapeInfo; + } + else + { + convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); + convexShape.shapeKey = newMeshKey; + ConvexHulls.Add(convexShape.shapeKey, retConvexHull); + } + + // Done with the base mesh + baseMesh.Dereference(physicsScene); + + retConvexHull.physShapeInfo = convexShape; + } + } + return retConvexHull; + } + public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + { + // Calling this reference means we want another handle to an existing shape + // (usually linksets) so return this copy. + IncrementReference(); + return this; + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + lock (ConvexHulls) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } +} + +// ============================================================================================================ public class BSShapeAvatar : BSShape { private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; -- cgit v1.1 From 304c5d4a8b8a1137bac18f7f6443ea85cec86184 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 3 May 2013 18:48:50 +0100 Subject: On startup, start scenes after we're set up all local scenes, rather than starting scenes before others have been created. This aims to avoid a race condition where scenes could look to inform neighbours that they were up before those neighbours had been created. http://opensimulator.org/mantis/view.php?id=6618 --- .../LoadRegions/LoadRegionsPlugin.cs | 23 ++++++++++++++-------- .../RemoteController/RemoteAdminPlugin.cs | 1 + OpenSim/Framework/IScene.cs | 7 ++++++- OpenSim/Region/Application/OpenSimBase.cs | 4 +--- OpenSim/Region/Framework/Scenes/Scene.cs | 16 +++++++++++++-- OpenSim/Region/Framework/Scenes/SceneBase.cs | 4 ++++ 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index fcb6991..1d63d26 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs @@ -115,6 +115,8 @@ namespace OpenSim.ApplicationPlugins.LoadRegions Environment.Exit(1); } + List createdScenes = new List(); + for (int i = 0; i < regionsToLoad.Length; i++) { IScene scene; @@ -123,17 +125,22 @@ namespace OpenSim.ApplicationPlugins.LoadRegions ")"); bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); + m_openSim.CreateRegion(regionsToLoad[i], true, out scene); + createdScenes.Add(scene); + if (changed) - regionsToLoad[i].EstateSettings.Save(); - - if (scene != null) + regionsToLoad[i].EstateSettings.Save(); + } + + foreach (IScene scene in createdScenes) + { + scene.Start(); + + m_newRegionCreatedHandler = OnNewRegionCreated; + if (m_newRegionCreatedHandler != null) { - m_newRegionCreatedHandler = OnNewRegionCreated; - if (m_newRegionCreatedHandler != null) - { - m_newRegionCreatedHandler(scene); - } + m_newRegionCreatedHandler(scene); } } } diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index d19b8b6..355f7b3 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -700,6 +700,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController IScene newScene; m_application.CreateRegion(region, out newScene); + newScene.Start(); // If an access specification was provided, use it. // Otherwise accept the default. diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index 87ec99e..8164f41 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -136,5 +136,10 @@ namespace OpenSim.Framework ISceneObject DeserializeObject(string representation); bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); + + /// + /// Start the scene and associated scripts within it. + /// + void Start(); } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index d86eefe..f9e0cf1 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -425,9 +425,6 @@ namespace OpenSim mscene = scene; - scene.Start(); - scene.StartScripts(); - return clientServers; } @@ -751,6 +748,7 @@ namespace OpenSim ShutdownClientServer(whichRegion); IScene scene; CreateRegion(whichRegion, true, out scene); + scene.Start(); } # region Setup methods diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 829a7e9..4f674a3 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -389,10 +389,12 @@ namespace OpenSim.Region.Framework.Scenes if (value) { if (!m_active) - Start(); + Start(false); } else { + // This appears assymetric with Start() above but is not - setting m_active = false stops the loops + // XXX: Possibly this should be in an explicit Stop() method for symmetry. m_active = false; } } @@ -1331,10 +1333,18 @@ namespace OpenSim.Region.Framework.Scenes } } + public override void Start() + { + Start(true); + } + /// /// Start the scene /// - public void Start() + /// + /// Start the scripts within the scene. + /// + public void Start(bool startScripts) { m_active = true; @@ -1353,6 +1363,8 @@ namespace OpenSim.Region.Framework.Scenes m_heartbeatThread = Watchdog.StartThread( Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false); + + StartScripts(); } /// diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index d3e968e..d2097ea 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -561,6 +561,10 @@ namespace OpenSim.Region.Framework.Scenes get { return false; } } + public virtual void Start() + { + } + public void Restart() { // This has to be here to fire the event -- cgit v1.1 From 5d93c99e8cf188b29b4c5265619eb4a4d3eeacf6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 3 May 2013 18:56:58 +0100 Subject: Fix possible race condition with local region cache if a region was added after startup. --- .../Grid/LocalGridServiceConnector.cs | 43 ++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index c0c2ca7..c32820e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs @@ -142,10 +142,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid scene.RegisterModuleInterface(this); - if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) - m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); - else - m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); + lock (m_LocalCache) + { + if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) + m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); + else + m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); + } } public void RemoveRegion(Scene scene) @@ -153,8 +156,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (!m_Enabled) return; - m_LocalCache[scene.RegionInfo.RegionID].Clear(); - m_LocalCache.Remove(scene.RegionInfo.RegionID); + lock (m_LocalCache) + { + m_LocalCache[scene.RegionInfo.RegionID].Clear(); + m_LocalCache.Remove(scene.RegionInfo.RegionID); + } } public void RegionLoaded(Scene scene) @@ -191,12 +197,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid // First see if it's a neighbour, even if it isn't on this sim. // Neighbour data is cached in memory, so this is fast - foreach (RegionCache rcache in m_LocalCache.Values) + + lock (m_LocalCache) { - region = rcache.GetRegionByPosition(x, y); - if (region != null) + foreach (RegionCache rcache in m_LocalCache.Values) { - return region; + region = rcache.GetRegionByPosition(x, y); + if (region != null) + { + return region; + } } } @@ -245,12 +255,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid { System.Text.StringBuilder caps = new System.Text.StringBuilder(); - foreach (KeyValuePair kvp in m_LocalCache) + lock (m_LocalCache) { - caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); - List regions = kvp.Value.GetNeighbours(); - foreach (GridRegion r in regions) - caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); + foreach (KeyValuePair kvp in m_LocalCache) + { + caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); + List regions = kvp.Value.GetNeighbours(); + foreach (GridRegion r in regions) + caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); + } } MainConsole.Instance.Output(caps.ToString()); -- cgit v1.1 From 5d25bb3084937d266375cba61b3a2c802bd57717 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 3 May 2013 14:23:53 -0700 Subject: BulletSim: zero vehicle motion when changing vehicle type. Rebuild compound linkset of any child in the linkset changes shape. Comments and better detailed logging messages. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 6 +++--- .../Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 16 +++++----------- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 4 ++++ .../Region/Physics/BulletSPlugin/BSShapeCollection.cs | 7 +++---- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 9 ++------- 6 files changed, 18 insertions(+), 26 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index b9bd909..c5bee6d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -559,9 +559,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin break; } - // Update any physical parameters based on this type. - Refresh(); - m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, m_linearFrictionTimescale, 1f); @@ -589,6 +586,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin { RegisterForSceneEvents(); } + + // Update any physical parameters based on this type. + Refresh(); } #endregion // Vehicle parameter setting diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 20eb871..1f16cc8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -246,7 +246,8 @@ public sealed class BSLinksetCompound : BSLinkset } // Routine called when rebuilding the body of some member of the linkset. - // Since we don't keep in world relationships, do nothing unless it's a child changing. + // If one of the bodies is being changed, the linkset needs rebuilding. + // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. // Returns 'true' of something was actually removed and would need restoring // Called at taint-time!! public override bool RemoveDependencies(BSPrimLinkable child) @@ -256,14 +257,7 @@ public sealed class BSLinksetCompound : BSLinkset DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); - if (!IsRoot(child)) - { - child.LinksetInfo = null; - } - - // Cannot schedule a refresh/rebuild here because this routine is called when - // the linkset is being rebuilt. - // InternalRefresh(LinksetRoot); + ScheduleRebuild(child); return ret; } @@ -322,7 +316,7 @@ public sealed class BSLinksetCompound : BSLinkset // Constraint linksets are rebuilt every time. // Note that this works for rebuilding just the root after a linkset is taken apart. // Called at taint time!! - private bool UseBulletSimRootOffsetHack = false; + private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting private void RecomputeLinksetCompound() { @@ -382,7 +376,7 @@ public sealed class BSLinksetCompound : BSLinkset OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", - LinksetRoot.LocalID, memberIndex, cPrim.PhysShape, offsetPos, offsetRot); + LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot); // Since we are borrowing the shape of the child, disable the origional child body if (!IsRoot(cPrim)) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 3d68d7f..d3f3475 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -511,7 +511,7 @@ public class BSPrim : BSPhysObject PhysScene.TaintedObject("setVehicleType", delegate() { - // Vehicle code changes the parameters for this vehicle type. + ZeroMotion(true /* inTaintTime */); VehicleActor.ProcessTypeChange(type); ActivateIfPhysical(false); }); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 5236909..235da78 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -182,6 +182,10 @@ public class BSPrimLinkable : BSPrimDisplaced { return false; } + + // TODO: handle collisions of other objects with with children of linkset. + // This is a problem for LinksetCompound since the children are packed into the root. + return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 794857c..64aaa15 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -254,10 +254,10 @@ public sealed class BSShapeCollection : IDisposable } else { + // The current shape on the prim is the correct one. We don't need the potential reference. potentialHull.Dereference(m_physicsScene); } - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X")); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); } else { @@ -277,8 +277,7 @@ public sealed class BSShapeCollection : IDisposable // We don't need this reference to the mesh that is already being using. potentialMesh.Dereference(m_physicsScene); } - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", - prim.LocalID, prim.PhysShape, prim.PhysShape.physShapeInfo.shapeKey.ToString("X")); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); } return ret; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 9ef2923..3e4ee5a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -352,9 +352,6 @@ public class BSShapeMesh : BSShape float lod; System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}", - prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); - BSShapeMesh retMesh = null; lock (Meshes) { @@ -380,6 +377,7 @@ public class BSShapeMesh : BSShape retMesh.physShapeInfo = newShape; } } + physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); return retMesh; } public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) @@ -507,9 +505,6 @@ public class BSShapeHull : BSShape float lod; System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - physicsScene.DetailLog("{0},BSShapeHull,getReference,newKey={1},size={2},lod={3}", - prim.LocalID, newHullKey.ToString("X"), prim.Size, lod); - BSShapeHull retHull = null; lock (Hulls) { @@ -531,10 +526,10 @@ public class BSShapeHull : BSShape // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); } - retHull.physShapeInfo = newShape; } } + physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); return retHull; } public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) -- cgit v1.1 From ad00466483c0bcdb5d05759130f35870c6a7a177 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 6 May 2013 09:17:54 -0700 Subject: Minor reordering of operations on NewUserConnection. The agent circuit needs to be added earlier for some of the checks to work correctly. --- OpenSim/Region/Framework/Scenes/Scene.cs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 69fe137..ff7e5ed 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3687,14 +3687,21 @@ namespace OpenSim.Region.Framework.Scenes sp.ControllingClient.Close(true); sp = null; } - + + // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. + // We need the circuit data here for some of the subsequent checks. (groups, for example) + // If the checks fail, we remove the circuit. + agent.teleportFlags = teleportFlags; + m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); + land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); - //On login test land permisions + // On login test land permisions if (vialogin) { if (land != null && !TestLandRestrictions(agent, land, out reason)) { + m_authenticateHandler.RemoveCircuit(agent.circuitcode); return false; } } @@ -3706,13 +3713,17 @@ namespace OpenSim.Region.Framework.Scenes try { if (!VerifyUserPresence(agent, out reason)) + { + m_authenticateHandler.RemoveCircuit(agent.circuitcode); return false; + } } catch (Exception e) { m_log.ErrorFormat( "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); + m_authenticateHandler.RemoveCircuit(agent.circuitcode); return false; } } @@ -3720,13 +3731,17 @@ namespace OpenSim.Region.Framework.Scenes try { if (!AuthorizeUser(agent, out reason)) + { + m_authenticateHandler.RemoveCircuit(agent.circuitcode); return false; + } } catch (Exception e) { m_log.ErrorFormat( "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); + m_authenticateHandler.RemoveCircuit(agent.circuitcode); return false; } @@ -3761,9 +3776,6 @@ namespace OpenSim.Region.Framework.Scenes } } - // In all cases, add or update the circuit data with the new agent circuit data and teleport flags - agent.teleportFlags = teleportFlags; - m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); if (vialogin) { -- cgit v1.1 From 90f03ccd42a045bb30f33ed866feb38677ed7780 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 6 May 2013 11:47:55 -0700 Subject: Added new method to Remote Admin for reloading the estate settings. This is meant to be called when some other program has changed the data on the backend. --- .../RemoteController/RemoteAdminPlugin.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 355f7b3..ad683b8 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -157,6 +157,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController availableMethods["admin_acl_add"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListAdd); availableMethods["admin_acl_remove"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListRemove); availableMethods["admin_acl_list"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListList); + availableMethods["admin_estate_reload"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcEstateReload); // Either enable full remote functionality or just selected features string enabledMethods = m_config.GetString("enabled_methods", "all"); @@ -1762,6 +1763,22 @@ namespace OpenSim.ApplicationPlugins.RemoteController m_log.Info("[RADMIN]: Access List List Request complete"); } + private void XmlRpcEstateReload(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) + { + m_log.Info("[RADMIN]: Received Estate Reload Request"); + + 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) + ); + + responseData["success"] = true; + + m_log.Info("[RADMIN]: Estate Reload Request complete"); + } + private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient) { Hashtable responseData = (Hashtable)response.Value; -- cgit v1.1 From f9fb1484aa00f8bfadead06ce71d004502fb564e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 3 May 2013 15:46:35 -0700 Subject: BulletSim: extend BSActorLockAxis to allow locking linear movement in addition to angular movement. Not enabled by anything yet. --- .../Physics/BulletSPlugin/BSActorLockAxis.cs | 25 +++++++++++++++++----- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 9 +++++--- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 4 ++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs index 7801d8e..8b0fdeb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs @@ -64,9 +64,9 @@ public class BSActorLockAxis : BSActor public override void Refresh() { m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", - m_controllingPrim.LocalID, m_controllingPrim.LockedAxis, Enabled, m_controllingPrim.IsPhysicallyActive); + m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive); // If all the axis are free, we don't need to exist - if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree) { Enabled = false; } @@ -123,23 +123,38 @@ public class BSActorLockAxis : BSActor // Free to move linearly in the region OMV.Vector3 linearLow = OMV.Vector3.Zero; OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; + if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis) + { + linearLow.X = m_controllingPrim.RawPosition.X; + linearHigh.X = m_controllingPrim.RawPosition.X; + } + if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis) + { + linearLow.Y = m_controllingPrim.RawPosition.Y; + linearHigh.Y = m_controllingPrim.RawPosition.Y; + } + if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis) + { + linearLow.Z = m_controllingPrim.RawPosition.Z; + linearHigh.Z = m_controllingPrim.RawPosition.Z; + } axisConstrainer.SetLinearLimits(linearLow, linearHigh); // Angular with some axis locked float fPI = (float)Math.PI; OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); - if (m_controllingPrim.LockedAxis.X != 1f) + if (m_controllingPrim.LockedAngularAxis.X != BSPhysObject.FreeAxis) { angularLow.X = 0f; angularHigh.X = 0f; } - if (m_controllingPrim.LockedAxis.Y != 1f) + if (m_controllingPrim.LockedAngularAxis.Y != BSPhysObject.FreeAxis) { angularLow.Y = 0f; angularHigh.Y = 0f; } - if (m_controllingPrim.LockedAxis.Z != 1f) + if (m_controllingPrim.LockedAngularAxis.Z != BSPhysObject.FreeAxis) { angularLow.Z = 0f; angularHigh.Z = 0f; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index e796804..cca887a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -108,7 +108,8 @@ public abstract class BSPhysObject : PhysicsActor CollisionScore = 0; // All axis free. - LockedAxis = LockedAxisFree; + LockedLinearAxis = LockedAxisFree; + LockedAngularAxis = LockedAxisFree; } // Tell the object to clean up. @@ -265,8 +266,10 @@ public abstract class BSPhysObject : PhysicsActor // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } - public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. - public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free + public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free. + public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free. + public const float FreeAxis = 1f; + public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free // Enable physical actions. Bullet will keep sleeping non-moving physical objects so // they need waking up when parameters are changed. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index d3f3475..f5b0361 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -256,9 +256,9 @@ public class BSPrim : BSPhysObject if (axis.X != 1) locking.X = 0f; if (axis.Y != 1) locking.Y = 0f; if (axis.Z != 1) locking.Z = 0f; - LockedAxis = locking; + LockedAngularAxis = locking; - EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, delegate() + EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() { return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); }); -- cgit v1.1 From bf318969836bf38dbd0325f24fa3d1bd12f34d77 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 3 May 2013 17:14:31 -0700 Subject: BulletSim: simplify parameter specification by reducing the number of specifications required for simple properties with defaults. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 283 +++++++-------------- 2 files changed, 94 insertions(+), 191 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index c5bee6d..0dd2aa5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -146,7 +146,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin enableAngularVerticalAttraction = true; enableAngularDeflection = false; enableAngularBanking = true; - if (BSParam.VehicleDebuggingEnabled) + if (BSParam.VehicleDebuggingEnable) { enableAngularVerticalAttraction = true; enableAngularDeflection = false; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 2ac68e3..3ca7e16 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -26,6 +26,7 @@ */ using System; using System.Collections.Generic; +using System.Reflection; using System.Text; using OpenSim.Region.Physics.Manager; @@ -144,7 +145,7 @@ public static class BSParam public static Vector3 VehicleAngularFactor { get; private set; } public static float VehicleGroundGravityFudge { get; private set; } public static float VehicleAngularBankingTimescaleFudge { get; private set; } - public static bool VehicleDebuggingEnabled { get; private set; } + public static bool VehicleDebuggingEnable { get; private set; } // Convex Hulls public static int CSHullMaxDepthSplit { get; private set; } @@ -236,17 +237,41 @@ public static class BSParam getter = pGetter; objectSet = pObjSetter; } - /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work - * TODO: Maybe use reflection and the name of the variable to create a reference for the getter/setter. - public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc) + // Simple parameter variable where property name is the same as the INI file name + // and the value is only a simple get and set. + public ParameterDefn(string pName, string pDesc, T pDefault) : base(pName, pDesc) { defaultValue = pDefault; - setter = (s, v) => { loc = v; }; - getter = (s) => { return loc; }; + setter = (s, v) => { SetValueByName(s, name, v); }; + getter = (s) => { return GetValueByName(s, name); }; objectSet = null; } - */ + // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. + private void SetValueByName(BSScene s, string pName, T val) + { + PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (prop == null) + { + // This should only be output when someone adds a new INI parameter and misspells the name. + s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); + } + else + { + prop.SetValue(null, val, null); + } + } + // Use reflection to find the property named 'pName' in BSParam and return the value in same. + private T GetValueByName(BSScene s, string pName) + { + PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (prop == null) + { + // This should only be output when someone adds a new INI parameter and misspells the name. + s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); + } + return (T)prop.GetValue(null, null); + } public override void AssignDefault(BSScene s) { setter(s, defaultValue); @@ -336,26 +361,16 @@ public static class BSParam (s) => { return ShouldUseHullsForPhysicalObjects; }, (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", - true, - (s) => { return ShouldRemoveZeroWidthTriangles; }, - (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), + true ), new ParameterDefn("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", - false, - (s) => { return ShouldUseBulletHACD; }, - (s,v) => { ShouldUseBulletHACD = v; } ), + false ), new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", - true, - (s) => { return ShouldUseSingleConvexHullForPrims; }, - (s,v) => { ShouldUseSingleConvexHullForPrims = v; } ), + true ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", - 5, - (s) => { return CrossingFailuresBeforeOutOfBounds; }, - (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ), + 5 ), new ParameterDefn("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", - 0.1f, - (s) => { return UpdateVelocityChangeThreshold; }, - (s,v) => { UpdateVelocityChangeThreshold = v; } ), + 0.1f ), new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 32f, @@ -422,18 +437,12 @@ public static class BSParam (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), // Density is passed around as 100kg/m3. This scales that to 1kg/m3. new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", - 0.01f, - (s) => { return DensityScaleFactor; }, - (s,v) => { DensityScaleFactor = v; } ), + 0.01f ), new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", - 2200f, - (s) => { return (float)PID_D; }, - (s,v) => { PID_D = v; } ), + 2200f ), new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", - 900f, - (s) => { return (float)PID_P; }, - (s,v) => { PID_P = v; } ), + 900f ), new ParameterDefn("DefaultFriction", "Friction factor used on new objects", 0.2f, @@ -500,94 +509,50 @@ public static class BSParam (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", - (float)BSTerrainPhys.TerrainImplementation.Mesh, - (s) => { return TerrainImplementation; }, - (s,v) => { TerrainImplementation = v; } ), + (float)BSTerrainPhys.TerrainImplementation.Mesh ), new ParameterDefn("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , - 2, - (s) => { return TerrainMeshMagnification; }, - (s,v) => { TerrainMeshMagnification = v; } ), + 2 ), new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , - 0.3f, - (s) => { return TerrainFriction; }, - (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), + 0.3f ), new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , - 0.8f, - (s) => { return TerrainHitFraction; }, - (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), + 0.8f ), new ParameterDefn("TerrainRestitution", "Bouncyness" , - 0f, - (s) => { return TerrainRestitution; }, - (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), + 0f ), new ParameterDefn("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , - 0.0f, - (s) => { return TerrainContactProcessingThreshold; }, - (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ), + 0.0f ), new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , - 0.08f, - (s) => { return TerrainCollisionMargin; }, - (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), + 0.08f ), new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", - 0.2f, - (s) => { return AvatarFriction; }, - (s,v) => { AvatarFriction = v; } ), + 0.2f ), new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", - 0.95f, - (s) => { return AvatarStandingFriction; }, - (s,v) => { AvatarStandingFriction = v; } ), + 0.95f ), new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", - 1.3f, - (s) => { return AvatarAlwaysRunFactor; }, - (s,v) => { AvatarAlwaysRunFactor = v; } ), + 1.3f ), new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", - 3.5f, - (s) => { return AvatarDensity; }, - (s,v) => { AvatarDensity = v; } ), + 3.5f) , new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", - 0f, - (s) => { return AvatarRestitution; }, - (s,v) => { AvatarRestitution = v; } ), + 0f ), new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", - 0.6f, - (s) => { return AvatarCapsuleWidth; }, - (s,v) => { AvatarCapsuleWidth = v; } ), + 0.6f ) , new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", - 0.45f, - (s) => { return AvatarCapsuleDepth; }, - (s,v) => { AvatarCapsuleDepth = v; } ), + 0.45f ), new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", - 1.5f, - (s) => { return AvatarCapsuleHeight; }, - (s,v) => { AvatarCapsuleHeight = v; } ), + 1.5f ), new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", - 0.1f, - (s) => { return AvatarContactProcessingThreshold; }, - (s,v) => { AvatarContactProcessingThreshold = v; } ), + 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", - 1.0f, - (s) => { return AvatarBelowGroundUpCorrectionMeters; }, - (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), + 1.0f ), new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", - 0.6f, - (s) => { return AvatarStepHeight; }, - (s,v) => { AvatarStepHeight = v; } ), + 0.6f ) , new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", - 0.6f, - (s) => { return AvatarStepApproachFactor; }, - (s,v) => { AvatarStepApproachFactor = v; } ), + 0.6f ), new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", - 1.0f, - (s) => { return AvatarStepForceFactor; }, - (s,v) => { AvatarStepForceFactor = v; } ), + 1.0f ), new ParameterDefn("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", - 1.0f, - (s) => { return AvatarStepUpCorrectionFactor; }, - (s,v) => { AvatarStepUpCorrectionFactor = v; } ), + 1.0f ), new ParameterDefn("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", - 2, - (s) => { return AvatarStepSmoothingSteps; }, - (s,v) => { AvatarStepSmoothingSteps = v; } ), + 2 ), new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", 1000.0f, @@ -598,37 +563,21 @@ public static class BSParam (s) => { return (float)VehicleMaxAngularVelocity; }, (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", - 0.0f, - (s) => { return VehicleAngularDamping; }, - (s,v) => { VehicleAngularDamping = v; } ), + 0.0f ), new ParameterDefn("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", - new Vector3(1f, 1f, 1f), - (s) => { return VehicleLinearFactor; }, - (s,v) => { VehicleLinearFactor = v; } ), + new Vector3(1f, 1f, 1f) ), new ParameterDefn("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", - new Vector3(1f, 1f, 1f), - (s) => { return VehicleAngularFactor; }, - (s,v) => { VehicleAngularFactor = v; } ), + new Vector3(1f, 1f, 1f) ), new ParameterDefn("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", - 0.0f, - (s) => { return VehicleFriction; }, - (s,v) => { VehicleFriction = v; } ), + 0.0f ), new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", - 0.0f, - (s) => { return VehicleRestitution; }, - (s,v) => { VehicleRestitution = v; } ), + 0.0f ), new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", - 0.2f, - (s) => { return VehicleGroundGravityFudge; }, - (s,v) => { VehicleGroundGravityFudge = v; } ), + 0.2f ), new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", - 60.0f, - (s) => { return VehicleAngularBankingTimescaleFudge; }, - (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), + 60.0f ), new ParameterDefn("VehicleDebuggingEnable", "Turn on/off vehicle debugging", - false, - (s) => { return VehicleDebuggingEnabled; }, - (s,v) => { VehicleDebuggingEnabled = v; } ), + false ), new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 0f, @@ -673,99 +622,53 @@ public static class BSParam (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), new ParameterDefn("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", - 7, - (s) => { return CSHullMaxDepthSplit; }, - (s,v) => { CSHullMaxDepthSplit = v; } ), + 7 ), new ParameterDefn("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", - 2, - (s) => { return CSHullMaxDepthSplitForSimpleShapes; }, - (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ), + 2 ), new ParameterDefn("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", - 5f, - (s) => { return CSHullConcavityThresholdPercent; }, - (s,v) => { CSHullConcavityThresholdPercent = v; } ), + 5f ), new ParameterDefn("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", - 5f, - (s) => { return CSHullVolumeConservationThresholdPercent; }, - (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ), + 5f ), new ParameterDefn("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", - 32, - (s) => { return CSHullMaxVertices; }, - (s,v) => { CSHullMaxVertices = v; } ), + 32 ), new ParameterDefn("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", - 0f, - (s) => { return CSHullMaxSkinWidth; }, - (s,v) => { CSHullMaxSkinWidth = v; } ), + 0f ), new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", - 100f, - (s) => { return BHullMaxVerticesPerHull; }, - (s,v) => { BHullMaxVerticesPerHull = v; } ), + 100f ), new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", - 2f, - (s) => { return BHullMinClusters; }, - (s,v) => { BHullMinClusters = v; } ), + 2f ), new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", - 2f, - (s) => { return BHullCompacityWeight; }, - (s,v) => { BHullCompacityWeight = v; } ), + 0.1f ), new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", - 0.1f, - (s) => { return BHullVolumeWeight; }, - (s,v) => { BHullVolumeWeight = v; } ), + 0f ), new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", - 100f, - (s) => { return BHullConcavity; }, - (s,v) => { BHullConcavity = v; } ), + 100f ), new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", - false, - (s) => { return BHullAddExtraDistPoints; }, - (s,v) => { BHullAddExtraDistPoints = v; } ), + false ), new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", - false, - (s) => { return BHullAddNeighboursDistPoints; }, - (s,v) => { BHullAddNeighboursDistPoints = v; } ), + false ), new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", - false, - (s) => { return BHullAddFacesPoints; }, - (s,v) => { BHullAddFacesPoints = v; } ), + false ), new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", - false, - (s) => { return BHullShouldAdjustCollisionMargin; }, - (s,v) => { BHullShouldAdjustCollisionMargin = v; } ), + false ), new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", - (float)BSLinkset.LinksetImplementation.Compound, - (s) => { return LinksetImplementation; }, - (s,v) => { LinksetImplementation = v; } ), + (float)BSLinkset.LinksetImplementation.Compound ), new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", - false, - (s) => { return LinkConstraintUseFrameOffset; }, - (s,v) => { LinkConstraintUseFrameOffset = v; } ), + false ), new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", - true, - (s) => { return LinkConstraintEnableTransMotor; }, - (s,v) => { LinkConstraintEnableTransMotor = v; } ), + true ), new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", - 5.0f, - (s) => { return LinkConstraintTransMotorMaxVel; }, - (s,v) => { LinkConstraintTransMotorMaxVel = v; } ), + 5.0f ), new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", - 0.1f, - (s) => { return LinkConstraintTransMotorMaxForce; }, - (s,v) => { LinkConstraintTransMotorMaxForce = v; } ), + 0.1f ), new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", - 0.1f, - (s) => { return LinkConstraintCFM; }, - (s,v) => { LinkConstraintCFM = v; } ), + 0.1f ), new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", - 0.1f, - (s) => { return LinkConstraintERP; }, - (s,v) => { LinkConstraintERP = v; } ), + 0.1f ), new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", - 40, - (s) => { return LinkConstraintSolverIterations; }, - (s,v) => { LinkConstraintSolverIterations = v; } ), + 40 ), new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", 0, -- cgit v1.1 From 045aaa838ac0a6e129ff1d8ec65053508df1d51a Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 6 May 2013 13:29:19 -0700 Subject: BulletSim: remove friction calcuation from BSMotor and move linear and angular friction computation into linear and angular movement code. The friction wasn't being applied properly. This will make it so vehicles don't drift as much and the drift is tunable by changing the friction timescales. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 1 - .../Region/Physics/BulletSPlugin/BSActorHover.cs | 1 - .../Physics/BulletSPlugin/BSActorMoveToTarget.cs | 1 - .../Physics/BulletSPlugin/BSActorSetForce.cs | 2 +- .../Physics/BulletSPlugin/BSActorSetTorque.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 44 ++++++++++----- OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 63 +++++----------------- 7 files changed, 47 insertions(+), 67 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 4e067b5..ac8c30c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -118,7 +118,6 @@ public class BSActorAvatarMove : BSActor m_velocityMotor = new BSVMotor("BSCharacter.Velocity", 0.2f, // time scale BSMotor.Infinite, // decay time scale - BSMotor.InfiniteVector, // friction timescale 1f // efficiency ); // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs index 3630ca8..8a79809 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs @@ -102,7 +102,6 @@ public class BSActorHover : BSActor m_hoverMotor = new BSFMotor("BSActorHover", m_controllingPrim.HoverTau, // timeScale BSMotor.Infinite, // decay time scale - BSMotor.Infinite, // friction timescale 1f // efficiency ); m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs index 1b598fd..75ff24e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs @@ -105,7 +105,6 @@ public class BSActorMoveToTarget : BSActor m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate", m_controllingPrim.MoveToTargetTau, // timeScale BSMotor.Infinite, // decay time scale - BSMotor.InfiniteVector, // friction timescale 1f // efficiency ); m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs index c0f40fd..96fa0b6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs @@ -101,7 +101,7 @@ public class BSActorSetForce : BSActor if (m_forceMotor == null) { // A fake motor that might be used someday - m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f, 1f); + m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f); m_physicsScene.BeforeStep += Mover; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs index b3806e1..65098e1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs @@ -101,7 +101,7 @@ public class BSActorSetTorque : BSActor if (m_torqueMotor == null) { // A fake motor that might be used someday - m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f, 1f); + m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f); m_physicsScene.BeforeStep += Mover; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 0dd2aa5..272a162 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -235,7 +235,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin // set all of the components to the same value case Vehicle.ANGULAR_FRICTION_TIMESCALE: m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); - m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; break; case Vehicle.ANGULAR_MOTOR_DIRECTION: m_angularMotorDirection = new Vector3(pValue, pValue, pValue); @@ -244,7 +243,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin break; case Vehicle.LINEAR_FRICTION_TIMESCALE: m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); - m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; break; case Vehicle.LINEAR_MOTOR_DIRECTION: m_linearMotorDirection = new Vector3(pValue, pValue, pValue); @@ -265,7 +263,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin { case Vehicle.ANGULAR_FRICTION_TIMESCALE: m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; break; case Vehicle.ANGULAR_MOTOR_DIRECTION: // Limit requested angular speed to 2 rps= 4 pi rads/sec @@ -278,7 +275,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin break; case Vehicle.LINEAR_FRICTION_TIMESCALE: m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); - m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; break; case Vehicle.LINEAR_MOTOR_DIRECTION: m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); @@ -559,14 +555,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin break; } - m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, - m_linearMotorDecayTimescale, m_linearFrictionTimescale, - 1f); + m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) - m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, - m_angularMotorDecayTimescale, m_angularFrictionTimescale, - 1f); + m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) /* Not implemented @@ -574,7 +566,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin BSMotor.Infinite, BSMotor.InfiniteVector, m_verticalAttractionEfficiency); // Z goes away and we keep X and Y - m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) */ @@ -1050,8 +1041,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}", - ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity); + // Friction reduces vehicle motion + Vector3 frictionFactor = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); + VehicleVelocity -= (VehicleVelocity * frictionFactor); + + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", + ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, + linearMotorVelocityW, VehicleVelocity, frictionFactor); } public void ComputeLinearTerrainHeightCorrection(float pTimestep) @@ -1342,6 +1338,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin // } VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; + + // Reduce any velocity by friction. + Vector3 frictionFactor = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); + VehicleRotationalVelocity -= (VehicleRotationalVelocity * frictionFactor); + VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", ControllingPrim.LocalID, angularMotorContributionV); } @@ -1629,6 +1630,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin } + // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce + // some value by to apply this friction. + private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) + { + Vector3 frictionFactor = Vector3.Zero; + if (friction != BSMotor.InfiniteVector) + { + // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; + // Individual friction components can be 'infinite' so compute each separately. + frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); + frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); + frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); + frictionFactor *= pTimestep; + } + return frictionFactor; + } + private float ClampInRange(float low, float val, float high) { return Math.Max(low, Math.Min(val, high)); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 0128d8d..ef662b5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -65,13 +65,11 @@ public abstract class BSMotor } // Motor which moves CurrentValue to TargetValue over TimeScale seconds. -// The TargetValue decays in TargetValueDecayTimeScale and -// the CurrentValue will be held back by FrictionTimeScale. +// The TargetValue decays in TargetValueDecayTimeScale. // This motor will "zero itself" over time in that the targetValue will // decay to zero and the currentValue will follow it to that zero. // The overall effect is for the returned correction value to go from large -// values (the total difference between current and target minus friction) -// to small and eventually zero values. +// values to small and eventually zero values. // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. // For instance, if something is moving at speed X and the desired speed is Y, @@ -88,7 +86,6 @@ public class BSVMotor : BSMotor public virtual float TimeScale { get; set; } public virtual float TargetValueDecayTimeScale { get; set; } - public virtual Vector3 FrictionTimescale { get; set; } public virtual float Efficiency { get; set; } public virtual float ErrorZeroThreshold { get; set; } @@ -111,16 +108,14 @@ public class BSVMotor : BSMotor { TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; Efficiency = 1f; - FrictionTimescale = BSMotor.InfiniteVector; CurrentValue = TargetValue = Vector3.Zero; ErrorZeroThreshold = 0.001f; } - public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) + public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency) : this(useName) { TimeScale = timeScale; TargetValueDecayTimeScale = decayTimeScale; - FrictionTimescale = frictionTimeScale; Efficiency = efficiency; CurrentValue = TargetValue = Vector3.Zero; } @@ -165,26 +160,11 @@ public class BSVMotor : BSMotor TargetValue *= (1f - decayFactor); } - // The amount we can correct the error is reduced by the friction - Vector3 frictionFactor = Vector3.Zero; - if (FrictionTimescale != BSMotor.InfiniteVector) - { - // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; - // Individual friction components can be 'infinite' so compute each separately. - frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); - frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); - frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); - frictionFactor *= timeStep; - CurrentValue *= (Vector3.One - frictionFactor); - } - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", BSScene.DetailLogZero, UseName, origCurrVal, origTarget, timeStep, error, correction); - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", - BSScene.DetailLogZero, UseName, - TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, - TargetValue, CurrentValue); + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", + BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); } else { @@ -235,9 +215,9 @@ public class BSVMotor : BSMotor // maximum number of outputs to generate. int maxOutput = 50; MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); - MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", + MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", BSScene.DetailLogZero, UseName, - TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, + TimeScale, TargetValueDecayTimeScale, Efficiency, CurrentValue, TargetValue); LastError = BSMotor.InfiniteVector; @@ -254,8 +234,8 @@ public class BSVMotor : BSMotor public override string ToString() { - return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", - UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); + return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", + UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); } } @@ -265,7 +245,6 @@ public class BSFMotor : BSMotor { public virtual float TimeScale { get; set; } public virtual float TargetValueDecayTimeScale { get; set; } - public virtual float FrictionTimescale { get; set; } public virtual float Efficiency { get; set; } public virtual float ErrorZeroThreshold { get; set; } @@ -283,12 +262,11 @@ public class BSFMotor : BSMotor return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); } - public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) + public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) : base(useName) { TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; Efficiency = 1f; - FrictionTimescale = BSMotor.Infinite; CurrentValue = TargetValue = 0f; ErrorZeroThreshold = 0.01f; } @@ -331,24 +309,11 @@ public class BSFMotor : BSMotor TargetValue *= (1f - decayFactor); } - // The amount we can correct the error is reduced by the friction - float frictionFactor = 0f; - if (FrictionTimescale != BSMotor.Infinite) - { - // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; - // Individual friction components can be 'infinite' so compute each separately. - frictionFactor = 1f / FrictionTimescale; - frictionFactor *= timeStep; - CurrentValue *= (1f - frictionFactor); - } - MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", BSScene.DetailLogZero, UseName, origCurrVal, origTarget, timeStep, error, correction); - MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", - BSScene.DetailLogZero, UseName, - TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, - TargetValue, CurrentValue); + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", + BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); } else { @@ -390,8 +355,8 @@ public class BSFMotor : BSMotor public override string ToString() { - return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", - UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); + return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", + UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); } } -- cgit v1.1 From 93e1986d690cda415c9cce639a2656bc773a9a29 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 6 May 2013 16:48:01 -0700 Subject: BulletSim: apply linear and angular friction in vehicle coordinates and not world coordinates. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 272a162..04ea289 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1042,12 +1042,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin VehicleVelocity += linearMotorVelocityW; // Friction reduces vehicle motion - Vector3 frictionFactor = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); - VehicleVelocity -= (VehicleVelocity * frictionFactor); + Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep) * VehicleOrientation; + VehicleVelocity -= (VehicleVelocity * frictionFactorW); VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, - linearMotorVelocityW, VehicleVelocity, frictionFactor); + linearMotorVelocityW, VehicleVelocity, frictionFactorW); } public void ComputeLinearTerrainHeightCorrection(float pTimestep) @@ -1340,10 +1340,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; // Reduce any velocity by friction. - Vector3 frictionFactor = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); - VehicleRotationalVelocity -= (VehicleRotationalVelocity * frictionFactor); + Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep) * VehicleOrientation; + VehicleRotationalVelocity -= (VehicleRotationalVelocity * frictionFactorW); - VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", ControllingPrim.LocalID, angularMotorContributionV); + VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV); } // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: -- cgit v1.1 From 4c83b5e719ad288b1250fbed3f74698fa34eff21 Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 7 May 2013 00:31:11 +0100 Subject: Step one of estate settings sharing - port the Avination Estate module (complete module) as changes are too extensive to apply manually --- .../EntityTransfer/EntityTransferModule.cs | 13 +++-- .../EntityTransfer/HGEntityTransferModule.cs | 21 +++++--- .../World/Estate/EstateManagementModule.cs | 57 +++++++++++++++++----- .../Framework/Interfaces/IEntityTransferModule.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 5 +- 5 files changed, 71 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ca0cef1..eac0da7 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -243,7 +243,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected virtual void OnNewClient(IClientAPI client) { - client.OnTeleportHomeRequest += TeleportHome; + client.OnTeleportHomeRequest += TriggerTeleportHome; client.OnTeleportLandmarkRequest += RequestTeleportLandmark; if (!DisableInterRegionTeleportCancellation) @@ -1071,7 +1071,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Teleport Home - public virtual void TeleportHome(UUID id, IClientAPI client) + public virtual void TriggerTeleportHome(UUID id, IClientAPI client) + { + TeleportHome(id, client); + } + + public virtual bool TeleportHome(UUID id, IClientAPI client) { m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); @@ -1086,7 +1091,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { // can't find the Home region: Tell viewer and abort client.SendTeleportFailed("Your home region could not be found."); - return; + return false; } m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", @@ -1096,6 +1101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer ((Scene)(client.Scene)).RequestTeleportLocation( client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); + return true; } else { @@ -1103,6 +1109,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: No grid user information found for {0} {1}. Cannot send home.", client.Name, client.AgentId); } + return false; } #endregion diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 33ea063..02ed1a0 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -184,7 +184,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected override void OnNewClient(IClientAPI client) { - client.OnTeleportHomeRequest += TeleportHome; + client.OnTeleportHomeRequest += TriggerTeleportHome; client.OnTeleportLandmarkRequest += RequestTeleportLandmark; client.OnConnectionClosed += new Action(OnConnectionClosed); } @@ -409,7 +409,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // return base.UpdateAgent(reg, finalDestination, agentData, sp); //} - public override void TeleportHome(UUID id, IClientAPI client) + public virtual void TriggerTeleportHome(UUID id, IClientAPI client) + { + TeleportHome(id, client); + } + + public override bool TeleportHome(UUID id, IClientAPI client) { m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); @@ -420,8 +425,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { // local grid user m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); - base.TeleportHome(id, client); - return; + return base.TeleportHome(id, client); } // Foreign user wants to go home @@ -431,7 +435,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { client.SendTeleportFailed("Your information has been lost"); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); - return; + return false; } IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); @@ -441,7 +445,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { client.SendTeleportFailed("Your home region could not be found"); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); - return; + return false; } ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); @@ -449,7 +453,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { client.SendTeleportFailed("Internal error"); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); - return; + return false; } GridRegion homeGatekeeper = MakeRegion(aCircuit); @@ -460,6 +464,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer DoTeleport( sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); + return true; } /// @@ -586,4 +591,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return region; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 60f6739..91f6501 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -32,6 +32,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Security; +using System.Timers; using log4net; using Mono.Addins; using Nini.Config; @@ -48,6 +49,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private Timer m_regionChangeTimer = new Timer(); public Scene Scene { get; private set; } public IUserManagement UserManager { get; private set; } @@ -65,6 +67,8 @@ namespace OpenSim.Region.CoreModules.World.Estate public event ChangeDelegate OnEstateInfoChange; public event MessageDelegate OnEstateMessage; + private int m_delayCount = 0; + #region Region Module interface public string Name { get { return "EstateManagementModule"; } } @@ -114,6 +118,12 @@ namespace OpenSim.Region.CoreModules.World.Estate #region Packet Data Responders + private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice) + { + sendDetailedEstateData(remote_client, invoice); + sendEstateLists(remote_client, invoice); + } + private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice) { uint sun = 0; @@ -136,7 +146,10 @@ namespace OpenSim.Region.CoreModules.World.Estate (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime, Scene.RegionInfo.EstateSettings.AbuseEmail, estateOwner); + } + private void sendEstateLists(IClientAPI remote_client, UUID invoice) + { remote_client.SendEstateList(invoice, (int)Constants.EstateAccessCodex.EstateManagers, Scene.RegionInfo.EstateSettings.EstateManagers, @@ -330,7 +343,7 @@ namespace OpenSim.Region.CoreModules.World.Estate timeInSeconds -= 15; } - restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); + restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false); m_log.InfoFormat( "User {0} requested restart of region {1} in {2} seconds", @@ -546,7 +559,11 @@ namespace OpenSim.Region.CoreModules.World.Estate { if (!s.IsChildAgent) { - Scene.TeleportClientHome(user, s.ControllingClient); + if (!Scene.TeleportClientHome(user, s.ControllingClient)) + { + s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); + s.ControllingClient.Close(); + } } } @@ -555,7 +572,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { remote_client.SendAlertMessage("User is already on the region ban list"); } - //m_scene.RegionInfo.regionBanlist.Add(Manager(user); + //Scene.RegionInfo.regionBanlist.Add(Manager(user); remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); } else @@ -611,7 +628,7 @@ namespace OpenSim.Region.CoreModules.World.Estate remote_client.SendAlertMessage("User is not on the region ban list"); } - //m_scene.RegionInfo.regionBanlist.Add(Manager(user); + //Scene.RegionInfo.regionBanlist.Add(Manager(user); remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); } else @@ -777,7 +794,11 @@ namespace OpenSim.Region.CoreModules.World.Estate ScenePresence s = Scene.GetScenePresence(prey); if (s != null) { - Scene.TeleportClientHome(prey, s.ControllingClient); + if (!Scene.TeleportClientHome(prey, s.ControllingClient)) + { + s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); + s.ControllingClient.Close(); + } } } } @@ -795,7 +816,13 @@ namespace OpenSim.Region.CoreModules.World.Estate // Also make sure they are actually in the region ScenePresence p; if(Scene.TryGetScenePresence(client.AgentId, out p)) - Scene.TeleportClientHome(p.UUID, p.ControllingClient); + { + if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) + { + p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); + p.ControllingClient.Close(); + } + } } }); } @@ -1170,7 +1197,7 @@ namespace OpenSim.Region.CoreModules.World.Estate private void EventManager_OnNewClient(IClientAPI client) { - client.OnDetailedEstateDataRequest += sendDetailedEstateData; + client.OnDetailedEstateDataRequest += clientSendDetailedEstateData; client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; // client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture; @@ -1218,8 +1245,6 @@ namespace OpenSim.Region.CoreModules.World.Estate flags |= RegionFlags.NoFly; if (Scene.RegionInfo.RegionSettings.RestrictPushing) flags |= RegionFlags.RestrictPushObject; - if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide) - flags |= RegionFlags.AllowParcelChanges; if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) flags |= RegionFlags.BlockParcelSearch; @@ -1229,11 +1254,11 @@ namespace OpenSim.Region.CoreModules.World.Estate flags |= RegionFlags.Sandbox; if (Scene.RegionInfo.EstateSettings.AllowVoice) flags |= RegionFlags.AllowVoice; + if (Scene.RegionInfo.EstateSettings.BlockDwell) + flags |= RegionFlags.BlockDwell; + if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport) + flags |= RegionFlags.ResetHomeOnTeleport; - // Fudge these to always on, so the menu options activate - // - flags |= RegionFlags.AllowLandmark; - flags |= RegionFlags.AllowSetHome; // TODO: SkipUpdateInterestList @@ -1294,6 +1319,12 @@ namespace OpenSim.Region.CoreModules.World.Estate public void TriggerRegionInfoChange() { + m_regionChangeTimer.Stop(); + m_regionChangeTimer.Start(); + } + + protected void RaiseRegionInfoChange(object sender, ElapsedEventArgs e) + { ChangeDelegate change = OnRegionInfoChange; if (change != null) diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index 69be83e..1c43a25 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs @@ -72,7 +72,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void TeleportHome(UUID id, IClientAPI client); + bool TeleportHome(UUID id, IClientAPI client); /// /// Show whether the given agent is being teleported. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 8fe2d72..2aba2dd 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3230,17 +3230,18 @@ namespace OpenSim.Region.Framework.Scenes /// /// The avatar's Unique ID /// The IClientAPI for the client - public virtual void TeleportClientHome(UUID agentId, IClientAPI client) + public virtual bool TeleportClientHome(UUID agentId, IClientAPI client) { if (EntityTransferModule != null) { - EntityTransferModule.TeleportHome(agentId, client); + return EntityTransferModule.TeleportHome(agentId, client); } else { m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); client.SendTeleportFailed("Unable to perform teleports on this simulator."); } + return false; } /// -- cgit v1.1 From 5d5edde4290030345bc25841a25d23552e533972 Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 7 May 2013 00:37:45 +0100 Subject: Step 2: commit the IEstateModuleInterface changes needed --- OpenSim/Region/Framework/Interfaces/IEstateModule.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs index 1983984..d49b24e 100644 --- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs @@ -40,11 +40,12 @@ namespace OpenSim.Region.Framework.Interfaces uint GetRegionFlags(); bool IsManager(UUID avatarID); - + /// /// Tell all clients about the current state of the region (terrain textures, water height, etc.). /// void sendRegionHandshakeToAll(); + void TriggerEstateInfoChange(); /// /// Fires the OnRegionInfoChange event. -- cgit v1.1 From 1c6b8293d7b9e312c5b1fb544a1de7fd3b145670 Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 7 May 2013 00:52:40 +0100 Subject: Step 3: Commit the Avination XEstate estate comms handler This adds estate-wide Teleport Home and Teleport All User Home as well --- .../CoreModules/World/Estate/XEstateConnector.cs | 215 +++++++++++++++ .../CoreModules/World/Estate/XEstateModule.cs | 254 ++++++++++++++++++ .../World/Estate/XEstateRequestHandler.cs | 298 +++++++++++++++++++++ 3 files changed, 767 insertions(+) create mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs create mode 100644 OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs new file mode 100644 index 0000000..948c893 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -0,0 +1,215 @@ +/* + * 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.Reflection; + +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenSim.Server.Base; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; +using OpenSim.Region.Framework.Scenes; + +using OpenMetaverse; +using log4net; + +namespace OpenSim.Region.CoreModules.World.Estate +{ + public class EstateConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected XEstateModule m_EstateModule; + + public EstateConnector(XEstateModule module) + { + m_EstateModule = module; + } + + public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "teleport_home_one_user"; + + sendData["EstateID"] = EstateID.ToString(); + sendData["PreyID"] = PreyID.ToString(); + + SendToEstate(EstateID, sendData); + } + + public void SendTeleportHomeAllUsers(uint EstateID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "teleport_home_all_users"; + + sendData["EstateID"] = EstateID.ToString(); + + SendToEstate(EstateID, sendData); + } + + public bool SendUpdateCovenant(uint EstateID, UUID CovenantID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "update_covenant"; + + sendData["CovenantID"] = CovenantID.ToString(); + sendData["EstateID"] = EstateID.ToString(); + + // Handle local regions locally + // + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + s.RegionInfo.RegionSettings.Covenant = CovenantID; +// s.ReloadEstateData(); + } + + SendToEstate(EstateID, sendData); + + return true; + } + + public bool SendUpdateEstate(uint EstateID) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "update_estate"; + + sendData["EstateID"] = EstateID.ToString(); + + // Handle local regions locally + // + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + s.ReloadEstateData(); + } + + SendToEstate(EstateID, sendData); + + return true; + } + + public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message) + { + Dictionary sendData = new Dictionary(); + sendData["METHOD"] = "estate_message"; + + sendData["EstateID"] = EstateID.ToString(); + sendData["FromID"] = FromID.ToString(); + sendData["FromName"] = FromName; + sendData["Message"] = Message; + + SendToEstate(EstateID, sendData); + } + + private void SendToEstate(uint EstateID, Dictionary sendData) + { + List regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); + + UUID ScopeID = UUID.Zero; + + // Handle local regions locally + // + foreach (Scene s in m_EstateModule.Scenes) + { + if (regions.Contains(s.RegionInfo.RegionID)) + { + // All regions in one estate are in the same scope. + // Use that scope. + // + ScopeID = s.RegionInfo.ScopeID; + regions.Remove(s.RegionInfo.RegionID); + } + } + + // 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; + + // Don't send to the same instance twice + // + List done = new List(); + + // Send to remote regions + // + foreach (UUID regionID in regions) + { + GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID); + if (region != null) + { + string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; + if (done.Contains(url)) + continue; + + Call(region, sendData); + done.Add(url); + } + } + } + + private bool Call(GridRegion region, Dictionary sendData) + { + string reqString = ServerUtils.BuildQueryString(sendData); + // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString); + try + { + string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; + string reply = SynchronousRestFormsRequester.MakeRequest("POST", + url + "/estate", + reqString); + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData.ContainsKey("RESULT")) + { + if (replyData["RESULT"].ToString().ToLower() == "true") + return true; + else + return false; + } + else + m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field"); + + } + else + m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply"); + } + catch (Exception e) + { + m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message); + } + + return false; + } + } +} diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs new file mode 100644 index 0000000..1f099c6 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs @@ -0,0 +1,254 @@ +/* + * 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.Generic; +using System.Reflection; +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Server.Base; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using Mono.Addins; + +namespace OpenSim.Region.CoreModules.World.Estate +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")] + public class XEstateModule : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected List m_Scenes = new List(); + protected bool m_InInfoUpdate = false; + + public bool InInfoUpdate + { + get { return m_InInfoUpdate; } + set { m_InInfoUpdate = value; } + } + + public List Scenes + { + get { return m_Scenes; } + } + + protected EstateConnector m_EstateConnector; + + public void Initialise(IConfigSource config) + { + int port = 0; + + IConfig estateConfig = config.Configs["Estate"]; + if (estateConfig != null) + { + port = estateConfig.GetInt("Port", 0); + } + + m_EstateConnector = new EstateConnector(this); + + // Instantiate the request handler + IHttpServer server = MainServer.GetHttpServer((uint)port); + server.AddStreamHandler(new EstateRequestHandler(this)); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public void AddRegion(Scene scene) + { + m_Scenes.Add(scene); + + scene.EventManager.OnNewClient += OnNewClient; + } + + public void RegionLoaded(Scene scene) + { + IEstateModule em = scene.RequestModuleInterface(); + + em.OnRegionInfoChange += OnRegionInfoChange; + em.OnEstateInfoChange += OnEstateInfoChange; + em.OnEstateMessage += OnEstateMessage; + } + + public void RemoveRegion(Scene scene) + { + scene.EventManager.OnNewClient -= OnNewClient; + + m_Scenes.Remove(scene); + } + + public string Name + { + get { return "EstateModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + private Scene FindScene(UUID RegionID) + { + foreach (Scene s in Scenes) + { + if (s.RegionInfo.RegionID == RegionID) + return s; + } + + return null; + } + + private void OnRegionInfoChange(UUID RegionID) + { + Scene s = FindScene(RegionID); + if (s == null) + return; + + if (!m_InInfoUpdate) + m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant); + } + + private void OnEstateInfoChange(UUID RegionID) + { + Scene s = FindScene(RegionID); + if (s == null) + return; + + if (!m_InInfoUpdate) + m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID); + } + + private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message) + { + Scene senderScenes = FindScene(RegionID); + if (senderScenes == null) + return; + + uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID; + + foreach (Scene s in Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == estateID) + { + IDialogModule dm = s.RequestModuleInterface(); + + if (dm != null) + { + dm.SendNotificationToUsersInRegion(FromID, FromName, + Message); + } + } + } + if (!m_InInfoUpdate) + 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) + return; + + if (!(client.Scene is Scene)) + return; + + Scene scene = (Scene)client.Scene; + + uint estateID = scene.RegionInfo.EstateSettings.EstateID; + + if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) + return; + + 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) + { + p.ControllingClient.SendTeleportStart(16); + scene.TeleportClientHome(prey, p.ControllingClient); + } + } + + m_EstateConnector.SendTeleportHomeOneUser(estateID, prey); + } + + private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID) + { + if (!(client.Scene is Scene)) + return; + + Scene scene = (Scene)client.Scene; + + uint estateID = scene.RegionInfo.EstateSettings.EstateID; + + if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) + return; + + foreach (Scene s in Scenes) + { + if (s == scene) + continue; // Already handles by estate module + if (s.RegionInfo.EstateSettings.EstateID != estateID) + continue; + + scene.ForEachScenePresence(delegate(ScenePresence p) { + if (p != null && !p.IsChildAgent) + { + p.ControllingClient.SendTeleportStart(16); + scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); + } + }); + } + + m_EstateConnector.SendTeleportHomeAllUsers(estateID); + } + } +} diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs new file mode 100644 index 0000000..eb74cda --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs @@ -0,0 +1,298 @@ +/* + * 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 OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; + +using OpenMetaverse; +using log4net; + +namespace OpenSim.Region.CoreModules.World.Estate +{ + public class EstateRequestHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected XEstateModule m_EstateModule; + protected Object m_RequestLock = new Object(); + + public EstateRequestHandler(XEstateModule fmodule) + : base("POST", "/estate") + { + m_EstateModule = fmodule; + } + + public override byte[] Handle(string path, Stream requestData, + IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + StreamReader sr = new StreamReader(requestData); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body); + + try + { + lock (m_RequestLock) + { + Dictionary request = + ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("METHOD")) + return FailureResult(); + + string method = request["METHOD"].ToString(); + request.Remove("METHOD"); + + try + { + m_EstateModule.InInfoUpdate = false; + + switch (method) + { + case "update_covenant": + return UpdateCovenant(request); + case "update_estate": + return UpdateEstate(request); + case "estate_message": + return EstateMessage(request); + case "teleport_home_one_user": + return TeleportHomeOneUser(request); + case "teleport_home_all_users": + return TeleportHomeAllUsers(request); + } + } + finally + { + m_EstateModule.InInfoUpdate = false; + } + } + } + catch (Exception e) + { + m_log.Debug("[XESTATE]: Exception {0}" + e.ToString()); + } + + return FailureResult(); + } + + byte[] TeleportHomeAllUsers(Dictionary request) + { + UUID PreyID = UUID.Zero; + int EstateID = 0; + + if (!request.ContainsKey("EstateID")) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + { + s.ForEachScenePresence(delegate(ScenePresence p) { + if (p != null && !p.IsChildAgent) + { + p.ControllingClient.SendTeleportStart(16); + s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); + } + }); + } + } + + return SuccessResult(); + } + + byte[] TeleportHomeOneUser(Dictionary request) + { + UUID PreyID = UUID.Zero; + int EstateID = 0; + + if (!request.ContainsKey("PreyID") || + !request.ContainsKey("EstateID")) + { + return FailureResult(); + } + + if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID)) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + { + ScenePresence p = s.GetScenePresence(PreyID); + if (p != null && !p.IsChildAgent) + { + p.ControllingClient.SendTeleportStart(16); + s.TeleportClientHome(PreyID, p.ControllingClient); + } + } + } + + return SuccessResult(); + } + + byte[] EstateMessage(Dictionary request) + { + UUID FromID = UUID.Zero; + string FromName = String.Empty; + string Message = String.Empty; + int EstateID = 0; + + if (!request.ContainsKey("FromID") || + !request.ContainsKey("FromName") || + !request.ContainsKey("Message") || + !request.ContainsKey("EstateID")) + { + return FailureResult(); + } + + if (!UUID.TryParse(request["FromID"].ToString(), out FromID)) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + FromName = request["FromName"].ToString(); + Message = request["Message"].ToString(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == EstateID) + { + IDialogModule dm = s.RequestModuleInterface(); + + if (dm != null) + { + dm.SendNotificationToUsersInRegion(FromID, FromName, + Message); + } + } + } + + return SuccessResult(); + } + + byte[] UpdateCovenant(Dictionary request) + { + UUID CovenantID = UUID.Zero; + int EstateID = 0; + + if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID")) + return FailureResult(); + + if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID)) + return FailureResult(); + + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) + s.RegionInfo.RegionSettings.Covenant = CovenantID; + } + + return SuccessResult(); + } + + byte[] UpdateEstate(Dictionary request) + { + int EstateID = 0; + + if (!request.ContainsKey("EstateID")) + return FailureResult(); + if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) + return FailureResult(); + + foreach (Scene s in m_EstateModule.Scenes) + { + if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) + s.ReloadEstateData(); + } + return SuccessResult(); + } + + private byte[] FailureResult() + { + return BoolResult(false); + } + + private byte[] SuccessResult() + { + return BoolResult(true); + } + + private byte[] BoolResult(bool value) + { + XmlDocument doc = new XmlDocument(); + + XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + + doc.AppendChild(xmlnode); + + XmlElement rootElement = doc.CreateElement("", "ServerResponse", + ""); + + doc.AppendChild(rootElement); + + XmlElement result = doc.CreateElement("", "RESULT", ""); + result.AppendChild(doc.CreateTextNode(value.ToString())); + + rootElement.AppendChild(result); + + return DocToBytes(doc); + } + + private byte[] DocToBytes(XmlDocument doc) + { + MemoryStream ms = new MemoryStream(); + XmlTextWriter xw = new XmlTextWriter(ms, null); + xw.Formatting = Formatting.Indented; + doc.WriteTo(xw); + xw.Flush(); + + return ms.ToArray(); + } + } +} -- cgit v1.1 From 84118c5735f49bb38ded2ccc72b1bd7d39c09010 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 6 May 2013 18:05:37 -0700 Subject: BulletSim: properly free references to simple convex hull shapes. Didn't loose memory since shapes are shared but did mess up usage accounting. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 45 +++++++++++++++++++----- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 3e4ee5a..9d47657 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -117,11 +117,11 @@ public abstract class BSShape StringBuilder buff = new StringBuilder(); if (physShapeInfo == null) { - buff.Append(",noPhys"); + buff.Append(" --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 04ea289..e93dbd7 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1028,6 +1028,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); + // Friction reduces vehicle motion + Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); + linearMotorCorrectionV -= (currentVelV * frictionFactorW); + // Motor is vehicle coordinates. Rotate it to world coordinates Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; @@ -1041,9 +1045,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; - // Friction reduces vehicle motion - Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep) * VehicleOrientation; - VehicleVelocity -= (VehicleVelocity * frictionFactorW); + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, -- cgit v1.1 From ac6dcd35fb77f118fc6c3d72cb029591306c7e99 Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Mon, 6 May 2013 21:19:48 -0400 Subject: Bulletsim: and the rotational friction. Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index e93dbd7..c16b7d3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1339,11 +1339,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin // angularMotorContributionV.Y = 0f; // } + // Reduce any velocity by friction. + Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); + angularMotorContributionV -= (currentAngularV * frictionFactorW); + VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; - // Reduce any velocity by friction. - Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep) * VehicleOrientation; - VehicleRotationalVelocity -= (VehicleRotationalVelocity * frictionFactorW); + VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV); } -- cgit v1.1 From e92c05ebbdc44084326c3dcfa0a2ca0958e4b5e6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 7 May 2013 18:01:48 -0700 Subject: Added AvatarPickerSearch capability handler. --- .../AvatarPickerSearchHandler.cs | 116 +++++++++++++++++ OpenSim/Capabilities/LLSDAvatarPicker.cs | 51 ++++++++ OpenSim/Framework/IPeople.cs | 47 +++++++ .../Linden/Caps/AvatarPickerSearchModule.cs | 140 +++++++++++++++++++++ .../UserManagement/HGUserManagementModule.cs | 2 +- .../UserManagement/UserManagementModule.cs | 72 ++++++----- bin/OpenSim.ini.example | 4 +- bin/OpenSimDefaults.ini | 4 + 8 files changed, 400 insertions(+), 36 deletions(-) create mode 100644 OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs create mode 100644 OpenSim/Capabilities/LLSDAvatarPicker.cs create mode 100644 OpenSim/Framework/IPeople.cs create mode 100644 OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs new file mode 100644 index 0000000..4dca592 --- /dev/null +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -0,0 +1,116 @@ +/* + * 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.Collections.Specialized; +using System.IO; +using System.Reflection; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers; +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 AvatarPickerSearchHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IPeople m_PeopleService; + + public AvatarPickerSearchHandler(string path, IPeople peopleService, string name, string description) + : base("GET", path, name, description) + { + m_PeopleService = peopleService; + } + + public override byte[] Handle(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 names = query.GetOne("names"); + string psize = query.GetOne("page_size"); + string pnumber = query.GetOne("page"); + + if (m_PeopleService == null) + return FailureResponse(names, (int)System.Net.HttpStatusCode.InternalServerError, httpResponse); + + if (string.IsNullOrEmpty(names) || names.Length < 3) + return FailureResponse(names, (int)System.Net.HttpStatusCode.BadRequest, httpResponse); + + m_log.DebugFormat("[AVATAR PICKER SEARCH]: search for {0}", names); + + 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 = ??; + httpResponse.ContentType = "application/llsd+xml"; + + List users = m_PeopleService.GetUserData(names, page_size, page_number); + + LLSDAvatarPicker osdReply = new LLSDAvatarPicker(); + osdReply.next_page_url = httpRequest.RawUrl; + foreach (UserData u in users) + osdReply.agents.Array.Add(ConvertUserData(u)); + + string reply = LLSDHelpers.SerialiseLLSDReply(osdReply); + return System.Text.Encoding.UTF8.GetBytes(reply); + } + + private LLSDPerson ConvertUserData(UserData user) + { + LLSDPerson p = new LLSDPerson(); + p.legacy_first_name = user.FirstName; + p.legacy_last_name = user.LastName; + p.display_name = user.FirstName + " " + user.LastName; + if (user.LastName.StartsWith("@")) + p.username = user.FirstName.ToLower() + user.LastName.ToLower(); + else + p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower(); + p.id = user.Id; + p.is_display_name_default = false; + return p; + } + + private byte[] FailureResponse(string names, int statuscode, IOSHttpResponse httpResponse) + { + m_log.Error("[AVATAR PICKER SEARCH]: Error searching for " + names); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return System.Text.Encoding.UTF8.GetBytes(string.Empty); + } + } +} \ No newline at end of file diff --git a/OpenSim/Capabilities/LLSDAvatarPicker.cs b/OpenSim/Capabilities/LLSDAvatarPicker.cs new file mode 100644 index 0000000..d0b3f3a --- /dev/null +++ b/OpenSim/Capabilities/LLSDAvatarPicker.cs @@ -0,0 +1,51 @@ +/* + * 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 OpenMetaverse; + +namespace OpenSim.Framework.Capabilities +{ + [OSDMap] + public class LLSDAvatarPicker + { + public string next_page_url; + // an array of LLSDPerson + public OSDArray agents = new OSDArray(); + } + + [OSDMap] + public class LLSDPerson + { + public string username; + public string display_name; + //'display_name_next_update':d"1970-01-01T00:00:00Z" + public string legacy_first_name; + public string legacy_last_name; + public UUID id; + public bool is_display_name_default; + } +} \ No newline at end of file diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs new file mode 100644 index 0000000..b88e103 --- /dev/null +++ b/OpenSim/Framework/IPeople.cs @@ -0,0 +1,47 @@ +/* + * 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 OpenMetaverse; + +namespace OpenSim.Framework +{ + public class UserData + { + public UUID Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string HomeURL { get; set; } + public Dictionary ServerURLs { get; set; } + } + + public interface IPeople + { + List GetUserData(string query, int page_size, int page_number); + } +} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs new file mode 100644 index 0000000..d7af1f2 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs @@ -0,0 +1,140 @@ +/* + * 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 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 = "AvatarPickerSearchModule")] + public class AvatarPickerSearchModule : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + private IPeople m_People; + private bool m_Enabled = false; + + private string m_URL; + + #region ISharedRegionModule Members + + public void Initialise(IConfigSource source) + { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config == null) + return; + + m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); + m_log.DebugFormat("[XXX]: Cap_AvatarPickerSearch = {0}", m_URL); + // Cap doesn't exist + if (m_URL != string.Empty) + m_Enabled = true; + } + + public void AddRegion(Scene s) + { + if (!m_Enabled) + return; + + m_scene = s; + } + + public void RemoveRegion(Scene s) + { + if (!m_Enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= RegisterCaps; + m_scene = null; + } + + public void RegionLoaded(Scene s) + { + if (!m_Enabled) + return; + + m_People = m_scene.RequestModuleInterface(); + m_scene.EventManager.OnRegisterCaps += RegisterCaps; + } + + public void PostInitialise() + { + } + + public void Close() { } + + public string Name { get { return "AvatarPickerSearchModule"; } } + + public Type ReplaceableInterface + { + get { return null; } + } + + #endregion + + public void RegisterCaps(UUID agentID, Caps caps) + { + UUID capID = UUID.Random(); + + if (m_URL == "localhost") + { + m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); + caps.RegisterHandler( + "AvatarPickerSearch", + new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); + } + else + { + // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); + caps.RegisterHandler("AvatarPickerSearch", m_URL); + } + } + + } +} diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index 8ce20e9..fac93e6 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs @@ -70,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #endregion ISharedRegionModule - protected override void AddAdditionalUsers(UUID avatarID, string query, List users) + protected override void AddAdditionalUsers(string query, List users) { if (query.Contains("@")) // First.Last@foo.com, maybe? { diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 7b823ba..6847e57 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -46,17 +46,8 @@ using Mono.Addins; namespace OpenSim.Region.CoreModules.Framework.UserManagement { - public class UserData - { - public UUID Id { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public string HomeURL { get; set; } - public Dictionary ServerURLs { get; set; } - } - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] - public class UserManagementModule : ISharedRegionModule, IUserManagement + public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -101,6 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_Scenes.Add(scene); scene.RegisterModuleInterface(this); + scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); } @@ -181,29 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); - // searhc the user accounts service - List accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); - - List users = new List(); - if (accs != null) - { - foreach (UserAccount acc in accs) - { - UserData ud = new UserData(); - ud.FirstName = acc.FirstName; - ud.LastName = acc.LastName; - ud.Id = acc.PrincipalID; - users.Add(ud); - } - } - - // search the local cache - foreach (UserData data in m_UserCache.Values) - if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && - (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) - users.Add(data); - - AddAdditionalUsers(avatarID, query, users); + List users = GetUserData(query, 500, 1); AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); // TODO: don't create new blocks if recycling an old packet @@ -249,12 +219,46 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement client.SendAvatarPickerReply(agent_data, data_args); } - protected virtual void AddAdditionalUsers(UUID avatarID, string query, List users) + protected virtual void AddAdditionalUsers(string query, List users) { } #endregion Event Handlers + #region IPeople + + public List GetUserData(string query, int page_size, int page_number) + { + // search the user accounts service + List accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); + + List users = new List(); + if (accs != null) + { + foreach (UserAccount acc in accs) + { + UserData ud = new UserData(); + ud.FirstName = acc.FirstName; + ud.LastName = acc.LastName; + ud.Id = acc.PrincipalID; + users.Add(ud); + } + } + + // search the local cache + foreach (UserData data in m_UserCache.Values) + if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && + (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) + users.Add(data); + + AddAdditionalUsers(query, users); + + return users; + + } + + #endregion IPeople + private void CacheCreators(SceneObjectGroup sog) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index ce2e600..5e486d4 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -507,8 +507,10 @@ ;; "" -- capability enabled and served by some other server ;; ; These are enabled by default to localhost. Change if you see fit. - Cap_GetTexture = "localhost" + Cap_GetTexture = "localhost" Cap_GetMesh = "localhost" + Cap_AvatarPickerSearch = "localhost" + ; This is disabled by default. Change if you see fit. Note that ; serving this cap from the simulators may lead to poor performace. Cap_WebFetchInventoryDescendents = "" diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 28c1db2..7666243 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -609,6 +609,10 @@ Cap_WebFetchInventoryDescendents = "" Cap_FetchInventoryDescendents2 = "localhost" Cap_FetchInventory2 = "localhost" + + ; Capability for searching for people + Cap_AvatarPickerSearch = "localhost" + [Chat] -- cgit v1.1 From 601aa9116348a88e8fe4d33f7dd7408ddc6fee28 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 7 May 2013 19:16:42 -0700 Subject: Delete "" entry for AvatarPicker cap. --- bin/OpenSimDefaults.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 7666243..0e35c63 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -545,7 +545,6 @@ ;; in OpenSim.ini ;; Cap_AttachmentResources = "" - Cap_AvatarPickerSearch = "" Cap_ChatSessionRequest = "" Cap_CopyInventoryFromNotecard = "localhost" Cap_DispatchRegionInfo = "" -- cgit v1.1 From 33aaa40bee37ca4d8a3afa10fbbea7c1be3a1d58 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 8 May 2013 13:13:51 -0700 Subject: Adds an event and a method so that handling of the CachedTexture packet can be pulled out of LLClientView and moved to AvatarFactory. The first pass at reusing textures (turned off by default) is included. When reusing textures, if the baked textures from a previous login are still in the asset service (which generally means that they are in the simulator's cache) then the avatar will not need to rebake. This is both a performance improvement (specifically that an avatars baked textures do not need to be sent to other users who have the old textures cached) and a resource improvement (don't have to deal with duplicate bakes in the asset service cache). --- OpenSim/Framework/CachedTextureEventArg.cs | 46 +++++++++++++++++ OpenSim/Framework/IClientAPI.cs | 5 ++ .../Region/ClientStack/Linden/UDP/LLClientView.cs | 58 +++++++++++++++------ .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 59 ++++++++++++++++++++++ .../Server/IRCClientView.cs | 6 +++ .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 6 +++ OpenSim/Tests/Common/Mock/TestClient.cs | 6 +++ bin/OpenSimDefaults.ini | 3 ++ 8 files changed, 174 insertions(+), 15 deletions(-) create mode 100644 OpenSim/Framework/CachedTextureEventArg.cs diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs new file mode 100644 index 0000000..239fc56 --- /dev/null +++ b/OpenSim/Framework/CachedTextureEventArg.cs @@ -0,0 +1,46 @@ +/* + * 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.Text; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public class CachedTextureRequestArg + { + public int BakedTextureIndex; + public UUID WearableHashID; + } + + public class CachedTextureResponseArg + { + public int BakedTextureIndex; + public UUID BakedTextureID; + public String HostName; + } +} diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 4d5ec3a..cfb36fe 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -64,6 +64,8 @@ namespace OpenSim.Framework public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); + public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List cachedTextureRequest); + public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams); public delegate void StartAnim(IClientAPI remoteClient, UUID animID); @@ -780,6 +782,7 @@ namespace OpenSim.Framework event EstateChangeInfo OnEstateChangeInfo; event EstateManageTelehub OnEstateManageTelehub; // [Obsolete("LLClientView Specific.")] + event CachedTextureRequest OnCachedTextureRequest; event SetAppearance OnSetAppearance; // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] event AvatarNowWearing OnAvatarNowWearing; @@ -1087,6 +1090,8 @@ namespace OpenSim.Framework /// void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); + void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures); + void SendStartPingCheck(byte seq); /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index bede379..47dd842 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event ModifyTerrain OnModifyTerrain; public event Action OnRegionHandShakeReply; public event GenericCall1 OnRequestWearables; + public event CachedTextureRequest OnCachedTextureRequest; public event SetAppearance OnSetAppearance; public event AvatarNowWearing OnAvatarNowWearing; public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; @@ -321,7 +322,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP private readonly byte[] m_channelVersion = Utils.EmptyBytes; private readonly IGroupsModule m_GroupsModule; - private int m_cachedTextureSerial; private PriorityQueue m_entityUpdates; private PriorityQueue m_entityProps; private Prioritizer m_prioritizer; @@ -11462,8 +11462,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP } /// - /// Send a response back to a client when it asks the asset server (via the region server) if it has - /// its appearance texture cached. /// /// /// At the moment, we always reply that there is no cached texture. @@ -11473,33 +11471,63 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) { - //m_log.Debug("texture cached: " + packet.ToString()); AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; - AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); if (cachedtex.AgentData.SessionID != SessionId) return false; + List requestArgs = new List(); + + for (int i = 0; i < cachedtex.WearableData.Length; i++) + { + CachedTextureRequestArg arg = new CachedTextureRequestArg(); + arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; + arg.WearableHashID = cachedtex.WearableData[i].ID; + + requestArgs.Add(arg); + } + + CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; + if (handlerCachedTextureRequest != null) + { + handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); + } + + return true; + } + + /// + /// Send a response back to a client when it asks the asset server (via the region server) if it has + /// its appearance texture cached. + /// + /// + /// + /// + /// + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + ScenePresence presence = avatar as ScenePresence; + if (presence == null) + return; + + AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); + // TODO: don't create new blocks if recycling an old packet - cachedresp.AgentData.AgentID = AgentId; + cachedresp.AgentData.AgentID = m_agentId; cachedresp.AgentData.SessionID = m_sessionId; - cachedresp.AgentData.SerialNum = m_cachedTextureSerial; - m_cachedTextureSerial++; - cachedresp.WearableData = - new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length]; + cachedresp.AgentData.SerialNum = serial; + cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; - for (int i = 0; i < cachedtex.WearableData.Length; i++) + for (int i = 0; i < cachedTextures.Count; i++) { cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); - cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex; - cachedresp.WearableData[i].TextureID = UUID.Zero; + cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; + cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; cachedresp.WearableData[i].HostName = new byte[0]; } cachedresp.Header.Zerocoded = true; OutPacket(cachedresp, ThrottleOutPacketType.Task); - - return true; } protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index c7ac7c4..b640b48 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -55,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory private int m_savetime = 5; // seconds to wait before saving changed appearance private int m_sendtime = 2; // seconds to wait before sending changed appearance + private bool m_reusetextures = false; private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); @@ -73,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); + m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures); + // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); } @@ -131,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory client.OnRequestWearables += Client_OnRequestWearables; client.OnSetAppearance += Client_OnSetAppearance; client.OnAvatarNowWearing += Client_OnAvatarNowWearing; + client.OnCachedTextureRequest += Client_OnCachedTextureRequest; } #endregion @@ -671,6 +675,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory QueueAppearanceSave(client.AgentId); } } + + /// + /// Respond to the cached textures request from the client + /// + /// + /// + /// + private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List cachedTextureRequest) + { + // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); + ScenePresence sp = m_scene.GetScenePresence(client.AgentId); + + List cachedTextureResponse = new List(); + foreach (CachedTextureRequestArg request in cachedTextureRequest) + { + UUID texture = UUID.Zero; + int index = request.BakedTextureIndex; + + if (m_reusetextures) + { + // this is the most insanely dumb way to do this... however it seems to + // actually work. if the appearance has been reset because wearables have + // changed then the texture entries are zero'd out until the bakes are + // uploaded. on login, if the textures exist in the cache (eg if you logged + // into the simulator recently, then the appearance will pull those and send + // them back in the packet and you won't have to rebake. if the textures aren't + // in the cache then the intial makeroot() call in scenepresence will zero + // them out. + // + // a better solution (though how much better is an open question) is to + // store the hashes in the appearance and compare them. Thats's coming. + + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; + if (face != null) + texture = face.TextureID; + + // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); + } + + CachedTextureResponseArg response = new CachedTextureResponseArg(); + response.BakedTextureIndex = index; + response.BakedTextureID = texture; + response.HostName = null; + + cachedTextureResponse.Add(response); + } + + // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial); + // The serial number appears to be used to match requests and responses + // in the texture transaction. We just send back the serial number + // that was provided in the request. The viewer bumps this for us. + client.SendCachedTextureResponse(sp, serial, cachedTextureResponse); + } + + #endregion public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 915ebd8..3644856 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -660,6 +660,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public event BakeTerrain OnBakeTerrain; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event SetAppearance OnSetAppearance; public event AvatarNowWearing OnAvatarNowWearing; public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; @@ -938,7 +939,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server { } + + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + } + public void SendStartPingCheck(byte seq) { diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 0ee00e9..8aae300 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -391,6 +391,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; @@ -569,6 +570,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + public virtual void Kick(string message) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 41402a4..664ecb6 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -196,6 +196,7 @@ namespace OpenSim.Tests.Common.Mock public event EstateCovenantRequest OnEstateCovenantRequest; public event EstateChangeInfo OnEstateChangeInfo; public event EstateManageTelehub OnEstateManageTelehub; + public event CachedTextureRequest OnCachedTextureRequest; public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; @@ -509,6 +510,11 @@ namespace OpenSim.Tests.Common.Mock { } + public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures) + { + + } + public virtual void Kick(string message) { } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 0e35c63..81843b1 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -683,6 +683,9 @@ ; in other situations (e.g. appearance baking failures where the avatar only appears as a cloud to others). ResendAppearanceUpdates = true + ; Turning this on responds to CachedTexture packets to possibly avoid rebaking the avatar + ; on every login + ReuseTextures = false [Attachments] ; Controls whether avatar attachments are enabled. -- cgit v1.1 From 543d1fe70b54fb26d7ce19b397468c66269f0e20 Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 8 May 2013 21:14:52 +0100 Subject: Guard the scene list when estates are updated --- .../Region/CoreModules/World/Estate/XEstateConnector.cs | 17 ++++++++++------- .../Region/CoreModules/World/Estate/XEstateModule.cs | 6 ++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs index 948c893..73e706c 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -136,15 +136,18 @@ namespace OpenSim.Region.CoreModules.World.Estate // Handle local regions locally // - foreach (Scene s in m_EstateModule.Scenes) + lock (m_EstateModule.Scenes) { - if (regions.Contains(s.RegionInfo.RegionID)) + foreach (Scene s in m_EstateModule.Scenes) { - // All regions in one estate are in the same scope. - // Use that scope. - // - ScopeID = s.RegionInfo.ScopeID; - regions.Remove(s.RegionInfo.RegionID); + if (regions.Contains(s.RegionInfo.RegionID)) + { + // All regions in one estate are in the same scope. + // Use that scope. + // + ScopeID = s.RegionInfo.ScopeID; + regions.Remove(s.RegionInfo.RegionID); + } } } diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs index 1f099c6..f54ab2c 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs @@ -93,7 +93,8 @@ namespace OpenSim.Region.CoreModules.World.Estate public void AddRegion(Scene scene) { - m_Scenes.Add(scene); + lock (m_Scenes) + m_Scenes.Add(scene); scene.EventManager.OnNewClient += OnNewClient; } @@ -111,7 +112,8 @@ namespace OpenSim.Region.CoreModules.World.Estate { scene.EventManager.OnNewClient -= OnNewClient; - m_Scenes.Remove(scene); + lock (m_Scenes) + m_Scenes.Remove(scene); } public string Name -- cgit v1.1 From 182ea00cb30042d8ff7f6184f480d7c39e2be8a1 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 9 May 2013 10:46:37 -0400 Subject: Application support: Adding some viwer supported url settings for destination guide and avatar picker apps. URL for the destinations should be: "secondlife:///app/teleport/slurl" --- OpenSim/Services/LLLoginService/LLLoginResponse.cs | 20 +++++++++++++++++++- OpenSim/Services/LLLoginService/LLLoginService.cs | 7 ++++++- bin/Robust.HG.ini.example | 6 ++++++ bin/Robust.ini.example | 6 ++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 9ec744f..400f303 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -227,7 +227,7 @@ namespace OpenSim.Services.LLLoginService GridRegion destination, List invSkel, FriendInfo[] friendsList, ILibraryService libService, string where, string startlocation, Vector3 position, Vector3 lookAt, List gestures, string message, GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency, - string DSTZone) + string DSTZone, string destinationsURL, string avatarsURL) : this() { FillOutInventoryData(invSkel, libService); @@ -246,6 +246,8 @@ namespace OpenSim.Services.LLLoginService MapTileURL = mapTileURL; ProfileURL = profileURL; OpenIDURL = openIDURL; + DestinationsURL = destinationsURL; + AvatarsURL = avatarsURL; SearchURL = searchURL; Currency = currency; @@ -533,6 +535,12 @@ namespace OpenSim.Services.LLLoginService if (profileURL != String.Empty) responseData["profile-server-url"] = profileURL; + if (DestinationsURL != String.Empty) + responseData["destination_guide_url"] = DestinationsURL; + + if (AvatarsURL != String.Empty) + responseData["avatar_picker_url"] = AvatarsURL; + // We need to send an openid_token back in the response too if (openIDURL != String.Empty) responseData["openid_url"] = openIDURL; @@ -1056,6 +1064,16 @@ namespace OpenSim.Services.LLLoginService set { currency = value; } } + public string DestinationsURL + { + get; set; + } + + public string AvatarsURL + { + get; set; + } + #endregion public class UserInfo diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 53a22d4..abda98f 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -78,6 +78,8 @@ namespace OpenSim.Services.LLLoginService protected string m_OpenIDURL; protected string m_SearchURL; protected string m_Currency; + protected string m_DestinationGuide; + protected string m_AvatarPicker; protected string m_AllowedClients; protected string m_DeniedClients; @@ -117,6 +119,8 @@ namespace OpenSim.Services.LLLoginService m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty); m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty); m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty); + m_DestinationGuide = m_LoginServerConfig.GetString ("DestinationGuide", string.Empty); + m_AvatarPicker = m_LoginServerConfig.GetString ("AvatarPicker", string.Empty); m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty); m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty); @@ -453,7 +457,8 @@ namespace OpenSim.Services.LLLoginService = new LLLoginResponse( account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, - m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone); + m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone, + m_DestinationGuide, m_AvatarPicker); m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index fee2a87..bc2b4cf 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -325,6 +325,12 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ; For V2/V3 webapp authentication SSO ; OpenIDServerURL = "http://127.0.0.1/openid/openidserver/" + ; For V3 destination guide + ; DestinationGuide = "http://127.0.0.1/guide" + + ; For V3 avatar picker (( work in progress )) + ; AvatarPicker = "http://127.0.0.1/avatars" + ; If you run this login server behind a proxy, set this to true ; HasProxy = false diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 2d5aa8c..1d66b7f 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -288,6 +288,12 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; For V2/V3 webapp authentication SSO ; OpenIDServerURL = "http://127.0.0.1/openid/openidserver/" + ; For V3 destination guide + ; DestinationGuide = "http://127.0.0.1/guide" + + ; For V3 avatar picker (( work in progress )) + ; AvatarPicker = "http://127.0.0.1/avatars" + ; If you run this login server behind a proxy, set this to true ; HasProxy = false -- cgit v1.1 From 641c636790f3e4421e089a44e6b00fed338726eb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 16:43:16 +0100 Subject: minor: Simplify test setup in SceneObjectDeRezTests since permissions module doesn't need different configuration anymore --- .../Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 52ad538..bde15cd 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -59,15 +59,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestDeRezSceneObject() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); TestScene scene = new SceneHelpers().SetupScene(); - IConfigSource configSource = new IniConfigSource(); - IConfig config = configSource.AddConfig("Startup"); - config.Set("serverside_object_permissions", true); - SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); + SceneHelpers.SetupSceneModules(scene, new object[] { new PermissionsModule() }); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. @@ -97,8 +93,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests /// /// Test deleting an object from a scene where the deleter is not the owner /// - /// + /// /// This test assumes that the deleter is not a god. + /// [Test] public void TestDeRezSceneObjectNotOwner() { @@ -109,10 +106,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); TestScene scene = new SceneHelpers().SetupScene(); - IConfigSource configSource = new IniConfigSource(); - IConfig config = configSource.AddConfig("Startup"); - config.Set("serverside_object_permissions", true); - SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); + SceneHelpers.SetupSceneModules(scene, new object[] { new PermissionsModule() }); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. -- cgit v1.1 From 2cb2f1d7e30fa583a9f43ddd6b420deb8e9b56bd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 18:02:19 +0100 Subject: Fix issue where objects removed via llDie() would not disappear for users looking in from neighbouring sims. This was because this particular code path (unlike user delete) only sent kills to root presences, for no apparent good reason. Added regression test for this case. This fixes http://opensimulator.org/mantis/view.php?id=6627 --- .../Attachments/Tests/AttachmentsModuleTests.cs | 4 +- .../Region/Framework/Scenes/SceneObjectGroup.cs | 14 ++-- .../Scenes/Tests/SceneObjectDeRezTests.cs | 78 +++++++++++++++++++++- .../Scenes/Tests/ScenePresenceCrossingTests.cs | 4 +- .../Scenes/Tests/ScenePresenceTeleportTests.cs | 14 ++-- .../Tests/Common/Helpers/EntityTransferHelpers.cs | 2 +- OpenSim/Tests/Common/Helpers/SceneHelpers.cs | 54 +-------------- OpenSim/Tests/Common/Mock/TestClient.cs | 20 ++---- 8 files changed, 102 insertions(+), 88 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 25444e5..508743c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -833,11 +833,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); - TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); + TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); - ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); + ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 9e7a986..3b2f537 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1221,11 +1221,11 @@ namespace OpenSim.Region.Framework.Scenes /// /// Delete this group from its scene. /// - /// + /// /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood /// up and all avatars receive notification of its removal. Removal of the scene object from database backup /// must be handled by the caller. - /// + /// /// If true then deletion is not broadcast to clients public void DeleteGroupFromScene(bool silent) { @@ -1234,10 +1234,10 @@ namespace OpenSim.Region.Framework.Scenes { SceneObjectPart part = parts[i]; - Scene.ForEachRootScenePresence(delegate(ScenePresence avatar) + Scene.ForEachScenePresence(sp => { - if (avatar.ParentID == LocalId) - avatar.StandUp(); + if (!sp.IsChildAgent && sp.ParentID == LocalId) + sp.StandUp(); if (!silent) { @@ -1245,9 +1245,9 @@ namespace OpenSim.Region.Framework.Scenes if (part == m_rootPart) { if (!IsAttachment - || AttachedAvatar == avatar.ControllingClient.AgentId + || AttachedAvatar == sp.UUID || !HasPrivateAttachmentPoint) - avatar.ControllingClient.SendKillObject(m_regionHandle, new List { part.LocalId }); + sp.ControllingClient.SendKillObject(m_regionHandle, new List { part.LocalId }); } } }); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index bde15cd..f738ff1 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -33,7 +33,9 @@ using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Region.CoreModules.World.Permissions; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; @@ -52,6 +54,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests [TestFixture] public class SceneObjectDeRezTests : OpenSimTestCase { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + // This facility was added after the original async delete tests were written, so it may be possible now + // to not bother explicitly disabling their async (since everything will be running sync). + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + /// /// Test deleting an object from a scene. /// @@ -63,7 +83,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); TestScene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, new object[] { new PermissionsModule() }); + SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. @@ -87,7 +107,59 @@ namespace OpenSim.Region.Framework.Scenes.Tests sogd.InventoryDeQueueAndDelete(); SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); - Assert.That(retrievedPart2, Is.Null); + Assert.That(retrievedPart2, Is.Null); + } + + /// + /// Test that child and root agents correctly receive KillObject notifications. + /// + [Test] + public void TestDeRezSceneObjectToAgents() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + // We need this so that the creation of the root client for userB in sceneB can trigger the creation of a child client in sceneA + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + EntityTransferModule etmB = new EntityTransferModule(); + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmB.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + + // We need this for derez + SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule()); + + UserAccount uaA = UserAccountHelpers.CreateUserWithInventory(sceneA, "Andy", "AAA", 0x1, ""); + UserAccount uaB = UserAccountHelpers.CreateUserWithInventory(sceneA, "Brian", "BBB", 0x2, ""); + + TestClient clientA = (TestClient)SceneHelpers.AddScenePresence(sceneA, uaA).ControllingClient; + + // This is the more long-winded route we have to take to get a child client created for userB in sceneA + // rather than just calling AddScenePresence() as for userA + AgentCircuitData acd = SceneHelpers.GenerateAgentData(uaB); + TestClient clientB = new TestClient(acd, sceneB); + List childClientsB = new List(); + EntityTransferHelpers.SetUpInformClientOfNeighbour(clientB, childClientsB); + + SceneHelpers.AddScenePresence(sceneB, clientB, acd); + + SceneObjectGroup so = SceneHelpers.AddSceneObject(sceneA); + uint soLocalId = so.LocalId; + + sceneA.DeleteSceneObject(so, false); + + Assert.That(clientA.ReceivedKills.Count, Is.EqualTo(1)); + Assert.That(clientA.ReceivedKills[0], Is.EqualTo(soLocalId)); + + Assert.That(childClientsB[0].ReceivedKills.Count, Is.EqualTo(1)); + Assert.That(childClientsB[0].ReceivedKills[0], Is.EqualTo(soLocalId)); } /// @@ -106,7 +178,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); TestScene scene = new SceneHelpers().SetupScene(); - SceneHelpers.SetupSceneModules(scene, new object[] { new PermissionsModule() }); + SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 8775949..5a72239 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -95,11 +95,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); - TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); + TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); - ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); originalSp.AbsolutePosition = new Vector3(128, 32, 10); // originalSp.Flying = true; diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index de4458d..297c66b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); - ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = new Vector3(30, 31, 32); List destinationTestClients = new List(); @@ -224,7 +224,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); - ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = preTeleportPosition; // Make sceneB return false on query access @@ -300,7 +300,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); - ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = preTeleportPosition; // Make sceneB refuse CreateAgent @@ -389,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); - ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); sp.AbsolutePosition = preTeleportPosition; sceneA.RequestTeleportLocation( @@ -428,7 +428,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestSameSimulatorNeighbouringRegions() { TestHelpers.InMethod(); - TestHelpers.EnableLogging(); +// TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); @@ -458,11 +458,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 teleportLookAt = new Vector3(20, 21, 22); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); - TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); + TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); - ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); + ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); Assert.That(beforeSceneASp, Is.Not.Null); diff --git a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs index 6cc7ff2..1b960b1 100644 --- a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs @@ -82,7 +82,7 @@ namespace OpenSim.Tests.Common Scene neighbourScene; SceneManager.Instance.TryGetScene(x, y, out neighbourScene); - TestClient neighbourTc = new TestClient(newAgent, neighbourScene, SceneManager.Instance); + TestClient neighbourTc = new TestClient(newAgent, neighbourScene); neighbourTcs.Add(neighbourTc); neighbourScene.AddNewClient(neighbourTc, PresenceType.User); }; diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index bdd9093..d9bb85e 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -447,9 +447,6 @@ namespace OpenSim.Tests.Common /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test /// /// - /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions - /// and teleport doesn't take place. - /// /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. /// @@ -462,22 +459,6 @@ namespace OpenSim.Tests.Common } /// - /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test - /// - /// - /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will - /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. - /// - /// - /// - /// - /// - public static ScenePresence AddScenePresence(Scene scene, UUID agentId, SceneManager sceneManager) - { - return AddScenePresence(scene, GenerateAgentData(agentId), sceneManager); - } - - /// /// Add a root agent. /// /// @@ -508,31 +489,7 @@ namespace OpenSim.Tests.Common /// public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) { - return AddScenePresence(scene, agentData, null); - } - - /// - /// Add a root agent. - /// - /// - /// This function - /// - /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the - /// userserver if grid) would give initial login data back to the client and separately tell the scene that the - /// agent was coming. - /// - /// 2) Connects the agent with the scene - /// - /// This function performs actions equivalent with notifying the scene that an agent is - /// coming and then actually connecting the agent to the scene. The one step missed out is the very first - /// - /// - /// - /// - /// - public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) - { - return AddScenePresence(scene, new TestClient(agentData, scene, sceneManager), agentData, sceneManager); + return AddScenePresence(scene, new TestClient(agentData, scene), agentData); } /// @@ -552,10 +509,9 @@ namespace OpenSim.Tests.Common /// /// /// - /// /// public static ScenePresence AddScenePresence( - Scene scene, IClientAPI client, AgentCircuitData agentData, SceneManager sceneManager) + Scene scene, IClientAPI client, AgentCircuitData agentData) { // We emulate the proper login sequence here by doing things in four stages @@ -578,10 +534,6 @@ namespace OpenSim.Tests.Common /// Introduce an agent into the scene by adding a new client. /// /// The scene presence added - /// - /// Scene manager. Can be null if there is only one region in the test or multiple regions that are not - /// neighbours and where no teleporting takes place. - /// /// /// /// @@ -607,7 +559,7 @@ namespace OpenSim.Tests.Common acd.child = true; // XXX: ViaLogin may not be correct for child agents - TestClient client = new TestClient(acd, scene, null); + TestClient client = new TestClient(acd, scene); return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin); } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 664ecb6..3f9690f 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -47,9 +47,9 @@ namespace OpenSim.Tests.Common.Mock EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); private Scene m_scene; - private SceneManager m_sceneManager; // Properties so that we can get at received data for test purposes + public List ReceivedKills { get; private set; } public List ReceivedOfflineNotifications { get; private set; } public List ReceivedOnlineNotifications { get; private set; } public List ReceivedFriendshipTerminations { get; private set; } @@ -434,33 +434,21 @@ namespace OpenSim.Tests.Common.Mock /// /// Constructor /// - /// - /// Can be used for a test where there is only one region or where there are multiple regions that are not - /// neighbours and where no teleporting takes place. In other situations, the constructor that takes in a - /// scene manager should be used. - /// - /// - /// - public TestClient(AgentCircuitData agentData, Scene scene) : this(agentData, scene, null) {} - - /// - /// Constructor - /// /// /// /// - public TestClient(AgentCircuitData agentData, Scene scene, SceneManager sceneManager) + public TestClient(AgentCircuitData agentData, Scene scene) { m_agentId = agentData.AgentID; m_firstName = agentData.firstname; m_lastName = agentData.lastname; m_circuitCode = agentData.circuitcode; m_scene = scene; - m_sceneManager = sceneManager; SessionId = agentData.SessionID; SecureSessionId = agentData.SecureSessionID; CapsSeedUrl = agentData.CapsPath; + ReceivedKills = new List(); ReceivedOfflineNotifications = new List(); ReceivedOnlineNotifications = new List(); ReceivedFriendshipTerminations = new List(); @@ -534,11 +522,13 @@ namespace OpenSim.Tests.Common.Mock public virtual void SendKillObject(ulong regionHandle, List localID) { + ReceivedKills.AddRange(localID); } public virtual void SetChildAgentThrottle(byte[] throttle) { } + public byte[] GetThrottlesPacked(float multiplier) { return new byte[0]; -- cgit v1.1 From 3290cd09d3ecd45c52bd131ada2a793c48fd99dc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 18:12:17 +0100 Subject: remove pointless region handle paramter from IClientAPI.SendKillObject() --- OpenSim/Framework/IClientAPI.cs | 3 +-- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 5 ++--- OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 5 +++-- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 2 +- .../Agent/InternetRelayClientView/Server/IRCClientView.cs | 2 +- OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | 2 +- OpenSim/Tests/Common/Mock/TestClient.cs | 4 +--- 8 files changed, 11 insertions(+), 14 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index cfb36fe..59ce2c4 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1097,9 +1097,8 @@ namespace OpenSim.Framework /// /// Tell the client that an object has been deleted /// - /// /// - void SendKillObject(ulong regionHandle, List localID); + void SendKillObject(List localID); void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 47dd842..e014471 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -1588,7 +1588,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pc, ThrottleOutPacketType.Unknown); } - public void SendKillObject(ulong regionHandle, List localIDs) + public void SendKillObject(List localIDs) { // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); @@ -11555,8 +11555,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (part == null) { // It's a ghost! tell the client to delete it from view. - simClient.SendKillObject(Scene.RegionInfo.RegionHandle, - new List { localId }); + simClient.SendKillObject(new List { localId }); } else { diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 7d16635..f69ec21 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -776,7 +776,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.ForEachClient( client => { if (client.AgentId != so.AttachedAvatar) - client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List() { so.LocalId }); + client.SendKillObject(new List() { so.LocalId }); }); } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2aba2dd..8cdde3f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3480,7 +3480,7 @@ namespace OpenSim.Region.Framework.Scenes delegate(IClientAPI client) { //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway - try { client.SendKillObject(avatar.RegionHandle, new List { avatar.LocalId }); } + try { client.SendKillObject(new List { avatar.LocalId }); } catch (NullReferenceException) { } }); } @@ -3560,7 +3560,8 @@ namespace OpenSim.Region.Framework.Scenes } deleteIDs.Add(localID); } - ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); }); + + ForEachClient(c => c.SendKillObject(deleteIDs)); } #endregion diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 3b2f537..38fa26a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1247,7 +1247,7 @@ namespace OpenSim.Region.Framework.Scenes if (!IsAttachment || AttachedAvatar == sp.UUID || !HasPrivateAttachmentPoint) - sp.ControllingClient.SendKillObject(m_regionHandle, new List { part.LocalId }); + sp.ControllingClient.SendKillObject(new List { part.LocalId }); } } }); diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 3644856..384eb1f 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -950,7 +950,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendKillObject(ulong regionHandle, List localID) + public void SendKillObject(List localID) { } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 8aae300..553443f 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -592,7 +592,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC } - public virtual void SendKillObject(ulong regionHandle, List localID) + public virtual void SendKillObject(List localID) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 3f9690f..09e751a 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -517,10 +517,9 @@ namespace OpenSim.Tests.Common.Mock public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) { - } - public virtual void SendKillObject(ulong regionHandle, List localID) + public virtual void SendKillObject(List localID) { ReceivedKills.AddRange(localID); } @@ -534,7 +533,6 @@ namespace OpenSim.Tests.Common.Mock return new byte[0]; } - public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) { } -- cgit v1.1 From b4a6f2195d6d1a3a5f91715f7badf4cc983f7689 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 18:53:34 +0100 Subject: Only send one kill object to the deleter when they derez an object rather than two. Extend regression test to check this. --- .../Framework/Scenes/AsyncSceneObjectGroupDeleter.cs | 10 ++-------- .../Framework/Scenes/Tests/SceneObjectDeRezTests.cs | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index f555b49..11a0146 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -104,14 +104,8 @@ namespace OpenSim.Region.Framework.Scenes // better than losing the object for now. if (permissionToDelete) { - List killIDs = new List(); - foreach (SceneObjectGroup g in objectGroups) - { killIDs.Add(g.LocalId); - g.DeleteGroupFromScene(true); - } - - m_scene.SendKillObject(killIDs); + g.DeleteGroupFromScene(false); } } @@ -160,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes if (x.permissionToDelete) { foreach (SceneObjectGroup g in x.objectGroups) - m_scene.DeleteSceneObject(g, false); + m_scene.DeleteSceneObject(g, true); } } catch (Exception e) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index f738ff1..d670dad 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -84,30 +84,31 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestScene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); - IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; + TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, userId).ControllingClient; // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; sogd.Enabled = false; - - SceneObjectPart part - = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); - part.Name = "obj1"; - scene.AddNewSceneObject(new SceneObjectGroup(part), false); + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", userId); + uint soLocalId = so.LocalId; List localIds = new List(); - localIds.Add(part.LocalId); + localIds.Add(so.LocalId); scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); // Check that object isn't deleted until we crank the sogd handle. - SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); Assert.That(retrievedPart, Is.Not.Null); Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); sogd.InventoryDeQueueAndDelete(); - SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); Assert.That(retrievedPart2, Is.Null); + + Assert.That(client.ReceivedKills.Count, Is.EqualTo(1)); + Assert.That(client.ReceivedKills[0], Is.EqualTo(soLocalId)); } /// -- cgit v1.1 From 9978f36d9f4edf89168093c0cd9b15281e02dc2a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 22:43:16 +0100 Subject: Don't send BulkUpdateInventory at the end up of UpdateInventoryItemAsset(). This is causing editing of worn clothes to fail frequently, possibly due to a race condition with a transaction. This looks to address http://opensimulator.org/mantis/view.php?id=6600 --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 8ddaa60..80581dc 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -490,7 +490,10 @@ namespace OpenSim.Region.Framework.Scenes item.SaleType = itemUpd.SaleType; InventoryService.UpdateItem(item); - remoteClient.SendBulkUpdateInventory(item); + + // We cannot send out a bulk update here, since this will cause editing of clothing to start + // failing frequently. Possibly this is a race with a separate transaction that uploads the asset. +// remoteClient.SendBulkUpdateInventory(item); } if (UUID.Zero != transactionID) -- cgit v1.1 From 0e6ad9482919bb551427003d76fe924bd8b7bde7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 22:44:45 +0100 Subject: minor: Remove mono compiler warning in RemoteAdminPlugin --- OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index ad683b8..3abf40b 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -1768,7 +1768,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController m_log.Info("[RADMIN]: Received Estate Reload Request"); Hashtable responseData = (Hashtable)response.Value; - Hashtable requestData = (Hashtable)request.Params[0]; +// Hashtable requestData = (Hashtable)request.Params[0]; m_application.SceneManager.ForEachScene(s => s.RegionInfo.EstateSettings = m_application.EstateDataService.LoadEstateSettings(s.RegionInfo.RegionID, false) -- cgit v1.1 From 292a6037add00c9e8f817c733d8fc375806caf99 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 22:48:10 +0100 Subject: minor: Remove unnecessary code that was generating warning in TestXInventoryDataPlugin --- OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs index 30b1f38..2be5524 100644 --- a/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/TestXInventoryDataPlugin.cs @@ -118,8 +118,8 @@ namespace OpenSim.Tests.Common.Mock folder.parentFolderID = new UUID(newParent); - XInventoryFolder[] newParentFolders - = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() }); +// XInventoryFolder[] newParentFolders +// = GetFolders(new string[] { "folderID" }, new string[] { folder.parentFolderID.ToString() }); // Console.WriteLine( // "Moved folder {0} {1}, to {2} {3}", -- cgit v1.1 From ff0332730d54cf23c53795a9e6bac0262b6c86c3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 9 May 2013 23:11:37 +0100 Subject: Implement delete key for local console --- OpenSim/Framework/Console/LocalConsole.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index d41481f..a967db6 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs @@ -426,6 +426,21 @@ namespace OpenSim.Framework.Console System.Console.Write("{0}", prompt); break; + case ConsoleKey.Delete: + if (m_cursorXPosition == m_commandLine.Length) + break; + + m_commandLine.Remove(m_cursorXPosition, 1); + + SetCursorLeft(0); + m_cursorYPosition = SetCursorTop(m_cursorYPosition); + + if (m_echo) + System.Console.Write("{0}{1} ", prompt, m_commandLine); + else + System.Console.Write("{0}", prompt); + + break; case ConsoleKey.End: m_cursorXPosition = m_commandLine.Length; break; -- cgit v1.1 From a1031772ebc240a3cda9cb8dcf581678be4b2143 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 10 May 2013 08:09:26 -0700 Subject: Delete debug message --- OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs index d7af1f2..9f2aed0 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs @@ -71,7 +71,6 @@ namespace OpenSim.Region.ClientStack.Linden return; m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); - m_log.DebugFormat("[XXX]: Cap_AvatarPickerSearch = {0}", m_URL); // Cap doesn't exist if (m_URL != string.Empty) m_Enabled = true; -- cgit v1.1 From a42bb799cca27c0dddbecbd2edd2bd5e6d379472 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 10 May 2013 14:48:52 -0700 Subject: BulletSim: fix CPU loop that occurs when any 'degenerate' sculptie is in a region. This fixes the high CPU usage for regions with nothing else going on. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 9d47657..262d734 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -368,9 +368,10 @@ public class BSShapeMesh : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape) + if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) { // If a mesh was what was created, remember the built shape for later sharing. + // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. Meshes.Add(newMeshKey, retMesh); } @@ -481,8 +482,11 @@ public class BSShapeMesh : BSShape } else { + // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); + physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); } } newShape.shapeKey = newMeshKey; @@ -521,7 +525,7 @@ public class BSShapeHull : BSShape // Check to see if hull was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape) + if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) { // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); -- cgit v1.1 From 81d8deb1a830765ec64948db5ec3902894761f24 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 11 May 2013 01:27:37 +0100 Subject: Send up the part missing from the Avination Estate commit. Warning - contains a small migration. --- .../Data/MySQL/Resources/EstateStore.migrations | 6 ++++ .../Data/SQLite/Resources/EstateStore.migrations | 9 ++++++ OpenSim/Framework/EstateSettings.cs | 34 +++++++++++++++++++++- .../World/Estate/EstateManagementModule.cs | 12 ++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 2 -- 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/MySQL/Resources/EstateStore.migrations b/OpenSim/Data/MySQL/Resources/EstateStore.migrations index df82a2e..2d1c2b5 100644 --- a/OpenSim/Data/MySQL/Resources/EstateStore.migrations +++ b/OpenSim/Data/MySQL/Resources/EstateStore.migrations @@ -77,5 +77,11 @@ BEGIN; ALTER TABLE estate_settings AUTO_INCREMENT = 100; COMMIT; +:VERSION 33 #--------------------- +BEGIN; +ALTER TABLE estate_settings ADD COLUMN `AllowLandmark` tinyint(4) NOT NULL default '1'; +ALTER TABLE estate_settings ADD COLUMN `AllowParcelChanges` tinyint(4) NOT NULL default '1'; +ALTER TABLE estate_settings ADD COLUMN `AllowSetHome` tinyint(4) NOT NULL default '1'; +COMMIT; diff --git a/OpenSim/Data/SQLite/Resources/EstateStore.migrations b/OpenSim/Data/SQLite/Resources/EstateStore.migrations index 62f6464..0aec49b 100644 --- a/OpenSim/Data/SQLite/Resources/EstateStore.migrations +++ b/OpenSim/Data/SQLite/Resources/EstateStore.migrations @@ -86,3 +86,12 @@ begin; alter table estate_settings add column DenyMinors tinyint not null default 0; commit; + +:VERSION 9 + +begin; +alter table estate_settings add column AllowLandmark tinyint not null default '1'; +alter table estate_settings add column AllowParcelChanges tinyint not null default '1'; +alter table estate_settings add column AllowSetHome tinyint not null default '1'; +commit; + diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs index a92abbf..a02993d 100644 --- a/OpenSim/Framework/EstateSettings.cs +++ b/OpenSim/Framework/EstateSettings.cs @@ -58,6 +58,30 @@ namespace OpenSim.Framework set { m_EstateName = value; } } + private bool m_AllowLandmark = true; + + public bool AllowLandmark + { + get { return m_AllowLandmark; } + set { m_AllowLandmark = value; } + } + + private bool m_AllowParcelChanges = true; + + public bool AllowParcelChanges + { + get { return m_AllowParcelChanges; } + set { m_AllowParcelChanges = value; } + } + + private bool m_AllowSetHome = true; + + public bool AllowSetHome + { + get { return m_AllowSetHome; } + set { m_AllowSetHome = value; } + } + private uint m_ParentEstateID = 1; public uint ParentEstateID @@ -374,10 +398,18 @@ namespace OpenSim.Framework return l_EstateAccess.Contains(user); } + public void SetFromFlags(ulong regionFlags) + { + ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport); + BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell); + AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark); + AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges); + AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome); + } + public bool GroupAccess(UUID groupID) { return l_EstateGroups.Contains(groupID); } - } } diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 91f6501..121b2aa 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -1245,6 +1245,8 @@ namespace OpenSim.Region.CoreModules.World.Estate flags |= RegionFlags.NoFly; if (Scene.RegionInfo.RegionSettings.RestrictPushing) flags |= RegionFlags.RestrictPushObject; + if (Scene.RegionInfo.RegionSettings.AllowLandJoinDivide) + flags |= RegionFlags.AllowParcelChanges; if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) flags |= RegionFlags.BlockParcelSearch; @@ -1254,6 +1256,10 @@ namespace OpenSim.Region.CoreModules.World.Estate flags |= RegionFlags.Sandbox; if (Scene.RegionInfo.EstateSettings.AllowVoice) flags |= RegionFlags.AllowVoice; + if (Scene.RegionInfo.EstateSettings.AllowLandmark) + flags |= RegionFlags.AllowLandmark; + if (Scene.RegionInfo.EstateSettings.AllowSetHome) + flags |= RegionFlags.AllowSetHome; if (Scene.RegionInfo.EstateSettings.BlockDwell) flags |= RegionFlags.BlockDwell; if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport) @@ -1299,6 +1305,12 @@ namespace OpenSim.Region.CoreModules.World.Estate flags |= RegionFlags.ResetHomeOnTeleport; if (Scene.RegionInfo.EstateSettings.TaxFree) flags |= RegionFlags.TaxFree; + if (Scene.RegionInfo.EstateSettings.AllowLandmark) + flags |= RegionFlags.AllowLandmark; + if (Scene.RegionInfo.EstateSettings.AllowParcelChanges) + flags |= RegionFlags.AllowParcelChanges; + if (Scene.RegionInfo.EstateSettings.AllowSetHome) + flags |= RegionFlags.AllowSetHome; if (Scene.RegionInfo.EstateSettings.DenyMinors) flags |= (RegionFlags)(1 << 30); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2aba2dd..1fa2fc7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4188,8 +4188,6 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); - // XPTO: if this agent is not allowed here as root, always return false - // TODO: This check should probably be in QueryAccess(). ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); if (nearestParcel == null) -- cgit v1.1 From 48f8b884c33ba5f5b7991d1047f4f2f988eb7415 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 11 May 2013 07:15:09 -0700 Subject: Handle SetHome properly --- .../CoreModules/World/Land/LandManagementModule.cs | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 693de1d..c295f3a 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -74,6 +74,8 @@ namespace OpenSim.Region.CoreModules.World.Land protected IUserManagement m_userManager; protected IPrimCountModule m_primCountModule; + protected IDialogModule m_Dialog; + protected IGroupsModule m_Groups; // Minimum for parcels to work is 64m even if we don't actually use them. #pragma warning disable 0429 @@ -153,6 +155,8 @@ namespace OpenSim.Region.CoreModules.World.Land { m_userManager = m_scene.RequestModuleInterface(); m_primCountModule = m_scene.RequestModuleInterface(); + m_Dialog = m_scene.RequestModuleInterface(); + m_Groups = m_scene.RequestModuleInterface(); } public void RemoveRegion(Scene scene) @@ -212,6 +216,7 @@ namespace OpenSim.Region.CoreModules.World.Land client.OnPreAgentUpdate += ClientOnPreAgentUpdate; client.OnParcelEjectUser += ClientOnParcelEjectUser; client.OnParcelFreezeUser += ClientOnParcelFreezeUser; + client.OnSetStartLocationRequest += ClientOnSetHome; EntityBase presenceEntity; @@ -1823,6 +1828,60 @@ namespace OpenSim.Region.CoreModules.World.Land } } + /// + /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in + /// + /// + /// + /// + /// + /// + public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) + { + m_log.DebugFormat("[XXX]: SetHome"); + // Let's find the parcel in question + ILandObject land = landChannel.GetLandObject(position); + if (land == null || m_scene.GridUserService == null) + { + m_Dialog.SendAlertToUser(remoteClient, "Set Home request Failed."); + return; + } + + // Can the user set home here? + bool canSetHome = false; + // (a) land owners can set home + if (remoteClient.AgentId == land.LandData.OwnerID) + canSetHome = true; + // (b) members of land-owned group in roles that can set home + if (land.LandData.IsGroupOwned && m_Groups != null) + { + ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID); + m_log.DebugFormat("[XXX]: GroupPowers 0x{0:x16}", gpowers); + if ((gpowers & (ulong)GroupPowers.AllowSetHome) == 1) + canSetHome = true; + } + // (c) parcels with telehubs can be the home of anyone + if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) + { + // If the telehub in this parcel? + SceneObjectGroup telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); + if (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)) + canSetHome = true; + } + + if (canSetHome) + { + if (m_scene.GridUserService != null && m_scene.GridUserService.SetHome(remoteClient.AgentId.ToString(), land.RegionUUID, position, lookAt)) + // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. + m_Dialog.SendAlertToUser(remoteClient, "Home position set."); + else + m_Dialog.SendAlertToUser(remoteClient, "Set Home request Failed."); + } + else + m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel."); + } + + protected void InstallInterfaces() { Command clearCommand -- cgit v1.1 From a4431381fa8a4f759a9c7eb9e30ae915504d4fdc Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 11 May 2013 07:58:14 -0700 Subject: Finalize the logic for SetHome. See comments in Land/LandManagementModule.cs about who has permission to set home where. --- .../CoreModules/World/Land/LandManagementModule.cs | 47 +++++++++------------- .../Region/CoreModules/World/Land/LandObject.cs | 7 ---- OpenSim/Region/Framework/Scenes/Scene.cs | 19 --------- 3 files changed, 19 insertions(+), 54 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index c295f3a..1789d6d 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -75,7 +75,6 @@ namespace OpenSim.Region.CoreModules.World.Land protected IUserManagement m_userManager; protected IPrimCountModule m_primCountModule; protected IDialogModule m_Dialog; - protected IGroupsModule m_Groups; // Minimum for parcels to work is 64m even if we don't actually use them. #pragma warning disable 0429 @@ -156,7 +155,6 @@ namespace OpenSim.Region.CoreModules.World.Land m_userManager = m_scene.RequestModuleInterface(); m_primCountModule = m_scene.RequestModuleInterface(); m_Dialog = m_scene.RequestModuleInterface(); - m_Groups = m_scene.RequestModuleInterface(); } public void RemoveRegion(Scene scene) @@ -1838,44 +1836,37 @@ namespace OpenSim.Region.CoreModules.World.Land /// public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) { - m_log.DebugFormat("[XXX]: SetHome"); // Let's find the parcel in question ILandObject land = landChannel.GetLandObject(position); if (land == null || m_scene.GridUserService == null) { - m_Dialog.SendAlertToUser(remoteClient, "Set Home request Failed."); + m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed."); return; } - // Can the user set home here? - bool canSetHome = false; - // (a) land owners can set home - if (remoteClient.AgentId == land.LandData.OwnerID) - canSetHome = true; - // (b) members of land-owned group in roles that can set home - if (land.LandData.IsGroupOwned && m_Groups != null) - { - ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID); - m_log.DebugFormat("[XXX]: GroupPowers 0x{0:x16}", gpowers); - if ((gpowers & (ulong)GroupPowers.AllowSetHome) == 1) - canSetHome = true; - } - // (c) parcels with telehubs can be the home of anyone + // Gather some data + ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID); + SceneObjectGroup telehub = null; if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) - { - // If the telehub in this parcel? - SceneObjectGroup telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); - if (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)) - canSetHome = true; - } + // Does the telehub exist in the scene? + telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); - if (canSetHome) - { - if (m_scene.GridUserService != null && m_scene.GridUserService.SetHome(remoteClient.AgentId.ToString(), land.RegionUUID, position, lookAt)) + // Can the user set home here? + if (// (a) gods and land managers can set home + m_scene.Permissions.IsAdministrator(remoteClient.AgentId) || + m_scene.Permissions.IsGod(remoteClient.AgentId) || + // (b) land owners can set home + remoteClient.AgentId == land.LandData.OwnerID || + // (c) members of the land-associated group in roles that can set home + ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) || + // (d) parcels with telehubs can be the home of anyone + (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))) + { + if (m_scene.GridUserService.SetHome(remoteClient.AgentId.ToString(), land.RegionUUID, position, lookAt)) // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. m_Dialog.SendAlertToUser(remoteClient, "Home position set."); else - m_Dialog.SendAlertToUser(remoteClient, "Set Home request Failed."); + m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed."); } else m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel."); diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 5969d45..8406442 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -228,13 +228,6 @@ namespace OpenSim.Region.CoreModules.World.Land if (estateModule != null) regionFlags = estateModule.GetRegionFlags(); - // In a perfect world, this would have worked. - // -// if ((landData.Flags & (uint)ParcelFlags.AllowLandmark) != 0) -// regionFlags |= (uint)RegionFlags.AllowLandmark; -// if (landData.OwnerID == remote_client.AgentId) -// regionFlags |= (uint)RegionFlags.AllowSetHome; - int seq_id; if (snap_selection && (sequence_id == 0)) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 80c4922..6bbcbd7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3090,7 +3090,6 @@ namespace OpenSim.Region.Framework.Scenes { //client.OnNameFromUUIDRequest += HandleUUIDNameRequest; client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; - client.OnSetStartLocationRequest += SetHomeRezPoint; client.OnRegionHandleRequest += RegionHandleRequest; } @@ -3215,7 +3214,6 @@ namespace OpenSim.Region.Framework.Scenes { //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest; client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest; - client.OnSetStartLocationRequest -= SetHomeRezPoint; client.OnRegionHandleRequest -= RegionHandleRequest; } @@ -3342,23 +3340,6 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in - /// - /// - /// - /// - /// - /// - public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) - { - if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) - // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. - m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); - else - m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed."); - } - - /// /// Get the avatar apperance for the given client. /// /// -- cgit v1.1 From 25fea820490603227432639dde1305957555abb2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 13 May 2013 07:29:17 -0700 Subject: Fixes mantis #6636 -- Groups --- OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 1 - OpenSim/Addons/Groups/Service/GroupsService.cs | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index f670272..7e0b112 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -186,7 +186,6 @@ namespace OpenSim.Groups 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; if (m_UserManagement.IsLocalGridUser(RequestingAgentID)) return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID, diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index 6a4348b..a2ef13a 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -130,6 +130,13 @@ namespace OpenSim.Groups { reason = string.Empty; + // Check if the group already exists + if (m_Database.RetrieveGroup(name) != null) + { + reason = "A group with that name already exists"; + return UUID.Zero; + } + // Create the group GroupData data = new GroupData(); data.GroupID = UUID.Random(); -- cgit v1.1 From af1fa958756a2c76810847a2059befa071956d09 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 13 May 2013 11:36:17 -0700 Subject: Groups: Improve error handling on remote connector. --- .../Addons/Groups/Remote/GroupsServiceRobustConnector.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index f991d01..28f7acc 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -170,11 +170,16 @@ namespace OpenSim.Groups } - grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); - if (grec == null) - NullResult(result, "Internal Error"); + if (grec.GroupID != UUID.Zero) + { + grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID); + if (grec == null) + NullResult(result, "Internal Error"); + else + result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + } else - result["RESULT"] = GroupsDataUtils.GroupRecord(grec); + NullResult(result, reason); } string xmlString = ServerUtils.BuildXmlResponse(result); -- cgit v1.1 From 4194d935ecd21a922859a640cb28acec7e5bae45 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 13 May 2013 13:07:39 -0700 Subject: Fixed mantis #6609 -- LoadPlugin error messages on Robust. --- OpenSim/Server/Base/ServerUtils.cs | 2 +- OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs | 8 ++++++-- .../Server/Handlers/Hypergrid/InstantMessageServerConnector.cs | 7 ++++++- OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs | 7 ++++++- OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs | 9 +++++++-- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 25957d3..08ba50d 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -286,7 +286,7 @@ namespace OpenSim.Server.Base e.InnerException == null ? e.Message : e.InnerException.Message, e.StackTrace); } - m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0}: {1}", dllName, e.Message); + m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0}: {1} args.Length {2}", dllName, e.Message, args.Length); return null; } diff --git a/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs index 0d4990a..ffe2f36 100644 --- a/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/GatekeeperServerConnector.cs @@ -76,10 +76,14 @@ namespace OpenSim.Server.Handlers.Hypergrid server.AddStreamHandler(new GatekeeperAgentHandler(m_GatekeeperService, m_Proxy)); } - public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server) - : this(config, server, null) + public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server, string configName) + : this(config, server, (ISimulationService)null) { } + public GatekeeperServiceInConnector(IConfigSource config, IHttpServer server) + : this(config, server, String.Empty) + { + } } } diff --git a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs index 80eb5d2..8145a21 100644 --- a/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/InstantMessageServerConnector.cs @@ -54,10 +54,15 @@ namespace OpenSim.Server.Handlers.Hypergrid private IInstantMessage m_IMService; public InstantMessageServerConnector(IConfigSource config, IHttpServer server) : - this(config, server, null) + this(config, server, (IInstantMessageSimConnector)null) { } + public InstantMessageServerConnector(IConfigSource config, IHttpServer server, string configName) : + this(config, server) + { + } + public InstantMessageServerConnector(IConfigSource config, IHttpServer server, IInstantMessageSimConnector simConnector) : base(config, server, String.Empty) { diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index db62aaa..b20f467 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -62,10 +62,15 @@ namespace OpenSim.Server.Handlers.Hypergrid private bool m_VerifyCallers = false; public UserAgentServerConnector(IConfigSource config, IHttpServer server) : - this(config, server, null) + this(config, server, (IFriendsSimConnector)null) { } + public UserAgentServerConnector(IConfigSource config, IHttpServer server, string configName) : + this(config, server) + { + } + public UserAgentServerConnector(IConfigSource config, IHttpServer server, IFriendsSimConnector friendsConnector) : base(config, server, String.Empty) { diff --git a/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs b/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs index 9a7ad34..1fb0dbc 100644 --- a/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs +++ b/OpenSim/Server/Handlers/Login/LLLoginServiceInConnector.cs @@ -60,8 +60,8 @@ namespace OpenSim.Server.Handlers.Login InitializeHandlers(server); } - public LLLoginServiceInConnector(IConfigSource config, IHttpServer server) : - base(config, server, String.Empty) + public LLLoginServiceInConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) { string loginService = ReadLocalServiceFromConfig(config); @@ -72,6 +72,11 @@ namespace OpenSim.Server.Handlers.Login InitializeHandlers(server); } + public LLLoginServiceInConnector(IConfigSource config, IHttpServer server) : + this(config, server, String.Empty) + { + } + private string ReadLocalServiceFromConfig(IConfigSource config) { IConfig serverConfig = config.Configs["LoginService"]; -- cgit v1.1 From 45f37e11ad6e9a9917a6ea07ec52dec9058393f0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 13 May 2013 08:40:24 -0700 Subject: BulletSim: use heightmap terrain when using BulletXNA. Output messages on features disabled when using BulletXNA. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 3ca7e16..5504478 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -90,7 +90,7 @@ public static class BSParam public static bool ShouldUseBulletHACD { get; set; } public static bool ShouldUseSingleConvexHullForPrims { get; set; } - public static float TerrainImplementation { get; private set; } + public static float TerrainImplementation { get; set; } public static int TerrainMeshMagnification { get; private set; } public static float TerrainFriction { get; private set; } public static float TerrainHitFraction { get; private set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index a4a8794..3f407ce 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -318,8 +318,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters ret = new BSAPIXNA(engineName, this); // Disable some features that are not implemented in BulletXNA m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); + m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader); BSParam.ShouldUseBulletHACD = false; + m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); BSParam.ShouldUseSingleConvexHullForPrims = false; + m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); + BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; break; } -- cgit v1.1 From 15360cbb6ba83e40f474cca84082c908af49c58e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 13 May 2013 13:03:13 -0700 Subject: BulletSim: add adjustment for avatar capsule height scaling. Makes avatar standing on ground view better and enables tuning. --- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 27 ++++++++++++++++++---- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 9 ++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 542f732..3671fc2 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -649,12 +649,12 @@ public sealed class BSCharacter : BSPhysObject OMV.Vector3 newScale; // Bullet's capsule total height is the "passed height + radius * 2"; - // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) + // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) // The number we pass in for 'scaling' is the multiplier to get that base // shape to be the size desired. // So, when creating the scale for the avatar height, we take the passed height // (size.Z) and remove the caps. - // Another oddity of the Bullet capsule implementation is that it presumes the Y + // An oddity of the Bullet capsule implementation is that it presumes the Y // dimension is the radius of the capsule. Even though some of the code allows // for a asymmetrical capsule, other parts of the code presume it is cylindrical. @@ -662,8 +662,27 @@ public sealed class BSCharacter : BSPhysObject newScale.X = size.X / 2f; newScale.Y = size.Y / 2f; + float heightAdjust = BSParam.AvatarHeightMidFudge; + if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) + { + // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. + // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 + float midHeightOffset = size.Z - 1.87f; + if (midHeightOffset < 0f) + { + // Small avatar. Add the adjustment based on the distance from midheight + heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; + } + else + { + // Large avatar. Add the adjustment based on the distance from midheight + heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; + } + } // The total scale height is the central cylindar plus the caps on the two ends. - newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; + newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; + // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); + // If smaller than the endcaps, just fake like we're almost that small if (newScale.Z < 0) newScale.Z = 0.1f; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 5504478..d33292f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -125,6 +125,9 @@ public static class BSParam public static float AvatarCapsuleWidth { get; private set; } public static float AvatarCapsuleDepth { get; private set; } public static float AvatarCapsuleHeight { get; private set; } + public static float AvatarHeightLowFudge { get; private set; } + public static float AvatarHeightMidFudge { get; private set; } + public static float AvatarHeightHighFudge { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; } public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } public static float AvatarStepHeight { get; private set; } @@ -539,6 +542,12 @@ public static class BSParam 0.45f ), new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 1.5f ), + new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", + -0.2f ), + new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", + 0.1f ), + new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", + 0.1f ), new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", -- cgit v1.1 From c86e828dbfed8b9cf72c7e7e8d1dad0c0e9f8940 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 13 May 2013 13:05:27 -0700 Subject: BulletSim: add a lock to try and catch a native shape creation/destruction race condition. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 262d734..72d039b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -283,8 +283,13 @@ public class BSShapeNative : BSShape public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { // Native shapes are not shared so we return a new shape. - return new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, - physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey) ); + BSShape ret = null; + lock (physShapeInfo) + { + ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, + physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); + } + return ret; } // Make this reference to the physical shape go away since native shapes are not shared. -- cgit v1.1 From f32a21d96707f87ecbdaf42c0059f8494a119d31 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 14 May 2013 08:12:01 -0700 Subject: HGTP-mesh bug: the mesh download requests were going to the departing sims for a little while. This was also true for local TPs. BUt for local TPs the assets are on the same server, so it doesn't matter. For HGTPs, it matters. This potential fix moves sending the initial data to later, after the client has completed the movement into the region. Fingers crossed that it doesn't mess other things up! --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 3 --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 985aa4d..0fa1c0e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1371,9 +1371,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // circuit code to the existing child agent. This is not particularly obvious. SendAckImmediate(endPoint, uccp.Header.Sequence); - // We only want to send initial data to new clients, not ones which are being converted from child to root. - if (client != null) - client.SceneAgent.SendInitialDataToMe(); } else { diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 215a689..be78bd0 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1348,6 +1348,8 @@ namespace OpenSim.Region.Framework.Scenes // Create child agents in neighbouring regions if (openChildAgents && !IsChildAgent) { + SendInitialDataToMe(); + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); if (m_agentTransfer != null) Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); @@ -1355,6 +1357,7 @@ namespace OpenSim.Region.Framework.Scenes IFriendsModule friendsModule = m_scene.RequestModuleInterface(); if (friendsModule != null) friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + } // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region -- cgit v1.1 From 645da54f25bb034eb76151daa9723763eae13303 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 14 May 2013 08:47:18 -0700 Subject: Revert "HGTP-mesh bug: the mesh download requests were going to the departing sims for a little while. This was also true for local TPs. BUt for local TPs the assets are on the same server, so it doesn't matter. For HGTPs, it matters. This potential fix moves sending the initial data to later, after the client has completed the movement into the region. Fingers crossed that it doesn't mess other things up!" This reverts commit f32a21d96707f87ecbdaf42c0059f8494a119d31. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 3 +++ OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 0fa1c0e..985aa4d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1371,6 +1371,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // circuit code to the existing child agent. This is not particularly obvious. SendAckImmediate(endPoint, uccp.Header.Sequence); + // We only want to send initial data to new clients, not ones which are being converted from child to root. + if (client != null) + client.SceneAgent.SendInitialDataToMe(); } else { diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index be78bd0..215a689 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1348,8 +1348,6 @@ namespace OpenSim.Region.Framework.Scenes // Create child agents in neighbouring regions if (openChildAgents && !IsChildAgent) { - SendInitialDataToMe(); - IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); if (m_agentTransfer != null) Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); @@ -1357,7 +1355,6 @@ namespace OpenSim.Region.Framework.Scenes IFriendsModule friendsModule = m_scene.RequestModuleInterface(); if (friendsModule != null) friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); - } // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region -- cgit v1.1 From b135f1d58a1f3532cb198bf25680864e335d4cb1 Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Thu, 9 May 2013 10:25:44 -0400 Subject: BulletSim: Fix for mantis 6487, also minor adjustment to fix flying while you are running. Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 3671fc2..ff5b6ab 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -419,7 +419,7 @@ public sealed class BSCharacter : BSPhysObject DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); m_targetVelocity = value; OMV.Vector3 targetVel = value; - if (_setAlwaysRun) + if (_setAlwaysRun && !_flying) targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); if (m_moveActor != null) @@ -481,7 +481,10 @@ public sealed class BSCharacter : BSPhysObject _orientation = value; PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() { - ForceOrientation = _orientation; + // Bullet assumes we know what we are doing when forcing orientation + // so it lets us go against all the rules and just compensates for them later. + // This keeps us from flipping the capsule over which the veiwer does not understand. + ForceOrientation = new OMV.Quaternion(0, 0, _orientation.Z,0); }); } } -- cgit v1.1 From 91091c3e5453088242e05a682283fc7f9f5c7ae3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 14 May 2013 09:06:58 -0700 Subject: Second take at HGTP-mesh bug: delay sending the initial data only for agents that are coming via TP (root agents) --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 8 +++++++- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 985aa4d..8eb2e06 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1373,7 +1373,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP // We only want to send initial data to new clients, not ones which are being converted from child to root. if (client != null) - client.SceneAgent.SendInitialDataToMe(); + { + AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); + bool tp = (aCircuit.teleportFlags > 0); + // Let's delay this for TP agents, otherwise the viewer doesn't know where to get meshes from + if (!tp) + client.SceneAgent.SendInitialDataToMe(); + } } else { diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 215a689..2a265db 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1348,6 +1348,7 @@ namespace OpenSim.Region.Framework.Scenes // Create child agents in neighbouring regions if (openChildAgents && !IsChildAgent) { + SendInitialDataToMe(); IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); if (m_agentTransfer != null) Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); -- cgit v1.1 From e9847a4dbd5657c16b11835301167a98e7ca7e55 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 14 May 2013 19:44:41 +0100 Subject: Comment out some debugging item permission messages since these are highly noisy on the console. Please re-enable when required --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 80581dc..6c79b13 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -422,13 +422,13 @@ namespace OpenSim.Region.Framework.Scenes // is not allowed to change the export flag. bool denyExportChange = false; - m_log.InfoFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); +// m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); // 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) denyExportChange = true; - m_log.InfoFormat("[XXX]: Deny Export Update {0}", denyExportChange); +// m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange); // If it is already set, force it set and also force full perm // else prevent setting it. It can and should never be set unless @@ -452,7 +452,7 @@ namespace OpenSim.Region.Framework.Scenes // If the new state is exportable, force full perm if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0) { - m_log.InfoFormat("[XXX]: Force full perm"); +// m_log.DebugFormat("[XXX]: Force full perm"); itemUpd.NextPermissions = (uint)(PermissionMask.All); } } -- cgit v1.1 From df2a0fec5f2b0d7e9938c1bc1bdc965b767ec25f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 14 May 2013 20:11:58 +0100 Subject: Comment out log message about looking for asset data in remove asset service for now, in order to reduce log levels in a test region with many hg origin avatars --- OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs index afbe56b..a168bfe 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs @@ -426,7 +426,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) assetServerURL = assetServerURL + "/"; - m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); +// m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); return; } -- cgit v1.1 From 23ebae1828a540a7754dafae1794467582fe35d5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 14 May 2013 13:40:07 -0700 Subject: Eliminate race condition where SimStatsReporter starts reporting stats before the region is completely initialized. --- OpenSim/Region/Framework/Scenes/SimStatsReporter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs index b9d615e..95f9caf 100644 --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -289,6 +289,9 @@ namespace OpenSim.Region.Framework.Scenes private void statsHeartBeat(object sender, EventArgs e) { + if (!m_scene.Active) + return; + SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[22]; SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); -- cgit v1.1 From 177a53fbcf521767f7277ccccabad689d7674953 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 15 May 2013 22:04:38 +0100 Subject: Fix issue where osMakeNotecard() would fail if given a list containing vectors or quaternions. http://opensimulator.org/mantis/view.php?id=6640 --- OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | 60 ++++++++++++------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 44fdd1a..9ca5ca9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -544,21 +544,33 @@ namespace OpenSim.Region.ScriptEngine.Shared set {m_data = value; } } - // Function to obtain LSL type from an index. This is needed - // because LSL lists allow for multiple types, and safely - // iterating in them requires a type check. + + /// + /// Obtain LSL type from an index. + /// + /// + /// This is needed because LSL lists allow for multiple types, and safely + /// iterating in them requires a type check. + /// + /// + /// public Type GetLSLListItemType(int itemIndex) { return m_data[itemIndex].GetType(); } - // Member functions to obtain item as specific types. - // For cases where implicit conversions would apply if items - // were not in a list (e.g. integer to float, but not float - // to integer) functions check for alternate types so as to - // down-cast from Object to the correct type. - // Note: no checks for item index being valid are performed - + /// + /// Obtain float from an index. + /// + /// + /// For cases where implicit conversions would apply if items + /// were not in a list (e.g. integer to float, but not float + /// to integer) functions check for alternate types so as to + /// down-cast from Object to the correct type. + /// Note: no checks for item index being valid are performed + /// + /// + /// public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) { if (m_data[itemIndex] is LSL_Types.LSLInteger) @@ -589,26 +601,14 @@ namespace OpenSim.Region.ScriptEngine.Shared public LSL_Types.LSLString GetLSLStringItem(int itemIndex) { - if (m_data[itemIndex] is LSL_Types.key) - { - return (LSL_Types.key)m_data[itemIndex]; - } - else if (m_data[itemIndex] is String) - { - return new LSL_Types.LSLString((string)m_data[itemIndex]); - } - else if (m_data[itemIndex] is LSL_Types.LSLFloat) - { - return new LSL_Types.LSLString((LSLFloat)m_data[itemIndex]); - } - else if (m_data[itemIndex] is LSL_Types.LSLInteger) - { - return new LSL_Types.LSLString((LSLInteger)m_data[itemIndex]); - } - else - { - return (LSL_Types.LSLString)m_data[itemIndex]; - } + if (m_data[itemIndex] is LSL_Types.key) + { + return (LSL_Types.key)m_data[itemIndex]; + } + else + { + return new LSL_Types.LSLString(m_data[itemIndex].ToString()); + } } public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) -- cgit v1.1 From 12289c4fd1f06371b317453f69283f1de11a9781 Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 16 May 2013 00:02:28 +0200 Subject: Removed obsolete libopenmetaverse file --- bin/OpenMetaverse.Http.XML | 57 ---------------------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 bin/OpenMetaverse.Http.XML diff --git a/bin/OpenMetaverse.Http.XML b/bin/OpenMetaverse.Http.XML deleted file mode 100644 index 23173ae..0000000 --- a/bin/OpenMetaverse.Http.XML +++ /dev/null @@ -1,57 +0,0 @@ - - - - OpenMetaverse.Http - - - - The number of milliseconds to wait before the connection times out - and an empty response is sent to the client. This value should be higher - than BATCH_WAIT_INTERVAL for the timeout to function properly - - - This interval defines the amount of time to wait, in milliseconds, - for new events to show up on the queue before sending a response to the - client and completing the HTTP request. The interval also specifies the - maximum time that can pass before the queue shuts down after Stop() or the - class destructor is called - - - Since multiple events can be batched together and sent in the same - response, this prevents the event queue thread from infinitely dequeueing - events and never sending a response if there is a constant stream of new - events - - - - Singleton logging class for the entire library - - - - log4net logging engine - - - - Singleton instance of this class - - - - - Delegate for handling incoming HTTP requests through a capability - - Client context - HTTP request - HTTP response - User-defined state object - - - = - - - Number of times we've received an unknown CAPS exception in series. - - - For exponential backoff on error. - - - -- cgit v1.1 From 71a5cc204146b33e291bae60a68b9913751d6c8c Mon Sep 17 00:00:00 2001 From: Latif Khalifa Date: Thu, 16 May 2013 00:07:55 +0200 Subject: Updated libopenmetaverse to a5ad7f200e9bd2e91604ba921d1db3768108686b --- bin/OpenMetaverse.Rendering.Meshmerizer.dll | Bin 24576 -> 24576 bytes bin/OpenMetaverse.StructuredData.XML | 234 +- bin/OpenMetaverse.StructuredData.dll | Bin 102400 -> 102400 bytes bin/OpenMetaverse.XML | 34510 +++++++++++++------------- bin/OpenMetaverse.dll | Bin 1785856 -> 1785856 bytes bin/OpenMetaverseTypes.XML | 3596 +-- bin/OpenMetaverseTypes.dll | Bin 114688 -> 114688 bytes 7 files changed, 19170 insertions(+), 19170 deletions(-) diff --git a/bin/OpenMetaverse.Rendering.Meshmerizer.dll b/bin/OpenMetaverse.Rendering.Meshmerizer.dll index 30b9c7b..100916c 100755 Binary files a/bin/OpenMetaverse.Rendering.Meshmerizer.dll and b/bin/OpenMetaverse.Rendering.Meshmerizer.dll differ diff --git a/bin/OpenMetaverse.StructuredData.XML b/bin/OpenMetaverse.StructuredData.XML index 3999d99..789ad5b 100644 --- a/bin/OpenMetaverse.StructuredData.XML +++ b/bin/OpenMetaverse.StructuredData.XML @@ -4,6 +4,123 @@ OpenMetaverse.StructuredData + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Uses reflection to create an SDMap from all of the SD + serializable types in an object + + Class or struct containing serializable types + An SDMap holding the serialized values from the + container object + + + + Uses reflection to deserialize member variables in an object from + an SDMap + + Reference to an object to fill with deserialized + values + Serialized values to put in the target + object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -228,122 +345,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Uses reflection to create an SDMap from all of the SD - serializable types in an object - - Class or struct containing serializable types - An SDMap holding the serialized values from the - container object - - - - Uses reflection to deserialize member variables in an object from - an SDMap - - Reference to an object to fill with deserialized - values - Serialized values to put in the target - object - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenMetaverse.StructuredData.dll b/bin/OpenMetaverse.StructuredData.dll index 4df771a..bb16ed0 100755 Binary files a/bin/OpenMetaverse.StructuredData.dll and b/bin/OpenMetaverse.StructuredData.dll differ diff --git a/bin/OpenMetaverse.XML b/bin/OpenMetaverse.XML index abd4cd5..457cbe1 100644 --- a/bin/OpenMetaverse.XML +++ b/bin/OpenMetaverse.XML @@ -24,6 +24,65 @@ + + + This is used to get a list of audio devices that can be used for capture (input) of voice. + + + + + + This is used to get a list of audio devices that can be used for render (playback) of voice. + + + + + This command is used to select the render device. + + The name of the device as returned by the Aux.GetRenderDevices command. + + + + This command is used to select the capture device. + + The name of the device as returned by the Aux.GetCaptureDevices command. + + + + This command is used to start the audio capture process which will cause + AuxAudioProperty Events to be raised. These events can be used to display a + microphone VU meter for the currently selected capture device. This command + should not be issued if the user is on a call. + + (unused but required) + + + + + This command is used to stop the audio capture process. + + + + + + This command is used to set the mic volume while in the audio tuning process. + Once an acceptable mic level is attained, the application must issue a + connector set mic volume command to have that level be used while on voice + calls. + + the microphone volume (-100 to 100 inclusive) + + + + + This command is used to set the speaker volume while in the audio tuning + process. Once an acceptable speaker level is attained, the application must + issue a connector set speaker volume command to have that level be used while + on voice calls. + + the speaker volume (-100 to 100 inclusive) + + Create a Session @@ -97,65 +156,6 @@ The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume - - - This is used to get a list of audio devices that can be used for capture (input) of voice. - - - - - - This is used to get a list of audio devices that can be used for render (playback) of voice. - - - - - This command is used to select the render device. - - The name of the device as returned by the Aux.GetRenderDevices command. - - - - This command is used to select the capture device. - - The name of the device as returned by the Aux.GetCaptureDevices command. - - - - This command is used to start the audio capture process which will cause - AuxAudioProperty Events to be raised. These events can be used to display a - microphone VU meter for the currently selected capture device. This command - should not be issued if the user is on a call. - - (unused but required) - - - - - This command is used to stop the audio capture process. - - - - - - This command is used to set the mic volume while in the audio tuning process. - Once an acceptable mic level is attained, the application must issue a - connector set mic volume command to have that level be used while on voice - calls. - - the microphone volume (-100 to 100 inclusive) - - - - - This command is used to set the speaker volume while in the audio tuning - process. Once an acceptable speaker level is attained, the application must - issue a connector set speaker volume command to have that level be used while - on voice calls. - - the speaker volume (-100 to 100 inclusive) - - Start up the Voice service. @@ -261,6 +261,36 @@ + + + This is used to login a specific user account(s). It may only be called after + Connector initialization has completed successfully + + Handle returned from successful Connector ‘create’ request + User's account name + User's account password + Values may be “AutoAnswer” or “VerifyAnswer” + "" + This is an integer that specifies how often + the daemon will send participant property events while in a channel. If this is not set + the default will be “on state change”, which means that the events will be sent when + the participant starts talking, stops talking, is muted, is unmuted. + The valid values are: + 0 – Never + 5 – 10 times per second + 10 – 5 times per second + 50 – 1 time per second + 100 – on participant state change (this is the default) + false + + + + + This is used to logout a user session. It should only be called with a valid AccountHandle. + + Handle returned from successful Connector ‘login’ request + + This is used to initialize and stop the Connector as a whole. The Connector @@ -311,36 +341,6 @@ The level of the audio, a number between -100 and 100 where 0 represents ‘normal’ speaking volume - - - This is used to login a specific user account(s). It may only be called after - Connector initialization has completed successfully - - Handle returned from successful Connector ‘create’ request - User's account name - User's account password - Values may be “AutoAnswer” or “VerifyAnswer” - "" - This is an integer that specifies how often - the daemon will send participant property events while in a channel. If this is not set - the default will be “on state change”, which means that the events will be sent when - the participant starts talking, stops talking, is muted, is unmuted. - The valid values are: - 0 – Never - 5 – 10 times per second - 10 – 5 times per second - 50 – 1 time per second - 100 – on participant state change (this is the default) - false - - - - - This is used to logout a user session. It should only be called with a valid AccountHandle. - - Handle returned from successful Connector ‘login’ request - - Event for most mundane request reposnses. @@ -410,25728 +410,25728 @@ 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 + + + + - - Velocity vector of the position + + - - At Orientation (X axis) of the position + + - - Up Orientation (Y axis) of the position + + - - Left Orientation (Z axis) of the position + + - - - Represents a string of characters encoded with specific formatting properties - + + - + + + + + + + - Base class for all Asset types + Status of the last application run. + Used for error reporting to the grid login service for statistical purposes. - - A byte array containing the raw asset data + + Application exited normally - - True if the asset it only stored on the server temporarily + + Application froze - - A unique ID + + Application detected error and exited abnormally - - - Construct a new Asset object - + + Other crash - - - Construct a new Asset object - - A unique specific to this asset - A byte array containing the raw asset data + + Application froze during logout - - - Regenerates the AssetData byte array from the properties - of the derived class. - + + Application crashed during logout - + - Decodes the AssetData, placing it in appropriate properties of the derived - class. + Login Request Parameters - True if the asset decoding succeeded, otherwise false - - The assets unique ID + + The URL of the Login Server - - - The "type" of asset, Notecard, Animation, etc - + + The number of milliseconds to wait before a login is considered + failed due to timeout - - A text string containing main text of the notecard + + The request method + login_to_simulator is currently the only supported method - - List of s embedded on the notecard + + The Agents First name - - Construct an Asset of type Notecard + + 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 + + - Construct an Asset object of type Notecard + Default constuctor, initializes sane default values - 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 + 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 - + - Decode the raw asset data including the Linden Text properties + Instantiates new LoginParams object and fills in the values - true if the AssetData was successfully decoded - - - Override the base classes AssetType + 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 - - The event subscribers, null of no subscribers - - - Raises the AttachedSound Event - A AttachedSoundEventArgs object containing - the data sent from the simulator + + true, false, indeterminate - - Thread sync lock object + + Login message of the day - - The event subscribers, null of no subscribers + + M or PG, also agent_region_access and agent_access_max - - Raises the AttachedSoundGainChange Event - A AttachedSoundGainChangeEventArgs object containing - the data sent from the simulator + + + 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 - - Thread sync lock object + + + 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 SoundTrigger Event - A SoundTriggerEventArgs object containing + + Raises the LoginProgress Event + A LoginProgressEventArgs object containing the data sent from the simulator - + Thread sync lock object - - The event subscribers, null of no subscribers + + Seed CAPS URL returned from the login server - - Raises the PreloadSound Event - A PreloadSoundEventArgs object containing - the data sent from the simulator + + Maximum number of groups an agent can belong to, -1 for unlimited - - Thread sync lock object + + Server side baking service URL - + + A list of packets obtained during the login process which + networkmanager will log but not process + + - Construct a new instance of the SoundManager class, used for playing and receiving - sound assets + Generate sane default values for a login request - A reference to the current GridClient instance + Account first name + Account last name + Account password + Client application name (channel) + Client application name + version + A populated struct containing + sane defaults - + - Plays a sound in the current region at full volume from avatar position + Simplified login that takes the most common and required fields - UUID of the sound to be played + 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 - + - Plays a sound in the current region at full volume + 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 - UUID of the sound to be played. - position for the sound to be played at. Normally the avatar. + 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 - + - Plays a sound in the current region + Login that takes a struct of all the values that will be passed to + the login server - 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 + 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 - + - Plays a sound in the specified sim + Build a start location URI for passing to the Login function - 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 + 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 - + - Play a sound asset + LoginParams and the initial login XmlRpcRequest were made on a remote machine. + This method now initializes libomv with the results. - 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 + + + Handles response from XML-RPC login replies + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Handles response from XML-RPC login replies with already parsed LoginResponseData + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Handle response from LLSD login replies + + + + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Get current OS + + Either "Win" or "Linux" - - Raised when the simulator sends us data containing - sound + + + Get clients default Mac Address + + A string containing the first found Mac Address - - Raised when the simulator sends us data containing - ... + + The event subscribers, null of no subscribers - - Raised when the simulator sends us data containing - ... + + Raises the PacketSent Event + A PacketSentEventArgs object containing + the data sent from the simulator - - Raised when the simulator sends us data containing - ... + + Thread sync lock object - - 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 ... - } - - + + The event subscribers, null of no subscribers - - - 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 + + Raises the LoggedOut Event + A LoggedOutEventArgs object containing + the data sent from the simulator - - Simulator where the event originated + + Thread sync lock object - - Get the sound asset id + + The event subscribers, null of no subscribers - - Get the ID of the owner + + Raises the SimConnecting Event + A SimConnectingEventArgs object containing + the data sent from the simulator - - Get the ID of the Object + + Thread sync lock object - - Get the volume level + + The event subscribers, null of no subscribers - - Get the + + Raises the SimConnected Event + A SimConnectedEventArgs object containing + the data sent from the simulator - - Provides data for the event - The event occurs when an attached sound - changes its volume level + + Thread sync lock object - - - Construct a new instance of the AttachedSoundGainChangedEventArgs class - - Simulator where the event originated - The ID of the Object - The new volume level + + The event subscribers, null of no subscribers - - Simulator where the event originated + + Raises the SimDisconnected Event + A SimDisconnectedEventArgs object containing + the data sent from the simulator - - Get the ID of the Object + + Thread sync lock object - - Get the volume level + + The event subscribers, null of no subscribers - - 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); - } - - + + Raises the Disconnected Event + A DisconnectedEventArgs object containing + the data sent from the simulator - - - 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 + + Thread sync lock object - - Simulator where the event originated + + The event subscribers, null of no subscribers - - Get the sound asset id + + Raises the SimChanged Event + A SimChangedEventArgs object containing + the data sent from the simulator - - Get the ID of the owner + + Thread sync lock object - - Get the ID of the Object + + The event subscribers, null of no subscribers - - Get the ID of the objects parent + + Raises the EventQueueRunning Event + A EventQueueRunningEventArgs object containing + the data sent from the simulator - - Get the volume level + + Thread sync lock object - - Get the regionhandle + + All of the simulators we are currently connected to - - Get the source position + + Handlers for incoming capability events - - 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") - } - - + + Handlers for incoming packets - + + Incoming packets that are awaiting handling + + + Outgoing packets that are awaiting handling + + - Construct a new instance of the PreloadSoundEventArgs class + Default constructor - Simulator where the event originated - The sound asset id - The ID of the owner - The ID of the object + Reference to the GridClient object - - Simulator where the event originated + + + 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 - - Get the sound asset id + + + 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 - - Get the ID of the owner + + + 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 - - Get the ID of the Object + + + 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 - + - Capabilities is the name of the bi-directional HTTP REST protocol - used to communicate non real-time transactions such as teleporting or - group messaging + 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 - - Reference to the simulator this system is connected to + + + Send a packet to the simulator the avatar is currently occupying + + Packet to send - + - Default constructor + Send a packet to a specified simulator - - + Packet to send + Simulator to send the packet to - + - Request the URI of a named capability + Connect to a simulator - Name of the capability to request - The URI of the requested capability, or String.Empty if - the capability does not exist + 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 - + - Process any incoming events, check to see if we have a message created for the event, + 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 - - Capabilities URI this system was initialized with + + + 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 + - - Whether the capabilities event queue is connected and - listening for incoming events + + + 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 + - + - Triggered when an event is received via the EventQueueGet - capability + Close a connection to the given simulator - Event name - Decoded event data - The simulator that generated the event + + - + - Manager class for our own avatar + 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 - - The event subscribers. null if no subcribers + + + 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 - - Raises the ChatFromSimulator event - A ChatEventArgs object containing the - data returned from the data server + + + 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 - - Thread sync lock object + + + Fire an event when an event queue connects for capabilities + + Simulator the event queue is attached to - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the ScriptDialog event - A SctriptDialogEventArgs object containing the - data returned from the data server + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the ScriptQuestion event - A ScriptQuestionEventArgs object containing the - data returned from the data server + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the LoadURL event - A LoadUrlEventArgs object containing the - data returned from the data server + + Raised when the simulator sends us data containing + ... - - Thread sync lock object + + Called when a reply is received from the login server, the + login sequence will block until this event returns - - The event subscribers. null if no subcribers + + Current state of logging in - - Raises the MoneyBalance event - A BalanceEventArgs object containing the - data returned from the data server + + Upon login failure, contains a short string key for the + type of login error that occurred - - Thread sync lock object + + The raw XML-RPC reply from the login server, exactly as it + was received (minus the HTTP header) - - The event subscribers. null if no subcribers + + 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 - - Raises the MoneyBalanceReply event - A MoneyBalanceReplyEventArgs object containing the - data returned from the data server + + Raised when the simulator sends us data containing + ... - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - The event subscribers. null if no subcribers + + Raised when the simulator sends us data containing + ... - - Raises the IM event - A InstantMessageEventArgs object containing the - data returned from the data server + + Raised when the simulator sends us data containing + ... - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - The event subscribers. null if no subcribers + + Raised when the simulator sends us data containing + ... - - Raises the TeleportProgress event - A TeleportEventArgs object containing the - data returned from the data server + + Raised when the simulator sends us data containing + ... - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - The event subscribers. null if no subcribers + + Unique identifier associated with our connections to + simulators - - Raises the AgentDataReply event - A AgentDataReplyEventArgs object containing the - data returned from the data server + + The simulator that the logged in avatar is currently + occupying - - Thread sync lock object + + Shows whether the network layer is logged in to the + grid or not - - The event subscribers. null if no subcribers + + Number of packets in the incoming queue - - Raises the AnimationsChanged event - A AnimationsChangedEventArgs object containing the - data returned from the data server + + Number of packets in the outgoing queue - - Thread sync lock object + + + + + + + + + - - The event subscribers. null if no subcribers + + + Explains why a simulator or the grid disconnected from us + - - Raises the MeanCollision event - A MeanCollisionEventArgs object containing the - data returned from the data server + + The client requested the logout or simulator disconnect - - Thread sync lock object + + The server notified us that it is disconnecting - - The event subscribers. null if no subcribers + + Either a socket was closed or network traffic timed out - - Raises the RegionCrossed event - A RegionCrossedEventArgs object containing the - data returned from the data server + + The last active simulator shut down - - Thread sync lock object + + + Holds a simulator reference and a decoded packet, these structs are put in + the packet inbox for event handling + - - The event subscribers. null if no subcribers + + Reference to the simulator that this packet came from - - Raises the GroupChatJoined event - A GroupChatJoinedEventArgs object containing the - data returned from the data server + + Packet that needs to be processed - - Thread sync lock object + + + Holds a simulator reference and a serialized packet, these structs are put in + the packet outbox for sending + - - The event subscribers. null if no subcribers + + Reference to the simulator this packet is destined for - - Raises the AlertMessage event - A AlertMessageEventArgs object containing the - data returned from the data server + + Packet that needs to be sent - - Thread sync lock object + + Sequence number of the wrapped packet - - The event subscribers. null if no subcribers + + Number of times this packet has been resent - - Raises the ScriptControlChange event - A ScriptControlEventArgs object containing the - data returned from the data server + + Environment.TickCount when this packet was last sent over the wire - - Thread sync lock object + + Type of the packet - - The event subscribers. null if no subcribers + + + Registers, unregisters, and fires events generated by incoming packets + - - Raises the CameraConstraint event - A CameraConstraintEventArgs object containing the - data returned from the data server + + Reference to the GridClient object - - Thread sync lock object + + + Default constructor + + - - The event subscribers. null if no subcribers + + + 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 - - Raises the ScriptSensorReply event - A ScriptSensorReplyEventArgs object containing the - data returned from the data server + + + Unregister an event handler + + Packet type to unregister the handler for + Callback to be unregistered - - Thread sync lock object + + + Fire the events registered for this packet type + + Incoming packet type + Incoming packet + Simulator this packet was received from - - The event subscribers. null if no subcribers + + + Object that is passed to worker threads in the ThreadPool for + firing packet callbacks + - - Raises the AvatarSitResponse event - A AvatarSitResponseEventArgs object containing the - data returned from the data server + + Callback to fire for this packet - - Thread sync lock object + + Reference to the simulator that this packet came from - - The event subscribers. null if no subcribers + + The packet that needs to be processed - - Raises the ChatSessionMemberAdded event - A ChatSessionMemberAddedEventArgs object containing the - data returned from the data server + + + Registers, unregisters, and fires events generated by the Capabilities + event queue + - - Thread sync lock object + + Reference to the GridClient object - - The event subscribers. null if no subcribers + + + Default constructor + + Reference to the GridClient object - - Raises the ChatSessionMemberLeft event - A ChatSessionMemberLeftEventArgs object containing the - data returned from the data server + + + 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 - - Thread sync lock object + + + Unregister a previously registered capabilities handler + + Capability event name unregister the + handler for + Callback to unregister - - The event subscribers, null of no subscribers + + + Fire the events registered for this event type synchronously + + Capability name + Decoded event body + Reference to the simulator that + generated this event - - Raises the SetDisplayNameReply Event - A SetDisplayNameReplyEventArgs object containing - the data sent from the simulator + + + Fire the events registered for this event type asynchronously + + Capability name + Decoded event body + Reference to the simulator that + generated this event - - Thread sync lock object + + + Object that is passed to worker threads in the ThreadPool for + firing CAPS callbacks + - - The event subscribers. null if no subcribers + + Callback to fire for this packet - - Raises the MuteListUpdated event - A EventArgs object containing the - data returned from the data server + + Name of the CAPS event - - Thread sync lock object + + Strongly typed decoded data - - Reference to the GridClient instance + + Reference to the simulator that generated this event - - Used for movement and camera tracking + + + Represends individual HTTP Download request + - - Currently playing animations for the agent. Can be used to - check the current movement status such as walking, hovering, aiming, - etc. by checking against system animations found in the Animations class + + URI of the item to fetch - - Dictionary containing current Group Chat sessions and members + + Timout specified in milliseconds - - Dictionary containing mute list keyead on mute name and key + + Download progress callback - - Various abilities and preferences sent by the grid + + Download completed callback - + + Accept the following content type + + + How many times will this request be retried + + + Current fetch attempt + + + Default constructor + + + Constructor + + - Constructor, setup callbacks for packets related to our avatar + Manages async HTTP downloads with a limit on maximum + concurrent downloads - A reference to the Class - + + Default constructor + + + Cleanup method + + + Setup http download request + + + Check the queue for pending work + + + Enqueue a new HTPP download + + + Maximum number of parallel downloads from a single endpoint + + + Client certificate + + - Send a text message from the Agent to the Simulator + Reads in a byte array of an Animation Asset created by the SecondLife(tm) client. - A containing the message - The channel to send the message on, 0 is the public channel. Channels above 0 - can be used however only scripts listening on the specified channel will see the message - Denotes the type of message being sent, shout, whisper, etc. - + - Request any instant messages sent while the client was offline to be resent. + Rotation Keyframe count (used internally) - + - Send an Instant Message to another Avatar + Position Keyframe count (used internally) - The recipients - A containing the message to send - + - Send an Instant Message to an existing group chat or conference chat + Animation Priority - The recipients - A containing the message to send - IM session ID (to differentiate between IM windows) - + - Send an Instant Message + The animation length in seconds. - The name this IM will show up as being from - Key of Avatar - Text message being sent - IM session ID (to differentiate between IM windows) - IDs of sessions for a conference - + - Send an Instant Message + Expression set in the client. Null if [None] is selected - The name this IM will show up as being from - Key of Avatar - Text message being sent - IM session ID (to differentiate between IM windows) - Type of instant message to send - Whether to IM offline avatars as well - Senders Position - RegionID Sender is In - Packed binary data that is specific to - the dialog type - + - Send an Instant Message to a group + The time in seconds to start the animation - of the group to send message to - Text Message being sent. - + - Send an Instant Message to a group the agent is a member of + The time in seconds to end the animation - The name this IM will show up as being from - of the group to send message to - Text message being sent - + - Send a request to join a group chat session + Loop the animation - of Group to leave - + - Exit a group chat session. This will stop further Group chat messages - from being sent until session is rejoined. + Meta data. Ease in Seconds. - of Group chat session to leave - + - Reply to script dialog questions. + Meta data. Ease out seconds. - Channel initial request came on - Index of button you're "clicking" - Label of button you're "clicking" - of Object that sent the dialog request - - + - Accept invite for to a chatterbox session + Meta Data for the Hand Pose - of session to accept invite to - + - Start a friends conference + Number of joints defined in the animation - List of UUIDs to start a conference with - the temportary session ID returned in the callback> - + - Start a particle stream between an agent and an object + Contains an array of joints - Key of the source agent - Key of the target object - - The type from the enum - A unique for this effect - + - Start a particle stream between an agent and an object + Searialize an animation asset into it's joints/keyframes/meta data - Key of the source agent - Key of the target object - A representing the beams offset from the source - A which sets the avatars lookat animation - of the Effect + - + - Create a particle beam between an avatar and an primitive - - The ID of source avatar - The ID of the target primitive - global offset - A object containing the combined red, green, blue and alpha - color values of particle beam - a float representing the duration the parcicle beam will last - A Unique ID for the beam - - - - - Create a particle swirl around a target position using a packet + Variable length strings seem to be null terminated in the animation asset.. but.. + use with caution, home grown. + advances the index. - global offset - A object containing the combined red, green, blue and alpha - color values of particle beam - a float representing the duration the parcicle beam will last - A Unique ID for the beam + The animation asset byte array + The offset to start reading + a string - + - Sends a request to sit on the specified object + Read in a Joint from an animation asset byte array + Variable length Joint fields, yay! + Advances the index - of the object to sit on - Sit at offset + animation asset byte array + Byte Offset of the start of the joint + The Joint data serialized into the binBVHJoint structure - + - Follows a call to to actually sit on the object + Read Keyframes of a certain type + advance i + Animation Byte array + Offset in the Byte Array. Will be advanced + Number of Keyframes + Scaling Min to pass to the Uint16ToFloat method + Scaling Max to pass to the Uint16ToFloat method + - - Stands up from sitting on a prim or the ground - true of AgentUpdate was sent + + + Determines whether the specified is equal to the current . + + + true if the specified is equal to the current ; otherwise, false. + + The to compare with the current . + The parameter is null. + 2 - + - Does a "ground sit" at the avatar's current position - + Serves as a hash function for a particular type. + + + A hash code for the current . + + 2 - - - Starts or stops flying + + + A Joint and it's associated meta data and keyframes - True to start flying, false to stop flying - - - Starts or stops crouching - - True to start crouching, false to stop crouching + + + Indicates whether this instance and a specified object are equal. + + + true if and this instance are the same type and represent the same value; otherwise, false. + + Another object to compare to. + 2 - - - Starts a jump (begin holding the jump key) - + + + Returns the hash code for this instance. + + + A 32-bit signed integer that is the hash code for this instance. + + 2 - + - Use the autopilot sim function to move the avatar to a new - position. Uses double precision to get precise movements + Name of the Joint. Matches the avatar_skeleton.xml in client distros - The z value is currently not handled properly by the simulator - Global X coordinate to move to - Global Y coordinate to move to - Z coordinate to move to - + - Use the autopilot sim function to move the avatar to a new position + Joint Animation Override? Was the same as the Priority in testing.. - The z value is currently not handled properly by the simulator - Integer value for the global X coordinate to move to - Integer value for the global Y coordinate to move to - Floating-point value for the Z coordinate to move to - + - Use the autopilot sim function to move the avatar to a new position + Array of Rotation Keyframes in order from earliest to latest - The z value is currently not handled properly by the simulator - Integer value for the local X coordinate to move to - Integer value for the local Y coordinate to move to - Floating-point value for the Z coordinate to move to - - - Macro to cancel autopilot sim function - Not certain if this is how it is really done - true if control flags were set and AgentUpdate was sent to the simulator - + - Grabs an object + Array of Position Keyframes in order from earliest to latest + This seems to only be for the Pelvis? - an unsigned integer of the objects ID within the simulator - - + - Overload: Grab a simulated object + Custom application data that can be attached to a joint - an unsigned integer of the objects ID within the simulator - - The texture coordinates to grab - The surface coordinates to grab - The face of the position to grab - The region coordinates of the position to grab - The surface normal of the position to grab (A normal is a vector perpindicular to the surface) - The surface binormal of the position to grab (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space - + - Drag an object + A Joint Keyframe. This is either a position or a rotation. - of the object to drag - Drag target in region coordinates - + - Overload: Drag an object + Either a Vector3 position or a Vector3 Euler rotation - of the object to drag - Drag target in region coordinates - - The texture coordinates to grab - The surface coordinates to grab - The face of the position to grab - The region coordinates of the position to grab - The surface normal of the position to grab (A normal is a vector perpindicular to the surface) - The surface binormal of the position to grab (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space - + - Release a grabbed object + Poses set in the animation metadata for the hands. - The Objects Simulator Local ID - - - - - - Release a grabbed object - - The Objects Simulator Local ID - The texture coordinates to grab - The surface coordinates to grab - The face of the position to grab - The region coordinates of the position to grab - The surface normal of the position to grab (A normal is a vector perpindicular to the surface) - The surface binormal of the position to grab (A binormal is a vector tangen to the surface - pointing along the U direction of the tangent space + + Information about agents display name - - - Touches an object - - an unsigned integer of the objects ID within the simulator - + + Agent UUID - - - Request the current L$ balance - + + Username - - - Give Money to destination Avatar - - UUID of the Target Avatar - Amount in L$ + + Display name - + + First name (legacy) + + + Last name (legacy) + + + Is display name default display name + + + Cache display name until + + + Last updated timestamp + + - Give Money to destination Avatar + Creates AgentDisplayName object from OSD - UUID of the Target Avatar - Amount in L$ - Description that will show up in the - recipients transaction history + Incoming OSD data + AgentDisplayName object - + - Give L$ to an object + Return object as OSD map - object to give money to - amount of L$ to give - name of object + OSD containing agent's display name data - + + Full name (legacy) + + - Give L$ to a group + Holds group information for Avatars such as those you might find in a profile - group to give money to - amount of L$ to give - - - Give L$ to a group - - group to give money to - amount of L$ to give - description of transaction + + true of Avatar accepts group notices - - - Pay texture/animation upload fee - + + Groups Key - - - Pay texture/animation upload fee - - description of the transaction + + Texture Key for groups insignia - - - Give Money to destination Object or Avatar - - UUID of the Target Object/Avatar - Amount in L$ - Reason (Optional normally) - The type of transaction - Transaction flags, mostly for identifying group - transactions + + Name of the group - - - Plays a gesture - - Asset of the gesture + + Powers avatar has in the group - - - Mark gesture active - - Inventory of the gesture - Asset of the gesture + + Avatars Currently selected title - - - Mark gesture inactive - - Inventory of the gesture + + true of Avatar has chosen to list this in their profile - + - Send an AgentAnimation packet that toggles a single animation on + Contains an animation currently being played by an agent - The of the animation to start playing - Whether to ensure delivery of this packet or not - - - Send an AgentAnimation packet that toggles a single animation off - - The of a - currently playing animation to stop playing - Whether to ensure delivery of this packet or not + + The ID of the animation asset - - - Send an AgentAnimation packet that will toggle animations on or off - - A list of animation s, and whether to - turn that animation on or off - Whether to ensure delivery of this packet or not + + A number to indicate start order of currently playing animations + On Linden Grids this number is unique per region, with OpenSim it is per client - - - Teleports agent to their stored home location - - true on successful teleport to home location + + - + - Teleport agent to a landmark + Holds group information on an individual profile pick - of the landmark to teleport agent to - true on success, false on failure - + - Attempt to look up a simulator name and teleport to the discovered - destination + Retrieve friend status notifications, and retrieve avatar names and + profiles - Region name to look up - Position to teleport to - True if the lookup and teleport were successful, otherwise - false - - - Attempt to look up a simulator name and teleport to the discovered - destination - - Region name to look up - Position to teleport to - Target to look at - True if the lookup and teleport were successful, otherwise - false + + The event subscribers, null of no subscribers - - - Teleport agent to another region - - handle of region to teleport agent to - position in destination sim to teleport to - true on success, false on failure - This call is blocking + + Raises the AvatarAnimation Event + An AvatarAnimationEventArgs object containing + the data sent from the simulator - - - Teleport agent to another region - - handle of region to teleport agent to - position in destination sim to teleport to - direction in destination sim agent will look at - true on success, false on failure - This call is blocking + + Thread sync lock object - - - Request teleport to a another simulator - - handle of region to teleport agent to - position in destination sim to teleport to + + The event subscribers, null of no subscribers - - - Request teleport to a another simulator - - handle of region to teleport agent to - position in destination sim to teleport to - direction in destination sim agent will look at + + Raises the AvatarAppearance Event + A AvatarAppearanceEventArgs object containing + the data sent from the simulator - - - Teleport agent to a landmark - - of the landmark to teleport agent to + + Thread sync lock object - - - Send a teleport lure to another avatar with default "Join me in ..." invitation message - - target avatars to lure + + The event subscribers, null of no subscribers - - - Send a teleport lure to another avatar with custom invitation message - - target avatars to lure - custom message to send with invitation + + Raises the UUIDNameReply Event + A UUIDNameReplyEventArgs object containing + the data sent from the simulator - - - Respond to a teleport lure by either accepting it and initiating - the teleport, or denying it - - of the avatar sending the lure - IM session of the incoming lure request - true to accept the lure, false to decline it + + Thread sync lock object - - - Update agent profile - - struct containing updated - profile information + + The event subscribers, null of no subscribers - - - Update agents profile interests - - selection of interests from struct + + Raises the AvatarInterestsReply Event + A AvatarInterestsReplyEventArgs object containing + the data sent from the simulator - - - Set the height and the width of the client window. This is used - by the server to build a virtual camera frustum for our avatar - - New height of the viewer window - New width of the viewer window + + Thread sync lock object - - - Request the list of muted objects and avatars for this agent - + + The event subscribers, null of no subscribers - - - Mute an object, resident, etc. - - Mute type - Mute UUID - Mute name + + Raises the AvatarPropertiesReply Event + A AvatarPropertiesReplyEventArgs object containing + the data sent from the simulator - - - Mute an object, resident, etc. - - Mute type - Mute UUID - Mute name - Mute flags + + Thread sync lock object - - - Unmute an object, resident, etc. - - Mute UUID - Mute name + + The event subscribers, null of no subscribers - - - Sets home location to agents current position - - will fire an AlertMessage () with - success or failure message + + Raises the AvatarGroupsReply Event + A AvatarGroupsReplyEventArgs object containing + the data sent from the simulator - - - Move an agent in to a simulator. This packet is the last packet - needed to complete the transition in to a new simulator - - Object + + Thread sync lock object - - - Reply to script permissions request - - Object - of the itemID requesting permissions - of the taskID requesting permissions - list of permissions to allow + + The event subscribers, null of no subscribers - + + Raises the AvatarPickerReply Event + A AvatarPickerReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the ViewerEffectPointAt Event + A ViewerEffectPointAtEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the ViewerEffectLookAt Event + A ViewerEffectLookAtEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the ViewerEffect Event + A ViewerEffectEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the AvatarPicksReply Event + A AvatarPicksReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the PickInfoReply Event + A PickInfoReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the AvatarClassifiedReply Event + A AvatarClassifiedReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the ClassifiedInfoReply Event + A ClassifiedInfoReplyEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + + The event subscribers, null of no subscribers + + + Raises the DisplayNameUpdate Event + A DisplayNameUpdateEventArgs object containing + the data sent from the simulator + + + Thread sync lock object + + - Respond to a group invitation by either accepting or denying it + Represents other avatars - UUID of the group (sent in the AgentID field of the invite message) - IM Session ID from the group invitation message - Accept the group invitation or deny it + - + + Tracks the specified avatar on your map + Avatar ID to track + + - Requests script detection of objects and avatars + Request a single avatar name - name of the object/avatar to search for - UUID of the object or avatar to search for - Type of search from ScriptSensorTypeFlags - range of scan (96 max?) - the arc in radians to search within - an user generated ID to correlate replies with - Simulator to perform search in + The avatar key to retrieve a name for - + - Create or update profile pick + Request a list of avatar names - UUID of the pick to update, or random UUID to create a new pick - Is this a top pick? (typically false) - UUID of the parcel (UUID.Zero for the current parcel) - Name of the pick - Global position of the pick landmark - UUID of the image displayed with the pick - Long description of the pick + The avatar keys to retrieve names for - + - Delete profile pick + Check if Display Names functionality is available - UUID of the pick to delete + True if Display name functionality is available - + - Create or update profile Classified + Request retrieval of display names (max 90 names per request) - UUID of the classified to update, or random UUID to create a new classified - Defines what catagory the classified is in - UUID of the image displayed with the classified - Price that the classified will cost to place for a week - Global position of the classified landmark - Name of the classified - Long description of the classified - if true, auto renew classified after expiration + List of UUIDs to lookup + Callback to report result of the operation - + - Create or update profile Classified + Start a request for Avatar Properties - UUID of the classified to update, or random UUID to create a new classified - Defines what catagory the classified is in - UUID of the image displayed with the classified - Price that the classified will cost to place for a week - Name of the classified - Long description of the classified - if true, auto renew classified after expiration + - + - Delete a classified ad + Search for an avatar (first name, last name) - The classified ads ID + The name to search for + An ID to associate with this query - + - Fetches resource usage by agents attachmetns + Start a request for Avatar Picks - Called when the requested information is collected + UUID of the avatar - + - Initates request to set a new display name + Start a request for Avatar Classifieds - Previous display name - Desired new display name + UUID of the avatar - + - Tells the sim what UI language is used, and if it's ok to share that with scripts + Start a request for details of a specific profile pick - Two letter language code - Share language info with scripts + UUID of the avatar + UUID of the profile pick - + - Take an incoming ImprovedInstantMessage packet, auto-parse, and if - OnInstantMessage is defined call that with the appropriate arguments + Start a request for details of a specific profile classified + UUID of the avatar + UUID of the profile classified + + + Process an incoming packet and raise the appropriate events The sender The EventArgs object containing the packet data - - - Take an incoming Chat packet, auto-parse, and if OnChat is defined call - that with the appropriate arguments. - + + Process an incoming packet and raise the appropriate events The sender The EventArgs object containing the packet data - - - Used for parsing llDialogs - + + Process an incoming packet and raise the appropriate events The sender The EventArgs object containing the packet data - - - Used for parsing llRequestPermissions dialogs - + + Process an incoming packet and raise the appropriate events The sender The EventArgs object containing the packet data - - - Handles Script Control changes when Script with permissions releases or takes a control - + + Process an incoming packet and raise the appropriate events The sender The EventArgs object containing the packet data - + - Used for parsing llLoadURL Dialogs - - The sender - The EventArgs object containing the packet data - - - - Update client's Position, LookAt and region handle from incoming packet - - The sender - The EventArgs object containing the packet data - This occurs when after an avatar moves into a new sim - - - 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 - - - - EQ Message fired with the result of SetDisplayName request + EQ Message fired when someone nearby changes their display name The message key the IMessage object containing the deserialized data sent from the simulator The which originated the packet - - - Process TeleportFailed message sent via EventQueue, informs agent its last teleport has failed and why. - - The Message Key - An IMessage object Deserialized from the recieved message event - The simulator originating the event message - - + - Process TeleportFinish from Event Queue and pass it onto our TeleportHandler + Crossed region handler for message that comes across the EventQueue. Sent to an agent + when the agent crosses a sim border into a new region. - The message system key for this event - IMessage object containing decoded data from OSD - The simulator originating the event message - - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - + 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 - - - Crossed region handler for message that comes across the EventQueue. Sent to an agent - when the agent crosses a sim border into a new region. - - The message key - the IMessage object containing the deserialized data sent from the simulator - The which originated the packet - - + Process an incoming packet and raise the appropriate events The sender The EventArgs object containing the packet data - This packet is now being sent via the EventQueue - - - - Group Chat event handler - - The capability Key - IMessage object containing decoded data from OSD - - - - - Response from request to join a group chat - - - IMessage object containing decoded data from OSD - - - - - Someone joined or left group chat - - - IMessage object containing decoded data from OSD - - - - - Handle a group chat Invitation - - Caps Key - IMessage object containing decoded data from OSD - Originating Simulator - - - - Moderate a chat session - - the of the session to moderate, for group chats this will be the groups UUID - the of the avatar to moderate - Either "voice" to moderate users voice, or "text" to moderate users text session - true to moderate (silence user), false to allow avatar to speak - + 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 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 the simulator sends us data containing + an agents animation playlist - - 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 the simulator sends us data containing + the appearance information for an agent - - Raised when a simulator sends agent specific information for our avatar. + + Raised when the simulator sends us data containing + agent names/id values - - Raised when our agents animation playlist changes + + Raised when the simulator sends us data containing + the interests listed in an agents profile - - Raised when an object or avatar forcefully collides with our agent + + Raised when the simulator sends us data containing + profile property information for an agent - - Raised when our agent crosses a region border into another region + + Raised when the simulator sends us data containing + the group membership an agent is a member of - - Raised when our agent succeeds or fails to join a group chat session + + Raised when the simulator sends us data containing + name/id pair - - 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 the simulator sends us data containing + the objects and effect when an agent is pointing at - - Raised when a script attempts to take or release specified controls for our agent + + Raised when the simulator sends us data containing + the objects and effect when an agent is looking at - - Raised when the simulator detects our agent is trying to view something - beyond its limits + + Raised when the simulator sends us data containing + an agents viewer effect information - - Raised when a script sensor reply is received from a simulator + + Raised when the simulator sends us data containing + the top picks from an agents profile - - Raised in response to a request + + Raised when the simulator sends us data containing + the Pick details - - Raised when an avatar enters a group chat session we are participating in + + Raised when the simulator sends us data containing + the classified ads an agent has placed - - Raised when an agent exits a group chat session we are participating in + + 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 - - 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 or PG - - - The CollisionPlane of Agent - - - An representing the velocity of our agent - - - An representing the acceleration of our agent + + + Callback giving results when fetching display names + + If the request was successful + Array of display names + Array of UUIDs that could not be fetched - - A which specifies the angular speed, and axis about which an Avatar is rotating. + + Provides data for the event + The event occurs when the simulator sends + the animation playlist for an agent + + The following code example uses the and + properties to display the animation playlist of an avatar on the window. + + // subscribe to the event + Client.Avatars.AvatarAnimation += Avatars_AvatarAnimation; + + private void Avatars_AvatarAnimation(object sender, AvatarAnimationEventArgs e) + { + // create a dictionary of "known" animations from the Animations class using System.Reflection + Dictionary<UUID, string> systemAnimations = new Dictionary<UUID, string>(); + Type type = typeof(Animations); + System.Reflection.FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + foreach (System.Reflection.FieldInfo field in fields) + { + systemAnimations.Add((UUID)field.GetValue(type), field.Name); + } + + // find out which animations being played are known animations and which are assets + foreach (Animation animation in e.Animations) + { + if (systemAnimations.ContainsKey(animation.AnimationID)) + { + Console.WriteLine("{0} is playing {1} ({2}) sequence {3}", e.AvatarID, + systemAnimations[animation.AnimationID], animation.AnimationSequence); + } + else + { + Console.WriteLine("{0} is playing {1} (Asset) sequence {2}", e.AvatarID, + animation.AnimationID, animation.AnimationSequence); + } + } + } + + - - Position avatar client will goto when login to 'home' or during - teleport request to 'home' region. + + + Construct a new instance of the AvatarAnimationEventArgs class + + The ID of the agent + The list of animations to start - - LookAt point saved/restored with HomePosition + + Get the ID of the agent - - Avatar First Name (i.e. Philip) + + Get the list of animations to start - - Avatar Last Name (i.e. Linden) + + 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") + } + + - - Avatar Full Name (i.e. Philip Linden) + + + 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 - - Gets the health of the agent + + Get the Simulator this request is from of the agent - - Gets the current balance of the agent + + Get the ID of the agent - - Gets the local ID of the prim the agent is sitting on, - zero if the avatar is not currently sitting + + true if the agent is a trial account - - Gets the of the agents active group. + + Get the default agent texture - - Gets the Agents powers in the currently active group + + Get the agents appearance layer textures - - Current status message for teleporting + + Get the for the agent - - Current position of the agent as a relative offset from - the simulator, or the parent object if we are sitting on something + + Version of the appearance system used. + Value greater than 0 indicates that server side baking is used - - Current rotation of the agent as a relative rotation from - the simulator, or the parent object if we are sitting on something + + Version of the Current Outfit Folder the appearance is based on - - Current position of the agent in the simulator + + Appearance flags, introduced with server side baking, currently unused - - - A representing the agents current rotation - + + Represents the interests from the profile of an agent - - Returns the global grid position of the avatar + + Get the ID of the agent - - - Used to specify movement actions for your agent - + + The properties of an agent - - Empty flag + + Get the ID of the agent - - Move Forward (SL Keybinding: W/Up Arrow) + + Get the ID of the agent - - Move Backward (SL Keybinding: S/Down Arrow) + + Get the ID of the agent - - Move Left (SL Keybinding: Shift-(A/Left Arrow)) + + Get the ID of the avatar - - Move Right (SL Keybinding: Shift-(D/Right Arrow)) + + + Event args class for display name notification messages + - - Not Flying: Jump/Flying: Move Up (SL Keybinding: E) + + + A linkset asset, containing a parent primitive and zero or more children + - - Not Flying: Croutch/Flying: Move Down (SL Keybinding: C) + + + Base class for all Asset types + - - Unused + + A byte array containing the raw asset data - - Unused + + True if the asset it only stored on the server temporarily - - Unused + + A unique ID - - Unused + + + Construct a new Asset object + - - ORed with AGENT_CONTROL_AT_* if the keyboard is being used + + + Construct a new Asset object + + A unique specific to this asset + A byte array containing the raw asset data - - ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used + + + Regenerates the AssetData byte array from the properties + of the derived class. + - - ORed with AGENT_CONTROL_UP_* if the keyboard is being used + + + Decodes the AssetData, placing it in appropriate properties of the derived + class. + + True if the asset decoding succeeded, otherwise false - - Fly + + The assets unique ID - - + + + The "type" of asset, Notecard, Animation, etc + - - Finish our current animation + + Initializes a new instance of an AssetPrim object - - Stand up from the ground or a prim seat + + + Initializes a new instance of an AssetPrim object + + A unique specific to this asset + A byte array containing the raw asset data - - Sit on the ground at our current location + + + + - - Whether mouselook is currently enabled + + + + + - - Legacy, used if a key was pressed for less than a certain amount of time + + Override the base classes AssetType - - Legacy, used if a key was pressed for less than a certain amount of time + + + Only used internally for XML serialization/deserialization + - - Legacy, used if a key was pressed for less than a certain amount of time + + + The deserialized form of a single primitive in a linkset asset + - - Legacy, used if a key was pressed for less than a certain amount of time + + Describes tasks returned in LandStatReply - - Legacy, used if a key was pressed for less than a certain amount of time + + + Estate level administration and utilities + - - Legacy, used if a key was pressed for less than a certain amount of time + + Textures for each of the four terrain height levels - - + + Upper/lower texture boundaries for each corner of the sim - - + + + Constructor for EstateTools class + + - - Set when the avatar is idled or set to away. Note that the away animation is - activated separately from setting this flag + + 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 - - - Agent movement and camera control - - Agent movement is controlled by setting specific - After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags - This is most easily accomplished by setting one or more of the AgentMovement properties - - Movement of an avatar is always based on a compass direction, for example AtPos will move the - agent from West to East or forward on the X Axis, AtNeg will of course move agent from - East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis - The Z axis is Up, finer grained control of movements can be done using the Nudge properties - + + Thread sync lock object - - Agent camera controls + + The event subscribers. null if no subcribers - - Currently only used for hiding your group title + + Raises the EstateUsersReply event + A EstateUsersReplyEventArgs object containing the + data returned from the data server - - Action state of the avatar, which can currently be - typing and editing + + 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 - - Timer for sending AgentUpdate packets + + The event subscribers. null if no subcribers - - Default constructor + + 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 + + - Send an AgentUpdate with the camera set at the current agent - position and pointing towards the heading specified + Requests estate information such as top scripts and colliders - Camera rotation in radians - Whether to send the AgentUpdate reliable - or not + + + + - + + 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 + + - Rotates the avatar body and camera toward a target position. - This will also anchor the camera position on the avatar + Set several estate specific configuration variables - Region coordinates to turn toward + 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 - + - Rotates the avatar body and camera toward a target position. - This will also anchor the camera position on the avatar + Request return of objects owned by specified avatar - Region coordinates to turn toward - whether to send update or not + 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 - + + + + + + - Send new AgentUpdate packet to update our current camera - position and rotation + Used for setting and retrieving various estate panel settings + EstateOwnerMessage Method field + List of parameters to include - + - Send new AgentUpdate packet to update our current camera - position and rotation + Kick an avatar from an estate - Whether to require server acknowledgement - of this packet + Key of Agent to remove - + - Send new AgentUpdate packet to update our current camera - position and rotation + 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 - Whether to require server acknowledgement - of this packet - Simulator to send the update to + Message to send all users in the estate - + - Builds an AgentUpdate packet entirely from parameters. This - will not touch the state of Self.Movement or - Self.Movement.Camera in any way + Send a message dialog to everyone in a simulator - - - - - - - - - - - + Message to send all users in the simulator - + - Sends update of Field of Vision vertical angle to the simulator + Send an avatar back to their home location - Angle in radians - - - Move agent positive along the X axis - - - Move agent negative along the X axis - - - Move agent positive along the Y axis + Key of avatar to send home - - Move agent negative along the Y axis + + + Begin the region restart process + - - Move agent positive along the Z axis + + + Cancels a region restart + - - Move agent negative along the Z axis + + 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 - - Causes simulator to make agent fly + + + Add estate manager + Key of Agent to Add + Add agent as manager to this estate and all others owned by the estate owner - - Stop movement + + + 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 - - Finish animation + + + Removes an agent from the estate Allowed list + Key of Agent to Remove + Removes agent as an allowed reisdent from All estates if true - - Stand up from a sit + + + + 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 - - Tells simulator to sit agent on ground + + + + Removes a group from the estate Allowed list + Key of Group to Remove + Removes Group as an allowed Group from All estates if true - - Place agent into mouselook mode + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Nudge agent positive along the X axis + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Nudge agent negative along the X axis + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Nudge agent positive along the Y axis + + Raised when the data server responds to a request. - - Nudge agent negative along the Y axis + + Raised when the data server responds to a request. - - Nudge agent positive along the Z axis + + Raised when the data server responds to a request. - - Nudge agent negative along the Z axis + + 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. - - Tell simulator to mark agent as away + + 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 - + - Returns "always run" value, or changes it by sending a SetAlwaysRunPacket + - - The current value of the agent control flags - - - Gets or sets the interval in milliseconds at which - AgentUpdate packets are sent to the current simulator. Setting - this to a non-zero value will also enable the packet sending if - it was previously off, and setting it to zero will disable - - - Gets or sets whether AgentUpdate packets are sent to - the current simulator - - - Reset movement controls every time we send an update + + No flags set - - - 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 - + + Only return targets scripted objects - - + + Only return targets objects if on others land - - The camera is a local frame of reference inside of - the larger grid space. This is where the math happens + + Returns target's scripted objects and objects on other parcels - - - Default constructor - + + 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 - + - Called once attachment resource usage information has been collected + The number of returned items in LandStatReply - Indicates if operation was successfull - Attachment resource usage information - + - Contains all mesh faces that belong to a prim + A Dictionary of Object UUIDs to tasks returned in LandStatReply - - List of primitive faces + + Raised on LandStatReply when the report type is for "top Scripts" - - - 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 + + Construct a new instance of the TopScriptsReplyEventArgs class + The number of returned items in LandStatReply + Dictionary of Object UUIDs to tasks returned in LandStatReply - + - A set of textures that are layered on texture of each other and "baked" - in to a single texture, for avatar appearances + The number of scripts returned in LandStatReply - - Final baked texture - - - Component layers - - - Width of the final baked image and scratchpad + + + A Dictionary of Object UUIDs to tasks returned in LandStatReply + - - Height of the final baked image and scratchpad + + Returned, along with other info, upon a successful .RequestInfo() - - Bake type + + 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 - + - Default constructor + The identifier of the estate - Bake type - + - Adds layer for baking + The number of returned itmes - TexturaData struct that contains texture and its params - + - Converts avatar texture index (face) to Bake type + List of UUIDs of Banned Users - Face number (AvatarTextureIndex) - BakeType, layer to which this texture belongs to - + + 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 + + - Make sure images exist, resize source if needed to match the destination + The identifier of the estate - Destination image - Source image - Sanitization was succefull - + - Fills a baked layer as a solid *appearing* color. The colors are - subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from - compressing it too far since it seems to cause upload failures if - the image is a pure solid color + The number of returned items - Color of the base of this layer - + - Fills a baked layer as a solid *appearing* color. The colors are - subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from - compressing it too far since it seems to cause upload failures if - the image is a pure solid color + List of UUIDs of Allowed Users - Red value - 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 + + Returned, along with other info, upon a successful .RequestInfo() - - Is this one of the 3 skin bakes + + Construct a new instance of the EstateGroupsReplyEventArgs class + The estate's identifier on the grid + The number of Groups + Allowed Groups UUIDs - + - Represents a Wearable Asset, Clothing, Hair, Skin, Etc + The identifier of the estate - - A string containing the name of the asset + + + The number of returned items + - - A string containing a short description of the asset + + + List of UUIDs of Allowed Groups + - - The Assets WearableType + + Returned, along with other info, upon a successful .RequestInfo() - - The For-Sale status of the object + + Construct a new instance of the EstateManagersReplyEventArgs class + The estate's identifier on the grid + The number of Managers + Managers UUIDs - - An Integer representing the purchase price of the asset + + + The identifier of the estate + - - The of the assets creator + + + The number of returned items + - - The of the assets current owner + + + List of UUIDs of the Estate's Managers + - - The of the assets prior owner + + Returned, along with other info, upon a successful .RequestInfo() - - The of the Group this asset is set to + + 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) - - True if the asset is owned by a + + + The Covenant + - - The Permissions mask of the asset + + + The timestamp + - - A Dictionary containing Key/Value pairs of the objects parameters + + + The Estate name + - - A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures + + + The Estate Owner's ID (can be a GroupID) + - - Initializes a new instance of an AssetWearable object + + Returned, along with other info, upon a successful .RequestInfo() - - Initializes a new instance of an AssetWearable object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + 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 + - + - Decode an assets byte encoded data to a string + The estate's name - true if the asset data was decoded successfully - + - Encode the assets string represantion into a format consumable by the asset server + The Estate Owner's ID (can be a GroupID) - - Information about agents display name + + + The identifier of the estate on the grid + - - Agent UUID + + - - Username + + + Manager class for our own avatar + - - Display name + + The event subscribers. null if no subcribers - - First name (legacy) + + Raises the ChatFromSimulator event + A ChatEventArgs object containing the + data returned from the data server - - Last name (legacy) + + Thread sync lock object - - Is display name default display name + + The event subscribers. null if no subcribers - - Cache display name until + + Raises the ScriptDialog event + A SctriptDialogEventArgs object containing the + data returned from the data server - - Last updated timestamp - - - - Creates AgentDisplayName object from OSD - - Incoming OSD data - AgentDisplayName object - - - - Return object as OSD map - - OSD containing agent's display name data + + Thread sync lock object - - Full name (legacy) + + The event subscribers. null if no subcribers - - - Holds group information for Avatars such as those you might find in a profile - + + Raises the ScriptQuestion event + A ScriptQuestionEventArgs object containing the + data returned from the data server - - true of Avatar accepts group notices + + Thread sync lock object - - Groups Key + + The event subscribers. null if no subcribers - - Texture Key for groups insignia + + Raises the LoadURL event + A LoadUrlEventArgs object containing the + data returned from the data server - - Name of the group + + Thread sync lock object - - Powers avatar has in the group + + The event subscribers. null if no subcribers - - Avatars Currently selected title + + Raises the MoneyBalance event + A BalanceEventArgs object containing the + data returned from the data server - - true of Avatar has chosen to list this in their profile + + Thread sync lock object - - - Contains an animation currently being played by an agent - + + The event subscribers. null if no subcribers - - The ID of the animation asset + + Raises the MoneyBalanceReply event + A MoneyBalanceReplyEventArgs object containing the + data returned from the data server - - A number to indicate start order of currently playing animations - On Linden Grids this number is unique per region, with OpenSim it is per client + + Thread sync lock object - - + + The event subscribers. null if no subcribers - - - Holds group information on an individual profile pick - + + Raises the IM event + A InstantMessageEventArgs object containing the + data returned from the data server - - - Retrieve friend status notifications, and retrieve avatar names and - profiles - + + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarAnimation Event - An AvatarAnimationEventArgs object containing - the data sent from the simulator + + Raises the TeleportProgress event + A TeleportEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarAppearance Event - A AvatarAppearanceEventArgs object containing - the data sent from the simulator + + Raises the AgentDataReply event + A AgentDataReplyEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the UUIDNameReply Event - A UUIDNameReplyEventArgs object containing - the data sent from the simulator + + Raises the AnimationsChanged event + A AnimationsChangedEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarInterestsReply Event - A AvatarInterestsReplyEventArgs object containing - the data sent from the simulator + + Raises the MeanCollision event + A MeanCollisionEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarPropertiesReply Event - A AvatarPropertiesReplyEventArgs object containing - the data sent from the simulator + + Raises the RegionCrossed event + A RegionCrossedEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarGroupsReply Event - A AvatarGroupsReplyEventArgs object containing - the data sent from the simulator + + Raises the GroupChatJoined event + A GroupChatJoinedEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarPickerReply Event - A AvatarPickerReplyEventArgs object containing - the data sent from the simulator + + Raises the AlertMessage event + A AlertMessageEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the ViewerEffectPointAt Event - A ViewerEffectPointAtEventArgs object containing - the data sent from the simulator + + Raises the ScriptControlChange event + A ScriptControlEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the ViewerEffectLookAt Event - A ViewerEffectLookAtEventArgs object containing - the data sent from the simulator + + Raises the CameraConstraint event + A CameraConstraintEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the ViewerEffect Event - A ViewerEffectEventArgs object containing - the data sent from the simulator + + Raises the ScriptSensorReply event + A ScriptSensorReplyEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarPicksReply Event - A AvatarPicksReplyEventArgs object containing - the data sent from the simulator + + Raises the AvatarSitResponse event + A AvatarSitResponseEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the PickInfoReply Event - A PickInfoReplyEventArgs object containing - the data sent from the simulator + + Raises the ChatSessionMemberAdded event + A ChatSessionMemberAddedEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the AvatarClassifiedReply Event - A AvatarClassifiedReplyEventArgs object containing - the data sent from the simulator + + Raises the ChatSessionMemberLeft event + A ChatSessionMemberLeftEventArgs object containing the + data returned from the data server - + Thread sync lock object - + The event subscribers, null of no subscribers - - Raises the ClassifiedInfoReply Event - A ClassifiedInfoReplyEventArgs object containing + + Raises the SetDisplayNameReply Event + A SetDisplayNameReplyEventArgs object containing the data sent from the simulator - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the DisplayNameUpdate Event - A DisplayNameUpdateEventArgs object containing - the data sent from the simulator + + Raises the MuteListUpdated event + A EventArgs object containing the + data returned from the data server - + Thread sync lock object - + + Reference to the GridClient instance + + + Used for movement and camera tracking + + + Currently playing animations for the agent. Can be used to + check the current movement status such as walking, hovering, aiming, + etc. by checking against system animations found in the Animations class + + + Dictionary containing current Group Chat sessions and members + + + Dictionary containing mute list keyead on mute name and key + + + Various abilities and preferences sent by the grid + + - Represents other avatars + Constructor, setup callbacks for packets related to our avatar - + A reference to the Class - - Tracks the specified avatar on your map - Avatar ID to track + + + Send a text message from the Agent to the Simulator + + A containing the message + The channel to send the message on, 0 is the public channel. Channels above 0 + can be used however only scripts listening on the specified channel will see the message + Denotes the type of message being sent, shout, whisper, etc. - + - Request a single avatar name + Request any instant messages sent while the client was offline to be resent. - The avatar key to retrieve a name for - + - Request a list of avatar names + Send an Instant Message to another Avatar - The avatar keys to retrieve names for + The recipients + A containing the message to send - + - Check if Display Names functionality is available + Send an Instant Message to an existing group chat or conference chat - True if Display name functionality is available + The recipients + A containing the message to send + IM session ID (to differentiate between IM windows) - + - Request retrieval of display names (max 90 names per request) + Send an Instant Message - List of UUIDs to lookup - Callback to report result of the operation + The name this IM will show up as being from + Key of Avatar + Text message being sent + IM session ID (to differentiate between IM windows) + IDs of sessions for a conference - + - Start a request for Avatar Properties + Send an Instant Message - + The name this IM will show up as being from + Key of Avatar + Text message being sent + IM session ID (to differentiate between IM windows) + Type of instant message to send + Whether to IM offline avatars as well + Senders Position + RegionID Sender is In + Packed binary data that is specific to + the dialog type - + - Search for an avatar (first name, last name) + Send an Instant Message to a group - The name to search for - An ID to associate with this query + of the group to send message to + Text Message being sent. - + - Start a request for Avatar Picks + Send an Instant Message to a group the agent is a member of - UUID of the avatar + The name this IM will show up as being from + of the group to send message to + Text message being sent - + - Start a request for Avatar Classifieds + Send a request to join a group chat session - UUID of the avatar + of Group to leave - + - Start a request for details of a specific profile pick + Exit a group chat session. This will stop further Group chat messages + from being sent until session is rejoined. - UUID of the avatar - UUID of the profile pick + of Group chat session to leave - + - Start a request for details of a specific profile classified + Reply to script dialog questions. - UUID of the avatar - UUID of the profile classified + Channel initial request came on + Index of button you're "clicking" + Label of button you're "clicking" + of Object that sent the dialog request + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Accept invite for to a chatterbox session + + of session to accept invite to - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Start a friends conference + + List of UUIDs to start a conference with + the temportary session ID returned in the callback> - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Start a particle stream between an agent and an object + + Key of the source agent + Key of the target object + + The type from the enum + A unique for this effect - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Start a particle stream between an agent and an object + + Key of the source agent + Key of the target object + A representing the beams offset from the source + A which sets the avatars lookat animation + of the Effect - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Create a particle beam between an avatar and an primitive + + The ID of source avatar + The ID of the target primitive + global offset + A object containing the combined red, green, blue and alpha + color values of particle beam + a float representing the duration the parcicle beam will last + A Unique ID for the beam + - + - EQ Message fired when someone nearby changes their display name + Create a particle swirl around a target position using a packet - The message key - the IMessage object containing the deserialized data sent from the simulator - The which originated the packet + global offset + A object containing the combined red, green, blue and alpha + color values of particle beam + a float representing the duration the parcicle beam will last + A Unique ID for the beam - + - Crossed region handler for message that comes across the EventQueue. Sent to an agent - when the agent crosses a sim border into a new region. + Sends a request to sit on the specified object - The message key - the IMessage object containing the deserialized data sent from the simulator - The which originated the packet + of the object to sit on + Sit at offset - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Follows a call to to actually sit on the object + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Stands up from sitting on a prim or the ground + true of AgentUpdate was sent - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Does a "ground sit" at the avatar's current position + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Starts or stops flying + + True to start flying, false to stop flying - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Starts or stops crouching + + True to start crouching, false to stop crouching - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Starts a jump (begin holding the jump key) + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Use the autopilot sim function to move the avatar to a new + position. Uses double precision to get precise movements + + The z value is currently not handled properly by the simulator + Global X coordinate to move to + Global Y coordinate to move to + Z coordinate to move to - - Raised when the simulator sends us data containing - an agents animation playlist + + + Use the autopilot sim function to move the avatar to a new position + + The z value is currently not handled properly by the simulator + Integer value for the global X coordinate to move to + Integer value for the global Y coordinate to move to + Floating-point value for the Z coordinate to move to - - Raised when the simulator sends us data containing - the appearance information for an agent + + + Use the autopilot sim function to move the avatar to a new position + + The z value is currently not handled properly by the simulator + Integer value for the local X coordinate to move to + Integer value for the local Y coordinate to move to + Floating-point value for the Z coordinate to move to - - Raised when the simulator sends us data containing - agent names/id values + + Macro to cancel autopilot sim function + Not certain if this is how it is really done + true if control flags were set and AgentUpdate was sent to the simulator - - Raised when the simulator sends us data containing - the interests listed in an agents profile + + + Grabs an object + + an unsigned integer of the objects ID within the simulator + - - Raised when the simulator sends us data containing - profile property information for an agent + + + Overload: Grab a simulated object + + an unsigned integer of the objects ID within the simulator + + The texture coordinates to grab + The surface coordinates to grab + The face of the position to grab + The region coordinates of the position to grab + The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + The surface binormal of the position to grab (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space - - Raised when the simulator sends us data containing - the group membership an agent is a member of + + + Drag an object + + of the object to drag + Drag target in region coordinates - - Raised when the simulator sends us data containing - name/id pair + + + Overload: Drag an object + + of the object to drag + Drag target in region coordinates + + The texture coordinates to grab + The surface coordinates to grab + The face of the position to grab + The region coordinates of the position to grab + The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + The surface binormal of the position to grab (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space - - Raised when the simulator sends us data containing - the objects and effect when an agent is pointing at + + + Release a grabbed object + + The Objects Simulator Local ID + + + - - Raised when the simulator sends us data containing - the objects and effect when an agent is looking at + + + Release a grabbed object + + The Objects Simulator Local ID + The texture coordinates to grab + The surface coordinates to grab + The face of the position to grab + The region coordinates of the position to grab + The surface normal of the position to grab (A normal is a vector perpindicular to the surface) + The surface binormal of the position to grab (A binormal is a vector tangen to the surface + pointing along the U direction of the tangent space - - Raised when the simulator sends us data containing - an agents viewer effect information + + + Touches an object + + an unsigned integer of the objects ID within the simulator + - - Raised when the simulator sends us data containing - the top picks from an agents profile + + + Request the current L$ balance + - - Raised when the simulator sends us data containing - the Pick details + + + Give Money to destination Avatar + + UUID of the Target Avatar + Amount in L$ - - Raised when the simulator sends us data containing - the classified ads an agent has placed + + + Give Money to destination Avatar + + UUID of the Target Avatar + Amount in L$ + Description that will show up in the + recipients transaction history - - Raised when the simulator sends us data containing - the details of a classified ad + + + Give L$ to an object + + object to give money to + amount of L$ to give + name of object - - Raised when the simulator sends us data containing - the details of display name change + + + Give L$ to a group + + group to give money to + amount of L$ to give - + - Callback giving results when fetching display names + Give L$ to a group - If the request was successful - Array of display names - Array of UUIDs that could not be fetched + group to give money to + amount of L$ to give + description of transaction - - Provides data for the event - The event occurs when the simulator sends - the animation playlist for an agent - - The following code example uses the and - properties to display the animation playlist of an avatar on the window. - - // subscribe to the event - Client.Avatars.AvatarAnimation += Avatars_AvatarAnimation; - - private void Avatars_AvatarAnimation(object sender, AvatarAnimationEventArgs e) - { - // create a dictionary of "known" animations from the Animations class using System.Reflection - Dictionary<UUID, string> systemAnimations = new Dictionary<UUID, string>(); - Type type = typeof(Animations); - System.Reflection.FieldInfo[] fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); - foreach (System.Reflection.FieldInfo field in fields) - { - systemAnimations.Add((UUID)field.GetValue(type), field.Name); - } - - // find out which animations being played are known animations and which are assets - foreach (Animation animation in e.Animations) - { - if (systemAnimations.ContainsKey(animation.AnimationID)) - { - Console.WriteLine("{0} is playing {1} ({2}) sequence {3}", e.AvatarID, - systemAnimations[animation.AnimationID], animation.AnimationSequence); - } - else - { - Console.WriteLine("{0} is playing {1} (Asset) sequence {2}", e.AvatarID, - animation.AnimationID, animation.AnimationSequence); - } - } - } - - + + + Pay texture/animation upload fee + - + - Construct a new instance of the AvatarAnimationEventArgs class + Pay texture/animation upload fee - The ID of the agent - The list of animations to start + description of the transaction - - Get the ID of the agent + + + Give Money to destination Object or Avatar + + UUID of the Target Object/Avatar + Amount in L$ + Reason (Optional normally) + The type of transaction + Transaction flags, mostly for identifying group + transactions - - Get the list of animations to start + + + Plays a gesture + + Asset of the gesture - - 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") - } - - + + + Mark gesture active + + Inventory of the gesture + Asset of the gesture - + - Construct a new instance of the AvatarAppearanceEventArgs class + Mark gesture inactive - 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 + Inventory of the gesture - - Get the Simulator this request is from of the agent + + + Send an AgentAnimation packet that toggles a single animation on + + The of the animation to start playing + Whether to ensure delivery of this packet or not - - Get the ID of the agent + + + Send an AgentAnimation packet that toggles a single animation off + + The of a + currently playing animation to stop playing + Whether to ensure delivery of this packet or not - - true if the agent is a trial account + + + Send an AgentAnimation packet that will toggle animations on or off + + A list of animation s, and whether to + turn that animation on or off + Whether to ensure delivery of this packet or not - - Get the default agent texture + + + Teleports agent to their stored home location + + true on successful teleport to home location - - Get the agents appearance layer textures + + + Teleport agent to a landmark + + of the landmark to teleport agent to + true on success, false on failure - - Get the for the agent + + + Attempt to look up a simulator name and teleport to the discovered + destination + + Region name to look up + Position to teleport to + True if the lookup and teleport were successful, otherwise + false - - Version of the appearance system used. - Value greater than 0 indicates that server side baking is used + + + Attempt to look up a simulator name and teleport to the discovered + destination + + Region name to look up + Position to teleport to + Target to look at + True if the lookup and teleport were successful, otherwise + false - - Version of the Current Outfit Folder the appearance is based on + + + Teleport agent to another region + + handle of region to teleport agent to + position in destination sim to teleport to + true on success, false on failure + This call is blocking - - Appearance flags, introduced with server side baking, currently unused + + + Teleport agent to another region + + handle of region to teleport agent to + position in destination sim to teleport to + direction in destination sim agent will look at + true on success, false on failure + This call is blocking - - Represents the interests from the profile of an agent + + + Request teleport to a another simulator + + handle of region to teleport agent to + position in destination sim to teleport to - - Get the ID of the agent + + + Request teleport to a another simulator + + handle of region to teleport agent to + position in destination sim to teleport to + direction in destination sim agent will look at - - The properties of an agent + + + Teleport agent to a landmark + + of the landmark to teleport agent to - - Get the ID of the agent + + + Send a teleport lure to another avatar with default "Join me in ..." invitation message + + target avatars to lure - - Get the ID of the agent + + + Send a teleport lure to another avatar with custom invitation message + + target avatars to lure + custom message to send with invitation - - Get the ID of the agent + + + Respond to a teleport lure by either accepting it and initiating + the teleport, or denying it + + of the avatar sending the lure + IM session of the incoming lure request + true to accept the lure, false to decline it - - Get the ID of the avatar + + + Update agent profile + + struct containing updated + profile information - + - Event args class for display name notification messages + Update agents profile interests + selection of interests from struct - + - Index of TextureEntry slots for avatar appearances + Set the height and the width of the client window. This is used + by the server to build a virtual camera frustum for our avatar + New height of the viewer window + New width of the viewer window - + - Bake layers for avatar appearance + Request the list of muted objects and avatars for this agent - + - Appearance Flags, introdued with server side baking, currently unused + Mute an object, resident, etc. + Mute type + Mute UUID + Mute name - - Maximum number of concurrent downloads for wearable assets and textures + + + Mute an object, resident, etc. + + Mute type + Mute UUID + Mute name + Mute flags - - Maximum number of concurrent uploads for baked textures - - - Timeout for fetching inventory listings - - - Timeout for fetching a single wearable, or receiving a single packet response - - - Timeout for fetching a single texture - - - Timeout for uploading a single baked texture - - - Number of times to retry bake upload - - - When changing outfit, kick off rebake after - 20 seconds has passed since the last change - - - Total number of wearables for each avatar - - - Total number of baked textures on each avatar - - - 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 - - - Magic values to finalize the cache check hashes for each - bake - - - Default avatar texture, used to detect when a custom - texture is not set for a face - - - The event subscribers. null if no subcribers - - - Raises the AgentWearablesReply event - An AgentWearablesReplyEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the CachedBakesReply event - An AgentCachedBakesReplyEventArgs object containing the - data returned from the data server AgentCachedTextureResponse - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the AppearanceSet event - An AppearanceSetEventArgs object indicating if the operatin was successfull - - - Thread sync lock object - - - The event subscribers. null if no subcribers - - - Raises the RebakeAvatarRequested event - An RebakeAvatarTexturesEventArgs object containing the - data returned from the data server - - - Thread sync lock object - - - Visual parameters last sent to the sim - - - Textures about this client sent to the sim - - - A cache of wearables currently being worn - - - A cache of textures currently being worn - - - Incrementing serial number for AgentCachedTexture packets - - - Incrementing serial number for AgentSetAppearance packets - - - Indicates if WearablesRequest succeeded - - - Indicates whether or not the appearance thread is currently - running, to prevent multiple appearance threads from running - simultaneously - - - Reference to our agent - - + - Timer used for delaying rebake on changing outfit + Unmute an object, resident, etc. + Mute UUID + Mute name - + - Main appearance thread + Sets home location to agents current position + will fire an AlertMessage () with + success or failure message - + - Is server baking complete. It needs doing only once + Move an agent in to a simulator. This packet is the last packet + needed to complete the transition in to a new simulator + Object - + - Default constructor + Reply to script permissions request - A reference to our agent + Object + of the itemID requesting permissions + of the taskID requesting permissions + list of permissions to allow - + - Obsolete method for setting appearance. This function no longer does anything. - Use RequestSetAppearance() to manually start the appearance thread + Respond to a group invitation by either accepting or denying it + UUID of the group (sent in the AgentID field of the invite message) + IM Session ID from the group invitation message + Accept the group invitation or deny it - + - Obsolete method for setting appearance. This function no longer does anything. - Use RequestSetAppearance() to manually start the appearance thread + Requests script detection of objects and avatars - Unused parameter + name of the object/avatar to search for + UUID of the object or avatar to search for + Type of search from ScriptSensorTypeFlags + range of scan (96 max?) + the arc in radians to search within + an user generated ID to correlate replies with + Simulator to perform search in - + - Starts the appearance setting thread + Create or update profile pick + UUID of the pick to update, or random UUID to create a new pick + Is this a top pick? (typically false) + UUID of the parcel (UUID.Zero for the current parcel) + Name of the pick + Global position of the pick landmark + UUID of the image displayed with the pick + Long description of the pick - + - Starts the appearance setting thread + Delete profile pick - True to force rebaking, otherwise false + UUID of the pick to delete - + - Check if current region supports server side baking + Create or update profile Classified - True if server side baking support is detected + UUID of the classified to update, or random UUID to create a new classified + Defines what catagory the classified is in + UUID of the image displayed with the classified + Price that the classified will cost to place for a week + Global position of the classified landmark + Name of the classified + Long description of the classified + if true, auto renew classified after expiration - + - Ask the server what textures our agent is currently wearing + Create or update profile Classified + UUID of the classified to update, or random UUID to create a new classified + Defines what catagory the classified is in + UUID of the image displayed with the classified + Price that the classified will cost to place for a week + Name of the classified + Long description of the classified + if true, auto renew classified after expiration - + - Build hashes out of the texture assetIDs for each baking layer to - ask the simulator whether it has cached copies of each baked texture + Delete a classified ad + The classified ads ID - + - Returns the AssetID of the asset that is currently being worn in a - given WearableType slot + Fetches resource usage by agents attachmetns - WearableType slot to get the AssetID for - The UUID of the asset being worn in the given slot, or - UUID.Zero if no wearable is attached to the given slot or wearables - have not been downloaded yet + Called when the requested information is collected - + - Add a wearable to the current outfit and set appearance + Initates request to set a new display name - Wearable to be added to the outfit + Previous display name + Desired new display name - + - Add a wearable to the current outfit and set appearance + Tells the sim what UI language is used, and if it's ok to share that with scripts - Wearable to be added to the outfit - Should existing item on the same point or of the same type be replaced + Two letter language code + Share language info with scripts - + - Add a list of wearables to the current outfit and set appearance + Take an incoming ImprovedInstantMessage packet, auto-parse, and if + OnInstantMessage is defined call that with the appropriate arguments - List of wearable inventory items to - be added to the outfit - Should existing item on the same point or of the same type be replaced + The sender + The EventArgs object containing the packet data - + - Add a list of wearables to the current outfit and set appearance + Take an incoming Chat packet, auto-parse, and if OnChat is defined call + that with the appropriate arguments. - List of wearable inventory items to - be added to the outfit - Should existing item on the same point or of the same type be replaced + The sender + The EventArgs object containing the packet data - + - Remove a wearable from the current outfit and set appearance + Used for parsing llDialogs - Wearable to be removed from the outfit + The sender + The EventArgs object containing the packet data - + - Removes a list of wearables from the current outfit and set appearance + Used for parsing llRequestPermissions dialogs - List of wearable inventory items to - be removed from the outfit + The sender + The EventArgs object containing the packet data - + - Replace the current outfit with a list of wearables and set appearance + Handles Script Control changes when Script with permissions releases or takes a control - List of wearable inventory items that - define a new outfit + The sender + The EventArgs object containing the packet data - + - Replace the current outfit with a list of wearables and set appearance + Used for parsing llLoadURL Dialogs - List of wearable inventory items that - define a new outfit - Check if we have all body parts, set this to false only - if you know what you're doing + The sender + The EventArgs object containing the packet data - + - Checks if an inventory item is currently being worn + Update client's Position, LookAt and region handle from incoming packet - The inventory item to check against the agent - wearables - The WearableType slot that the item is being worn in, - or WearbleType.Invalid if it is not currently being worn + The sender + The EventArgs object containing the packet data + This occurs when after an avatar moves into a new sim - - - Returns a copy of the agents currently worn wearables - - A copy of the agents currently worn wearables - Avoid calling this function multiple times as it will make - a copy of all of the wearable data each time + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Calls either or - depending on the value of - replaceItems - - List of wearable inventory items to add - to the outfit or become a new outfit - True to replace existing items with the - new list of items, false to add these items to the existing outfit + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Adds a list of attachments to our agent - - A List containing the attachments to add - If true, tells simulator to remove existing attachment - first + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Adds a list of attachments to our agent + EQ Message fired with the result of SetDisplayName request - A List containing the attachments to add - If true, tells simulator to remove existing attachment - If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) - first + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - + - Attach an item to our agent at a specific attach point + Process TeleportFailed message sent via EventQueue, informs agent its last teleport has failed and why. - A to attach - the on the avatar - to attach the item to + The Message Key + An IMessage object Deserialized from the recieved message event + The simulator originating the event message - + - Attach an item to our agent at a specific attach point + Process TeleportFinish from Event Queue and pass it onto our TeleportHandler - A to attach - the on the avatar - If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) - to attach the item to + The message system key for this event + IMessage object containing decoded data from OSD + The simulator originating the event message - - - Attach an item to our agent specifying attachment details - - The of the item to attach - The attachments owner - The name of the attachment - The description of the attahment - The to apply when attached - The of the attachment - The on the agent - to attach the item to + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Attach an item to our agent specifying attachment details - - The of the item to attach - The attachments owner - The name of the attachment - The description of the attahment - The to apply when attached - The of the attachment - The on the agent - If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) - to attach the item to + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Detach an item from our agent using an object - - An object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Detach an item from our agent + Crossed region handler for message that comes across the EventQueue. Sent to an agent + when the agent crosses a sim border into a new region. - The inventory itemID of the item to detach + The message key + the IMessage object containing the deserialized data sent from the simulator + The which originated the packet - - - Inform the sim which wearables are part of our current outfit - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + This packet is now being sent via the EventQueue - + - Replaces the Wearables collection with a list of new wearable items + Group Chat event handler - Wearable items to replace the Wearables collection with + The capability Key + IMessage object containing decoded data from OSD + - + - Calculates base color/tint for a specific wearable - based on its params + Response from request to join a group chat - All the color info gathered from wearable's VisualParams - passed as list of ColorParamInfo tuples - Base color/tint for the wearable + + IMessage object containing decoded data from OSD + - + - Blocking method to populate the Wearables dictionary + Someone joined or left group chat - True on success, otherwise false + + IMessage object containing decoded data from OSD + - + - Blocking method to populate the Textures array with cached bakes + Handle a group chat Invitation - True on success, otherwise false + Caps Key + IMessage object containing decoded data from OSD + Originating Simulator - + - Populates textures and visual params from a decoded asset + Moderate a chat session - Wearable to decode + the of the session to moderate, for group chats this will be the groups UUID + the of the avatar to moderate + Either "voice" to moderate users voice, or "text" to moderate users text session + true to moderate (silence user), false to allow avatar to speak - - - Blocking method to download and parse currently worn wearable assets - - True on success, otherwise false + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Get a list of all of the textures that need to be downloaded for a - single bake layer - - Bake layer to get texture AssetIDs for - A list of texture AssetIDs to download + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Helper method to lookup the TextureID for a single layer and add it - to a list if it is not already present - - - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Blocking method to download all of the textures needed for baking - the given bake layers - - A list of layers that need baking - No return value is given because the baking will happen - whether or not all textures are successfully downloaded - - - - Blocking method to create and upload baked textures for all of the - missing bakes - - True on success, otherwise false + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Blocking method to create and upload a baked texture for a single - bake layer - - Layer to bake - True on success, otherwise false + + Raised when a scripted object or agent within range sends a public message - - - Blocking method to upload a baked texture - - Five channel JPEG2000 texture data to upload - UUID of the newly created asset on success, otherwise UUID.Zero + + Raised when a scripted object sends a dialog box containing possible + options an agent can respond to - - - Creates a dictionary of visual param values from the downloaded wearables - - A dictionary of visual param indices mapping to visual param - values for our agent that can be fed to the Baker class + + Raised when an object requests a change in the permissions an agent has permitted - - - Initate server baking process - - True if the server baking was successful + + Raised when a script requests an agent open the specified URL - - - Get the latest version of COF - - Current Outfit Folder (or null if getting the data failed) + + Raised when an agents currency balance is updated - - - Create an AgentSetAppearance packet from Wearables data and the - Textures array and send it - + + Raised when a transaction occurs involving currency such as a land purchase - - - Converts a WearableType to a bodypart or clothing WearableType - - A WearableType - AssetType.Bodypart or AssetType.Clothing or AssetType.Unknown + + 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 - - - Converts a BakeType to the corresponding baked texture slot in AvatarTextureIndex - - A BakeType - The AvatarTextureIndex slot that holds the given BakeType + + 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 - - - Gives the layer number that is used for morph mask - - >A BakeType - Which layer number as defined in BakeTypeToTextures is used for morph mask + + Raised when a simulator sends agent specific information for our avatar. - - - Converts a BakeType to a list of the texture slots that make up that bake - - A BakeType - A list of texture slots that are inputs for the given bake + + Raised when our agents animation playlist changes - - Triggered when an AgentWearablesUpdate packet is received, - telling us what our avatar is currently wearing - request. + + Raised when an object or avatar forcefully collides with our agent - - Raised when an AgentCachedTextureResponse packet is - received, giving a list of cached bakes that were found on the - simulator - request. + + Raised when our agent crosses a region border into another region - - - Raised when appearance data is sent to the simulator, also indicates - the main appearance thread is finished. - - request. + + Raised when our agent succeeds or fails to join a group chat session - - - Triggered when the simulator requests the agent rebake its appearance. - - + + 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 - - - Returns true if AppearanceManager is busy and trying to set or change appearance will fail - + + Raised when a script attempts to take or release specified controls for our agent - - - Contains information about a wearable inventory item - + + Raised when the simulator detects our agent is trying to view something + beyond its limits - - Inventory ItemID of the wearable + + Raised when a script sensor reply is received from a simulator - - AssetID of the wearable asset + + Raised in response to a request - - WearableType of the wearable + + Raised when an avatar enters a group chat session we are participating in - - AssetType of the wearable + + Raised when an agent exits a group chat session we are participating in - - Asset data for the wearable + + Raised when the simulator sends us data containing + the details of display name change - - - Data collected from visual params for each wearable - needed for the calculation of the color - + + Raised when a scripted object or agent within range sends a public message - - - 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 - + + Your (client) avatars + "client", "agent", and "avatar" all represent the same thing - - A texture AssetID + + Temporary assigned to this session, used for + verifying our identity in packets - - Asset data for the texture + + Shared secret that is never sent over the wire - - Collection of alpha masks that needs applying + + Your (client) avatar ID, local to the current region/sim - - Tint that should be applied to the texture + + Where the avatar started at login. Can be "last", "home" + or a login - - Where on avatar does this texture belong + + The access level of this agent, usually M or PG - - Contains the Event data returned from the data server from an AgentWearablesRequest + + The CollisionPlane of Agent - - Construct a new instance of the AgentWearablesReplyEventArgs class + + An representing the velocity of our agent - - Contains the Event data returned from the data server from an AgentCachedTextureResponse + + An representing the acceleration of our agent - - Construct a new instance of the AgentCachedBakesReplyEventArgs class + + A which specifies the angular speed, and axis about which an Avatar is rotating. - - Contains the Event data returned from an AppearanceSetRequest + + Position avatar client will goto when login to 'home' or during + teleport request to 'home' region. - - - Triggered when appearance data is sent to the sim and - the main appearance thread is done. - Indicates whether appearance setting was successful + + LookAt point saved/restored with HomePosition - - Indicates whether appearance setting was successful + + Avatar First Name (i.e. Philip) - - Contains the Event data returned from the data server from an RebakeAvatarTextures + + Avatar Last Name (i.e. Linden) - - - Triggered when the simulator sends a request for this agent to rebake - its appearance - - The ID of the Texture Layer to bake + + Avatar Full Name (i.e. Philip Linden) - - The ID of the Texture Layer to bake + + Gets the health of the agent - - - Image width - + + Gets the current balance of the agent - - - Image height - + + Gets the local ID of the prim the agent is sitting on, + zero if the avatar is not currently sitting - - - Image channel flags - + + Gets the of the agents active group. - - - Red channel data - + + Gets the Agents powers in the currently active group - - - Green channel data - + + Current status message for teleporting - - - Blue channel data - + + Current position of the agent as a relative offset from + the simulator, or the parent object if we are sitting on something - - - Alpha channel data - + + Current rotation of the agent as a relative rotation from + the simulator, or the parent object if we are sitting on something - - - Bump channel data - + + Current position of the agent in the simulator - + - Create a new blank image + A representing the agents current rotation - width - height - channel flags - - - - - + + Returns the global grid position of the avatar - + - Convert the channels in the image. Channels are created or destroyed as required. + Used to specify movement actions for your agent - new channel flags - - - Resize or stretch the image using nearest neighbor (ugly) resampling - - new width - new height + + Empty flag - - - Create a byte array containing 32-bit RGBA data with a bottom-left - origin, suitable for feeding directly into OpenGL - - A byte array containing raw texture data + + Move Forward (SL Keybinding: W/Up Arrow) - - - Represents an Animation - + + Move Backward (SL Keybinding: S/Down Arrow) - - Default Constructor + + Move Left (SL Keybinding: Shift-(A/Left Arrow)) - - - Construct an Asset object of type Animation - - Asset type - A unique specific to this asset - A byte array containing the raw asset data + + Move Right (SL Keybinding: Shift-(D/Right Arrow)) - - Override the base classes AssetType + + Not Flying: Jump/Flying: Move Up (SL Keybinding: E) - - - - + + Not Flying: Croutch/Flying: Move Down (SL Keybinding: C) - - + + Unused - - + + Unused - - + + Unused - - - Thrown when a packet could not be successfully deserialized - + + Unused - - - Default constructor - + + ORed with AGENT_CONTROL_AT_* if the keyboard is being used - - - Constructor that takes an additional error message - - An error message to attach to this exception + + ORed with AGENT_CONTROL_LEFT_* if the keyboard is being used - - - The header of a message template packet. Holds packet flags, sequence - number, packet ID, and any ACKs that will be appended at the end of - the packet - + + ORed with AGENT_CONTROL_UP_* if the keyboard is being used - - - Convert the AckList to a byte array, used for packet serializing - - Reference to the target byte array - Beginning position to start writing to in the byte - array, will be updated with the ending position of the ACK list + + Fly - - - - - - - - + + - - - - - - - + + Finish our current animation - - - A block of data in a packet. Packets are composed of one or more blocks, - each block containing one or more fields - + + Stand up from the ground or a prim seat - - - Create a block from a byte array - - Byte array containing the serialized block - Starting position of the block in the byte array. - This will point to the data after the end of the block when the - call returns + + Sit on the ground at our current location - - - Serialize this block into a byte array - - Byte array to serialize this block into - Starting position in the byte array to serialize to. - This will point to the position directly after the end of the - serialized block when the call returns + + Whether mouselook is currently enabled - - Current length of the data in this packet + + Legacy, used if a key was pressed for less than a certain amount of time - - A generic value, not an actual packet type + + Legacy, used if a key was pressed for less than a certain amount of time - - - Attempts to convert an LLSD structure to a known Packet type - - Event name, this must match an actual - packet name for a Packet to be successfully built - LLSD to convert to a Packet - A Packet on success, otherwise null + + Legacy, used if a key was pressed for less than a certain amount of time - - + + Legacy, used if a key was pressed for less than a certain amount of time - - + + Legacy, used if a key was pressed for less than a certain amount of time - - + + Legacy, used if a key was pressed for less than a certain amount of time - - + + - - + + - - + + Set when the avatar is idled or set to away. Note that the away animation is + activated separately from setting this flag - - + + - - + + - - + + - - + + - - + + + Agent movement and camera control + + Agent movement is controlled by setting specific + After the control flags are set, An AgentUpdate is required to update the simulator of the specified flags + This is most easily accomplished by setting one or more of the AgentMovement properties + + Movement of an avatar is always based on a compass direction, for example AtPos will move the + agent from West to East or forward on the X Axis, AtNeg will of course move agent from + East to West or backward on the X Axis, LeftPos will be South to North or forward on the Y Axis + 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 + - - + + + 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 - - + + Move agent positive along the X axis - - + + Move agent negative along the X axis - - + + Move agent positive along the Y axis - - + + Move agent negative along the Y axis - - + + Move agent positive along the Z axis - - + + Move agent negative along the Z axis - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + Causes simulator to make agent fly - - + + Stop movement - - + + Finish animation - - + + Stand up from a sit - - + + Tells simulator to sit agent on ground - - + + Place agent into mouselook mode - - + + Nudge agent positive along the X axis - - + + Nudge agent negative along the X axis - - + + Nudge agent positive along the Y axis - - + + Nudge agent negative along the Y axis - - + + Nudge agent positive along the Z axis - - + + Nudge agent negative along the Z axis - - + + - - - - - + + - - + + Tell simulator to mark agent as away - - + + - - + + - - + + - - + + - - + + + Returns "always run" value, or changes it by sending a SetAlwaysRunPacket + - - + + The current value of the agent control flags - - + + Gets or sets the interval in milliseconds at which + AgentUpdate packets are sent to the current simulator. Setting + this to a non-zero value will also enable the packet sending if + it was previously off, and setting it to zero will disable - - + + Gets or sets whether AgentUpdate packets are sent to + the current simulator - - + + Reset movement controls every time we send an update - - + + + 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 + - - + + - - + + The camera is a local frame of reference inside of + the larger grid space. This is where the math happens - - + + + Default constructor + - - + + - - + + - - + + - - + + - - + + + Called once attachment resource usage information has been collected + + Indicates if operation was successfull + Attachment resource usage information - - + + + Represents an that can be worn on an avatar + such as a Shirt, Pants, etc. + - - + + + Represents a Wearable Asset, Clothing, Hair, Skin, Etc + - - + + A string containing the name of the asset - - + + A string containing a short description of the asset - - + + The Assets WearableType - - + + The For-Sale status of the object - - + + An Integer representing the purchase price of the asset - - + + The of the assets creator - - + + The of the assets current owner - - + + The of the assets prior owner - - + + The of the Group this asset is set to - - + + True if the asset is owned by a - - + + The Permissions mask of the asset - - + + A Dictionary containing Key/Value pairs of the objects parameters - - + + A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures - - + + Initializes a new instance of an AssetWearable object - - + + Initializes a new instance of an AssetWearable object with parameters + A unique specific to this asset + A byte array containing the raw asset data - - + + + Decode an assets byte encoded data to a string + + true if the asset data was decoded successfully - - + + + Encode the assets string represantion into a format consumable by the asset server + - - + + 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 - - + + + + - - + + - - + + - - + + - - + + + Thrown when a packet could not be successfully deserialized + - - + + + Default constructor + - - + + + Constructor that takes an additional error message + + An error message to attach to this exception - - + + + The header of a message template packet. Holds packet flags, sequence + number, packet ID, and any ACKs that will be appended at the end of + the packet + - - + + + Convert the AckList to a byte array, used for packet serializing + + Reference to the target byte array + Beginning position to start writing to in the byte + array, will be updated with the ending position of the ACK list - - + + + + + + + + - - + + + + + + + - - + + + A block of data in a packet. Packets are composed of one or more blocks, + each block containing one or more fields + - - + + + Create a block from a byte array + + Byte array containing the serialized block + Starting position of the block in the byte array. + This will point to the data after the end of the block when the + call returns - - + + + Serialize this block into a byte array + + Byte array to serialize this block into + Starting position in the byte array to serialize to. + 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 - - + + + Attempts to convert an LLSD structure to a known Packet type + + Event name, this must match an actual + packet name for a Packet to be successfully built + LLSD to convert to a Packet + A Packet on success, otherwise null - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - 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. + + - - - Add a custom decoder callback - - The key of the field to decode - The custom decode handler + + - - - Remove a custom decoder callback - - The key of the field to decode - The custom decode handler + + - - - Creates a formatted string containing the values of a Packet - - The Packet - A formatted string of values of the nested items in the Packet object + + - - - Decode an IMessage object into a beautifully formatted string - - The IMessage object - 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 + + - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - 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 + + - - 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 + + + Add a custom decoder callback + + The key of the field to decode + The custom decode handler - - Raises the SimDisconnected Event - A SimDisconnectedEventArgs object containing - the data sent from the simulator + + + Remove a custom decoder callback + + The key of the field to decode + The custom decode handler - + + + Creates a formatted string containing the values of a Packet + + The Packet + A formatted string of values of the nested items in the Packet object + + + + Decode an IMessage object into a beautifully formatted string + + The IMessage object + 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 + + + + 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 of no subscribers + + The event subscribers. null if no subcribers - - Raises the Disconnected Event - A DisconnectedEventArgs object containing - the data sent from the simulator + + Raises the DirEventsReply event + An DirEventsReplyEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the SimChanged Event - A SimChangedEventArgs object containing - the data sent from the simulator + + Raises the PlacesReply event + A PlacesReplyEventArgs object containing the + data returned from the data server - + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - - Raises the EventQueueRunning Event - A EventQueueRunningEventArgs object containing - the data sent from the simulator + + Raises the DirPlacesReply event + A DirPlacesReplyEventArgs object containing the + data returned from the data server - + Thread sync lock object - - All of the simulators we are currently connected to + + The event subscribers. null if no subcribers - - Handlers for incoming capability events + + Raises the DirClassifiedsReply event + A DirClassifiedsReplyEventArgs object containing the + data returned from the data server - - Handlers for incoming packets + + Thread sync lock object - - Incoming packets that are awaiting handling + + The event subscribers. null if no subcribers - - Outgoing packets that are awaiting handling + + Raises the DirGroupsReply event + A DirGroupsReplyEventArgs object containing the + data returned from the data server - - - Default constructor - - Reference to the GridClient object + + Thread sync lock 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 + + The event subscribers. null if no subcribers - - - 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 + + Raises the DirPeopleReply event + A DirPeopleReplyEventArgs object containing the + data returned from the data server - - - 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 + + Thread sync lock object - - - 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 + + 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 + + - 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 + Constructs a new instance of the DirectoryManager class - Name of the CAPS event this callback is - registered with - Callback to stop firing events for + An instance of GridClient - + - Send a packet to the simulator the avatar is currently occupying + 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 - Packet to send + A string containing a list of keywords to search for + A UUID to correlate the results when the event is raised - + - Send a packet to a specified simulator + 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 - Packet to send - Simulator to send the packet to + 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 + - + - Connect to a simulator + Starts search for places (Overloaded) + + The event is raised when a response is received from the 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 + 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 - + - Connect to a simulator + 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 - 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 + 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 + - + - 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 + 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. - + - 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 + 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. - + - Close a connection to the given simulator + 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); + - + - 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 + Search for Groups - Type of shutdown + The name or portion of the name of the group you wish to search for + Start from the match number + - + - 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 + Search for Groups - Type of shutdown - Shutdown message + The name or portion of the name of the group you wish to search for + Start from the match number + Search flags + - + - Searches through the list of currently connected simulators to find - one attached to the given IPEndPoint + Search the People directory for other avatars - IPEndPoint of the Simulator to search for - A Simulator reference on success, otherwise null + The name or portion of the name of the avatar you wish to search for + + - + - Fire an event when an event queue connects for capabilities + Search Places for parcels of land you personally own - Simulator the event queue is attached to - + + + 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 - - 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 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Current state of logging in + + Raised when the data server responds to a request. - - Upon login failure, contains a short string key for the - type of login error that occurred + + Raised when the data server responds to a request. - - The raw XML-RPC reply from the login server, exactly as it - was received (minus the HTTP header) + + Raised when the data server responds to a request. - - 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 data server responds to a request. - - Raised when the simulator sends us data containing - ... + + Raised when the data server responds to a request. - - Raised when the simulator sends us data containing - ... + + Raised when the data server responds to a request. - - Raised when the simulator sends us data containing - ... + + Raised when the data server responds to a request. - - Raised when the simulator sends us data containing - ... + + Raised when the data server responds to a request. - - Raised when the simulator sends us data containing - ... + + Classified Ad categories - - Raised when the simulator sends us data containing - ... + + Classified is listed in the Any category - - Raised when the simulator sends us data containing - ... + + Classified is shopping related - - Unique identifier associated with our connections to - simulators + + Classified is - - 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 + + Event Categories - - 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 + + - + - Return a decoded capabilities message as a strongly typed object + 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 - A string containing the name of the capabilities message key - An to decode - A strongly typed object containing the decoded information from the capabilities message, or null - if no existing Message object exists for the specified event - - - Capability to load TGAs to Bitmap - + + Query the People database - - - 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 + + Query the Groups database - - - InventoryManager requests inventory information on login, - GridClient initializes an Inventory store for main inventory. - + + Query the Events database - - - InventoryManager requests library information on login, - GridClient initializes an Inventory store for the library. - + + Query the land holdings database for land owned by the currently connected agent - - Number of milliseconds between sending pings to each sim + + - - Number of milliseconds between sending camera updates + + Query the land holdings database for land which is owned by a Group - - Number of milliseconds between updating the current - positions of moving, non-accelerating and non-colliding objects + + Specifies the query should pre sort the results based upon traffic + when searching the Places database - - 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 + + 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 - - Login server to connect to + + 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 - - IP Address the client will bind to + + 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 - - Use XML-RPC Login or LLSD Login, default is XML-RPC Login + + 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 - - - Use Caps for fetching inventory where available - + + 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 - - Number of milliseconds before an asset transfer will time - out + + 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 - - Number of milliseconds before a teleport attempt will time - out + + 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 - - 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 + + Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases - - Milliseconds before a packet is assumed lost and resent + + Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases - - Milliseconds without receiving a packet before the - connection to a simulator is assumed lost + + Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases - - 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 + + + Land types to search dataserver for + - - Maximum number of queued ACKs to be sent before SendAcks() - is forced + + Search Auction, Mainland and Estate - - Network stats queue length (seconds) + + Land which is currently up for auction - - - 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 - + + Parcels which are on the mainland (Linden owned) continents - - - Pool parcel data between clients (saves on requesting multiple times when all clients may need it) - + + Parcels which are on privately owned simulators - + - 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 + The content rating of the event - - 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 + + Event is PG - - 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 + + Event is Mature - - Enable/disable the sending of pings to monitor lag and - packet loss + + Event is Adult - - Should we connect to multiple sims? This will allow - viewing in to neighboring simulators and sim crossings - (Experimental) + + + Classified Ad Options + + There appear to be two formats the flags are packed in. + This set of flags is for the newer style - - 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 + + + Classified ad query options + - - If true, and SEND_AGENT_UPDATES is true, - AgentUpdate packets will continuously be sent out to give the bot - smoother movement and autopiloting + + Include all ads in results - - 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 + + Include PG ads in results - - 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 + + Include Mature ads in results - - 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 + + Include Adult ads in results - + - If true, utilization statistics will be tracked. There is a minor penalty - in CPU time for enabling this option. + The For Sale flag in PlacesReplyData - - If true, parcel details will be stored in the - Simulator.Parcels dictionary as they are received + + Parcel is not listed for sale - - - If true, an incoming parcel properties reply will automatically send - a request for the parcel access list - + + Parcel is For Sale - + - if true, an incoming parcel properties reply will automatically send - a request for the traffic count. + A classified ad on the grid - - - If true, images, and other assets downloaded from the server - will be cached in a local directory - + + UUID for this ad, useful for looking up detailed + information about it - - Path to store cached texture data + + The title of this classified ad - - Maximum size cached files are allowed to take on disk (bytes) + + Flags that show certain options applied to the classified - - Default color used for viewer particle effects + + Creation date of the ad - - Maximum number of times to resend a failed packet + + Expiration date of the ad - - Throttle outgoing packet rate + + Price that was paid for this ad - - UUID of a texture used by some viewers to indentify type of client used + + Print the struct data as a string + A string containing the field name, and field value - + - Download textures using GetTexture capability when available + A parcel retrieved from the dataserver such as results from the + "For-Sale" listings or "Places" Search - - 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 + + The unique dataserver parcel ID + This id is used to obtain additional information from the entry + by using the method - - - Textures taking longer than this value will be flagged as timed out and removed from the pipeline - + + A string containing the name of the parcel - - - 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 + + The size of the parcel + This field is not returned for Places searches - - Log packet retransmission info + + The price of the parcel + This field is not returned for Places searches - - Log disk cache misses and other info + + If True, this parcel is flagged to be auctioned - - Constructor - Reference to a GridClient object + + If true, this parcel is currently set for sale - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Parcel traffic - - Cost of uploading an asset - Read-only since this value is dynamically fetched at login + + Print the struct data as a string + A string containing the field name, and field value - + - 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. - + An Avatar returned from the dataserver - Key - Value - - Internal dictionary that this class wraps around. Do not - modify or enumerate the contents of this dictionary without locking - on this member + + Online status of agent + This field appears to be obsolete and always returns false - - - 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>(); - - + + The agents first name - - - 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); - - + + The agents last name - - - 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); - - + + The agents - - - 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); - - - + + Print the struct data as a string + A string containing the field name, and field value - + - Finds the specified match. + Response to a "Groups" Search - 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)); - } - ); - - + + The Group ID - - 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); - } - ); - - + + The name of the group - - 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); - } - }); - - + + The current number of members - - Perform an on each key of an - to perform + + Print the struct data as a string + A string containing the field name, and field value - + - Perform an on each KeyValuePair of an + 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 - to perform - - Check if Key exists in Dictionary - Key to check for - if found, otherwise + + The ID of the Agent of Group that owns the parcel - - Check if Value exists in Dictionary - Value to check for - if found, otherwise + + The name - - - Adds the specified key to the dictionary, dictionary locking is not performed, - - - The key - The value + + The description - - - Removes the specified key, dictionary locking is not performed - - The key. - if successful, otherwise + + The Size of the parcel - - - Gets the number of Key/Value pairs contained in the - + + 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 - - - Indexer for the dictionary - - The key - The value + + Indicates the ForSale status of the parcel - - - Avatar profile flags - + + The Gridwide X position - - - Represents an avatar (other than your own) - + + The Gridwide Y position - - - Particle system specific enumerators, flags and methods. - + + 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 + - - Foliage type for this primitive. Only applicable if this - primitive is foliage + + The ID of the event creator - - Unknown + + 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 - - Identifies the owner if audio or a particle system is - active + + 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 - - Objects physics engine propertis + + The ID returned by - - Extra data about primitive + + A list of "Events" returned by the data server - - Indicates if prim is attached to an avatar + + Contains the "Event" list data returned from the data server - - Number of clients referencing this prim + + 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 - - - Default constructor - + + The ID returned by - - - 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 + + A list of "Places" returned by the data server - - - 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 + + Contains the places data returned from the data server - - - Current version of the media data for the prim - + + 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 - - - Array of media entries indexed by face number - + + The ID returned by - - + + A list containing Places data returned by the data server - - Uses basic heuristics to estimate the primitive shape + + Contains the classified data returned from the data server - - - Texture animation mode - + + Construct a new instance of the DirClassifiedsReplyEventArgs class + A list of classified ad data returned from the data server - - Disable texture animation + + A list containing Classified Ads returned by the data server - - Enable texture animation + + Contains the group data returned from the data server - - Loop when animating textures + + 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 - - Animate in reverse direction + + The ID returned by - - Animate forward then reverse + + A list containing Groups data returned by the data server - - Slide texture smoothly instead of frame-stepping + + Contains the people data returned from the data server - - Rotate texture instead of using frames + + 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 - - Scale texture instead of using frames + + 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 + + - A single textured face. Don't instantiate this class yourself, use the - methods in TextureEntry + Interface requirements for Messaging system - + - Contains the definition for individual faces + Image width - - + - + Image height - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - In the future this will specify whether a webpage is - attached to this face - - - - - - - + - Represents all of the texturable faces for an object + Image channel flags - 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 - - + + + Red channel data + - - + + + Green channel data + - + - Constructor that takes a default texture UUID + Blue channel data - Texture UUID to use as the default texture - + - Constructor that takes a TextureEntryFace for the - default face + Alpha channel data - Face to use as the default face - + - Constructor that creates the TextureEntry class from a byte array + Bump channel data - 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 + Create a new blank image - The index number of the face to create or - retrieve - A TextureEntryFace containing all the properties for that - face + width + height + channel flags - + - - + - + - + Convert the channels in the image. Channels are created or destroyed as required. - + new channel flags - + - + Resize or stretch the image using nearest neighbor (ugly) resampling - + new width + new height - + - + Create a byte array containing 32-bit RGBA data with a bottom-left + origin, suitable for feeding directly into OpenGL - + A byte array containing raw texture data - + - Controls the texture animation of a particular prim + 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 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 - - + - Parameters used to construct a visual representation of a primitive + 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 - - + + + + - - + + + 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 + + + - - + + + 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 - + - Calculdates hash code for prim construction data + 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 has - - - Attachment point to an avatar - - - + 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 - - - Information on the flexible properties of a primitive - + + 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 + 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 - + - Information on the light properties of a primitive + 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 - - - - - - - - - - - - - - - - + - Default constructor + 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 - + - Information on the light properties of a primitive as texture map + 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 - + - Default constructor + 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. + + + 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 - + - Information on the sculpt properties of a sculpted primitive + Object pool for packet buffers. This is used to allocate memory for all + incoming and outgoing packets, and zerocoding buffers for those packets - + - Default constructor + 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. - + - Render inside out (inverts the normals). + Forces the segment cleanup algorithm to be run. This method is intended + primarly for use from the Unit Test libraries. - + - Render an X axis mirror of the sculpty. + Responsible for allocate 1 instance of an object that will be stored in a segment. + An instance of whatever objec the pool is pooling. - + - Extended properties to describe an object + 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 + + + - + - Default constructor + 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 - + - Set the properties that are set in an ObjectPropertiesFamily packet + Default constructor - that has - been partially filled by an ObjectPropertiesFamily packet - + - Describes physics attributes of the prim + Check a packet buffer out of the pool + A packet buffer object - - 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 + + + Singleton logging class for the entire library + - - Restitution + + log4net logging engine - + - Creates PhysicsProperties from OSD + Default constructor - OSDMap with incoming data - Deserialized PhysicsProperties object - + - Serializes PhysicsProperties to OSD + Send a log message to the logging engine - OSDMap with serialized PhysicsProperties data + The log message + The severity of the log entry - + - Complete structure for the particle system + Send a log message to the logging engine + The log message + The severity of the log entry + Instance of the client - - 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 + + + Send a log message to the logging engine + + The log message + The severity of the log entry + Exception that was raised - - pattern of particles + + + 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 - - A representing the maximimum age (in seconds) particle will be displayed - Maximum value is 30 seconds + + + 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 - - 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 + + + 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 - - A in radians that specifies where particles will not be created + + Triggered whenever a message is logged. If this is left + null, log messages will go to the console - - A in radians that specifies where particles will be created + + + Callback used for client apps to receive log messages from + the library + + Data being logged + The severity of the log entry from - - 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. + + The avatar has no rights - - A representing in seconds, the minimum speed between bursts of new particles - being emitted + + The avatar can see the online status of the target avatar - - A representing in seconds the maximum speed of new particles being emitted. + + The avatar can see the location of the target avatar on the map - - A representing the maximum number of particles emitted per burst + + The avatar can modify the ojects of the target avatar - - A which represents the velocity (speed) from the source which particles are emitted + + + 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 + - - A which represents the Acceleration from the source which particles are emitted + + + 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 - - The Key of the texture displayed on the particle + + + FriendInfo represented as a string + + A string reprentation of both my rights and my friends rights - - The Key of the specified target object or avatar particles will follow + + + System ID of the avatar + - - Flags of particle from + + + full name of the avatar + - - Max Age particle system will emit particles for + + + True if the avatar is online + - - The the particle has at the beginning of its lifecycle + + + True if the friend can see if I am online + - - The the particle has at the ending of its lifecycle + + + True if the friend can see me on the map + - - A that represents the starting X size of the particle - Minimum value is 0, maximum value is 4 + + + True if the freind can modify my objects + - - A that represents the starting Y size of the particle - Minimum value is 0, maximum value is 4 + + + True if I can see if my friend is online + - - A that represents the ending X size of the particle - Minimum value is 0, maximum value is 4 + + + True if I can see if my friend is on the map + - - A that represents the ending Y size of the particle - Minimum value is 0, maximum value is 4 + + + True if I can modify my friend's objects + - + - Decodes a byte[] array into a ParticleSystem Object + My friend's rights represented as bitmapped flags - ParticleSystem object - Start position for BitPacker - + - Generate byte[] array from particle data + My rights represented as bitmapped flags - Byte array - + - Particle source pattern + This class is used to add and remove avatars from your friends list and to manage their permission. - - None + + The event subscribers. null if no subcribers - - Drop particles from source position with no force + + Raises the FriendOnline event + A FriendInfoEventArgs object containing the + data returned from the data server - - "Explode" particles in all directions + + Thread sync lock object - - Particles shoot across a 2D area + + The event subscribers. null if no subcribers - - Particles shoot across a 3D Cone + + Raises the FriendOffline event + A FriendInfoEventArgs object containing the + data returned from the data server - - Inverse of AngleCone (shoot particles everywhere except the 3D cone defined + + Thread sync lock object - - - Particle Data Flags - - - - None - - - Interpolate color and alpha from start to end - - - Interpolate scale from start to end + + The event subscribers. null if no subcribers - - Bounce particles off particle sources Z height + + Raises the FriendRightsUpdate event + A FriendInfoEventArgs object containing the + data returned from the data server - - velocity of particles is dampened toward the simulators wind + + Thread sync lock object - - Particles follow the source + + The event subscribers. null if no subcribers - - Particles point towards the direction of source's velocity + + Raises the FriendNames event + A FriendNamesEventArgs object containing the + data returned from the data server - - Target of the particles + + Thread sync lock object - - Particles are sent in a straight line + + The event subscribers. null if no subcribers - - Particles emit a glow + + Raises the FriendshipOffered event + A FriendshipOfferedEventArgs object containing the + data returned from the data server - - used for point/grab/touch + + Thread sync lock object - - - Particle Flags Enum - + + The event subscribers. null if no subcribers - - None + + Raises the FriendshipResponse event + A FriendshipResponseEventArgs object containing the + data returned from the data server - - Acceleration and velocity for particles are - relative to the object rotation + + Thread sync lock object - - Particles use new 'correct' angle parameters + + The event subscribers. null if no subcribers - - Groups that this avatar is a member of + + Raises the FriendshipTerminated event + A FriendshipTerminatedEventArgs object containing the + data returned from the data server - - Positive and negative ratings + + Thread sync lock object - - Avatar properties including about text, profile URL, image IDs and - publishing settings + + The event subscribers. null if no subcribers - - Avatar interests including spoken languages, skills, and "want to" - choices + + Raises the FriendFoundReply event + A FriendFoundReplyEventArgs object containing the + data returned from the data server - - Movement control flags for avatars. Typically not set or used by - clients. To move your avatar, use Client.Self.Movement instead + + Thread sync lock object - + - Contains the visual parameters describing the deformation of the avatar + 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 - + - Appearance version. Value greater than 0 indicates using server side baking + 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 - + - Version of the Current Outfit Folder that the appearance is based on + Internal constructor + A reference to the GridClient Object - + - Appearance flags. Introduced with server side baking, currently unused. + Accept a friendship request + agentID of avatatar to form friendship with + imSessionID of the friendship request message - + - List of current avatar animations + Decline a friendship request + of friend + imSessionID of the friendship request message - + - Default constructor + Overload: Offer friendship to an avatar. + System ID of the avatar you are offering friendship to - - First name - - - Last name + + + Offer friendship to an avatar. + + System ID of the avatar you are offering friendship to + A message to send with the request - - Full name + + + Terminate a friendship with an avatar + + System ID of the avatar you are terminating the friendship with - - Active group + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Positive and negative ratings + 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. - - Positive ratings for Behavior + + + Use to map a friends location on the grid. + + Friends UUID to find + - - Negative ratings for Behavior + + + Use to track a friends movement on the grid + + Friends Key - - Positive ratings for Appearance + + + Ask for a notification of friend's online status + + Friend's UUID - - Negative ratings for Appearance + + + This handles the asynchronous response of a RequestAvatarNames call. + + + names cooresponding to the the list of IDs sent the the RequestAvatarNames call. - - Positive ratings for Building + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Negative ratings for Building + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Positive ratings given by this avatar + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Negative ratings given by this avatar + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Avatar properties including about text, profile URL, image IDs and - publishing settings + 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 - - First Life about text - - - First Life image ID + + 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 - - Profile image ID - - - Flags of the profile + + Raised when a request we sent to friend another agent is accepted or declined - - Web URL for this profile + + Raised when the simulator sends notification one of the members in our friends list has terminated + our friendship - - Should this profile be published on the web + + Raised when the simulator sends the location of a friend we have + requested map location info for - - Avatar Online Status + + Contains information on a member of our friends list - - Is this a mature profile + + + Construct a new instance of the FriendInfoEventArgs class + + The FriendInfo - - + + Get the FriendInfo - - + + Contains Friend Names - + - Avatar interests including spoken languages, skills, and "want to" - choices + 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 - - Languages profile field + + 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 - - - Throttles the network traffic for various different traffic types. - Access this class through GridClient.Throttle - + + 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 + + - Default constructor, uses a default high total of 1500 KBps (1536000) + 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 + + - Constructor that decodes an existing AgentThrottle packet in to - individual values + Construct a new instance of the FrindshipTerminatedEventArgs class - Reference to the throttle data in an AgentThrottle - packet - Offset position to start reading at in the - throttle data - This is generally not needed in clients as the server will - never send a throttle packet to the client + 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 + + - Send an AgentThrottle packet to the current server using the - current values + Data sent in response to a request which contains the information to allow us to map the friends location - + - Send an AgentThrottle packet to the specified server using the - current values + 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 + + - Convert the current throttle values to a byte array that can be put - in an AgentThrottle packet + Static pre-defined animations available to all agents - Byte array containing all the throttle values - - Maximum bits per second for resending unacknowledged packets + + Agent with afraid expression on face - - Maximum bits per second for LayerData terrain + + Agent aiming a bazooka (right handed) - - Maximum bits per second for LayerData wind data + + Agent aiming a bow (left handed) - - Maximum bits per second for LayerData clouds + + Agent aiming a hand gun (right handed) - - Unknown, includes object data + + Agent aiming a rifle (right handed) - - Maximum bits per second for textures + + Agent with angry expression on face - - Maximum bits per second for downloaded assets + + Agent hunched over (away) - - Maximum bits per second the entire connection, divided up - between invidiual streams using default multipliers + + Agent doing a backflip - - = + + Agent laughing while holding belly - - Number of times we've received an unknown CAPS exception in series. + + Agent blowing a kiss - - For exponential backoff on error. + + Agent with bored expression on face - - - Represents Mesh asset - + + Agent bowing to audience - - - Decoded mesh data - + + Agent brushing himself/herself off - - Initializes a new instance of an AssetMesh object + + Agent in busy mode - - Initializes a new instance of an AssetMesh object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + Agent clapping hands - - - TODO: Encodes Collada file into LLMesh format - + + Agent doing a curtsey bow - - - Decodes mesh asset. See - to furter decode it for rendering - true + + Agent crouching - - Override the base classes AssetType + + Agent crouching while walking - - X position of this patch + + Agent crying - - Y position of this patch + + Agent unanimated with arms out (e.g. setting appearance) - - A 16x16 array of floats holding decompressed layer data + + Agent re-animated after set appearance finished - - - 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 - + + Agent dancing - - - 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 + + Agent dancing - - - Permission request flags, asked when a script wants to control an Avatar - + + Agent dancing - - Placeholder for empty values, shouldn't ever see this + + Agent dancing - - Script wants ability to take money from you + + Agent dancing - - Script wants to take camera controls for you + + Agent dancing - - Script wants to remap avatars controls + + Agent dancing - - Script wants to trigger avatar animations - This function is not implemented on the grid + + Agent dancing - - Script wants to attach or detach the prim or primset to your avatar + + Agent on ground unanimated - - Script wants permission to release ownership - This function is not implemented on the grid - The concept of "public" objects does not exist anymore. + + Agent boozing it up - - Script wants ability to link/delink with other prims + + Agent with embarassed expression on face - - Script wants permission to change joints - This function is not implemented on the grid + + Agent with afraid expression on face - - Script wants permissions to change permissions - This function is not implemented on the grid + + Agent with angry expression on face - - Script wants to track avatars camera position and rotation + + Agent with bored expression on face - - Script wants to control your camera + + Agent crying - - Script wants the ability to teleport you + + Agent showing disdain (dislike) for something - - - Special commands used in Instant Messages - + + Agent with embarassed expression on face - - Indicates a regular IM from another agent + + Agent with frowning expression on face - - Simple notification box with an OK button + + Agent with kissy face - - You've been invited to join a group. + + Agent expressing laughgter - - Inventory offer + + Agent with open mouth - - Accepted inventory offer + + Agent with repulsed expression on face - - Declined inventory offer + + Agent expressing sadness - - Group vote + + Agent shrugging shoulders - - An object is offering its inventory + + Agent with a smile - - Accept an inventory offer from an object + + Agent expressing surprise - - Decline an inventory offer from an object + + Agent sticking tongue out - - Unknown + + Agent with big toothy smile - - Start a session, or add users to a session + + Agent winking - - Start a session, but don't prune offline users + + Agent expressing worry - - Start a session with your group + + Agent falling down - - Start a session without a calling card (finder or objects) + + Agent walking (feminine version) - - Send a message to a session + + Agent wagging finger (disapproval) - - Leave a session + + I'm not sure I want to know - - Indicates that the IM is from an object + + Agent in superman position - - Sent an IM to a busy user, this is the auto response + + Agent in superman position - - Shows the message in the console and chat history + + Agent greeting another - - Send a teleport lure + + Agent holding bazooka (right handed) - - Response sent to the agent which inititiated a teleport invitation + + Agent holding a bow (left handed) - - Response sent to the agent which inititiated a teleport invitation + + Agent holding a handgun (right handed) - - Only useful if you have Linden permissions + + Agent holding a rifle (right handed) - - Request a teleport lure + + Agent throwing an object (right handed) - - IM to tell the user to go to an URL + + Agent in static hover - - IM for help + + Agent hovering downward - - IM sent automatically on call for help, sends a lure - to each Helper reached + + Agent hovering upward - - Like an IM but won't go to email + + Agent being impatient - - IM from a group officer to all group members + + Agent jumping - - Unknown + + Agent jumping with fervor - - Unknown + + Agent point to lips then rear end - - Accept a group invitation + + Agent landing from jump, finished flight, etc - - Decline a group invitation + + Agent laughing - - Unknown + + Agent landing from jump, finished flight, etc - - An avatar is offering you friendship + + Agent sitting on a motorcycle - - An avatar has accepted your friendship offer + + - - An avatar has declined your friendship offer + + Agent moving head side to side - - Indicates that a user has started typing + + Agent moving head side to side with unhappy expression - - Indicates that a user has stopped typing + + Agent taunting another - - - Flag in Instant Messages, whether the IM should be delivered to - offline avatars as well - + + - - Only deliver to online avatars + + Agent giving peace sign - - If the avatar is offline the message will be held until - they login next, and possibly forwarded to their e-mail account - - - - Conversion type to denote Chat Packet types in an easier-to-understand format - - - - Whisper (5m radius) + + Agent pointing at self - - Normal chat (10/20m radius), what the official viewer typically sends + + Agent pointing at another - - Shouting! (100m radius) + + Agent preparing for jump (bending knees) - - Event message when an Avatar has begun to type + + Agent punching with left hand - - Event message when an Avatar has stopped typing + + Agent punching with right hand - - Send the message to the debug channel + + Agent acting repulsed - - Event message when an object uses llOwnerSay + + Agent trying to be Chuck Norris - - Special value to support llRegionSay, never sent to the client + + Rocks, Paper, Scissors 1, 2, 3 - - - Identifies the source of a chat message - + + Agent with hand flat over other hand - - Chat from the grid or simulator + + Agent with fist over other hand - - Chat from another avatar + + Agent with two fingers spread over other hand - - Chat from an object + + Agent running - - - - + + Agent appearing sad - - + + Agent saluting - - + + Agent shooting bow (left handed) - - + + Agent cupping mouth as if shouting - - - Effect type used in ViewerEffect packets - + + Agent shrugging shoulders - - + + Agent in sit position - - + + Agent in sit position (feminine) - - + + Agent in sit position (generic) - - + + Agent sitting on ground - - + + Agent sitting on ground - + - - + + Agent sleeping on side - - Project a beam from a source to a destination, such as - the one used when editing an object + + Agent smoking - - + + Agent inhaling smoke - + - - + + Agent taking a picture - - Create a swirl of particles around an object + + Agent standing - - + + Agent standing up - - + + Agent standing - - Cause an avatar to look at an object + + Agent standing - - Cause an avatar to point at an object + + Agent standing - - - The action an avatar is doing when looking at something, used in - ViewerEffect packets for the LookAt effect - + + Agent standing - - + + Agent stretching - - + + Agent in stride (fast walk) - - + + Agent surfing - - + + Agent acting surprised - - + + Agent striking with a sword - - + + Agent talking (lips moving) - - Deprecated + + Agent throwing a tantrum - - + + Agent throwing an object (right handed) - - + + Agent trying on a shirt - - + + Agent turning to the left - - + + Agent turning to the right - - - The action an avatar is doing when pointing at something, used in - ViewerEffect packets for the PointAt effect - + + Agent typing - - + + Agent walking - - + + Agent whispering - - + + Agent whispering with fingers in mouth - - + + Agent winking - - - Money transaction types - + + Agent winking - - + + Agent worried - - + + Agent nodding yes - - + + Agent nodding yes with happy face - - + + Agent floating with legs and arms crossed - - + + + A dictionary containing all pre-defined animations + + A dictionary containing the pre-defined animations, + where the key is the animations ID, and the value is a string + containing a name to identify the purpose of the animation - - + + + Throttles the network traffic for various different traffic types. + Access this class through GridClient.Throttle + - - + + + Default constructor, uses a default high total of 1500 KBps (1536000) + - - + + + Constructor that decodes an existing AgentThrottle packet in to + individual values + + Reference to the throttle data in an AgentThrottle + packet + Offset position to start reading at in the + throttle data + This is generally not needed in clients as the server will + never send a throttle packet to the client - - + + + Send an AgentThrottle packet to the current server using the + current values + - - + + + Send an AgentThrottle packet to the specified server using the + current values + - - + + + Convert the current throttle values to a byte array that can be put + in an AgentThrottle packet + + 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 - - + + + Represents a single Voice Session to the Vivox service. + - - + + + Close this session. + - - + + + Look up an existing Participants in this session + + + - + + + Extract the avatar UUID encoded in a SIP URI + + + + + + + Permissions for control of object media + + + + + Style of cotrols that shold be displayed to the user + + + + + Class representing media data for a single face + + + + Is display of the alternative image enabled + + + Should media auto loop + + + Shoule media be auto played + + + Auto scale media to prim face + + + Should viewer automatically zoom in on the face when clicked + + + Should viewer interpret first click as interaction with the media + or when false should the first click be treated as zoom in commadn + + + Style of controls viewer should display when + viewer media on this face + + + Starting URL for the media + + + Currently navigated URL + + + Media height in pixes + + + Media width in pixels + + + Who can controls the media + + + Who can interact with the media + + + Is URL whitelist enabled + + + Array of URLs that are whitelisted + + + + Serialize to OSD + + OSDMap with the serialized data + + + + Deserialize from OSD data + + 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 + + + - + - + - + - + - + - + - + - + + 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 - + - Flags sent when a script takes or releases a control + Default constructor - NOTE: (need to verify) These might be a subset of the ControlFlags enum in Movement, - - - No Flags set - - - Forward (W or up Arrow) - - - Back (S or down arrow) - - - Move left (shift+A or left arrow) - - - Move right (shift+D or right arrow) - - - Up (E or PgUp) - - - Down (C or PgDown) - - - Rotate left (A or left arrow) - - - Rotate right (D or right arrow) - - - Left Mouse Button - - Left Mouse button in MouseLook - - + - Currently only used to hide your group title + 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 - - No flags set - - - Hide your group title - - + - Action state of the avatar, which can currently be typing and - editing + 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 - + - Current teleport status + Texture animation mode - - Unknown status + + Disable texture animation - - Teleport initialized + + Enable texture animation - - Teleport in progress + + Loop when animating textures - - Teleport failed + + Animate in reverse direction - - Teleport completed + + Animate forward then reverse - - Teleport cancelled + + 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 - - No flags set, or teleport failed + + + Contains the definition for individual faces + + - - Set when newbie leaves help island for first time + + + + + - + - - Via Lure - - - Via Landmark - - - Via Location - - - Via Home - - - Via Telehub - - - Via Login + + - - Linden Summoned + + - - Linden Forced me + + - + - - Agent Teleported Home via Script + + - + - + - + - - forced to new location for example when avatar is banned or ejected + + - - Teleport Finished via a Lure + + In the future this will specify whether a webpage is + attached to this face - - Finished, Sim Changed + + - - Finished, Same Sim + + - + - + 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 - - - - - - - - - - + - Type of mute entry + 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 - - Object muted by name + + + 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 - - Muted residet + + + + + + - - Object muted by UUID + + + + + - - Muted group + + + + + - - Muted external entry + + + + + - + - Flags of mute entry + Controls the texture animation of a particular prim - - No exceptions + + - - Don't mute text chat + + - - Don't mute voice chat + + - - Don't mute particles + + - - Don't mute sounds + + - - Don't mute + + - + + + + - Instant Message + + + - - Key of sender + + + + + - - Name of sender + + + Parameters used to construct a visual representation of a primitive + - - Key of destination avatar + + - - ID of originating estate + + - - Key of originating region + + - - Coordinates in originating region + + - - Instant message type + + - - Group IM session toggle + + - - Key of IM session, for Group Messages, the groups UUID + + - - Timestamp of the instant message + + - - Instant message text + + - - Whether this message is held for offline avatars + + - - Context specific packed data + + - - Print the struct data as a string - A string containing the field name, and field value + + - - Represents muted object or resident + + - - Type of the mute entry + + - - UUID of the mute etnry + + - - Mute entry name + + - - Mute flags + + - - Transaction detail sent with MoneyBalanceReply message + + - - Type of the transaction + + - - UUID of the transaction source + + - - Is the transaction source a group + + - - UUID of the transaction destination + + + Calculdates hash code for prim construction data + + The has - - Is transaction destination a group + + Attachment point to an avatar - - Transaction amount + + - - Transaction description + + - - - - + + - + + + + - Construct a new instance of the ChatEventArgs object + Information on the flexible properties of a primitive - 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 + + - - Get the message sent + + - - Get the audible level of the message + + - - Get the type of message sent: whisper, shout, etc + + - - Get the source type of the message sender + + - - Get the name of the agent or object sending the message + + - - Get the ID of the agent or object sending the message - - - Get the ID of the object owner, or the agent ID sending the message - - - Get 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 + Default constructor - 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 - - - Get the name of the object that sent the dialog request - - - Get the ID of the image to be displayed - - - Get the ID of the primitive sending the dialog - - - Get the first name of the senders owner - - - Get the last name of the senders owner - - - Get the communication channel the dialog was sent on, responses - should also send responses on this same channel - - - Get 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 + + + Information on the light properties of a primitive + - - Get the ID of the script making the request + + - - Get the ID of the primitive containing the script making the request + + - - Get the name of the primitive making the request + + - - Get the name of the owner of the object making the request + + - - Get the permissions being requested + + - - Contains the data sent when a primitive sends a request - to an agent to open the specified URL + + + Default constructor + - + - 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 + + + + + - - Get the ID of the object sending the request + + + + + - - Get the ID of the owner of the object sending the request + + + Information on the light properties of a primitive as texture map + - - True if the object is owned by a group + + - - Get the message sent with the request + + - - Get the URL the object sent + + + Default constructor + - - The date received from an ImprovedInstantMessage + + + + + + - + - Construct a new instance of the InstantMessageEventArgs object + - the InstantMessage object - the simulator where the InstantMessage origniated + - - Get the InstantMessage object + + + + + - - Get the simulator where the InstantMessage origniated + + + Information on the sculpt properties of a sculpted primitive + - - Contains the currency balance + + + Default constructor + - + - Construct a new BalanceEventArgs object + - The currenct balance + + - + - Get the currenct balance + Render inside out (inverts the normals). - - Contains the transaction summary when an item is purchased, - money is given, or land is purchased + + + Render an X axis mirror of the sculpty. + - + - Construct a new instance of the MoneyBalanceReplyEventArgs object + Extended properties to describe an 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 + + - - True of the transaction was successful + + - - Get the remaining currency balance + + - - Get the meters credited + + - - Get the meters comitted + + - - Get the description of the transaction + + - - Detailed transaction information + + - - 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 - - - Get the agents last name - - - Get the active group ID of your agent + + - - Get the active groups title of your agent + + - - Get the combined group powers of your agent + + - - Get the active group name of your agent + + - - Data sent by the simulator to indicate the active/changed animations - applied to your agent + + - - - 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 + + - - Get the ID of the agent or object that collided with your agent + + - - Get the ID of the agent that was attacked + + - - A value indicating the strength of the collision + + - - Get the time the collision occurred + + - - Data sent to your agent when it crosses region boundaries + + - + - Construct a new instance of the RegionCrossedEventArgs class + Default constructor - 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 + Set the properties that are set in an ObjectPropertiesFamily packet - 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 - - - Get the name of the session - - - Get the temporary session ID used for establishing new sessions - - - True if your agent successfully joined the session - - - Data sent by the simulator containing urgent messages + that has + been partially filled by an ObjectPropertiesFamily packet - + - Construct a new instance of the AlertMessageEventArgs class + Describes physics attributes of the prim - The alert message - - - Get the alert message - - Data sent by a script requesting to take or release specified controls to your agent + + Primitive's local ID - - - 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 + + Density (1000 for normal density) - - Get the controls the script is attempting to take or release to the agent + + Friction - - True if the script is passing controls back to the agent + + Gravity multiplier (1 for normal gravity) - - True if the script is requesting controls be released to the script + + Type of physics representation of this primitive in the simulator - - - Data sent from the simulator to an agent to indicate its view limits - + + Restitution - + - Construct a new instance of the CameraConstraintEventArgs class + Creates PhysicsProperties from OSD - The collision plane - - - Get the collision plane + OSDMap with incoming data + Deserialized PhysicsProperties object - + - Data containing script sensor requests which allow an agent to know the specific details - of a primitive sending script sensor requests + Serializes PhysicsProperties to OSD + OSDMap with serialized PhysicsProperties data - + - Construct a new instance of the ScriptSensorReplyEventArgs + Complete structure for the particle system - 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 + + 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 - - Get the ID of the group associated with the primitive + + pattern of particles - - Get the name of the primitive sending the sensor + + A representing the maximimum age (in seconds) particle will be displayed + Maximum value is 30 seconds - - Get the ID of the primitive sending the sensor + + 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 - - Get the ID of the owner of the primitive sending the sensor + + A in radians that specifies where particles will not be created - - Get the position of the primitive sending the sensor + + A in radians that specifies where particles will be created - - Get the range the primitive specified to scan + + A representing the number of seconds between burts. - - Get the rotation of the primitive sending the sensor + + A representing the number of meters + around the center of the source where particles will be created. - - Get the type of sensor the primitive sent + + A representing in seconds, the minimum speed between bursts of new particles + being emitted - - Get the velocity of the primitive sending the sensor + + A representing in seconds the maximum speed of new particles being emitted. - - Contains the response data returned from the simulator in response to a + + A representing the maximum number of particles emitted per burst - - Construct a new instance of the AvatarSitResponseEventArgs object + + A which represents the velocity (speed) from the source which particles are emitted - - Get the ID of the primitive the agent will be sitting on + + A which represents the Acceleration from the source which particles are emitted - - True if the simulator Autopilot functions were involved + + The Key of the texture displayed on the particle - - Get the camera offset of the agent when seated + + The Key of the specified target object or avatar particles will follow - - Get the camera eye offset of the agent when seated + + Flags of particle from - - True of the agent will be in mouselook mode when seated + + Max Age particle system will emit particles for - - Get the position of the agent when seated + + The the particle has at the beginning of its lifecycle - - Get the rotation of the agent when seated + + The the particle has at the ending of its lifecycle - - Data sent when an agent joins a chat session your agent is currently participating in + + A that represents the starting X size of the particle + Minimum value is 0, maximum value is 4 - - - Construct a new instance of the ChatSessionMemberAddedEventArgs object - - The ID of the chat session - The ID of the agent joining + + A that represents the starting Y size of the particle + Minimum value is 0, maximum value is 4 - - Get the ID of the chat session + + A that represents the ending X size of the particle + Minimum value is 0, maximum value is 4 - - Get the ID of the agent that joined + + A that represents the ending Y size of the particle + Minimum value is 0, maximum value is 4 - - Data sent when an agent exits a chat session your agent is currently participating in + + + Decodes a byte[] array into a ParticleSystem Object + + ParticleSystem object + Start position for BitPacker - + - Construct a new instance of the ChatSessionMemberLeftEventArgs object + Generate byte[] array from particle data - The ID of the chat session - The ID of the Agent that left + Byte array - - Get the ID of the chat session + + + Particle source pattern + - - Get the ID of the agent that left + + None - - Event arguments with the result of setting display name operation + + Drop particles from source position with no force - - Default constructor + + "Explode" particles in all directions - - Status code, 200 indicates settign display name was successful + + Particles shoot across a 2D area - - Textual description of the status + + Particles shoot across a 3D Cone - - Details of the newly set display name + + Inverse of AngleCone (shoot particles everywhere except the 3D cone defined - + - Represents an LSL Text object containing a string of UTF encoded characters + Particle Data Flags - - A string of characters represting the script contents + + None - - Initializes a new AssetScriptText object + + Interpolate color and alpha from start to end - - - Initializes a new AssetScriptText object with parameters - - A unique specific to this asset - A byte array containing the raw asset data + + Interpolate scale from start to end - - - Encode a string containing the scripts contents into byte encoded AssetData - + + Bounce particles off particle sources Z height - - - Decode a byte array containing the scripts contents into a string - - true if decoding is successful + + velocity of particles is dampened toward the simulators wind - - Override the base classes AssetType + + Particles follow the source - - - Type of gesture step - + + Particles point towards the direction of source's velocity - - - Base class for gesture steps - + + Target of the particles - - - Retururns what kind of gesture step this is - + + Particles are sent in a straight line - - - Describes animation step of a gesture - + + Particles emit a glow - - - If true, this step represents start of animation, otherwise animation stop - + + used for point/grab/touch - + - Animation asset + Particle Flags Enum - - - Animation inventory name - + + None - + + Acceleration and velocity for particles are + relative to the object rotation + + + Particles use new 'correct' angle parameters + + - Returns what kind of gesture step this is + Return a decoded capabilities message as a strongly typed object + A string containing the name of the capabilities message key + An to decode + A strongly typed object containing the decoded information from the capabilities message, or null + if no existing Message object exists for the specified event - + - Describes sound step of a gesture + A Wrapper around openjpeg to encode and decode images to and from byte arrays - + + TGA Header size + + + OpenJPEG is not threadsafe, so this object is used to lock + during calls into unmanaged code + + - Sound asset + Encode a object into a byte array + The object to encode + true to enable lossless conversion, only useful for small images ie: sculptmaps + A byte array containing the encoded Image object - + - Sound inventory name + Encode a object into a byte array + The object to encode + a byte array of the encoded image - + - Returns what kind of gesture step this is + Decode JPEG2000 data to an and + + JPEG2000 encoded data + ManagedImage object to decode to + Image object to decode to + True if the decode succeeds, otherwise false - + - Describes sound step of a gesture + + + + - + - Text to output in chat + + + + + - + - Returns what kind of gesture step this is + Encode a object into a byte array + The source object to encode + true to enable lossless decoding + A byte array containing the source Bitmap object - + - Describes sound step of a gesture + Defines the beginning and ending file positions of a layer in an + LRCP-progression JPEG2000 file - + - If true in this step we wait for all animations to finish + This structure is used to marshal both encoded and decoded images. + MUST MATCH THE STRUCT IN dotnet.h! - + - If true gesture player should wait for the specified amount of time + Information about a single packet in a JPEG2000 stream - - - Time in seconds to wait if WaitForAnimation is false - + + Packet start position - - - Returns what kind of gesture step this is - + + Packet header end position - - - Describes the final step of a gesture - + + Packet end position - - - Returns what kind of gesture step this is - + + The event subscribers. null if no subcribers - - - Represents a sequence of animations, sounds, and chat actions - + + Raises the LandPatchReceived event + A LandPatchReceivedEventArgs object containing the + data returned from the simulator - - - Keyboard key that triggers the gestyre - + + Thread sync lock object - + - Modifier to the trigger key + Default constructor + - - - String that triggers playing of the gesture sequence - + + Raised when the simulator responds sends - - - Text that replaces trigger in chat once gesture is triggered - + + Simulator from that sent tha data - - - Sequence of gesture steps - + + Sim coordinate of the patch - - - Constructs guesture asset - + + Sim coordinate of the patch - - - Constructs guesture asset - - A unique specific to this asset - A byte array containing the raw asset data + + Size of tha patch - + + Heightmap for the patch + + - Encodes gesture asset suitable for uplaod + Capabilities is the name of the bi-directional HTTP REST protocol + used to communicate non real-time transactions such as teleporting or + group messaging - + + Reference to the simulator this system is connected to + + - Decodes gesture assset into play sequence + Default constructor - true if the asset data was decoded successfully + + - + - Returns asset type + Request the URI of a named capability + Name of the capability to request + The URI of the requested capability, or String.Empty if + the capability does not exist - + - pre-defined built in sounds + Process any incoming events, check to see if we have a message created for the event, + + - - - - - - - - - - - - - - + + 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 - - + + + + - - coins + + OK - - cash register bell + + Transfer completed - + - + - - rubber - - - plastic - - - flesh - - - wood splintering? + + Unknown error occurred - - glass break + + Equivalent to a 404 error - - metal clunk + + Client does not have permission for that resource - - whoosh + + Unknown status - - shake + + + + - + - - ding + + Unknown - - + + Virtually all asset transfers use this channel - - + + + + - + - - + + Asset from the asset server - - + + Inventory item - - + + Estate asset, such as an estate covenant - - + + + + - + - + - + - - + + + When requesting image download, type of the image requested + - - + + Normal in-world object texture - - + + Avatar texture - - + + Server baked avatar texture - + - A dictionary containing all pre-defined sounds + Image file format - 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 - + - 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 + + Number of milliseconds passed since the last transfer + packet was received - + - 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 + + Number of milliseconds to wait for a transfer header packet if out of order data was received - - Name of Group + + The event subscribers. null if no subcribers - - Text of Group Charter + + Raises the XferReceived event + A XferReceivedEventArgs object containing the + data returned from the simulator - - Title of "everyone" role + + Thread sync lock object - - Is the group open for enrolement to everyone + + The event subscribers. null if no subcribers - - Will group show up in search + + Raises the AssetUploaded event + A AssetUploadedEventArgs object containing the + data returned from the simulator - - + + Thread sync lock object - - + + The event subscribers. null if no subcribers - - + + Raises the UploadProgress event + A UploadProgressEventArgs object containing the + data returned from the simulator - - Is the group Mature + + Thread sync lock object - - Cost of group membership + + The event subscribers. null if no subcribers - - + + Raises the InitiateDownload event + A InitiateDownloadEventArgs object containing the + data returned from the simulator - - + + Thread sync lock object - - The total number of current members this group has + + The event subscribers. null if no subcribers - - The number of roles this group has configured + + Raises the ImageReceiveProgress event + A ImageReceiveProgressEventArgs object containing the + data returned from the simulator - - Show this group in agent's profile + + Thread sync lock object - - Returns the name of the group - A string containing the name of the group + + Texture download cache - + - A group Vote + Default constructor + A reference to the GridClient object - - Key of Avatar who created Vote - - - Text of the Vote proposal - - - Total number of votes - - + - A group proposal + Request an asset download + Asset UUID + Asset type, must be correct for the transfer to succeed + Whether to give this transfer an elevated priority + The callback to fire when the simulator responds with the asset data - - The Text of the proposal - - - The minimum number of members that must vote before proposal passes or failes + + + Request an asset download + + Asset UUID + Asset type, must be correct for the transfer to succeed + Whether to give this transfer an elevated priority + Source location of the requested asset + The callback to fire when the simulator responds with the asset data - - 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 + + + Request an asset download + + Asset UUID + Asset type, must be correct for the transfer to succeed + Whether to give this transfer an elevated priority + Source location of the requested asset + UUID of the transaction + The callback to fire when the simulator responds with the asset data - - The duration in days votes are accepted + + + Request an asset download through the almost deprecated Xfer system + + Filename of the asset to request + Whether or not to delete the asset + off the server after it is retrieved + Use large transfer packets or not + UUID of the file to request, if filename is + left empty + Asset type of vFileID, or + AssetType.Unknown if filename is not empty + Sets the FilePath in the request to Cache + (4) if true, otherwise Unknown (0) is used + - + + Use UUID.Zero if you do not have the + asset ID but have all the necessary permissions + The item ID of this asset in the inventory + Use UUID.Zero if you are not requesting an + asset from an object inventory + The owner of this asset + Asset type + Whether to prioritize this asset download or not + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Used to force asset data into the PendingUpload property, ie: for raw terrain uploads + + An AssetUpload object containing the data to upload to the simulator - - + + + Request an asset be uploaded to the simulator + + The Object containing the asset data + If True, the asset once uploaded will be stored on the simulator + in which the client was connected in addition to being stored on the asset server + The of the transfer, can be used to correlate the upload with + events being fired - - + + + Request an asset be uploaded to the simulator + + The of the asset being uploaded + A byte array containing the encoded asset data + If True, the asset once uploaded will be stored on the simulator + in which the client was connected in addition to being stored on the asset server + The of the transfer, can be used to correlate the upload with + events being fired - - + + + Request an asset be uploaded to the simulator + + + Asset type to upload this data as + A byte array containing the encoded asset data + If True, the asset once uploaded will be stored on the simulator + in which the client was connected in addition to being stored on the asset server + The of the transfer, can be used to correlate the upload with + events being fired - - + + + Initiate an asset upload + + The ID this asset will have if the + upload succeeds + Asset type to upload this data as + Raw asset data to upload + Whether to store this asset on the local + simulator or the grid-wide asset server + The tranaction id for the upload + The transaction ID of this transfer - - + + + 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. Sending with value -1 combined with priority of 0 cancels an in-progress + transfer. + A bug exists in the Linden Simulator where a -1 will occasionally be sent with a non-zero priority + indicating an off-by-one error. + 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 + + Request an image and fire a callback when the request is complete + + Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); + + private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) + { + if(state == TextureRequestState.Finished) + { + Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", + asset.AssetID, + asset.AssetData.Length); + } + } + + Request an image and use an inline anonymous method to handle the downloaded texture data + + Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, delegate(TextureRequestState state, AssetTexture asset) + { + if(state == TextureRequestState.Finished) + { + Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", + asset.AssetID, + asset.AssetData.Length); + } + } + ); + + Request a texture, decode the texture to a bitmap image and apply it to a imagebox + + Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); + + private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) + { + if(state == TextureRequestState.Finished) + { + ManagedImage imgData; + Image bitmap; + + if (state == TextureRequestState.Finished) + { + OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData, out bitmap); + picInsignia.Image = bitmap; + } + } + } + + - + - Struct representing a group notice + Overload: 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 callback to fire when the image is retrieved. The callback + will contain the result of the request and the texture asset data - - + + + Overload: 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 + The callback to fire when the image is retrieved. The callback + will contain the result of the request and the texture asset data - - + + + Overload: 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 + 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 - - + + + Cancel a texture request + + The texture assets - - + + + Requests download of a mesh asset + + UUID of the mesh asset + Callback when the request completes - + - + Fetach avatar texture on a grid capable of server side baking - + ID of the avatar + ID of the texture + Name of the part of the avatar texture applies to + Callback invoked on operation completion - + - Struct representing a group notice list entry + Lets TexturePipeline class fire the progress event + The texture ID currently being downloaded + the number of bytes transferred + the total number of bytes expected - - Notice ID + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Creation timestamp of notice + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Agent name who created notice + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Notice subject + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Is there an attachment? + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Attachment Type + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Struct representing a member of a group chat session and their settings - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The of the Avatar + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - True if user has voice chat enabled + + Raised when the simulator responds sends - - True of Avatar has moderator abilities + + Raised during upload completes - - True if a moderator has muted this avatars chat + + Raised during upload with progres update - - True if a moderator has muted this avatars voice + + 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 + + - Role update flags + 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 - - Can send invitations to groups default role + + + A callback that fires upon the completition of the RequestMesh call + + Was the download successfull + Resulting mesh or null on problems - - Can eject members from group + + Xfer data - - Can toggle 'Open Enrollment' and change 'Signup fee' + + Upload data - - Member is visible in the public member list + + Filename used on the simulator - - Can create new roles + + Filename used by the client - - Can delete existing roles + + UUID of the image that is in progress - - Can change Role names, titles and descriptions + + Number of bytes received so far - - Can assign other members to assigners role + + Image size in bytes - - Can assign other members to any role + + + Represents an LSL Text object containing a string of UTF encoded characters + - - Can remove members from roles + + A string of characters represting the script contents - - Can assign and remove abilities in roles + + Initializes a new AssetScriptText object - - Can change group Charter, Insignia, 'Publish on the web' and which - members are publicly visible in group member listings + + + Initializes a new AssetScriptText object with parameters + + A unique specific to this asset + A byte array containing the raw asset data - - Can buy land or deed land to group + + + Encode a string containing the scripts contents into byte encoded AssetData + - - Can abandon group owned land to Governor Linden on mainland, or Estate owner for - private estates + + + Decode a byte array containing the scripts contents into a string + + true if decoding is successful - - Can set land for-sale information on group owned parcels + + Override the base classes AssetType - - Can subdivide and join parcels + + + Represents an AssetScriptBinary object containing the + LSO compiled bytecode of an LSL script + - - Can join group chat sessions + + Initializes a new instance of an AssetScriptBinary object - - Can use voice chat in Group Chat sessions + + Initializes a new instance of an AssetScriptBinary object with parameters + A unique specific to this asset + A byte array containing the raw asset data - - Can moderate group chat sessions + + + TODO: Encodes a scripts contents into a LSO Bytecode file + - - Can toggle "Show in Find Places" and set search category + + + TODO: Decode LSO Bytecode into a string + + true - - Can change parcel name, description, and 'Publish on web' settings + + Override the base classes AssetType - - Can set the landing point and teleport routing on group land + + + Represents a Callingcard with AvatarID and Position vector + - - Can change music and media settings + + UUID of the Callingcard target avatar - - Can toggle 'Edit Terrain' option in Land settings + + Construct an Asset of type Callingcard - - Can toggle various About Land > Options settings + + + Construct an Asset object of type Callingcard + + A unique specific to this asset + A byte array containing the raw asset data - - Can always terraform land, even if parcel settings have it turned off + + + Constuct an asset of type Callingcard + + UUID of the target avatar - - Can always fly while over group owned land + + + Encode the raw contents of a string with the specific Callingcard format + - - Can always rez objects on group owned land + + + Decode the raw asset data, populating the AvatarID and Position + + true if the AssetData was successfully decoded to a UUID and Vector - - Can always create landmarks for group owned parcels + + Override the base classes AssetType - - Can set home location on any group owned parcel + + + + - - Can modify public access settings for group owned parcels + + The event subscribers, null of no subscribers - - Can manager parcel ban lists on group owned land + + Raises the AttachedSound Event + A AttachedSoundEventArgs object containing + the data sent from the simulator - - Can manage pass list sales information + + Thread sync lock object - - Can eject and freeze other avatars on group owned land + + The event subscribers, null of no subscribers - - Can return objects set to group + + Raises the AttachedSoundGainChange Event + A AttachedSoundGainChangeEventArgs object containing + the data sent from the simulator - - Can return non-group owned/set objects + + Thread sync lock object - - Can return group owned objects + + The event subscribers, null of no subscribers - - Can landscape using Linden plants + + Raises the SoundTrigger Event + A SoundTriggerEventArgs object containing + the data sent from the simulator - - Can deed objects to group + + Thread sync lock object - - Can move group owned objects + + The event subscribers, null of no subscribers - - Can set group owned objects for-sale + + Raises the PreloadSound Event + A PreloadSoundEventArgs object containing + the data sent from the simulator - - Pay group liabilities and receive group dividends + + Thread sync lock object - - List and Host group events + + + Construct a new instance of the SoundManager class, used for playing and receiving + sound assets + + A reference to the current GridClient instance - - Can send group notices + + + Plays a sound in the current region at full volume from avatar position + + UUID of the sound to be played - - Can receive group notices + + + 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. - - Can create group proposals + + + 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 - - Can vote on group proposals + + + 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 - + - Handles all network traffic related to reading and writing group - information + 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 - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the CurrentGroups event - A CurrentGroupsEventArgs object containing the - data sent from the simulator + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the GroupNamesReply event - A GroupNamesEventArgs object containing the - data response from the simulator + + Raised when the simulator sends us data containing + sound - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - The event subscribers. null if no subcribers + + Raised when the simulator sends us data containing + ... - - Raises the GroupProfile event - An GroupProfileEventArgs object containing the - data returned from the simulator + + Raised when the simulator sends us data containing + ... - - Thread sync lock object + + 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 ... + } + + - - The event subscribers. null if no subcribers + + + 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 - - Raises the GroupMembers event - A GroupMembersEventArgs object containing the - data returned from the simulator + + Simulator where the event originated - - Thread sync lock object + + Get the sound asset id - - The event subscribers. null if no subcribers + + Get the ID of the owner - - Raises the GroupRolesDataReply event - A GroupRolesDataReplyEventArgs object containing the - data returned from the simulator + + Get the ID of the Object - - Thread sync lock object + + Get the volume level - - The event subscribers. null if no subcribers + + Get the - - Raises the GroupRoleMembersReply event - A GroupRolesRoleMembersReplyEventArgs object containing the - data returned from the simulator + + Provides data for the event + The event occurs when an attached sound + changes its volume level - - Thread sync lock object + + + Construct a new instance of the AttachedSoundGainChangedEventArgs class + + Simulator where the event originated + The ID of the Object + The new volume level - - The event subscribers. null if no subcribers + + Simulator where the event originated - - Raises the GroupTitlesReply event - A GroupTitlesReplyEventArgs object containing the - data returned from the simulator + + Get the ID of the Object - - Thread sync lock object + + Get the volume level - - The event subscribers. null if no subcribers + + 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); + } + + - - Raises the GroupAccountSummary event - A GroupAccountSummaryReplyEventArgs object containing the - data returned from the simulator + + + 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 - - Thread sync lock object + + Simulator where the event originated - - The event subscribers. null if no subcribers + + Get the sound asset id - - Raises the GroupCreated event - An GroupCreatedEventArgs object containing the - data returned from the simulator + + Get the ID of the owner - - Thread sync lock object + + Get the ID of the Object - - The event subscribers. null if no subcribers + + Get the ID of the objects parent - - Raises the GroupJoined event - A GroupOperationEventArgs object containing the - result of the operation returned from the simulator + + Get the volume level - - Thread sync lock object + + Get the regionhandle - - The event subscribers. null if no subcribers + + Get the source position - - Raises the GroupLeft event - A GroupOperationEventArgs object containing the - result of the operation returned from the simulator + + 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") + } + + - - Thread sync lock 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 - - The event subscribers. null if no subcribers + + Simulator where the event originated - - Raises the GroupDropped event - An GroupDroppedEventArgs object containing the - the group your agent left + + Get the sound asset id - - Thread sync lock object + + Get the ID of the owner - - The event subscribers. null if no subcribers + + Get the ID of the Object - - Raises the GroupMemberEjected event - An GroupMemberEjectedEventArgs object containing the - data returned from the simulator + + Positional vector of the users position - - Thread sync lock object + + Velocity vector of the position - - The event subscribers. null if no subcribers + + At Orientation (X axis) of the position - - Raises the GroupNoticesListReply event - An GroupNoticesListReplyEventArgs object containing the - data returned from the simulator + + Up Orientation (Y axis) of the position - - Thread sync lock object + + Left Orientation (Z axis) of the position - - The event subscribers. null if no subcribers + + + Contains all mesh faces that belong to a prim + - - Raises the GroupInvitation event - An GroupInvitationEventArgs object containing the - data returned from the simulator + + List of primitive faces - - Thread sync lock object + + + 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 - - A reference to the current instance + + + Type of gesture step + - - Currently-active group members requests + + + Base class for gesture steps + - - Currently-active group roles requests + + + Retururns what kind of gesture step this is + - - Currently-active group role-member requests + + + Describes animation step of a gesture + - - Dictionary keeping group members while request is in progress + + + If true, this step represents start of animation, otherwise animation stop + - - Dictionary keeping mebmer/role mapping while request is in progress + + + Animation asset + - - Dictionary keeping GroupRole information while request is in progress + + + Animation inventory name + - - Caches group name lookups + + + Returns what kind of gesture step this is + - + + + Describes sound step of a gesture + + + - Construct a new instance of the GroupManager class + Sound asset - A reference to the current instance - + - Request a current list of groups the avatar is a member of. + Sound inventory name - CAPS Event Queue must be running for this to work since the results - come across CAPS. - + - Lookup name of group based on groupID + Returns what kind of gesture step this is - groupID of group to lookup name for. - + - Request lookup of multiple group names + Describes sound step of a gesture - 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) + + + Text to output in chat + - - 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 + + + Returns what kind of gesture step this is + - - Request group roles - Subscribe to OnGroupRoles event to receive the results. - group ID (UUID) - UUID of the request, use to index into cache + + + Describes sound step of a gesture + - - 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 + + + If true in this step we wait for all animations to finish + - - Request a groups Titles - Subscribe to OnGroupTitles event to receive the results. - group ID (UUID) - UUID of the request, use to index into cache + + + If true gesture player should wait for the specified amount of time + - - 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) + + + Time in seconds to wait if WaitForAnimation is false + - - 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 + + + Returns what kind of gesture step this is + - - Set a group as the current active group - group ID (UUID) + + + Describes the final step of a gesture + - - Change the role that determines your active title - Group ID to use - Role ID to change to + + + Returns what kind of gesture step this is + - - Set this avatar's tier contribution - Group ID to change tier in - amount of tier to donate + + + Represents a sequence of animations, sounds, and chat actions + - + - Save wheather agent wants to accept group notices and list this group in their profile + Keyboard key that triggers the gestyre - 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. + + + Modifier to the trigger key + - + - Request to create a new group. If the group is successfully - created, L$100 will automatically be deducted + String that triggers playing of the gesture sequence - 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. + + + Text that replaces trigger in chat once gesture is triggered + - - Eject a user from a group - Group ID to eject the user from - Avatar's key to eject + + + Sequence of gesture steps + - - Update role information - Modified role to be updated + + + Constructs guesture asset + - - Create a new group role - Group ID to update - Role to create + + + Constructs guesture asset + + A unique specific to this asset + A byte array containing the raw asset data - - Delete a group role - Group ID to update - Role to delete + + + Encodes gesture asset suitable for uplaod + - - Remove an avatar from a role - Group ID to update - Role ID to be removed from - Avatar's Key to remove + + + Decodes gesture assset into play sequence + + true if the asset data was decoded successfully - - Assign an avatar to a role - Group ID to update - Role ID to assign to - Avatar's ID to assign to role + + + Returns asset type + - - Request the group notices list - Group ID to fetch notices for + + + Type of return to use when returning objects from a parcel + - - Request a group notice by key - ID of group notice + + - - Send out a group notice - Group ID to update - GroupNotice structure containing notice data + + Return objects owned by parcel owner - - Start a group proposal (vote) - The Group ID to send proposal to - GroupProposal structure containing the proposal + + Return objects set to group - - Request to leave a group - Subscribe to OnGroupLeft event to receive confirmation - The group to leave + + Return objects not owned by parcel owner or set to group - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Return a specific list of objects on parcel - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Return objects that are marked for-sale - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Blacklist/Whitelist flags used in parcels Access List + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Agent is denied access - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Agent is granted access - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + The result of a request for parcel properties + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + No matches were found for the request - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Request matched a single parcel - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Request matched multiple parcels - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Flags used in the ParcelAccessListRequest packet to specify whether + we want the access list (whitelist), ban list (blacklist), or both + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Request the access list - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Request the ban list - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Request both White and Black lists - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Sequence ID in ParcelPropertiesReply packets (sent when avatar + tries to cross a parcel border) + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Parcel is currently selected - - Raised when the simulator sends us data containing - our current group membership + + Parcel restricted to a group the avatar is not a + member of - - Raised when the simulator responds to a RequestGroupName - or RequestGroupNames request + + Avatar is banned from the parcel - - Raised when the simulator responds to a request + + Parcel is restricted to an access list that the + avatar is not on - - Raised when the simulator responds to a request + + Response to hovering over a parcel - - Raised when the simulator responds to a request + + + The tool to use when modifying terrain levels + - - Raised when the simulator responds to a request + + Level the terrain - - Raised when the simulator responds to a request + + Raise the terrain - - Raised when a response to a RequestGroupAccountSummary is returned - by the simulator + + Lower the terrain - - Raised when a request to create a group is successful + + Smooth the terrain - - Raised when a request to join a group either - fails or succeeds + + Add random noise to the terrain - - Raised when a request to leave a group either - fails or succeeds + + Revert terrain to simulator default - - Raised when A group is removed from the group server + + + The tool size to use when changing terrain levels + - - Raised when a request to eject a member from a group either - fails or succeeds + + Small - - Raised when the simulator sends us group notices - + + Medium - - Raised when another agent invites our avatar to join a group + + Large - - Contains the current groups your agent is a member of + + + Reasons agent is denied access to a parcel on the simulator + - - Construct a new instance of the CurrentGroupsEventArgs class - The current groups your agent is a member of + + Agent is not denied, access is granted - - Get the current groups your agent is a member of + + Agent is not a member of the group set for the parcel, or which owns the parcel - - A Dictionary of group names, where the Key is the groups ID and the value is the groups name + + Agent is not on the parcels specific allow list - - Construct a new instance of the GroupNamesEventArgs class - The Group names dictionary + + Agent is on the parcels ban list - - Get the Group Names dictionary + + Unknown - - Represents the members of a group + + Agent is not age verified and parcel settings deny access to non age verified avatars - + - Construct a new instance of the GroupMembersReplyEventArgs class + 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 - The ID of the request - The ID of the group - The membership list of the group + 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 - - Get the ID as returned by the request to correlate - this result set and the request + + Public land - - Get the ID of the group + + Land is owned by another avatar - - Get the dictionary of members + + Land is owned by a group - - Represents the roles associated with a group + + Land is owned by the current avatar - - 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 + + Land is for sale - - Get the ID as returned by the request to correlate - this result set and the request + + Land is being auctioned - - Get the ID of the group + + Land is private - - Get the dictionary containing the roles + + To the west of this area is a parcel border - - Represents the Role to Member mappings for a group + + To the south of this area is a parcel border - - 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 + + + Various parcel properties + - - Get the ID as returned by the request to correlate - this result set and the request + + No flags set - - Get the ID of the group + + 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 - - Get the member to roles map + + Foreign avatars can create objects here - - Represents the titles for a group + + All objects on this parcel can be purchased - - 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 + + Access is restricted to a group - - Get the ID as returned by the request to correlate - this result set and the request + + Access is restricted to a whitelist - - Get the ID of the group + + Ban blacklist is enabled - - Get the titles + + Unknown - - Represents the summary data for a group + + List this parcel in the search directory - - Construct a new instance of the GroupAccountSummaryReplyEventArgs class - The ID of the group - The summary data + + Allow personally owned parcels to be deeded to group - - Get the ID of the group + + If Deeded, owner contributes required tier to group parcel is deeded to - - Get the summary data + + Restrict sounds originating on this parcel to the + parcel boundaries - - A response to a group create request + + Objects on this parcel are sold when the land is + purchsaed - - 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 + + Allow this parcel to be published on the web - - Get the ID of the group + + The information for this parcel is mature content - - true of the group was created successfully + + The media URL is an HTML page - - A string containing the message + + The media URL is a raw HTML string - - Represents a response to a request + + Restrict foreign object pushes - - Construct a new instance of the GroupOperationEventArgs class - The ID of the group - true of the request was successful + + Ban all non identified/transacted avatars - - Get the ID of the group + + Allow group-owned scripts to run - - true of the request was successful + + Allow object creation by group members or group + objects - - Represents your agent leaving a group + + Allow all objects to enter this parcel - - Construct a new instance of the GroupDroppedEventArgs class - The ID of the group + + Only allow group and owner objects to enter this parcel - - Get the ID of the group + + Voice Enabled on this parcel - - Represents a list of active group notices + + Use Estate Voice channel for Voice on this parcel - - Construct a new instance of the GroupNoticesListReplyEventArgs class - The ID of the group - The list containing active notices + + Deny Age Unverified Users - - Get the ID of the group + + + Parcel ownership status + - - Get the notices list + + Placeholder - - Represents the profile of a group + + Parcel is leased (owned) by an avatar or group - - Construct a new instance of the GroupProfileEventArgs class - The group profile + + Parcel is in process of being leased (purchased) by an avatar or group - - Get the group profile + + Parcel has been abandoned back to Governor Linden - + - Provides notification of a group invitation request sent by another Avatar + Category parcel is listed in under search - 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 + + No assigned category - - The name of the Avatar sending the group invitation + + Linden Infohub or public area - - A message containing the request information which includes - the name of the group, the groups charter and the fee to join details + + Adult themed area - - The Simulator + + Arts and Culture - - Set to true to accept invitation, false to decline + + Business - - - Level of Detail mesh - + + Educational - - - Represents an that can be worn on an avatar - such as a Shirt, Pants, etc. - + + Gaming - - Initializes a new instance of an AssetScriptBinary object + + Hangout or Club - - Initializes a new instance of an AssetScriptBinary object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + Newcomer friendly - - Override the base classes AssetType + + Parks and Nature - - - Temporary code to do the bare minimum required to read a tar archive for our purposes - + + Residential - - - Binary reader for the underlying stream - + + Shopping - - - Used to trim off null chars - + + Not Used? - - - Used to trim off space chars - + + Other - - - Generate a tar reader which reads from the given stream. - - + + Not an actual category, only used for queries - + - Read the next entry in the tar file. + Type of teleport landing for a parcel - - - the data for the entry. Returns null if there are no more entries - - - Read the next 512 byte chunk of data as a tar header. - - A tar header struct. null if we have reached the end of the archive. + + Unset, simulator default - - - Read data following a header - - - + + Specific landing point set for this parcel - - - Convert octal bytes to a decimal representation - - - - - + + No landing point set, direct teleports enabled for + this parcel - + - Type of return to use when returning objects from a parcel + Parcel Media Command used in ParcelMediaCommandMessage - - + + Stop the media stream and go back to the first frame - - Return objects owned by parcel owner + + Pause the media stream (stop playing but stay on current frame) - - Return objects set to group + + Start the current media stream playing and stop when the end is reached - - Return objects not owned by parcel owner or set to group + + Start the current media stream playing, + loop to the beginning when the end is reached and continue to play - - Return a specific list of objects on parcel + + 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. - - Return objects that are marked for-sale + + Specifies the movie URL (254 characters max) - - - Blacklist/Whitelist flags used in parcels Access List - + + Specifies the time index at which to begin playing - - Agent is denied access + + Specifies a single agent to apply the media command to - - Agent is granted access + + 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. - - - The result of a request for parcel properties - + + 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. - - No matches were found for the request + + Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). + Use "text/html" for HTML. - - Request matched a single parcel + + Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). + This might still not be working - - Request matched multiple parcels + + Sets a description for the media being displayed (1.19.1 RC0 and later only). - + - Flags used in the ParcelAccessListRequest packet to specify whether - we want the access list (whitelist), ban list (blacklist), or both + Some information about a parcel of land returned from a DirectoryManager search - - Request the access list - - - Request the ban list + + Global Key of record - - Request both White and Black lists + + Parcel Owners - - - Sequence ID in ParcelPropertiesReply packets (sent when avatar - tries to cross a parcel border) - + + Name field of parcel, limited to 128 characters - - Parcel is currently selected + + Description field of parcel, limited to 256 characters - - Parcel restricted to a group the avatar is not a - member of + + Total Square meters of parcel - - Avatar is banned from the parcel + + Total area billable as Tier, for group owned land this will be 10% less than ActualArea - - Parcel is restricted to an access list that the - avatar is not on + + True of parcel is in Mature simulator - - Response to hovering over a parcel + + Grid global X position of parcel - - - The tool to use when modifying terrain levels - + + Grid global Y position of parcel - - Level the terrain + + Grid global Z position of parcel (not used) - - Raise the terrain + + Name of simulator parcel is located in - - Lower the terrain + + Texture of parcels display picture - - Smooth the terrain + + Float representing calculated traffic based on time spent on parcel by avatars - - Add random noise to the terrain + + Sale price of parcel (not used) - - Revert terrain to simulator default + + Auction ID of parcel - + - The tool size to use when changing terrain levels + Parcel Media Information - - Small - - - Medium - - - Large + + A byte, if 0x1 viewer should auto scale media to fit object - - - Reasons agent is denied access to a parcel on the simulator - + + A boolean, if true the viewer should loop the media - - Agent is not denied, access is granted + + The Asset UUID of the Texture which when applied to a + primitive will display the media - - Agent is not a member of the group set for the parcel, or which owns the parcel + + A URL which points to any Quicktime supported media type - - Agent is not on the parcels specific allow list + + A description of the media - - Agent is on the parcels ban list + + An Integer which represents the height of the media - - Unknown + + An integer which represents the width of the media - - Agent is not age verified and parcel settings deny access to non age verified avatars + + A string which contains the mime type of the media - + - 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 + Parcel of land, a portion of virtual real estate in a simulator - 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 + + The total number of contiguous 4x4 meter blocks your agent owns within this parcel - - Land is owned by another avatar + + The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own - - Land is owned by a group + + Deprecated, Value appears to always be 0 - - Land is owned by the current avatar + + Simulator-local ID of this parcel - - Land is for sale + + UUID of the owner of this parcel - - Land is being auctioned + + Whether the land is deeded to a group or not - - Land is private + + - - To the west of this area is a parcel border + + Date land was claimed - - To the south of this area is a parcel border + + Appears to always be zero - - - Various parcel properties - + + This field is no longer used - - No flags set + + Minimum corner of the axis-aligned bounding box for this + parcel - - Allow avatars to fly (a client-side only restriction) + + Maximum corner of the axis-aligned bounding box for this + parcel + + + Bitmap describing land layout in 4x4m squares across the + entire region - - Allow foreign scripts to run + + Total parcel land area - - This parcel is for sale + + - - Allow avatars to create a landmark on this parcel + + Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used - - Allows all avatars to edit the terrain on this parcel + + 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 - - Avatars have health and can take damage on this parcel. - If set, avatars can be killed and sent home here + + Maximum number of primitives this parcel supports - - Foreign avatars can create objects here + + Total number of primitives on this parcel - - All objects on this parcel can be purchased + + 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 - - Access is restricted to a group + + 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. - - Access is restricted to a whitelist + + Total number of prims owned by other avatars that are not set to group, or not the parcel owner - - Ban blacklist is enabled + + 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 - - Unknown + + Autoreturn value in minutes for others' objects - - List this parcel in the search directory + + - - Allow personally owned parcels to be deeded to group + + 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 - - If Deeded, owner contributes required tier to group parcel is deeded to + + Parcel Name - - Restrict sounds originating on this parcel to the - parcel boundaries + + Parcel Description - - Objects on this parcel are sold when the land is - purchsaed + + URL For Music Stream - - Allow this parcel to be published on the web + + - - The information for this parcel is mature content + + Price for a temporary pass - - The media URL is an HTML page + + How long is pass valid for - - The media URL is a raw HTML string + + - - Restrict foreign object pushes + + Key of authorized buyer - - Ban all non identified/transacted avatars + + Key of parcel snapshot - - Allow group-owned scripts to run + + The landing point location - - Allow object creation by group members or group - objects + + The landing point LookAt - - Allow all objects to enter this parcel + + The type of landing enforced from the enum - - 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 + + Access list of who is whitelisted on this + parcel - - - Parcel ownership status - + + Access list of who is blacklisted on this + parcel - - Placeholder + + TRUE of region denies access to age unverified users - - Parcel is leased (owned) by an avatar or group + + true to obscure (hide) media url - - Parcel is in process of being leased (purchased) by an avatar or group + + true to obscure (hide) music url - - Parcel has been abandoned back to Governor Linden + + A struct containing media details - + - Category parcel is listed in under search + Displays a parcel object in string format + string containing key=value pairs of a parcel object - - No assigned category + + + Defalt constructor + + Local ID of this parcel - - Linden Infohub or public area + + + 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 - - Adult themed area + + + Set Autoreturn time + + Simulator to send the update to - - Arts and Culture + + + Parcel (subdivided simulator lots) subsystem + - - Business + + The event subscribers. null if no subcribers - - Educational + + Raises the ParcelDwellReply event + A ParcelDwellReplyEventArgs object containing the + data returned from the simulator - - Gaming + + Thread sync lock object - - Hangout or Club + + The event subscribers. null if no subcribers - - Newcomer friendly + + Raises the ParcelInfoReply event + A ParcelInfoReplyEventArgs object containing the + data returned from the simulator - - Parks and Nature + + Thread sync lock object - - Residential + + The event subscribers. null if no subcribers - - Shopping + + Raises the ParcelProperties event + A ParcelPropertiesEventArgs object containing the + data returned from the simulator - - Not Used? + + Thread sync lock object - - Other + + The event subscribers. null if no subcribers - - Not an actual category, only used for queries + + Raises the ParcelAccessListReply event + A ParcelAccessListReplyEventArgs object containing the + data returned from the simulator - - - Type of teleport landing for a parcel - + + Thread sync lock object - - Unset, simulator default + + The event subscribers. null if no subcribers - - Specific landing point set for this parcel + + Raises the ParcelObjectOwnersReply event + A ParcelObjectOwnersReplyEventArgs object containing the + data returned from the simulator + + + Thread sync lock object - - No landing point set, direct teleports enabled for - this parcel + + The event subscribers. null if no subcribers - - - Parcel Media Command used in ParcelMediaCommandMessage - + + Raises the SimParcelsDownloaded event + A SimParcelsDownloadedEventArgs object containing the + data returned from the simulator - - Stop the media stream and go back to the first frame + + Thread sync lock object - - Pause the media stream (stop playing but stay on current frame) + + The event subscribers. null if no subcribers - - Start the current media stream playing and stop when the end is reached + + Raises the ForceSelectObjectsReply event + A ForceSelectObjectsReplyEventArgs object containing the + data returned from the simulator - - Start the current media stream playing, - loop to the beginning when the end is reached and continue to play + + Thread sync lock object - - 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. + + The event subscribers. null if no subcribers - - Specifies the movie URL (254 characters max) + + Raises the ParcelMediaUpdateReply event + A ParcelMediaUpdateReplyEventArgs object containing the + data returned from the simulator - - Specifies the time index at which to begin playing + + Thread sync lock object - - Specifies a single agent to apply the media command to + + The event subscribers. null if no subcribers - - 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. + + Raises the ParcelMediaCommand event + A ParcelMediaCommandEventArgs object containing the + data returned from the simulator - - 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. + + Thread sync lock object - - Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). - Use "text/html" for HTML. + + + Default constructor + + A reference to the GridClient object - - Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). - This might still not be working + + + Request basic information for a single parcel + + Simulator-local ID of the parcel - - Sets a description for the media being displayed (1.19.1 RC0 and later only). + + + 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 - + - Some information about a parcel of land returned from a DirectoryManager search + 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 + - - Global Key of record + + + 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 - - Parcel Owners + + + Request all simulator parcel properties (used for populating the Simulator.Parcels + dictionary) + + Simulator to request parcels from (must be connected) - - Name field of parcel, limited to 128 characters + + + 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 - - Description field of parcel, limited to 256 characters + + + Request the dwell value for a parcel + + Simulator containing the parcel + Simulator-local ID of the parcel - - Total Square meters of 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 + - - Total area billable as Tier, for group owned land this will be 10% less than ActualArea + + + Reclaim a parcel of land + + The simulator the parcel is in + The parcels region specific local ID - - True of parcel is in Mature simulator + + + Deed a parcel to a group + + The simulator the parcel is in + The parcels region specific local ID + The groups - - Grid global X position of parcel + + + Request prim owners of a parcel of land. + + Simulator parcel is in + The parcels region specific local ID - - Grid global Y position of parcel + + + 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 - - Grid global Z position of parcel (not used) + + + Subdivide (split) a parcel + + + + + + - - Name of simulator parcel is located in + + + Join two parcels of land creating a single parcel + + + + + + - - Texture of parcels display picture + + + 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. - - Float representing calculated traffic based on time spent on parcel by avatars + + + 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() - - Sale price of parcel (not used) + + + 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() - - Auction ID of parcel + + + 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() - + - Parcel Media Information + 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 - - A byte, if 0x1 viewer should auto scale media to fit object + + + 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 - - A boolean, if true the viewer should loop the media + + + Eject and optionally ban a user from a parcel + + target key of avatar to eject + true to also ban target - - The Asset UUID of the Texture which when applied to a - primitive will display the media + + + Freeze or unfreeze an avatar over your land + + target key to freeze + true to freeze, false to unfreeze - - A URL which points to any Quicktime supported media type + + + Abandon a parcel of land + + Simulator parcel is in + Simulator local ID of parcel - - A description of the media + + + 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 - - An Integer which represents the height of the media + + + 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 - - An integer which represents the width of the media + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - A string which contains the mime type of the media + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - - Parcel of land, a portion of virtual real estate in a simulator - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - The total number of contiguous 4x4 meter blocks your agent owns within this parcel + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - The total number of contiguous 4x4 meter blocks contained in this parcel owned by a group or agent other than your own + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - Deprecated, Value appears to always be 0 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Simulator-local ID of this parcel + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data + Raises the event - - UUID of the owner of this parcel + + Raised when the simulator responds to a request - - Whether the land is deeded to a group or not + + Raised when the simulator responds to a request - - + + Raised when the simulator responds to a request - - Date land was claimed + + Raised when the simulator responds to a request - - Appears to always be zero + + Raised when the simulator responds to a request - - This field is no longer used + + Raised when the simulator responds to a request - - Minimum corner of the axis-aligned bounding box for this - parcel + + Raised when the simulator responds to a request - - Maximum corner of the axis-aligned bounding box for this - parcel + + Raised when the simulator responds to a Parcel Update request - - Bitmap describing land layout in 4x4m squares across the - entire region + + Raised when the parcel your agent is located sends a ParcelMediaCommand - - Total parcel land area + + + Parcel Accesslist + - + + Agents + + - - Maximum primitives across the entire simulator owned by the same agent or group that owns this parcel that can be used + + Flags for specific entry in white/black lists - - 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 + + + Owners of primitives on parcel + - - Maximum number of primitives this parcel supports + + Prim Owners - - Total number of primitives on this parcel + + True of owner is group - - 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 count of prims owned by OwnerID - - 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. + + true of OwnerID is currently online and is not a group - - Total number of prims owned by other avatars that are not set to group, or not the parcel owner + + The date of the most recent prim left by OwnerID - - 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 + + + Called once parcel resource usage information has been collected + + Indicates if operation was successfull + Parcel resource usage information - - Autoreturn value in minutes for others' objects + + 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 - - 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 + + Get the global ID of the parcel - - Parcel Name + + Get the simulator specific ID of the parcel - - Parcel Description + + Get the calculated dwell - - URL For Music Stream + + 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 - - Price for a temporary pass + + Get the object containing basic parcel info - - How long is pass valid for + + 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: - - Key of authorized buyer + + Get the simulator the parcel is located in - - Key of parcel snapshot + + Get the object containing the details + If Result is NoData, this object will not contain valid data - - The landing point location + + Get the result of the request - - The landing point LookAt + + Get the number of primitieves your agent is + currently selecting and or sitting on in this parcel - - The type of landing enforced from the enum + + 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 - - Access list of who is whitelisted on this - parcel + + Get the simulator the parcel is located in - - Access list of who is blacklisted on this - parcel + + Get the user assigned ID used to correlate a request with + these results - - TRUE of region denies access to age unverified users + + Get the simulator specific ID of the parcel - - true to obscure (hide) media url + + TODO: - - true to obscure (hide) music url + + Get the list containing the white/blacklisted agents for the parcel - - A struct containing media details + + Contains blacklist and whitelist data returned from the + simulator in response to an request - + - Displays a parcel object in string format + Construct a new instance of the ParcelObjectOwnersReplyEventArgs class - string containing key=value pairs of a parcel object + The simulator the parcel is located in + The list containing prim ownership counts - - - Defalt constructor - - Local ID of this parcel + + Get the simulator the parcel is located in - - - 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 + + Get the list containing prim ownership counts - - - Set Autoreturn time - - Simulator to send the update to + + Contains the data returned when all parcel data has been retrieved from a simulator - + - Parcel (subdivided simulator lots) subsystem + 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. - - 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 + + Get the simulator the parcel data was retrieved from - - The event subscribers. null if no subcribers + + A dictionary containing the parcel data where the key correlates to the ParcelMap entry - - Raises the ParcelInfoReply event - A ParcelInfoReplyEventArgs object containing the - data returned from the simulator + + Get the multidimensional array containing a x,y grid mapped + to each 64x64 parcel's LocalID. - - Thread sync lock object + + Contains the data returned when a request - - The event subscribers. null if no subcribers + + + 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 - - Raises the ParcelProperties event - A ParcelPropertiesEventArgs object containing the - data returned from the simulator + + Get the simulator the parcel data was retrieved from - - Thread sync lock object + + Get the list of primitive IDs - - The event subscribers. null if no subcribers + + true if the list is clean and contains the information + only for a given request - - Raises the ParcelAccessListReply event - A ParcelAccessListReplyEventArgs object containing the - data returned from the simulator + + Contains data when the media data for a parcel the avatar is on changes - - Thread sync lock object + + + Construct a new instance of the ParcelMediaUpdateReplyEventArgs class + + the simulator the parcel media data was updated in + The updated media information - - The event subscribers. null if no subcribers + + Get the simulator the parcel media data was updated in - - Raises the ParcelObjectOwnersReply event - A ParcelObjectOwnersReplyEventArgs object containing the - data returned from the simulator + + Get the updated media information - - Thread sync lock object + + Contains the media command for a parcel the agent is currently on - - The event subscribers. null if no subcribers + + + Construct a new instance of the ParcelMediaCommandEventArgs class + + The simulator the parcel media command was issued in + + + The media command that was sent + - - Raises the SimParcelsDownloaded event - A SimParcelsDownloadedEventArgs object containing the - data returned from the simulator + + Get the simulator the parcel media command was issued in - - 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 + + Get the media command that was sent - - Thread sync lock object + + - - The event subscribers. null if no subcribers + + + A Name Value pair with additional settings, used in the protocol + primarily to transmit avatar names and active group in object packets + - - 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 + Constructor that takes all the fields as parameters - A reference to the GridClient object + + + + + - + - Request basic information for a single parcel + Constructor that takes a single line from a NameValue field - 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 + + Type of the value - - - 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 - + + Unknown - - - 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 + + String value - - - 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 + + Deprecated - - - Deed a parcel to a group - - The simulator the parcel is in - The parcels region specific local ID - The groups + + String value, but designated as an asset - - - 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 + Level of Detail mesh - 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 + Temporary code to produce a tar archive in tar v7 format - 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 + Binary writer for the underlying stream - target key of avatar to eject - true to also ban target - + - Freeze or unfreeze an avatar over your land + Write a directory entry to the tar archive. We can only handle one path level right now! - target key to freeze - true to freeze, false to unfreeze + - + - Abandon a parcel of land + Write a file to the tar archive - Simulator parcel is in - Simulator local ID of parcel + + - + - Requests the UUID of the parcel in a remote region at a specified location + Write a file to the tar archive - 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 + Finish writing the raw tar archive data to a stream. The stream will be closed on completion. - 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 + + + Write a particular entry + + + + - + - Parcel Accesslist + Temporary code to do the bare minimum required to read a tar archive for our purposes - - Agents + + + Binary reader for the underlying stream + - - + + + Used to trim off null chars + - - Flags for specific entry in white/black lists + + + Used to trim off space chars + - + - Owners of primitives on parcel + Generate a tar reader which reads from the given stream. + - - Prim Owners + + + Read the next entry in the tar file. + + + + the data for the entry. Returns null if there are no more entries - - True of owner is group + + + Read the next 512 byte chunk of data as a tar header. + + A tar header struct. null if we have reached the end of the archive. - - Total count of prims owned by OwnerID + + + Read data following a header + + + - - true of OwnerID is currently online and is not a group + + + Convert octal bytes to a decimal representation + + + + + - - The date of the most recent prim left by OwnerID + + + Operation to apply when applying color to texture + - + - Called once parcel resource usage information has been collected + Information needed to translate visual param value to RGBA color - Indicates if operation was successfull - Parcel resource usage information - - Contains a parcels dwell data returned from the simulator in response to an + + + Construct VisualColorParam + + Operation to apply when applying color to texture + Colors - + - Construct a new instance of the ParcelDwellReplyEventArgs class + Represents alpha blending and bump infor for a visual parameter + such as sleive length - 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 + + Stregth of the alpha to apply - - Get the simulator specific ID of the parcel + + File containing the alpha channel - - Get the calculated dwell + + Skip blending if parameter value is 0 - - Contains basic parcel information data returned from the - simulator in response to an request + + Use miltiply insted of alpha blending - + - Construct a new instance of the ParcelInfoReplyEventArgs class + Create new alhpa information for a visual param - 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 + Stregth of the alpha to apply + File containing the alpha channel + Skip blending if parameter value is 0 + Use miltiply insted of alpha blending - + - Construct a new instance of the ParcelPropertiesEventArgs class + A single visual characteristic of an avatar mesh, such as eyebrow height - 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 + + Index of this visual param - - Get the object containing the details - If Result is NoData, this object will not contain valid data + + Internal name - - Get the result of the request + + Group ID this parameter belongs to - - Get the number of primitieves your agent is - currently selecting and or sitting on in this parcel + + Name of the wearable this parameter belongs to - - Get the user assigned ID used to correlate a request with - these results + + Displayable label of this characteristic - - TODO: + + Displayable label for the minimum value of this characteristic - - Contains blacklist and whitelist data returned from the simulator in response to an request + + Displayable label for the maximum value of this characteristic - - - 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 + + Default value - - Get the simulator the parcel is located in + + Minimum value - - Get the user assigned ID used to correlate a request with - these results + + Maximum value - - Get the simulator specific ID of the parcel + + Is this param used for creation of bump layer? - - TODO: + + Alpha blending/bump info - - Get the list containing the white/blacklisted agents for the parcel + + Color information - - Contains blacklist and whitelist data returned from the - simulator in response to an request + + Array of param IDs that are drivers for this parameter - + - Construct a new instance of the ParcelObjectOwnersReplyEventArgs class + Set all the values through the constructor - The simulator the parcel is located in - The list containing prim ownership counts - - - Get the simulator the parcel is located in + Index of this visual param + Internal name + + + Displayable label of this characteristic + Displayable label for the minimum value of this characteristic + Displayable label for the maximum value of this characteristic + Default value + Minimum value + Maximum value + Is this param used for creation of bump layer? + Array of param IDs that are drivers for this parameter + Alpha blending/bump info + Color information - - Get the list containing prim ownership counts + + + Holds the Params array of all the avatar appearance parameters + - - Contains the data returned when all parcel data has been retrieved from a simulator + + + + - + - Construct a new instance of the SimParcelsDownloadedEventArgs class + Initialize the UDP packet handler in server mode - 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. + Port to listening for incoming UDP packets on - - Get the simulator the parcel data was retrieved from + + + Initialize the UDP packet handler in client mode + + Remote UDP server to connect to - - 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 + Static helper functions and global variables - 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 + + This header flag signals that ACKs are appended to the packet - - Get the list of primitive IDs + + This header flag signals that this packet has been sent before - - true if the list is clean and contains the information - only for a given request + + This header flags signals that an ACK is expected for this packet - - Contains data when the media data for a parcel the avatar is on changes + + This header flag signals that the message is compressed using zerocoding - + - 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 + + + + + + - - + + + + + + + - - + + + 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 - - Get the media command that was sent + + + 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 - + - A Name Value pair with additional settings, used in the protocol - primarily to transmit avatar names and active group in object packets + 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 - + - Constructor that takes all the fields as parameters + 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 - + - Constructor that takes a single line from a NameValue field + 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 - - Type of the value + + + 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); + } + + - - Unknown + + + Passed to Logger.Log() to identify the severity of a log entry + - - String value + + 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. + - - Deprecated + + = - - String value, but designated as an asset + + Number of times we've received an unknown CAPS exception in series. - - + + For exponential backoff on error. - + - + The type of bump-mapping applied to a face - + - + - + - + - - - - - - + - + - + - + - + - - - Abstract base for rendering plugins - - - - - Generates a basic mesh structure from a primitive - - Primitive to generate the mesh from - Level of detail to generate the mesh at - The generated mesh - - - - Generates a basic mesh structure from a sculpted primitive and - texture - - Sculpted primitive to generate the mesh from - Sculpt texture - Level of detail to generate the mesh at - The generated mesh - - - - Generates a series of faces, each face containing a mesh and - metadata - - Primitive to generate the mesh from - Level of detail to generate the mesh at - The generated mesh - - - - Generates a series of faces for a sculpted prim, each face - containing a mesh and metadata - - Sculpted primitive to generate the mesh from - Sculpt texture - Level of detail to generate the mesh at - The generated mesh - - - - Apply texture coordinate modifications from a - to a list of vertices - - Vertex list to modify texture coordinates for - Center-point of the face - Face texture parameters - Scale of the prim + + - - - 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 + + - + - Temporary code to produce a tar archive in tar v7 format + The level of shininess applied to a face - - - Binary writer for the underlying stream - + + - - - Write a directory entry to the tar archive. We can only handle one path level right now! - - + + - - - Write a file to the tar archive - - - + + - - - Write a file to the tar archive - - - + + - + - Finish writing the raw tar archive data to a stream. The stream will be closed on completion. + The texture mapping style used for a face - - - Write a particular entry - - - - + + - - - Operation to apply when applying color to texture - + + - - - Information needed to translate visual param value to RGBA color - + + - - - Construct VisualColorParam - - Operation to apply when applying color to texture - Colors + + - + - Represents alpha blending and bump infor for a visual parameter - such as sleive length + Flags in the TextureEntry block that describe which properties are + set - - Stregth of the alpha to apply + + - - File containing the alpha channel + + - - Skip blending if parameter value is 0 + + - - Use miltiply insted of alpha blending + + - - - Create new alhpa information for a visual param - - Stregth of the alpha to apply - File containing the alpha channel - Skip blending if parameter value is 0 - Use miltiply insted of alpha blending + + - - - A single visual characteristic of an avatar mesh, such as eyebrow height - + + - - Index of this visual param + + - - Internal name + + - - Group ID this parameter belongs to + + - - Name of the wearable this parameter belongs to + + - - Displayable label of this characteristic + + - - Displayable label for the minimum value of this characteristic + + - - Displayable label for the maximum value of this characteristic + + - - Default value + + + Wrapper around a byte array that allows bit to be packed and unpacked + one at a time or by a variable amount. Useful for very tightly packed + data like LayerData packets + - - Minimum value + + - - Maximum value + + + Default constructor, initialize the bit packer / bit unpacker + with a byte array and starting position + + Byte array to pack bits in to or unpack from + Starting position in the byte array - - Is this param used for creation of bump layer? + + + Pack a floating point value in to the data + + Floating point value to pack - - Alpha blending/bump info + + + Pack part or all of an integer in to the data + + Integer containing the data to pack + Number of bits of the integer to pack - - Color information + + + Pack part or all of an unsigned integer in to the data + + Unsigned integer containing the data to pack + Number of bits of the integer to pack - - Array of param IDs that are drivers for this parameter + + + Pack a single bit in to the data + + Bit to pack - + - Set all the values through the constructor + - Index of this visual param - Internal name - - - Displayable label of this characteristic - Displayable label for the minimum value of this characteristic - Displayable label for the maximum value of this characteristic - Default value - Minimum value - Maximum value - Is this param used for creation of bump layer? - Array of param IDs that are drivers for this parameter - Alpha blending/bump info - Color information + + + + - + - Holds the Params array of all the avatar appearance parameters + + - + + - + - Initialize the UDP packet handler in server mode + Unpacking a floating point value from the data + + Unpacked floating point value + + + + Unpack a variable number of bits from the data in to integer format - Port to listening for incoming UDP packets on + Number of bits to unpack + An integer containing the unpacked bits + This function is only useful up to 32 bits - + - Initialize the UDP packet handler in client mode + Unpack a variable number of bits from the data in to unsigned + integer format - Remote UDP server to connect to + Number of bits to unpack + An unsigned integer containing the unpacked bits + This function is only useful up to 32 bits - + - + Unpack a 16-bit signed integer + 16-bit signed integer - + - + Unpack a 16-bit unsigned integer + 16-bit unsigned integer - + - + Unpack a 32-bit signed integer + 32-bit signed integer - + - The type of bump-mapping applied to a face + Unpack a 32-bit unsigned integer + 32-bit unsigned integer - - - - - - - + - + - - + + + Permission request flags, asked when a script wants to control an Avatar + - - + + Placeholder for empty values, shouldn't ever see this - - + + Script wants ability to take money from you - - + + Script wants to take camera controls for you - - + + Script wants to remap avatars controls - - + + Script wants to trigger avatar animations + This function is not implemented on the grid - - + + Script wants to attach or detach the prim or primset to your avatar - - + + Script wants permission to release ownership + This function is not implemented on the grid + The concept of "public" objects does not exist anymore. - - + + Script wants ability to link/delink with other prims - - + + Script wants permission to change joints + This function is not implemented on the grid - - + + Script wants permissions to change permissions + This function is not implemented on the grid - - + + Script wants to track avatars camera position and rotation - - + + Script wants to control your camera - - + + Script wants the ability to teleport you - + - The level of shininess applied to a face + Special commands used in Instant Messages - - + + Indicates a regular IM from another agent - - + + Simple notification box with an OK button - - + + You've been invited to join a group. - - + + Inventory offer - - - The texture mapping style used for a face - + + Accepted inventory offer - - + + Declined inventory offer - - + + Group vote - - + + An object is offering its inventory - - + + Accept an inventory offer from an object - - - Flags in the TextureEntry block that describe which properties are - set - + + Decline an inventory offer from an object - - + + Unknown - - + + Start a session, or add users to a session - - + + Start a session, but don't prune offline users - - + + Start a session with your group - - + + Start a session without a calling card (finder or objects) - - + + Send a message to a session - - + + Leave a session - - + + Indicates that the IM is from an object - - + + Sent an IM to a busy user, this is the auto response - - + + Shows the message in the console and chat history - - + + Send a teleport lure - - + + Response sent to the agent which inititiated a teleport invitation + + + Response sent to the agent which inititiated a teleport invitation + + + Only useful if you have Linden permissions + + + Request a teleport lure + + + IM to tell the user to go to an URL + + + IM for help + + + IM sent automatically on call for help, sends a lure + to each Helper reached + + + Like an IM but won't go to email + + + IM from a group officer to all group members + + + Unknown + + + Unknown + + + Accept a group invitation + + + Decline a group invitation + + + Unknown + + + An avatar is offering you friendship + + + An avatar has accepted your friendship offer + + + An avatar has declined your friendship offer + + + Indicates that a user has started typing - - + + Indicates that a user has stopped typing - + - Represents an Animation + Flag in Instant Messages, whether the IM should be delivered to + offline avatars as well - - Default Constructor + + Only deliver to online avatars - + + If the avatar is offline the message will be held until + they login next, and possibly forwarded to their e-mail account + + - Construct an Asset object of type Animation + Conversion type to denote Chat Packet types in an easier-to-understand format - A unique specific to this asset - A byte array containing the raw asset data - - Override the base classes AssetType + + Whisper (5m radius) - - - Static helper functions and global variables - + + Normal chat (10/20m radius), what the official viewer typically sends - - This header flag signals that ACKs are appended to the packet + + Shouting! (100m radius) - - This header flag signals that this packet has been sent before + + Event message when an Avatar has begun to type - - This header flags signals that an ACK is expected for this packet + + Event message when an Avatar has stopped typing - - This header flag signals that the message is compressed using zerocoding + + Send the message to the debug channel - - - - - - + + Event message when an object uses llOwnerSay - - - - - - - + + Special value to support llRegionSay, never sent to the client - + - + Identifies the source of a chat message - - - + + Chat from the grid or simulator + + + Chat from another avatar + + + Chat from an object + + - - - - - - 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 + Effect type used in ViewerEffect packets - 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 - + + Project a beam from a source to a destination, such as + the one used when editing an object - - No logging information will be output + + + + + + + + + + + Create a swirl of particles around an object - - 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 + + Cause an avatar to look at an object - - 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. - + + Cause an avatar to point at an object - + - Checks the instance back into the object pool + The action an avatar is doing when looking at something, used in + ViewerEffect packets for the LookAt effect - - - Returns an instance of the class that has been checked out of 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. + + Deprecated - - - 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 action an avatar is doing when pointing at something, used in + ViewerEffect packets for the PointAt effect - - - Wrapper around a byte array that allows bit to be packed and unpacked - one at a time or by a variable amount. Useful for very tightly packed - data like LayerData packets - + + - + - - - Default constructor, initialize the bit packer / bit unpacker - with a byte array and starting position - - Byte array to pack bits in to or unpack from - Starting position in the byte array + + - - - Pack a floating point value in to the data - - Floating point value to pack + + - + - Pack part or all of an integer in to the data + Money transaction types - Integer containing the data to pack - Number of bits of the integer to pack - - - Pack part or all of an unsigned integer in to the data - - Unsigned integer containing the data to pack - Number of bits of the integer to pack + + - - - Pack a single bit in to the data - - Bit to pack + + - - - - - - - - + + - - - - - + + - - - - - + + - - - Unpacking a floating point value from the data - - Unpacked floating point value + + - - - Unpack a variable number of bits from the data in to integer format - - Number of bits to unpack - An integer containing the unpacked bits - This function is only useful up to 32 bits + + - - - Unpack a variable number of bits from the data in to unsigned - integer format - - Number of bits to unpack - An unsigned integer containing the unpacked bits - This function is only useful up to 32 bits + + - - - Unpack a 16-bit signed integer - - 16-bit signed integer + + - - - Unpack a 16-bit unsigned integer - - 16-bit unsigned integer + + - - - Unpack a 32-bit signed integer - - 32-bit signed integer + + + + + + + + + + + + + + - - - Unpack a 32-bit unsigned integer - - 32-bit unsigned integer + + - + - + - - - 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 + + - - 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 + + + Flags sent when a script takes or releases a control + + NOTE: (need to verify) These might be a subset of the ControlFlags enum in Movement, - - The of the creator of this item + + No Flags set - - A Description of this item + + Forward (W or up Arrow) - - The s this item is set to or owned by + + Back (S or down arrow) - - If true, item is owned by a group + + Move left (shift+A or left arrow) - - The price this item can be purchased for + + Move right (shift+D or right arrow) - - The type of sale from the enum + + Up (E or PgUp) - - Combined flags from + + Down (C or PgDown) - - Time and date this inventory item was created, stored as - UTC (Coordinated Universal Time) + + Rotate left (A or left arrow) - - Used to update the AssetID in requests sent to the server + + Rotate right (D or right arrow) - - The of the previous owner of the item + + Left Mouse Button - - - Construct a new InventoryItem object - - The of the item + + Left Mouse button in MouseLook - + - Construct a new InventoryItem object of a specific Type + Currently only used to hide your group title - 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 + + No flags set - - - - - + + Hide your group title - + - + Action state of the avatar, which can currently be typing and + editing - - - - 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 + Current teleport status - The object to compare against - true if objects are the same - - - Create InventoryItem from OSD - - OSD Data that makes up InventoryItem - Inventory item created + + Unknown status - - - Convert InventoryItem to OSD - - OSD representation of InventoryItem + + Teleport initialized - - - InventoryTexture Class representing a graphical image - - + + Teleport in progress - - - Construct an InventoryTexture object - - A which becomes the - objects AssetUUID + + Teleport failed - - - Construct an InventoryTexture object from a serialization stream - + + Teleport completed - - - InventorySound Class representing a playable sound - + + Teleport cancelled - + - Construct an InventorySound object + - A which becomes the - objects AssetUUID - - - Construct an InventorySound object from a serialization stream - + + No flags set, or teleport failed - - - InventoryCallingCard Class, contains information on another avatar - + + Set when newbie leaves help island for first time - - - Construct an InventoryCallingCard object - - A which becomes the - objects AssetUUID + + - - - Construct an InventoryCallingCard object from a serialization stream - + + Via Lure - - - InventoryLandmark Class, contains details on a specific location - + + Via Landmark - - - Construct an InventoryLandmark object - - A which becomes the - objects AssetUUID + + Via Location - - - Construct an InventoryLandmark object from a serialization stream - + + Via Home - - - Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited - + + Via Telehub - - - InventoryObject Class contains details on a primitive or coalesced set of primitives - + + Via Login - - - Construct an InventoryObject object - - A which becomes the - objects AssetUUID + + Linden Summoned - - - Construct an InventoryObject object from a serialization stream - + + Linden Forced me - - - Gets or sets the upper byte of the Flags value - + + - - - Gets or sets the object attachment point, the lower byte of the Flags value - + + Agent Teleported Home via Script - - - 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 - + + + + + forced to new location for example when avatar is banned or ejected + + + Teleport Finished via a Lure + + + Finished, Sim Changed + + + Finished, Same Sim - + - 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 + Type of mute entry - - - Construct an InventoryAttachment object - - A which becomes the - objects AssetUUID + + Object muted by name - - - Construct an InventoryAttachment object from a serialization stream - + + Muted residet - - - Get the last AttachmentPoint this object was attached to - + + Object muted by UUID - - - InventoryWearable Class, details on a clothing item or body part - + + Muted group - - - Construct an InventoryWearable object - - A which becomes the - objects AssetUUID + + Muted external entry - + - Construct an InventoryWearable object from a serialization stream + Flags of mute entry - - - The , Skin, Shape, Skirt, Etc - + + No exceptions - - - InventoryAnimation Class, A bvh encoded object which animates an avatar - + + Don't mute text chat - - - Construct an InventoryAnimation object - - A which becomes the - objects AssetUUID + + Don't mute voice chat - - - Construct an InventoryAnimation object from a serialization stream - + + Don't mute particles - - - InventoryGesture Class, details on a series of animations, sounds, and actions - + + Don't mute sounds - - - Construct an InventoryGesture object - - A which becomes the - objects AssetUUID + + Don't mute - + - Construct an InventoryGesture object from a serialization stream + Instant Message - - - A folder contains s and has certain attributes specific - to itself - + + Key of sender - - The Preferred for a folder. + + Name of sender - - The Version of this folder + + Key of destination avatar - - Number of child items this folder contains. + + ID of originating estate - - - Constructor - - UUID of the folder + + Key of originating region - - - - - + + Coordinates in originating region - - - Get Serilization data for this InventoryFolder object - + + Instant message type - - - Construct an InventoryFolder object from a serialization stream - + + Group IM session toggle - - - - - + + Key of IM session, for Group Messages, the groups UUID - - - - - - + + Timestamp of the instant message - - - - - - + + Instant message text - - - - - - + + Whether this message is held for offline avatars - - - Create InventoryFolder from OSD - - OSD Data that makes up InventoryFolder - Inventory folder created + + Context specific packed data - - - Convert InventoryItem to OSD - - OSD representation of InventoryItem + + Print the struct data as a string + A string containing the field name, and field value + + + Represents muted object or resident + + + Type of the mute entry + + + UUID of the mute etnry + + + Mute entry name + + + Mute flags + + + Transaction detail sent with MoneyBalanceReply message + + + Type of the transaction - - - Tools for dealing with agents inventory - + + UUID of the transaction source - - Used for converting shadow_id to asset_id + + Is the transaction source a group - - The event subscribers, null of no subscribers + + UUID of the transaction destination - - Raises the ItemReceived Event - A ItemReceivedEventArgs object containing - the data sent from the simulator + + Is transaction destination a group - - Thread sync lock object + + Transaction amount - - The event subscribers, null of no subscribers + + Transaction description - - Raises the FolderUpdated Event - A FolderUpdatedEventArgs object containing - the data sent from the simulator + + + + - - Thread sync lock object + + + 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 - - The event subscribers, null of no subscribers + + Get the simulator sending the message - - Raises the InventoryObjectOffered Event - A InventoryObjectOfferedEventArgs object containing - the data sent from the simulator + + Get the message sent - - Thread sync lock object + + Get the audible level of the message - - The event subscribers, null of no subscribers + + Get the type of message sent: whisper, shout, etc - - Raises the TaskItemReceived Event - A TaskItemReceivedEventArgs object containing - the data sent from the simulator + + Get the source type of the message sender - - Thread sync lock object + + Get the name of the agent or object sending the message - - The event subscribers, null of no subscribers + + Get the ID of the agent or object sending the message - - Raises the FindObjectByPath Event - A FindObjectByPathEventArgs object containing - the data sent from the simulator + + Get the ID of the object owner, or the agent ID sending the message - - Thread sync lock object + + Get the position of the agent or object sending the message - - The event subscribers, null of no subscribers + + Contains the data sent when a primitive opens a dialog with this agent - - Raises the TaskInventoryReply Event - A TaskInventoryReplyEventArgs object containing - the data sent from the simulator + + + 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 - - Thread sync lock object + + Get the dialog message - - The event subscribers, null of no subscribers + + Get the name of the object that sent the dialog request - - Raises the SaveAssetToInventory Event - A SaveAssetToInventoryEventArgs object containing - the data sent from the simulator + + Get the ID of the image to be displayed - - Thread sync lock object + + Get the ID of the primitive sending the dialog - - The event subscribers, null of no subscribers + + Get the first name of the senders owner - - Raises the ScriptRunningReply Event - A ScriptRunningReplyEventArgs object containing - the data sent from the simulator + + Get the last name of the senders owner - - Thread sync lock object + + Get the communication channel the dialog was sent on, responses + should also send responses on this same channel - - Partial mapping of AssetTypes to folder names + + Get the string labels containing the options presented in this dialog - - - Default constructor - - Reference to the GridClient object + + UUID of the scritped object owner - - - 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 + + Contains the data sent when a primitive requests debit or other permissions + requesting a YES or NO answer - + - Request A single inventory item + Construct a new instance of the ScriptQuestionEventArgs - The items - The item Owners - + 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 - - - Request inventory items - - Inventory items to request - Owners of the inventory items - + + Get the simulator containing the object sending the request - - - Request inventory items via Capabilities - - Inventory items to request - Owners of the inventory items - + + Get the ID of the script making the request - - - 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 + + Get the ID of the primitive containing the script making the request - - - 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 - + + Get the name of the primitive making the request - - - 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 - + + Get the name of the owner of the object making the request - - - 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 + + Get the permissions being requested + + + Contains the data sent when a primitive sends a request + to an agent to open the specified URL - + - Find an object in inventory using a specific path to search + Construct a new instance of the LoadUrlEventArgs - 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 + 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 - - - 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 + + Get the name of the object sending the request - - - 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 + + Get the ID of the object sending the request - - - Move an inventory item or folder to a new location - - The item or folder to move - The to move item or folder to + + Get the ID of the owner of the object sending the request - - - 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 + + True if the object is owned by a group - - - Move and rename a folder - - The source folders - The destination folders - The name to change the folder to + + Get the message sent with the request - - - Update folder properties - - of the folder to update - Sets folder's parent to - Folder name - Folder type + + Get the URL the object sent - - - Move a folder - - The source folders - The destination folders + + The date received from an ImprovedInstantMessage - + - Move multiple folders, the keys in the Dictionary parameter, - to a new parents, the value of that folder's key. + Construct a new instance of the InstantMessageEventArgs object - A Dictionary containing the - of the source as the key, and the - of the destination as the value + the InstantMessage object + the simulator where the InstantMessage origniated - - - Move an inventory item to a new folder - - The of the source item to move - The of the destination folder + + Get the InstantMessage object - - - 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 + + Get the simulator where the InstantMessage origniated - - - 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 + + Contains the currency balance - + - Remove descendants of a folder + Construct a new BalanceEventArgs object - The of the folder + The currenct balance - + - Remove a single item from inventory + Get the currenct balance - The of the inventory item to remove - - - Remove a folder from inventory - - The of the folder to remove + + Contains the transaction summary when an item is purchased, + money is given, or land is purchased - + - Remove multiple items or folders from inventory + Construct a new instance of the MoneyBalanceReplyEventArgs object - A List containing the s of items to remove - A List containing the s of the folders to remove + 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 - - - Empty the Lost and Found folder - + + Get the ID of the transaction - - - Empty the Trash folder - + + True of the transaction was successful - - - - - - - - - Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. - - - + + Get the remaining currency balance - - - - - - - - - Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. - - - - + + Get the meters credited - - - 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 + + Get the meters comitted - - - 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 + + Get the description of the transaction - + + Detailed transaction information + + + Data sent from the simulator containing information about your agent and active group information + + - Create an inventory item and upload asset data + Construct a new instance of the AgentDataReplyEventArgs object - 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 + 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 + + + Get the agents last name + + + Get the active group ID of your agent + + + Get the active groups title of your agent + + + Get the combined group powers of your agent + + + Get the active group name of your agent - - - 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 + + Data sent by the simulator to indicate the active/changed animations + applied to your agent - + - Creates inventory link to another inventory item or folder + Construct a new instance of the AnimationsChangedEventArgs class - Put newly created link in folder with this UUID - Inventory item or folder - Method to call upon creation of the link + The dictionary that contains the changed animations - - - 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 + + Get the dictionary that contains the changed animations - + - Creates inventory link to another inventory folder + Data sent from a simulator indicating a collision with your agent - 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 + Construct a new instance of the MeanCollisionEventArgs class - 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 + 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 + + + Get the ID of the agent or object that collided with your agent + + + Get the ID of the agent that was attacked + + + A value indicating the strength of the collision + + + Get the time the collision occurred + + + Data sent to your agent when it crosses region boundaries + + - + Construct a new instance of the RegionCrossedEventArgs class - - - - + 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 + + + Get the name of the session + + + Get the temporary session ID used for establishing new sessions + + + True if your agent successfully joined the session + + + Data sent by the simulator containing urgent messages + + - + 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 + + - Request a copy of an asset embedded within a notecard + Construct a new instance of the ScriptControlEventArgs class - 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 + 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 + + + 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 - - + - + 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 + + + Get the ID of the group associated with the primitive + + + Get the name of the primitive sending the sensor + + + Get the ID of the primitive sending the sensor + + + Get the ID of the owner of the primitive sending the sensor + + + Get the position of the primitive sending the sensor + + + Get the range the primitive specified to scan + + + Get the rotation of the primitive sending the sensor + + + Get the type of sensor the primitive sent + + + Get 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 + + + True if the simulator Autopilot functions were involved + + + Get the camera offset of the agent when seated + + + Get the camera eye offset of the agent when seated + + + True of the agent will be in mouselook mode when seated + + + Get the position of the agent when seated + + + Get the rotation of the agent when seated + + + Data sent when an agent joins a chat session your agent is currently participating in - + - Save changes to notecard embedded in object contents + Construct a new instance of the ChatSessionMemberAddedEventArgs object - Encoded notecard asset data - Notecard UUID - Object's UUID - Called upon finish of the upload with status information + The ID of the chat session + The ID of the agent joining - - - Upload new gesture asset for an inventory gesture item - - Encoded gesture asset - Gesture inventory UUID - Callback whick will be called when upload is complete + + Get the ID of the chat session - - - 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 - + + Get the ID of the agent that joined - - - 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 - + + Data sent when an agent exits a chat session your agent is currently participating in - + - Rez an object from inventory + Construct a new instance of the ChatSessionMemberLeftEventArgs object - Simulator to place object in - Rotation of the object when rezzed - Vector of where to place object - InventoryItem object containing item details + The ID of the chat session + The ID of the Agent that left - - - 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 + + Get the ID of the chat session - - - 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 + + Get the ID of the agent that left - - - 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 + + Event arguments with the result of setting display name operation - - - 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 + + Default constructor - - - 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 + + Status code, 200 indicates settign display name was successful - - - Rez an item from inventory to its previous simulator location - - - - - + + Textual description of the status - + + Details of the newly set display name + + - Give an inventory item to another avatar + Abstract base for rendering plugins - 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 + Generates a basic mesh structure from a primitive - 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 + Primitive to generate the mesh from + Level of detail to generate the mesh at + The generated mesh - + - Copy or move an from agent inventory to a task (primitive) inventory + Generates a basic mesh structure from a sculpted primitive and + texture - 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 + Sculpted primitive to generate the mesh from + Sculpt texture + Level of detail to generate the mesh at + The generated mesh - + - Retrieve a listing of the items contained in a task (Primitive) + Generates a series of faces, each face containing a mesh and + metadata - 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 + Primitive to generate the mesh from + Level of detail to generate the mesh at + The generated mesh - + - Request the contents of a tasks (primitives) inventory from the - current simulator + Generates a series of faces for a sculpted prim, each face + containing a mesh and metadata - The LocalID of the object - + Sculpted primitive to generate the mesh from + Sculpt texture + Level of detail to generate the mesh at + The generated mesh - + - Request the contents of a tasks (primitives) inventory + Apply texture coordinate modifications from a + to a list of vertices - The simulator Local ID of the object - A reference to the simulator object that contains the object - + Vertex list to modify texture coordinates for + Center-point of the face + Face texture parameters + Scale of the prim - + - Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory + Represents Mesh asset - 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 + Decoded mesh data - 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]); - - + + Initializes a new instance of an AssetMesh object - - - 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 - + + Initializes a new instance of an AssetMesh object with parameters + A unique specific to this asset + A byte array containing the raw asset data - + - Send a request to set the running state of a script contained in a task (primitive) inventory + TODO: Encodes Collada file into LLMesh format - 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 + Decodes mesh asset. See + to furter decode it for rendering + true - + + Override the base classes AssetType + + - Reverses a cheesy XORing with a fixed UUID to convert a shadow_id to an asset_id + Archives assets - 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 + Archive assets - asset_id value to obfuscate - Obfuscated shadow_id value - + - Wrapper for creating a new object + Archive the assets given to this archiver to the given archive. - 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 + Write an assets metadata file to the given archive - 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 + + + Write asset data files to the given archive + + - + - 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 + Avatar group management - 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 + + Key of Group Member - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Total land contribution - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Online status information - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Abilities that the Group Member has - - Raised when the simulator sends us data containing - ... + + Current group title - - Raised when the simulator sends us data containing - ... + + Is a group owner - - Raised when the simulator sends us data containing - an inventory object sent by another avatar or primitive + + + Role manager for a group + - - Raised when the simulator sends us data containing - ... + + Key of the group - - Raised when the simulator sends us data containing - ... + + Key of Role - - Raised when the simulator sends us data containing - ... + + Name of Role - - Raised when the simulator sends us data containing - ... + + Group Title associated with Role - - Raised when the simulator sends us data containing - ... + + Description of Role - - - Get this agents Inventory data - + + Abilities Associated with Role - - - 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 + + Returns the role's title + The role's title - + - Callback for an inventory item being create from an uploaded asset + Class to represent Group Title - true if inventory item creation was successful - - - - - - - - + + Key of the group - - - Reply received when uploading an inventory asset - - Has upload been successful - Error message if upload failed - Inventory asset UUID - New asset UUID + + ID of the role title belongs to - - - 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 + + Group Title - - Set to true to accept offer, false to decline it + + Whether title is Active - - The folder to accept the inventory into, if null default folder for will be used + + Returns group title - + - 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. + Represents a group on the grid - - - 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(); - } - } - } - - + + Key of Group - - Networking subsystem + + Key of Group Insignia - - Settings class including constant values and changeable - parameters for everything + + Key of Group Founder + + + Key of Group Role for Owners + + + Name of Group - - Parcel (subdivided simulator lots) subsystem + + Text of Group Charter - - Our own avatars subsystem + + Title of "everyone" role - - Other avatars subsystem + + Is the group open for enrolement to everyone - - Estate subsystem + + Will group show up in search - - Friends list subsystem + + - - Grid (aka simulator group) subsystem + + - - Object subsystem + + - - Group subsystem + + Is the group Mature - - Asset subsystem + + Cost of group membership - - Appearance subsystem + + - - Inventory subsystem + + - - Directory searches including classifieds, people, land - sales, etc + + The total number of current members this group has - - Handles land, wind, and cloud heightmaps + + The number of roles this group has configured - - Handles sound-related networking + + Show this group in agent's profile - - Throttling total bandwidth usage, or allocating bandwidth - for specific data stream types + + Returns the name of the group + A string containing the name of the group - + - Default constructor + A group Vote - - - Return the full name of this instance - - Client avatars full name + + Key of Avatar who created Vote - - - Class that handles the local asset cache - + + Text of the Vote proposal - - - Default constructor - - A reference to the GridClient object + + Total number of votes - + - Disposes cleanup timer + A group proposal - - - Only create timer when needed - + + The Text of the proposal - - - Return bytes read from the local asset cache, null if it does not exist - - UUID of the asset we want to get - Raw bytes of the asset, or null on failure + + The minimum number of members that must vote before proposal passes or failes - - - Returns ImageDownload object of the - image from the local image cache, null if it does not exist - - UUID of the image we want to get - ImageDownload object containing the image, or null on failure + + 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 - - - Constructs a file name of the cached asset - - UUID of the asset - String with the file name of the cahced asset + + The duration in days votes are accepted - + - Constructs a file name of the static cached asset + - UUID of the asset - String with the file name of the static cached asset - - - Saves an asset to the local cache - - UUID of the asset - Raw bytes the asset consists of - Weather the operation was successfull + + - - - Get the file name of the asset stored with gived UUID - - UUID of the asset - Null if we don't have that UUID cached on disk, file name if found in the cache folder + + - - - Checks if the asset exists in the local cache - - UUID of the asset - True is the asset is stored in the cache, otherwise false + + - - - Wipes out entire cache - + + - - - Brings cache size to the 90% of the max size - + + - - - Asynchronously brings cache size to the 90% of the max size - + + - - - Adds up file sizes passes in a FileInfo array - + + - - - Checks whether caching is enabled - + + - - - Periodically prune the cache - + + - - - Nicely formats file sizes - - 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 - + + - - - Represents a single Voice Session to the Vivox service. - + + - + + + + + + + + + + + + + + + + - Close this session. + Struct representing a group notice - + + + + + + + + + + + + + - Look up an existing Participants in this session + - - + - + Struct representing a group notice list entry - - - - + + Notice ID - - - - + + Creation timestamp of notice - - - - + + Agent name who created notice - - - - - - + + Notice subject - - - 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 + + Is there an attachment? - - - A dictionary of callbacks to fire when specified action occurs - + + Attachment Type - + - Register a callback to be fired when an action occurs + Struct representing a member of a group chat session and their settings - The action - The callback to fire - - - Unregister a callback - - The action - The callback to fire + + The of the Avatar - - - - - - + + True if user has voice chat enabled - - Internal dictionary that this class wraps around. Do not - modify or enumerate the contents of this dictionary without locking + + True of Avatar has moderator abilities - - - 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>(); - - + + True if a moderator has muted this avatars chat - - - 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); - - + + True if a moderator has muted this avatars voice - + - Try to get entry from the with specified key + Role update flags - 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 - + + Can send invitations to groups default role - - - Enumerator for iterating dictionary entries - - + + Can eject members from group - - - Gets the number of Key/Value pairs contained in the - + + Can toggle 'Open Enrollment' and change 'Signup fee' - - - Indexer for the dictionary - - The key - The value + + Member is visible in the public member list - - - Reads in a byte array of an Animation Asset created by the SecondLife(tm) client. - + + Can create new roles - - - Rotation Keyframe count (used internally) - + + Can delete existing roles - - - Position Keyframe count (used internally) - + + Can change Role names, titles and descriptions - - - Animation Priority - + + Can assign other members to assigners role + + + Can assign other members to any role - - - The animation length in seconds. - + + Can remove members from roles - - - Expression set in the client. Null if [None] is selected - + + Can assign and remove abilities in roles - - - The time in seconds to start the animation - + + Can change group Charter, Insignia, 'Publish on the web' and which + members are publicly visible in group member listings - - - The time in seconds to end the animation - + + Can buy land or deed land to group - - - Loop the animation - + + Can abandon group owned land to Governor Linden on mainland, or Estate owner for + private estates - - - Meta data. Ease in Seconds. - + + Can set land for-sale information on group owned parcels - - - Meta data. Ease out seconds. - + + Can subdivide and join parcels - - - Meta Data for the Hand Pose - + + Can join group chat sessions - - - Number of joints defined in the animation - + + Can use voice chat in Group Chat sessions - - - Contains an array of joints - + + Can moderate group chat sessions - - - Searialize an animation asset into it's joints/keyframes/meta data - - + + Can toggle "Show in Find Places" and set search category - - - Variable length strings seem to be null terminated in the animation asset.. but.. - use with caution, home grown. - advances the index. - - The animation asset byte array - The offset to start reading - a string + + Can change parcel name, description, and 'Publish on web' settings - - - Read in a Joint from an animation asset byte array - Variable length Joint fields, yay! - Advances the index - - animation asset byte array - Byte Offset of the start of the joint - The Joint data serialized into the binBVHJoint structure + + Can set the landing point and teleport routing on group land - - - Read Keyframes of a certain type - advance i - - Animation Byte array - Offset in the Byte Array. Will be advanced - Number of Keyframes - Scaling Min to pass to the Uint16ToFloat method - Scaling Max to pass to the Uint16ToFloat method - + + Can change music and media settings - - - Determines whether the specified is equal to the current . - - - true if the specified is equal to the current ; otherwise, false. - - The to compare with the current . - The parameter is null. - 2 + + Can toggle 'Edit Terrain' option in Land settings - - - Serves as a hash function for a particular type. - - - A hash code for the current . - - 2 + + Can toggle various About Land > Options settings - - - A Joint and it's associated meta data and keyframes - + + Can always terraform land, even if parcel settings have it turned off - - - Indicates whether this instance and a specified object are equal. - - - true if and this instance are the same type and represent the same value; otherwise, false. - - Another object to compare to. - 2 + + Can always fly while over group owned land - - - Returns the hash code for this instance. - - - A 32-bit signed integer that is the hash code for this instance. - - 2 + + Can always rez objects on group owned land - - - Name of the Joint. Matches the avatar_skeleton.xml in client distros - + + Can always create landmarks for group owned parcels - - - Joint Animation Override? Was the same as the Priority in testing.. - + + Can set home location on any group owned parcel - - - Array of Rotation Keyframes in order from earliest to latest - + + Can modify public access settings for group owned parcels - - - Array of Position Keyframes in order from earliest to latest - This seems to only be for the Pelvis? - + + Can manager parcel ban lists on group owned land - - - Custom application data that can be attached to a joint - + + Can manage pass list sales information - - - A Joint Keyframe. This is either a position or a rotation. - + + Can eject and freeze other avatars on group owned land - - - Either a Vector3 position or a Vector3 Euler rotation - + + Can return objects set to group - - - Poses set in the animation metadata for the hands. - + + Can return non-group owned/set objects - - - Represents an AssetScriptBinary object containing the - LSO compiled bytecode of an LSL script - + + Can return group owned objects - - Initializes a new instance of an AssetScriptBinary object + + Can landscape using Linden plants - - Initializes a new instance of an AssetScriptBinary object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + Can deed objects to group - - - TODO: Encodes a scripts contents into a LSO Bytecode file - + + Can move group owned objects - - - TODO: Decode LSO Bytecode into a string - - true + + Can set group owned objects for-sale - - Override the base classes AssetType + + Pay group liabilities and receive group dividends - - - A linkset asset, containing a parent primitive and zero or more children - + + List and Host group events - - Initializes a new instance of an AssetPrim object + + Can send group notices - - - Initializes a new instance of an AssetPrim object - - A unique specific to this asset - A byte array containing the raw asset data + + Can receive group notices + + + Can create group proposals - - - - + + Can vote on group proposals - + - + Handles all network traffic related to reading and writing group + information - - - Override the base classes AssetType + + The event subscribers. null if no subcribers - - - Only used internally for XML serialization/deserialization - + + Raises the CurrentGroups event + A CurrentGroupsEventArgs object containing the + data sent from the simulator - - - The deserialized form of a single primitive in a linkset asset - + + 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 - - + + 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. + + - Singleton logging class for the entire library + 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 - - log4net logging engine + + Update a group's profile and other information + Groups ID (UUID) to update. + Group struct to update. - - - Default constructor - + + Eject a user from a group + Group ID to eject the user from + Avatar's key to eject - - - Send a log message to the logging engine - - The log message - The severity of the log entry + + Update role information + Modified role to be updated - - - Send a log message to the logging engine - - The log message - The severity of the log entry - Instance of the client + + Create a new group role + Group ID to update + Role to create - - - Send a log message to the logging engine - - The log message - The severity of the log entry - Exception that was raised + + Delete a group role + Group ID to update + Role to delete - - - 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 + + Remove an avatar from a role + Group ID to update + Role ID to be removed from + Avatar's Key to remove - - - 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 + + Assign an avatar to a role + Group ID to update + Role ID to assign to + Avatar's ID to assign to role - - - 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 + + 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 + + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Triggered whenever a message is logged. If this is left - null, log messages will go to the console + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Callback used for client apps to receive log messages from - the library - - Data being logged - The severity of the log entry from + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Represents a Callingcard with AvatarID and Position vector - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - UUID of the Callingcard target avatar + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Construct an Asset of type Callingcard + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Construct an Asset object of type Callingcard - - A unique specific to this asset - A byte array containing the raw asset data + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Constuct an asset of type Callingcard - - UUID of the target avatar + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Encode the raw contents of a string with the specific Callingcard format - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Decode the raw asset data, populating the AvatarID and Position - - true if the AssetData was successfully decoded to a UUID and Vector + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Override the base classes AssetType + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - Simulator (region) properties - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - No flags set + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Agents can take damage and be killed + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Landmarks can be created here + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Home position can be set in this sim + + Raised when the simulator sends us data containing + our current group membership - - Home position is reset when an agent teleports away + + Raised when the simulator responds to a RequestGroupName + or RequestGroupNames request - - Sun does not move + + Raised when the simulator responds to a request - - No object, land, etc. taxes + + Raised when the simulator responds to a request - - Disable heightmap alterations (agents can still plant - foliage) + + Raised when the simulator responds to a request - - Land cannot be released, sold, or purchased + + Raised when the simulator responds to a request - - All content is wiped nightly + + Raised when the simulator responds to a request - - Unknown: Related to the availability of an overview world map tile.(Think mainland images when zoomed out.) + + Raised when a response to a RequestGroupAccountSummary is returned + by the simulator - - Unknown: Related to region debug flags. Possibly to skip processing of agent interaction with world. + + Raised when a request to create a group is successful - - Region does not update agent prim interest lists. Internal debugging option. + + Raised when a request to join a group either + fails or succeeds - - No collision detection for non-agent objects + + Raised when a request to leave a group either + fails or succeeds - - No scripts are ran + + Raised when A group is removed from the group server - - All physics processing is turned off + + Raised when a request to eject a member from a group either + fails or succeeds - - Region can be seen from other regions on world map. (Legacy world map option?) + + Raised when the simulator sends us group notices + - - Region can be seen from mainland on world map. (Legacy world map option?) + + Raised when another agent invites our avatar to join a group - - Agents not explicitly on the access list can visit the region. + + Contains the current groups your agent is a member of - - Traffic calculations are not run across entire region, overrides parcel settings. + + Construct a new instance of the CurrentGroupsEventArgs class + The current groups your agent is a member of - - Flight is disabled (not currently enforced by the sim) + + Get the current groups your agent is a member of - - Allow direct (p2p) teleporting + + A Dictionary of group names, where the Key is the groups ID and the value is the groups name - - Estate owner has temporarily disabled scripting + + Construct a new instance of the GroupNamesEventArgs class + The Group names dictionary - - Restricts the usage of the LSL llPushObject function, applies to whole region. + + Get the Group Names dictionary - - Deny agents with no payment info on file + + Represents the members of a group - - Deny agents with payment info on file + + + Construct a new instance of the GroupMembersReplyEventArgs class + + The ID of the request + The ID of the group + The membership list of the group - - Deny agents who have made a monetary transaction + + Get the ID as returned by the request to correlate + this result set and the request - - Parcels within the region may be joined or divided by anyone, not just estate owners/managers. + + Get the ID of the group - - Abuse reports sent from within this region are sent to the estate owner defined email. + + Get the dictionary of members - - Region is Voice Enabled + + Represents the roles associated with a group - - Removes the ability from parcel owners to set their parcels to show in search. + + 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 - - Deny agents who have not been age verified from entering the region. + + Get the ID as returned by the request to correlate + this result set and the request - - - Region protocol flags - + + Get the ID of the group + + + Get the dictionary containing the roles - - - Access level for a simulator - + + Represents the Role to Member mappings for a group - - Unknown or invalid access level + + 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 - - Trial accounts allowed + + Get the ID as returned by the request to correlate + this result set and the request - - PG rating + + Get the ID of the group - - Mature rating + + Get the member to roles map - - Adult rating + + Represents the titles for a group - - Simulator is offline + + 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 - - Simulator does not exist + + Get the ID as returned by the request to correlate + this result set and the request - - - - + + Get the ID of the group - - A public reference to the client that this Simulator object - is attached to + + Get the titles - - A Unique Cache identifier for this simulator + + Represents the summary data for a group - - The capabilities for this simulator + + Construct a new instance of the GroupAccountSummaryReplyEventArgs class + The ID of the group + The summary data - - + + Get the ID of the group - - The current version of software this simulator is running + + Get the summary data - - + + A response to a group create request - - A 64x64 grid of parcel coloring values. The values stored - in this array are of the type + + 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 - - true if your agent has Estate Manager rights on this region + + 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 - - Statistics information for this simulator and the - connection to the simulator, calculated by the simulator itself - and the library + + + A set of textures that are layered on texture of each other and "baked" + in to a single texture, for avatar appearances + - - The regions Unique ID + + Final baked texture - - The physical data center the simulator is located - Known values are: - - Dallas - Chandler - SF - - + + Component layers - - The CPU Class of the simulator - Most full mainland/estate sims appear to be 5, - Homesteads and Openspace appear to be 501 + + Width of the final baked image and scratchpad - - The number of regions sharing the same CPU as this one - "Full Sims" appear to be 1, Homesteads appear to be 4 + + Height of the final baked image and scratchpad - - 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) - - + + Bake type - - 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 - - + + + Default constructor + + Bake type - + - Flags indicating which protocols this region supports + Adds layer for baking + TexturaData struct that contains texture and its params - - 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 + Converts avatar texture index (face) to Bake type + Face number (AvatarTextureIndex) + BakeType, layer to which this texture belongs to - + - A thread-safe dictionary containing primitives in a simulator + Make sure images exist, resize source if needed to match the destination + Destination image + Source image + Sanitization was succefull - + - Checks simulator parcel map to make sure it has downloaded all data successfully + Fills a baked layer as a solid *appearing* color. The colors are + subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from + compressing it too far since it seems to cause upload failures if + the image is a pure solid color - true if map is full (contains no 0's) + Color of the base of this layer - + - Is it safe to send agent updates to this sim - AgentMovementComplete message received + Fills a baked layer as a solid *appearing* color. The colors are + subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from + compressing it too far since it seems to cause upload failures if + the image is a pure solid color + Red value + Green value + Blue value - - Used internally to track sim disconnections + + Final baked texture - - Event that is triggered when the simulator successfully - establishes a connection + + Component layers - - Whether this sim is currently connected or not. Hooked up - to the property Connected + + Width of the final baked image and scratchpad - - Coarse locations of avatars in this simulator + + Height of the final baked image and scratchpad - - AvatarPositions key representing TrackAgent target + + Bake type - - Sequence numbers of packets we've received - (for duplicate checking) + + Is this one of the 3 skin bakes - - Packets we sent out that need ACKs from the simulator + + + Represents a Sound Asset + - - Sequence number for pause/resume + + Initializes a new instance of an AssetSound object - - Indicates if UDP connection to the sim is fully established + + 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 - Reference to the GridClient object - IPEndPoint of the simulator - handle of the simulator - + - Called when this Simulator object is being destroyed + TODO: Decode a sound file + true - - - 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 + + Override the base classes AssetType - + - Initiates connection to the simulator + Represents an that represents an avatars body ie: Hair, Etc. - Should we block until ack for this packet is recieved - - - Disconnect from this simulator - + + Initializes a new instance of an AssetBodyPart object - - - Instructs the simulator to stop sending update (and possibly other) packets - + + Initializes a new instance of an AssetBodyPart object with parameters + A unique specific to this asset + A byte array containing the raw asset data - - - Instructs the simulator to resume sending update packets (unpause) - + + Override the base classes AssetType - + - Retrieve the terrain height at a given coordinate + Avatar profile flags - 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 + Represents an avatar (other than your own) - Packet to be sent - - - - + + Groups that this avatar is a member of - - - Returns Simulator Name as a String - - + + 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 - - - + - Sends out pending acknowledgements + Appearance version. Value greater than 0 indicates using server side baking - Number of ACKs sent - + - Resend unacknowledged packets + Version of the Current Outfit Folder that the appearance is based on - + - Provides access to an internal thread-safe dictionary containing parcel - information found in this simulator + Appearance flags. Introduced with server side baking, currently unused. - + - Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped - to each 64x64 parcel's LocalID. + List of current avatar animations - - 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 + Default constructor - - 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 + + First name - - Total number of pings sent to this simulator by this agent + + Last name - - Total number of ping replies sent to this agent by this simulator + + Full name - - - Incoming bytes per second - - It would be nice to have this claculated on the fly, but - this is far, far easier + + Active group - + - Outgoing bytes per second + Positive and negative ratings - It would be nice to have this claculated on the fly, but - this is far, far easier - - Time last ping was sent + + Positive ratings for Behavior - - ID of last Ping sent + + Negative ratings for Behavior - - + + Positive ratings for Appearance - - + + Negative ratings for Appearance - - Current time dilation of this simulator + + Positive ratings for Building - - Current Frames per second of simulator + + Negative ratings for Building - - Current Physics frames per second of simulator + + Positive ratings given by this avatar - - + + Negative ratings given by this avatar - - + + + Avatar properties including about text, profile URL, image IDs and + publishing settings + - - + + First Life about text - - + + First Life image ID - + - + - + - + - - Total number of objects Simulator is simulating + + Profile image ID - - Total number of Active (Scripted) objects running + + Flags of the profile - - Number of agents currently in this simulator + + Web URL for this profile - - Number of agents in neighbor simulators + + Should this profile be published on the web - - Number of Active scripts running in this simulator + + Avatar Online Status - - + + Is this a mature profile - + - + - - Number of downloads pending + + + Avatar interests including spoken languages, skills, and "want to" + choices + - - Number of uploads pending + + Languages profile field - + - + - - 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 + Index of TextureEntry slots for avatar appearances - + - + Bake layers for avatar appearance - - 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 + Appearance Flags, introdued with server side baking, currently unused - - 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 + + Maximum number of concurrent downloads for wearable assets and textures - - Whether the object has a name value pairs string + + Maximum number of concurrent uploads for baked textures - - Whether the object has a Media URL set + + Timeout for fetching inventory listings - - - Specific Flags for MultipleObjectUpdate requests - + + Timeout for fetching a single wearable, or receiving a single packet response - - None + + Timeout for fetching a single texture - - Change position of prims + + Timeout for uploading a single baked texture - - Change rotation of prims + + Number of times to retry bake upload - - Change size of prims + + When changing outfit, kick off rebake after + 20 seconds has passed since the last change - - Perform operation on link set + + Total number of wearables for each avatar - - Scale prims uniformly, same as selecing ctrl+shift in the - viewer. Used in conjunction with Scale + + Total number of baked textures on each avatar - - - Special values in PayPriceReply. If the price is not one of these - literal value of the price should be use - + + Total number of wearables per bake layer - - - Indicates that this pay option should be hidden - + + Mask for multiple attachments - - - Indicates that this pay option should have the default value - + + Mapping between BakeType and AvatarTextureIndex - - - Contains the variables sent in an object update packet for objects. - Used to track position and movement of prims and avatars - + + Map of what wearables are included in each bake - - + + Magic values to finalize the cache check hashes for each + bake - - + + Default avatar texture, used to detect when a custom + texture is not set for a face - - + + The event subscribers. null if no subcribers - - + + Raises the AgentWearablesReply event + An AgentWearablesReplyEventArgs object containing the + data returned from the data server - - + + Thread sync lock object - - + + The event subscribers. null if no subcribers - - + + Raises the CachedBakesReply event + An AgentCachedBakesReplyEventArgs object containing the + data returned from the data server AgentCachedTextureResponse - - + + Thread sync lock object - - + + The event subscribers. null if no subcribers - - + + Raises the AppearanceSet event + An AppearanceSetEventArgs object indicating if the operatin was successfull - - - Handles all network traffic related to prims and avatar positions and - movement. - + + Thread sync lock object - - The event subscribers, null of no subscribers + + The event subscribers. null if no subcribers - + + Raises the RebakeAvatarRequested event + An RebakeAvatarTexturesEventArgs object containing the + data returned from the data server + + Thread sync lock object - - The event subscribers, null of no subscribers + + Visual parameters last sent to the sim - - Raises the ObjectProperties Event - A ObjectPropertiesEventArgs object containing - the data sent from the simulator + + Textures about this client sent to the sim - - Thread sync lock object + + A cache of wearables currently being worn - - The event subscribers, null of no subscribers + + A cache of textures currently being worn - - Raises the ObjectPropertiesUpdated Event - A ObjectPropertiesUpdatedEventArgs object containing - the data sent from the simulator + + Incrementing serial number for AgentCachedTexture packets - - Thread sync lock object + + Incrementing serial number for AgentSetAppearance packets - - The event subscribers, null of no subscribers + + Indicates if WearablesRequest succeeded - - Raises the ObjectPropertiesFamily Event - A ObjectPropertiesFamilyEventArgs object containing - the data sent from the simulator + + Indicates whether or not the appearance thread is currently + running, to prevent multiple appearance threads from running + simultaneously - - Thread sync lock object + + Reference to our agent - - The event subscribers, null of no subscribers + + + Timer used for delaying rebake on changing outfit + - - Raises the AvatarUpdate Event - A AvatarUpdateEventArgs object containing - the data sent from the simulator + + + Main appearance thread + - - Thread sync lock object + + + Is server baking complete. It needs doing only once + - - The event subscribers, null of no subscribers + + + Default constructor + + A reference to our agent - - Thread sync lock object + + + Obsolete method for setting appearance. This function no longer does anything. + Use RequestSetAppearance() to manually start the appearance thread + - - The event subscribers, null of no subscribers + + + Obsolete method for setting appearance. This function no longer does anything. + Use RequestSetAppearance() to manually start the appearance thread + + Unused parameter - - Raises the ObjectDataBlockUpdate Event - A ObjectDataBlockUpdateEventArgs object containing - the data sent from the simulator + + + Starts the appearance setting thread + - - Thread sync lock object + + + Starts the appearance setting thread + + True to force rebaking, otherwise false - - The event subscribers, null of no subscribers + + + Check if current region supports server side baking + + True if server side baking support is detected - - Raises the KillObject Event - A KillObjectEventArgs object containing - the data sent from the simulator + + + Ask the server what textures our agent is currently wearing + - - Thread sync lock object + + + Build hashes out of the texture assetIDs for each baking layer to + ask the simulator whether it has cached copies of each baked texture + - - The event subscribers, null of no subscribers + + + Returns the AssetID of the asset that is currently being worn in a + given WearableType slot + + WearableType slot to get the AssetID for + The UUID of the asset being worn in the given slot, or + UUID.Zero if no wearable is attached to the given slot or wearables + have not been downloaded yet - - Raises the KillObjects Event - A KillObjectsEventArgs object containing - the data sent from the simulator + + + Add a wearable to the current outfit and set appearance + + Wearable to be added to the outfit - - Thread sync lock object + + + Add a wearable to the current outfit and set appearance + + Wearable to be added to the outfit + Should existing item on the same point or of the same type be replaced - - The event subscribers, null of no subscribers + + + Add a list of wearables to the current outfit and set appearance + + List of wearable inventory items to + be added to the outfit + Should existing item on the same point or of the same type be replaced - - Raises the AvatarSitChanged Event - A AvatarSitChangedEventArgs object containing - the data sent from the simulator + + + Add a list of wearables to the current outfit and set appearance + + List of wearable inventory items to + be added to the outfit + Should existing item on the same point or of the same type be replaced - - Thread sync lock object + + + Remove a wearable from the current outfit and set appearance + + Wearable to be removed from the outfit - - The event subscribers, null of no subscribers + + + Removes a list of wearables from the current outfit and set appearance + + List of wearable inventory items to + be removed from the outfit - - Raises the PayPriceReply Event - A PayPriceReplyEventArgs object containing - the data sent from the simulator + + + Replace the current outfit with a list of wearables and set appearance + + List of wearable inventory items that + define a new outfit - - Thread sync lock object + + + Replace the current outfit with a list of wearables and set appearance + + List of wearable inventory items that + define a new outfit + Check if we have all body parts, set this to false only + if you know what you're doing - - The event subscribers, null of no subscribers + + + Checks if an inventory item is currently being worn + + The inventory item to check against the agent + wearables + The WearableType slot that the item is being worn in, + or WearbleType.Invalid if it is not currently being worn - - Raises the PhysicsProperties Event - A PhysicsPropertiesEventArgs object containing - the data sent from the simulator + + + Returns a copy of the agents currently worn wearables + + A copy of the agents currently worn wearables + Avoid calling this function multiple times as it will make + a copy of all of the wearable data each time - - Thread sync lock object + + + Calls either or + depending on the value of + replaceItems + + List of wearable inventory items to add + to the outfit or become a new outfit + True to replace existing items with the + new list of items, false to add these items to the existing outfit - - Reference to the GridClient object + + + Adds a list of attachments to our agent + + A List containing the attachments to add + If true, tells simulator to remove existing attachment + first - - Does periodic dead reckoning calculation to convert - velocity and acceleration to new positions for objects + + + Adds a list of attachments to our agent + + A List containing the attachments to add + If true, tells simulator to remove existing attachment + If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + first - + - Construct a new instance of the ObjectManager class + Attach an item to our agent at a specific attach point - A reference to the instance + A to attach + the on the avatar + to attach the item to - + - Request information for a single object from a - you are currently connected to + Attach an item to our agent at a specific attach point - The the object is located - The Local ID of the object + A to attach + the on the avatar + If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + to attach the item to - + - Request information for multiple objects contained in - the same simulator + Attach an item to our agent specifying attachment details - The the objects are located - An array containing the Local IDs of the objects + The of the item to attach + The attachments owner + The name of the attachment + The description of the attahment + The to apply when attached + The of the attachment + The on the agent + to attach the item to - - - 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); - - + + + Attach an item to our agent specifying attachment details + + The of the item to attach + The attachments owner + The name of the attachment + The description of the attahment + The to apply when attached + The of the attachment + The on the agent + If true replace existing attachment on this attachment point, otherwise add to it (multi-attachments) + to attach the item to - + - 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 + Detach an item from our agent using an object - The the object is located - The ID of the object - The result is raised in the event + An object - + - Select a single object. This will cause the to send us - an which will raise the event + Detach an item from our agent - The the object is located - The Local ID of the object - + The inventory itemID of the item to detach - + - Select a single object. This will cause the to send us - an which will raise the event + Inform the sim which wearables are part of our current outfit - 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 - + Replaces the Wearables collection with a list of new wearable items + + Wearable items to replace the Wearables collection with - + - 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 - + Calculates base color/tint for a specific wearable + based on its params + + All the color info gathered from wearable's VisualParams + passed as list of ColorParamInfo tuples + Base color/tint for the wearable - + - Update the properties of an object + Blocking method to populate the Wearables dictionary - 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 + True on success, otherwise false - + - Update the properties of an object + Blocking method to populate the Textures array with cached bakes - 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 + True on success, otherwise false - + - Sets the sale properties of a single object + Populates textures and visual params from a decoded asset - The the object is located - The Local ID of the object - One of the options from the enum - The price of the object + Wearable to decode - + - 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 + Blocking method to download and parse currently worn wearable assets + + True on success, otherwise false - + - Deselect a single object + Get a list of all of the textures that need to be downloaded for a + single bake layer - The the object is located - The Local ID of the object + Bake layer to get texture AssetIDs for + A list of texture AssetIDs to download - + - Deselect multiple objects. + Helper method to lookup the TextureID for a single layer and add it + to a list if it is not already present - The the objects are located - An array containing the Local IDs of the objects + + - + - Perform a click action on an object + Blocking method to download all of the textures needed for baking + the given bake layers - The the object is located - The Local ID of the object + A list of layers that need baking + No return value is given because the baking will happen + whether or not all textures are successfully downloaded - + - Perform a click action (Grab) on a single object + Blocking method to create and upload baked textures for all of the + missing bakes - 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 + True on success, otherwise false - + - Create (rez) a new prim object in a simulator + Blocking method to create and upload a baked texture for a single + bake layer - 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 + Layer to bake + True on success, otherwise false - + - Create (rez) a new prim object in a simulator + Blocking method to upload a baked texture - 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 + Five channel JPEG2000 texture data to upload + UUID of the newly created asset on success, otherwise UUID.Zero - + - Rez a Linden tree + Creates a dictionary of visual param values from the downloaded wearables - 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 + A dictionary of visual param indices mapping to visual param + values for our agent that can be fed to the Baker class - + - Rez grass and ground cover + Initate server baking process - 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 + True if the server baking was successful - + - Set the textures to apply to the faces of an object + Get the latest version of COF - 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 + Current Outfit Folder (or null if getting the data failed) - + - Set the textures to apply to the faces of an object + Create an AgentSetAppearance packet from Wearables data and the + Textures array and send it - 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 + Converts a WearableType to a bodypart or clothing WearableType - 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 + A WearableType + AssetType.Bodypart or AssetType.Clothing or AssetType.Unknown - + - Set the flexible data on an object + Converts a BakeType to the corresponding baked texture slot in AvatarTextureIndex - 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 + A BakeType + The AvatarTextureIndex slot that holds the given BakeType - + - Set the sculptie texture and data on an object + Gives the layer number that is used for morph mask - 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 + >A BakeType + Which layer number as defined in BakeTypeToTextures is used for morph mask - + - Unset additional primitive parameters on an object + Converts a BakeType to a list of the texture slots that make up that bake - 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 + 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. + + - Link multiple prims into a linkset + Raised when appearance data is sent to the simulator, also indicates + the main appearance thread is finished. - 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? + request. - + - Delink/Unlink multiple prims from a linkset + Triggered when the simulator requests the agent rebake its appearance. - 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 + Returns true if AppearanceManager is busy and trying to set or change appearance will fail - 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 + Contains information about a wearable inventory item - 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 - + + Inventory ItemID of the wearable + + + AssetID of the wearable asset + + + WearableType of the wearable + + + AssetType of the wearable + + + Asset data for the wearable + + - Set the name of multiple objects + Data collected from visual params for each wearable + needed for the calculation of the color - 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 + 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 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 - + + 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 + + + Construct a new instance of the AgentWearablesReplyEventArgs class + + + Contains the Event data returned from the data server from an AgentCachedTextureResponse + + + Construct a new instance of the AgentCachedBakesReplyEventArgs class + + + Contains the Event data returned from an AppearanceSetRequest + + - 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 + 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 - - - 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 + + Contains the Event data returned from the data server from an RebakeAvatarTextures - + - Drop an attached object from this avatar + Triggered when the simulator sends a request for this agent to rebake + its appearance - 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 + The ID of the Texture Layer to bake - + + The ID of the Texture Layer to bake + + - Detach an object from yourself + Represents an Animation - 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 - + + Default Constructor + + - Change the position of an object, Will change position of entire linkset + Construct an Asset object of type Animation - 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 + A unique specific to this asset + A byte array containing the raw asset data - + + Override the base classes AssetType + + - 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() + 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. - 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 + Key + Value - + - Set the permissions on multiple objects + A dictionary of callbacks to fire when specified action occurs - 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 + Register a callback to be fired when an action occurs - A reference to the object where the object resides - + The action + The callback to fire - + - Request additional properties for an object + Unregister a callback - A reference to the object where the object resides - Absolute UUID of the object - Whether to require server acknowledgement of this request + The action + The callback to fire - + - 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 + + - + + Internal dictionary that this class wraps around. Do not + modify or enumerate the contents of this dictionary without locking + + - Update current URL of the previously set prim media + Initializes a new instance of the Class + with the specified key/value, has the default initial capacity. - UUID of the prim - Set current URL to this - Prim face number - Simulator in which prim is located + + + // 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>(); + + - + - Set object media + Initializes a new instance of the Class + with the specified key/value, With its initial capacity specified. - 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 + 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); + + - + - Retrieve information about object media + Try to get entry from the with specified key - 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 + 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); + + + - + - A terse object update, used when a transformation matrix or - velocity/acceleration for an object changes but nothing else - (scale/position/rotation/acceleration/velocity) + Finds the specified match. - 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 + 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; }); + + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + 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)); + } + ); + + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + 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); + } + ); + + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Check if Key exists in Dictionary + Key to check for + if found, otherwise - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + 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 - + - Setup construction data for a basic primitive shape + Removes the specified key, dictionary locking is not performed - Primitive shape to construct - Construction data that can be plugged into a + The key. + if successful, otherwise - + - + Clear the contents of the dictionary - - - - - + - + Enumerator for iterating dictionary entries - - + - + - Set the Shape data of an object + Gets the number of Key/Value pairs contained in the - 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 + Indexer for the dictionary - 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 + The key + The value - + - - - - - + - - - - - + - + - + De-serialization constructor for the InventoryNode Class - - - - - - - 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 + Serialization handler for the InventoryNode Class - 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 + De-serialization handler for the InventoryNode 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); - } - - + + + For inventory folder nodes specifies weather the folder needs to be + refreshed from the server + - + - Construct a new instance of the ObjectPropertiesEventArgs class + Capability to load TGAs to Bitmap - The simulator the object is located - The primitive Properties - - Get the simulator the object is located + + + Represents a string of characters encoded with specific formatting properties + - - Get the primitive properties + + A text string containing main text of the notecard - - 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 - + + List of s embedded on the notecard - + + Construct an Asset of type Notecard + + - Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class - - The simulator the object is located - The Primitive - The primitive Properties + Construct an Asset object of type Notecard + + A unique specific to this asset + A byte array containing the raw asset data - - Get the primitive details + + + Encode the raw contents of a string with the specific Linden Text 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 - + + + Decode the raw asset data including the Linden Text properties + + true if the AssetData was successfully decoded - - Get the simulator the object is located + + Override the base classes AssetType - - + + + Simulator (region) properties + - - + + No flags set - - Provides primitive data containing updated location, velocity, rotation, textures for the event - The event occurs when the simulator sends updated location, velocity, rotation, etc - + + Agents can take damage and be killed - - Get the simulator the object is located + + Landmarks can be created here - - Get the primitive details + + 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 - - Get the simulator the object is located + + Disable heightmap alterations (agents can still plant + foliage) - - Get the primitive details + + 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. - - Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the - event + + No collision detection for non-agent objects - - Get the simulator the object is located + + No scripts are ran - - The LocalID of the object + + All physics processing is turned off - - Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the - event + + Region can be seen from other regions on world map. (Legacy world map option?) - - Get the simulator the object is located + + Region can be seen from mainland on world map. (Legacy world map option?) - - The LocalID of the object + + Agents not explicitly on the access list can visit the region. - - - Provides updates sit position data - + + Traffic calculations are not run across entire region, overrides parcel settings. - - Get the simulator the object is located + + 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 - - Get the simulator the object is located + + 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. - + - Indicates if the operation was successful + Region protocol flags - + - Media version string + Access level for a simulator - - - Array of media entries indexed by face number - + + Unknown or invalid access level - - - Set when simulator sends us infomation on primitive's physical properties - + + Trial accounts allowed - - Simulator where the message originated + + PG rating - - Updated physical properties + + Mature rating - - - Constructor - - Simulator where the message originated - Updated physical properties + + Adult rating - - - - + + Simulator is offline - + + Simulator does not exist + + - - - - De-serialization constructor for the InventoryNode Class - + + A public reference to the client that this Simulator object + is attached to - - - Serialization handler for the InventoryNode Class - + + A Unique Cache identifier for this simulator - - - De-serialization handler for the InventoryNode Class - + + 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 + + - + - + - - - For inventory folder nodes specifies weather the folder needs to be - refreshed from the server - + + - - - 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 + + true if your agent has Estate Manager rights on this region - - - 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 - ... + + 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 root folder of this avatars inventory - + + 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 + + - + - The default shared library folder + Flags indicating which protocols this region supports - - - The root node of the avatars inventory - + + The current sequence number for packets sent to this + simulator. Must be Interlocked before modifying. Only + useful for applications manipulating sequence numbers - + - The root node of the default shared library + A thread-safe dictionary containing avatars in a simulator - + - 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. + A thread-safe dictionary containing primitives in a simulator - The UUID of the InventoryObject to get or set, ignored if set to non-null value. - The InventoryObject corresponding to uuid. - + - Map layer request type + Checks simulator parcel map to make sure it has downloaded all data successfully + true if map is full (contains no 0's) - - 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. + Is it safe to send agent updates to this sim + AgentMovementComplete message received - - Telehub + + Used internally to track sim disconnections - - PG rated event + + Event that is triggered when the simulator successfully + establishes a connection - - Mature rated event + + Whether this sim is currently connected or not. Hooked up + to the property Connected - - Popular location + + Coarse locations of avatars in this simulator - - Locations of avatar groups in a region + + AvatarPositions key representing TrackAgent target - - Land for sale + + Sequence numbers of packets we've received + (for duplicate checking) - - Classified ad + + Packets we sent out that need ACKs from the simulator - - Adult rated event + + Sequence number for pause/resume - - Adult land for sale + + Indicates if UDP connection to the sim is fully established - + - Information about a region on the grid map + + Reference to the GridClient object + IPEndPoint of the simulator + handle of the simulator - - Sim X position on World Map - - - Sim Y position on World Map + + + Called when this Simulator object is being destroyed + - - Sim Name (NOTE: In lowercase!) + + + 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 - - Appears to always be zero (None) + + + Disconnect from this simulator + - - Sim's defined Water Height + + + Instructs the simulator to stop sending update (and possibly other) packets + - - + + + Instructs the simulator to resume sending update packets (unpause) + - - UUID of the World Map image + + + 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 - - Unique identifier for this region, a combination of the X - and Y position + + + Sends a packet + + Packet to be sent - + + + + + Returns Simulator Name as a String + - + - + - + - Visual chunk of the grid map + Sends out pending acknowledgements + Number of ACKs sent - + - Base class for Map Items + Resend unacknowledged packets - - The Global X position of the item + + + Provides access to an internal thread-safe dictionary containing parcel + information found in this simulator + - - The Global Y position of the item + + + Provides access to an internal thread-safe multidimensional array containing a x,y grid mapped + to each 64x64 parcel's LocalID. + - - Get the Local X position of the item + + The IP address and port of the server - - Get the Local Y position of the item + + Whether there is a working connection to the simulator or + not - - Get the Handle of the region + + Coarse locations of avatars in this simulator - + + AvatarPositions key representing TrackAgent target + + + Indicates if UDP connection to the sim is fully established + + - Represents an agent or group of agents location + 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 + + - Represents a Telehub location + Incoming bytes per second + It would be nice to have this claculated on the fly, but + this is far, far easier - + - Represents a non-adult parcel of land for sale + Outgoing bytes per second + It would be nice to have this claculated on the fly, but + this is far, far easier - - - Represents an Adult parcel of land for sale - + + Time last ping was sent - - - Represents a PG Event - + + ID of last Ping sent - - - Represents a Mature event - + + - - - Represents an Adult event - + + - - - Manages grid-wide tasks such as the world map - + + Current time dilation of this simulator - - The event subscribers. null if no subcribers + + Current Frames per second of simulator - - Raises the CoarseLocationUpdate event - A CoarseLocationUpdateEventArgs object containing the - data sent by simulator + + Current Physics frames per second of 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 + + Total number of objects Simulator is simulating - - Thread sync lock object + + Total number of Active (Scripted) objects running - - The event subscribers. null if no subcribers + + Number of agents currently in this simulator - - Raises the RegionHandleReply event - A RegionHandleReplyEventArgs object containing the - data sent by simulator + + Number of agents in neighbor simulators - - Thread sync lock object + + Number of Active scripts running in this simulator - - 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 + + - - - - - + + Number of downloads pending - - - Request a map layer - - The name of the region - The type of layer + + 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 - - - - + - Request data for all mainland (Linden managed) simulators + The cache of prims used and unused in this simulator - + - Request the region handle for the specified region UUID + Shared parcel info only when POOL_PARCEL_DATA == true - 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 + + - - - 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 - - - + + No report + + + Unknown report type + + + Bug report + + + Complaint report + + + Customer service report + + - Search Places for parcels of land you personally own + 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 + + - Searches Places for land owned by the specified group + Specific Flags for MultipleObjectUpdate requests - 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. - + + 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 + + - Search the Places directory for parcels that are listed in search and contain the specified keywords + Special values in PayPriceReply. If the price is not one of these + literal value of the price should be use - A string containing the keywords to search for - Transaction (Query) ID which can be associated with results from your request. - + - Search Places - All Options + Indicates that this pay option should be hidden - 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 + Indicates that this pay option should have the default value - 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 + Contains the variables sent in an object update packet for objects. + Used to track position and movement of prims and avatars - 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. + + + Handles all network traffic related to prims and avatar positions and + movement. + - - Raised when the data server responds to a request. + + The event subscribers, null of no subscribers - - Raised when the data server responds to a request. + + Thread sync lock object - - Raised when the data server responds to a request. + + The event subscribers, null of no subscribers - - Raised when the data server responds to a request. + + Raises the ObjectProperties Event + A ObjectPropertiesEventArgs object containing + the data sent from the simulator - - Raised when the data server responds to a request. + + Thread sync lock object - - Raised when the data server responds to a request. + + The event subscribers, null of no subscribers - - Raised when the data server responds to a request. + + Raises the ObjectPropertiesUpdated Event + A ObjectPropertiesUpdatedEventArgs object containing + the data sent from the simulator - - Classified Ad categories + + Thread sync lock object - - Classified is listed in the Any category + + The event subscribers, null of no subscribers - - Classified is shopping related + + Raises the ObjectPropertiesFamily Event + A ObjectPropertiesFamilyEventArgs object containing + the data sent from the simulator - - Classified is + + 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 - - Event Categories + + 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 - - - 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 - + + The event subscribers, null of no subscribers - - Query the People database + + Raises the PhysicsProperties Event + A PhysicsPropertiesEventArgs object containing + the data sent from the simulator - - + + Thread sync lock object - - + + Reference to the GridClient object - - Query the Groups database + + Does periodic dead reckoning calculation to convert + velocity and acceleration to new positions for objects - - Query the Events database + + + Construct a new instance of the ObjectManager class + + A reference to the instance - - Query the land holdings database for land owned by the currently connected agent + + + 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 - - Query the land holdings database for land which is owned by a Group + + + 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); + + - - Specifies the query should pre sort the results based upon traffic - when searching the Places database + + + 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 + - - 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 + + + 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 - - 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 + + + 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 - - 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 + + + 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 - - 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 + + + 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 - - 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 + + + Deselect a single object + + The the object is located + The Local ID of the object - - 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 + + + Deselect multiple objects. + + The the objects are located + An array containing the Local IDs of the objects - - 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 + + + 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 - - Include PG land in results. This flag is used when searching both the Groups, Events and Land sales databases + + + 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 - - Include Mature land in results. This flag is used when searching both the Groups, Events and Land sales databases + + + 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 - - Include Adult land in results. This flag is used when searching both the Groups, Events and Land sales databases + + + 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 - + - Land types to search dataserver for + 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) - - Search Auction, Mainland and Estate + + + 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 - - Land which is currently up for auction + + + 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 - - Parcels which are on the mainland (Linden owned) continents + + + 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 - - Parcels which are on privately owned simulators + + + 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 - + - The content rating of the event + 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? - - Event is PG - - - Event is Mature - - - Event is Adult - - + - Classified Ad Options + Delink/Unlink multiple prims from a linkset - There appear to be two formats the flags are packed in. - This set of flags is for the newer style - - - - - - - - - - - - - - - + A reference to the object where the objects reside + An array which contains the IDs of the objects to delink - + - Classified ad query options + 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 - - 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 + 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 - - Parcel is not listed for sale + + + 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 - - Parcel is For Sale + + + 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 - + - A classified ad on the grid + 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 - - UUID for this ad, useful for looking up detailed - information about it + + + 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 - - The title of this classified ad + + + 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 - - Flags that show certain options applied to the classified + + + 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 - - Creation date of the ad + + + 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 - - Expiration date of the ad + + + 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 - - Price that was paid for this ad + + + 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 - - Print the struct data as a string - A string containing the field name, and field value + + + 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 - + - A parcel retrieved from the dataserver such as results from the - "For-Sale" listings or "Places" Search + 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 - - The unique dataserver parcel ID - This id is used to obtain additional information from the entry - by using the method + + + 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 - - A string containing the name of the parcel + + + 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 - - The size of the parcel - This field is not returned for Places searches + + + 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 - - The price of the parcel - This field is not returned for Places searches + + + Request additional properties for an object + + A reference to the object where the object resides + - - If True, this parcel is flagged to be auctioned + + + 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 - - If true, this parcel is currently set for sale + + + 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 - - Parcel traffic + + + 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 - - Print the struct data as a string - A string containing the field name, and field value + + + 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 - + - An Avatar returned from the dataserver + Retrieve information about object media + UUID of the primitive + Simulator where prim is located + Call this callback when done - - 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 + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - + - Response to a "Groups" Search + 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 - - The Group ID - - - The name of the group - - - The current number of members + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Print the struct data as a string - A string containing the field name, and field value + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - - 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 - + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The ID of the Agent of Group that owns the parcel + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The name + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The description + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - 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 + + + Setup construction data for a basic primitive shape + + Primitive shape to construct + Construction data that can be plugged into a - - Indicates the ForSale status of the parcel + + + + + + + + - - The Gridwide X position + + + + + + - - The Gridwide Y position + + + 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 - - The Z position of the parcel, or 0 if no landing point set + + + 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 - - 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) - - + + Raised when the simulator sends us data containing + A , Foliage or Attachment + + - - No longer used, will always be 0 + + Raised when the simulator sends us data containing + additional information + + - - Get a SL URL for the parcel - A string, containing a standard SLURL + + Raised when the simulator sends us data containing + Primitive.ObjectProperties for an object we are currently tracking - - Print the struct data as a string - A string containing the field name, and field value + + Raised when the simulator sends us data containing + additional and details + - - - An "Event" Listing summary - + + Raised when the simulator sends us data containing + updated information for an - - The ID of the event creator + + Raised when the simulator sends us data containing + and movement changes - - The name of the event + + Raised when the simulator sends us data containing + updates to an Objects DataBlock - - The events ID + + Raised when the simulator informs us an + or is no longer within view - - A string containing the short date/time the event will begin + + Raised when the simulator informs us when a group of + or is no longer within view - - The event start time in Unixtime (seconds since epoch) + + Raised when the simulator sends us data containing + updated sit information for our - - The events maturity rating + + Raised when the simulator sends us data containing + purchase price information for a - - Print the struct data as a string - A string containing the field name, and field value + + Raised when the simulator sends us data containing + additional information + + - + - The details of an "Event" + 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 events ID - - - The ID of the event creator - - - The name of the event - - - The category + + 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); + } + + + + + - - The events description + + + 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 - - The short date/time the event will begin + + Get the simulator the originated from - - The event start time in Unixtime (seconds since epoch) UTC adjusted + + Get the details - - The length of the event in minutes + + true if the did not exist in the dictionary before this update (always true if object tracking has been disabled) - - 0 if no cover charge applies + + true if the is attached to an - - The cover charge amount in L$ if applicable + + Get the simulator Time Dilation - - The name of the region where the event is being held + + 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); + } + } + + + + - - The gridwide location of the event + + + 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 - - The maturity rating + + Get the simulator the object originated from - - Get a SL URL for the parcel where the event is hosted - A string, containing a standard SLURL + + Get the data - - Print the struct data as a string - A string containing the field name, and field value + + Get the simulator time dilation - - Contains the Event data returned from the data server from an EventInfoRequest + + 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 EventInfoReplyEventArgs class - A single EventInfo object containing the details of an event + + 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); + } + + - + - A single EventInfo object containing the details of an event + Construct a new instance of the ObjectPropertiesEventArgs class + The simulator the object is located + The primitive Properties - - Contains the "Event" detail data returned from the data server + + Get the simulator the object is located - - 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 + + Get the primitive properties - - The ID returned by + + 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 + - - A list of "Events" returned by the data server + + + Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class + + The simulator the object is located + The Primitive + The primitive Properties - - Contains the "Event" list data returned from the data server + + Get the primitive details - - 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 + + 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 + - - The ID returned by + + Get the simulator the object is located - - 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 + + Provides primitive data containing updated location, velocity, rotation, textures for the event + The event occurs when the simulator sends updated location, velocity, rotation, etc + - - The ID returned by + + Get the simulator the object is located + + + Get the primitive details - - 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 + + Get the simulator the object is located - - Contains the group data returned from the data server + + Get the primitive details - - 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 + + Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the + event - - The ID returned by + + Get the simulator the object is located - - A list containing People data returned by the data server + + The LocalID of the object - - Contains the land sales data returned from the data server + + Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the + event - - Construct a new instance of the DirLandReplyEventArgs class - A list of parcels for sale returned by the data server + + Get the simulator the object is located - - A list containing land forsale data returned by the data server + + The LocalID of the object - + - Sent to the client to indicate a teleport request has completed + Provides updates sit position data - + + Get the simulator the object is located + + + + + + + + + + + - Interface requirements for Messaging system + - - The of the agent + + Get the simulator the object is located - + - - The simulators handle the agent teleported to - - - A Uri which contains a list of Capabilities the simulator supports + + - - Indicates the level of access required - to access the simulator, or the content rating, or the simulators - map status + + - - The IP Address of the simulator + + + Indicates if the operation was successful + - - The UDP Port the simulator will listen for UDP traffic on + + + Media version string + - - Status flags indicating the state of the Agent upon arrival, Flying, etc. + + + Array of media entries indexed by face number + - + - Serialize the object + Set when simulator sends us infomation on primitive's physical properties - An containing the objects data - + + Simulator where the message originated + + + Updated physical properties + + - Deserialize the message + Constructor - An containing the data + Simulator where the message originated + Updated physical properties - + - Sent to the viewer when a neighboring simulator is requesting the agent make a connection to it. + Exception class to identify inventory exceptions - + - Serialize the object + 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. - An containing the objects data - + + 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 + + - Deserialize the message + Returns the contents of the specified folder - An containing the data + A folder's UUID + The contents of the folder corresponding to folder + When folder does not exist in the inventory - + - Serialize the object + 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 - An containing the objects data + The InventoryObject to store - + - Deserialize the message + Removes the InventoryObject and all related node data from Inventory. - An containing the data + The InventoryObject to remove. - + - Serialize the object + Used to find out if Inventory contains the InventoryObject + specified by uuid. - An containing the objects data + The UUID to check. + true if inventory contains uuid, false otherwise - + - Deserialize the message + Saves the current inventory structure to a cache file - An containing the data + Name of the cache file to save to - + - A message sent to the client which indicates a teleport request has failed - and contains some information on why it failed + 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 + ... - - A string key of the reason the teleport failed e.g. CouldntTPCloser - Which could be used to look up a value in a dictionary or enum + + Raised when the simulator sends us data containing + ... - - The of the Agent + + Raised when the simulator sends us data containing + ... - - A string human readable message containing the reason - An example: Could not teleport closer to destination + + + The root folder of this avatars inventory + - + - Serialize the object + The default shared library folder - An containing the objects data - + - Deserialize the message + The root node of the avatars inventory - An containing the data - + - Serialize the object + The root node of the default shared library - An containing the objects data - + - Deserialize the message + 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. - An containing the data + The UUID of the InventoryObject to get or set, ignored if set to non-null value. + The InventoryObject corresponding to uuid. - + - Contains a list of prim owner information for a specific parcel in a simulator + 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. + - - A Simulator will always return at least 1 entry - If agent does not have proper permission the OwnerID will be UUID.Zero - If agent does not have proper permission OR there are no primitives on parcel - the DataBlocksExtended map will not be sent from the simulator - + Key + Value - - An Array of objects + + Internal dictionary that this class wraps around. Do not + modify or enumerate the contents of this dictionary without locking + on this member - + - Serialize the object + Initializes a new instance of the Class + with the specified key/value, has the default initial capacity. - An containing the objects data + + + // 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>(); + + - + - Deserialize the message + Initializes a new instance of the Class + with the specified key/value, has its initial valies copied from the specified + - An containing the data + + 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); + + - + - Prim ownership information for a specified owner on a single parcel + 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); + + - - The of the prim owner, - UUID.Zero if agent has no permission to view prim owner information - - - The total number of prims - - - True if the OwnerID is a - - - True if the owner is online - This is no longer used by the LL Simulators - - - The date the most recent prim was rezzed - - + - The details of a single parcel in a region, also contains some regionwide globals + 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); + + + - - Simulator-local ID of this parcel - - - Maximum corner of the axis-aligned bounding box for this - parcel - - - Minimum corner of the axis-aligned bounding box for this - parcel - - - Total parcel land area - - - - - - Key of authorized buyer - - - Bitmap describing land layout in 4x4m squares across the - entire region - - - - - - Date land was claimed - - - Appears to always be zero - - - Parcel Description - - - - - - - - - Total number of primitives owned by the parcel group on - this parcel - - - Whether the land is deeded to a group or not - - - - - - Maximum number of primitives this parcel supports - - - The Asset UUID of the Texture which when applied to a - primitive will display the media + + + 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; }); + + - - A URL which points to any Quicktime supported media type + + 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)); + } + ); + + - - A byte, if 0x1 viewer should auto scale media to fit object + + 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); + } + ); + + - - URL For Music Stream + + 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); + } + }); + + - - Parcel Name + + Perform an on each key of an + to perform - - Autoreturn value in minutes for others' objects + + + Perform an on each KeyValuePair of an + + to perform - - + + Check if Key exists in Dictionary + Key to check for + if found, otherwise - - Total number of other primitives on this parcel + + Check if Value exists in Dictionary + Value to check for + if found, otherwise - - UUID of the owner of this parcel + + + Adds the specified key to the dictionary, dictionary locking is not performed, + + + The key + The value - - Total number of primitives owned by the parcel owner on - this parcel + + + Removes the specified key, dictionary locking is not performed + + The key. + if successful, otherwise - - + + + Gets the number of Key/Value pairs contained in the + - - How long is pass valid for + + + Indexer for the dictionary + + The key + The value - - Price for a temporary pass + + + Constants for the archiving module + - - + + + The location of the archive control file + - - Disallows people outside the parcel from being able to see in + + + Path for the assets held in an archive + - - + + + Path for the prims file + - - + + + Path for terrains. Technically these may be assets, but I think it's quite nice to split them out. + - - + + + Path for region settings. + - - True if the region denies access to age unverified users + + + The character the separates the uuid from extension information in an archived asset filename + - - + + + Extensions used for asset types in the archive + - - This field is no longer used + + X position of this patch - - The result of a request for parcel properties + + Y position of this patch - - 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 + + A 16x16 array of floats holding decompressed layer data - + - Number of primitives your avatar is currently - selecting and sitting on in this parcel + 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 + - - - - + - A number which increments by 1, starting at 0 for each ParcelProperties request. - Can be overriden by specifying the sequenceID with the ParcelPropertiesRequest being sent. - a Negative number indicates the action in has occurred. + 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 - - Maximum primitives across the entire simulator - - - Total primitives across the entire simulator + + + pre-defined built in sounds + - + - - Key of parcel snapshot + + - - Parcel ownership status + + - - Total number of primitives on this parcel + + - + - + - - A description of the media + + - - An Integer which represents the height of the media + + - - An integer which represents the width of the media + + coins - - A boolean, if true the viewer should loop the media + + cash register bell - - A string which contains the mime type of the media + + - - true to obscure (hide) media url + + - - true to obscure (hide) music url + + rubber - - - Serialize the object - - An containing the objects data + + plastic - - - Deserialize the message - - An containing the data + + flesh - - A message sent from the viewer to the simulator to updated a specific parcels settings + + wood splintering? - - The of the agent authorized to purchase this - parcel of land or a NULL if the sale is authorized to anyone + + glass break - - true to enable auto scaling of the parcel media + + metal clunk - - The category of this parcel used when search is enabled to restrict - search results + + whoosh - - A string containing the description to set + + shake - - The of the which allows for additional - powers and restrictions. + + - - The which specifies how avatars which teleport - to this parcel are handled + + ding - - The LocalID of the parcel to update settings on + + - - A string containing the description of the media which can be played - to visitors + + - + - + - + - + - + - + - + - + - + - + - + - + - + + + 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 + + + + + + + + + + + + - + - + - + - + - + - + - Deserialize the message + - An containing the data - + - Serialize the object + Checks the instance back into the object pool - An containing the objects data - - Base class used for the RemoteParcelRequest message + + + Returns an instance of the class that has been checked out of the Object Pool. + - + - A message sent from the viewer to the simulator to request information - on a remote parcel + Sent to the client to indicate a teleport request has completed - - Local sim position of the parcel we are looking up + + The of the agent - - Region handle of the parcel we are looking up + + - - Region of the parcel we are looking up + + The simulators handle the agent teleported to - + + A Uri which contains a list of Capabilities the simulator supports + + + Indicates the level of access required + to access the simulator, or the content rating, or the simulators + map status + + + The IP Address of the simulator + + + The UDP Port the simulator will listen for UDP traffic on + + + Status flags indicating the state of the Agent upon arrival, Flying, etc. + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - A message sent from the simulator to the viewer in response to a - which will contain parcel information + Sent to the viewer when a neighboring simulator is requesting the agent make a connection to it. - - The grid-wide unique parcel ID + + + Serialize the object + + An containing the objects data - + + + Deserialize the message + + An containing the data + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - A message containing a request for a remote parcel from a viewer, or a response - from the simulator to that request + Serialize the object + An containing the objects data - - The request or response details block + + + Deserialize the message + + An containing the data - + + + A message sent to the client which indicates a teleport request has failed + and contains some information on why it failed + + + + + + + A string key of the reason the teleport failed e.g. CouldntTPCloser + Which could be used to look up a value in a dictionary or enum + + + The of the Agent + + + A string human readable message containing the reason + An example: Could not teleport closer to destination + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + + + Contains a list of prim owner information for a specific parcel in a simulator + + + A Simulator will always return at least 1 entry + If agent does not have proper permission the OwnerID will be UUID.Zero + If agent does not have proper permission OR there are no primitives on parcel + 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 - + - A message sent from the simulator to an agent which contains - the groups the agent is in + Prim ownership information for a specified owner on a single parcel + + + + The of the prim owner, + UUID.Zero if agent has no permission to view prim owner information + + + The total number of prims + + + True if the OwnerID is a + + + True if the owner is online + This is no longer used by the LL Simulators + + + The date the most recent prim was rezzed + + + + The details of a single parcel in a region, also contains some regionwide globals - - The Agent receiving the message + + Simulator-local ID of this parcel + + + Maximum corner of the axis-aligned bounding box for this + parcel + + + Minimum corner of the axis-aligned bounding box for this + parcel + + + Total parcel land area + + + + + + Key of authorized buyer + + + Bitmap describing land layout in 4x4m squares across the + entire region + + + + + + Date land was claimed + + + Appears to always be zero - - An array containing information - for each the agent is a member of + + Parcel Description - - 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 + + Total number of primitives owned by the parcel group on + this parcel - - Group Details specific to the agent + + Whether the land is deeded to a group or not - - true of the agent accepts group notices + + - - The agents tier contribution to the group + + Maximum number of primitives this parcel supports - - The Groups + + The Asset UUID of the Texture which when applied to a + primitive will display the media - - The of the groups insignia + + A URL which points to any Quicktime supported media type - - The name of the group + + A byte, if 0x1 viewer should auto scale media to fit object - - The aggregate permissions the agent has in the group for all roles the agent - is assigned + + URL For Music Stream - - An optional block containing additional agent specific information + + Parcel Name - - true of the agent allows this group to be - listed in their profile + + Autoreturn value in minutes for others' objects - - - A message sent from the viewer to the simulator which - specifies the language and permissions for others to detect - the language specified - + + - - A string containng the default language - to use for the agent + + Total number of other primitives on this parcel - - true of others are allowed to - know the language setting + + UUID of the owner of this parcel - - - Serialize the object - - An containing the objects data + + Total number of primitives owned by the parcel owner on + this parcel - - - Deserialize the message - - An containing the data + + - - - An EventQueue message sent from the simulator to an agent when the agent - leaves a group - + + How long is pass valid for - - - An Array containing the AgentID and GroupID - + + Price for a temporary pass - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + Disallows people outside the parcel from being able to see in - - 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 + + True if the region denies access to age unverified users - - - The request state - + + - - - Serialize the object - - An containing the objects data + + This field is no longer used - - - Deserialize the message - - An containing the data + + The result of a request for parcel properties - + + 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 + + - A message sent from the viewer to the simulator to request a temporary upload capability - which allows an asset to be uploaded + Number of primitives your avatar is currently + selecting and sitting on in this parcel - - The Capability URL sent by the simulator to upload the baked texture to + + - + - A message sent from the simulator that will inform the agent the upload is complete, - and the UUID of the uploaded asset + A number which increments by 1, starting at 0 for each ParcelProperties request. + Can be overriden by specifying the sequenceID with the ParcelPropertiesRequest being sent. + a Negative number indicates the action in has occurred. - - The uploaded texture asset ID + + Maximum primitives across the entire simulator - - - A message sent from the viewer to the simulator to request a temporary - capability URI which is used to upload an agents baked appearance textures - + + Total primitives across the entire simulator - - Object containing request or response + + - - - Serialize the object - - An containing the objects data + + Key of parcel snapshot - - - Deserialize the message - - An containing the data + + Parcel ownership status - - - A message sent from the simulator which indicates the minimum version required for - using voice chat - + + Total number of primitives on this parcel - - Major Version Required + + - - Minor version required + + - - The name of the region sending the version requrements + + A description of the media - - - Serialize the object - - An containing the objects data + + An Integer which represents the height of the media - - - Deserialize the message - - An containing the data + + An integer which represents the width of the media - - - A message sent from the simulator to the viewer containing the - voice server URI - + + A boolean, if true the viewer should loop the media - - The Parcel ID which the voice server URI applies + + A string which contains the mime type of the media - - The name of the region + + true to obscure (hide) media url - - A uri containing the server/channel information - which the viewer can utilize to participate in voice conversations + + true to obscure (hide) music url - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - - - + + A message sent from the viewer to the simulator to updated a specific parcels settings - + + The of the agent authorized to purchase this + parcel of land or a NULL if the sale is authorized to anyone + + + true to enable auto scaling of the parcel media + + + The category of this parcel used when search is enabled to restrict + search results + + + A string containing the description to set + + + The of the which allows for additional + powers and restrictions. + + + The which specifies how avatars which teleport + to this parcel are handled + + + The LocalID of the parcel to update settings on + + + A string containing the description of the media which can be played + to visitors + + - + - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - - A message sent by the viewer to the simulator to request a temporary - capability for a script contained with in a Tasks inventory to be updated - + + - - Object containing request or response + + - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - - A message sent from the simulator to the viewer to indicate - a Tasks scripts status. - + + - - The Asset ID of the script + + - - True of the script is compiled/ran using the mono interpreter, false indicates it - uses the older less efficient lsl2 interprter + + - - The Task containing the scripts + + - - true of the script is in a running state + + - - - Serialize the object - - An containing the objects data + + - - - Deserialize the message - - An containing the data + + - - - A message containing the request/response used for updating a gesture - contained with an agents inventory - + + - - Object containing request or response + + - - - Serialize the object - - An containing the objects data + + - + Deserialize the message An containing the data - - - A message request/response which is used to update a notecard contained within - a tasks inventory - - - - The of the Task containing the notecard asset to update - - - The notecard assets contained in the tasks inventory - - + Serialize the object An containing the objects data - - - Deserialize the message - - An containing the data + + Base class used for the RemoteParcelRequest message - + - A reusable class containing a message sent from the viewer to the simulator to request a temporary uploader capability - which is used to update an asset in an agents inventory + A message sent from the viewer to the simulator to request information + on a remote parcel - - - The Notecard AssetID to replace - + + Local sim position of the parcel we are looking up - + + Region handle of the parcel we are looking up + + + Region of the parcel we are looking up + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - - A message containing the request/response used for updating a notecard - contained with an agents inventory - - - - Object containing request or response - - + - Serialize the object + A message sent from the simulator to the viewer in response to a + which will contain parcel information - An containing the objects data - - - Deserialize the message - - An containing the data + + The grid-wide unique parcel ID - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - - A message sent from the simulator to the viewer which indicates - an error occurred while attempting to update a script in an agents or tasks - inventory - - - - true of the script was successfully compiled by the simulator - - - A string containing the error which occured while trying - to update the script - - - A new AssetID assigned to the script - - + - A message sent from the viewer to the simulator - requesting the update of an existing script contained - within a tasks inventory - - - - if true, set the script mode to running - - - The scripts InventoryItem ItemID to update - - - A lowercase string containing either "mono" or "lsl2" which - specifies the script is compiled and ran on the mono runtime, or the older - lsl runtime + A message containing a request for a remote parcel from a viewer, or a response + from the simulator to that request + - - The tasks which contains the script to update + + The request or response details block - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - A message containing either the request or response used in updating a script inside - a tasks inventory + Serialize the object + An containing the objects data - - Object containing request or response + + + Deserialize the message + + An containing the data - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - Response from the simulator to notify the viewer the upload is completed, and - the UUID of the script asset and its compiled status + A message sent from the simulator to an agent which contains + the groups the agent is in - - The uploaded texture asset ID - - - true of the script was compiled successfully - - - - A message sent from a viewer to the simulator requesting a temporary uploader capability - used to update a script contained in an agents inventory - + + The Agent receiving the message - - The existing asset if of the script in the agents inventory to replace + + An array containing information + for each the agent is a member of - - The language of the script - Defaults to lsl version 2, "mono" might be another possible option + + 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 + + + true of the agent accepts group notices + + + The agents tier contribution to the group + + + The Groups + + + The of the groups insignia + + + The name of the group + + + The aggregate permissions the agent has in the group for all roles the agent + is assigned + + + An optional block containing additional agent specific information + + + true of the agent allows this group to be + listed in their profile + + - A message containing either the request or response used in updating a script inside - an agents inventory + A message sent from the viewer to the simulator which + specifies the language and permissions for others to detect + the language specified - - Object containing request or response + + A string containng the default language + to use for the agent - + + true of others are allowed to + know the language setting + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + + + An EventQueue message sent from the simulator to an agent when the agent + leaves a group + + + + + An Array containing the AgentID and GroupID + + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - Base class for Map Layers via Capabilities + + 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 + + + + The request state + + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - Sent by an agent to the capabilities server to request map layers + A message sent from the viewer to the simulator to request a temporary upload capability + which allows an asset to be uploaded - + + The Capability URL sent by the simulator to upload the baked texture to + + - A message sent from the simulator to the viewer which contains an array of map images and their grid coordinates + A message sent from the simulator that will inform the agent the upload is complete, + and the UUID of the uploaded asset - - An array containing LayerData items + + The uploaded texture asset ID - + + + A message sent from the viewer to the simulator to request a temporary + capability URI which is used to upload an agents baked appearance textures + + + + Object containing request or response + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - An object containing map location details + A message sent from the simulator which indicates the minimum version required for + using voice chat - - The Asset ID of the regions tile overlay - - - The grid location of the southern border of the map tile - - - The grid location of the western border of the map tile - - - The grid location of the eastern border of the map tile + + Major Version Required - - The grid location of the northern border of the map tile + + Minor version required - - Object containing request or response + + The name of the region sending the version requrements - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - New as of 1.23 RC1, no details yet. + A message sent from the simulator to the viewer containing the + voice server URI - + + The Parcel ID which the voice server URI applies + + + The name of the region + + + A uri containing the server/channel information + which the viewer can utilize to participate in voice conversations + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + + + + + + + + + + + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - A string containing the method used - - + - A request sent from an agent to the Simulator to begin a new conference. - Contains a list of Agents which will be included in the conference - - - - An array containing the of the agents invited to this conference + A message sent by the viewer to the simulator to request a temporary + capability for a script contained with in a Tasks inventory to be updated + - - The conferences Session ID + + Object containing request or response - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - A moderation request sent from a conference moderator - Contains an agent and an optional action to take - + A message sent from the simulator to the viewer to indicate + a Tasks scripts status. + - - The Session ID + + The Asset ID of the script - - + + True of the script is compiled/ran using the mono interpreter, false indicates it + uses the older less efficient lsl2 interprter - - A list containing Key/Value pairs, known valid values: - key: text value: true/false - allow/disallow specified agents ability to use text in session - key: voice value: true/false - allow/disallow specified agents ability to use voice in session - - "text" or "voice" + + The Task containing the scripts - - + + true of the script is in a running state - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - A message sent from the agent to the simulator which tells the - simulator we've accepted a conference invitation + A message containing the request/response used for updating a gesture + contained with an agents inventory - - The conference SessionID + + Object containing request or response - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + + + A message request/response which is used to update a notecard contained within + a tasks inventory + + + + The of the Task containing the notecard asset to update + + + The notecard assets contained in the tasks inventory + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - Serialize the object + A reusable class containing a message sent from the viewer to the simulator to request a temporary uploader capability + which is used to update an asset in an agents inventory - An containing the objects data - + - Deserialize the message + The Notecard AssetID to replace - An containing the data - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - Key of sender - - - Name of sender - - - Key of destination avatar - - - ID of originating estate - - - Key of originating region - - - Coordinates in originating region - - - Instant message type - - - Group IM session toggle - - - Key of IM session, for Group Messages, the groups UUID - - - Timestamp of the instant message - - - Instant message text - - - Whether this message is held for offline avatars - - - Context specific packed data + + + A message containing the request/response used for updating a notecard + contained with an agents inventory + - - Is this invitation for voice group/conference chat + + Object containing request or response - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - - Sent from the simulator to the viewer. - - When an agent initially joins a session the AgentUpdatesBlock object will contain a list of session members including - a boolean indicating they can use voice chat in this session, a boolean indicating they are allowed to moderate - this session, and lastly a string which indicates another agent is entering the session with the Transition set to "ENTER" - - During the session lifetime updates on individuals are sent. During the update the booleans sent during the initial join are - excluded with the exception of the Transition field. This indicates a new user entering or exiting the session with - the string "ENTER" or "LEAVE" respectively. - - - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - An EventQueue message sent when the agent is forcibly removed from a chatterbox session + A message sent from the simulator to the viewer which indicates + an error occurred while attempting to update a script in an agents or tasks + inventory - - - A string containing the reason the agent was removed - + + true of the script was successfully compiled by the simulator - + + A string containing the error which occured while trying + to update the script + + + A new AssetID assigned to the script + + - The ChatterBoxSession's SessionID + A message sent from the viewer to the simulator + requesting the update of an existing script contained + within a tasks inventory - + + if true, set the script mode to running + + + The scripts InventoryItem ItemID to update + + + A lowercase string containing either "mono" or "lsl2" which + specifies the script is compiled and ran on the mono runtime, or the older + lsl runtime + + + The tasks which contains the script to update + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - Serialize the object + A message containing either the request or response used in updating a script inside + a tasks inventory - An containing the objects data - - - Deserialize the message - - An containing the data + + Object containing request or response - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - Serialize the object + Response from the simulator to notify the viewer the upload is completed, and + the UUID of the script asset and its compiled status - An containing the objects data - + + The uploaded texture asset ID + + + true of the script was compiled successfully + + - Deserialize the message + A message sent from a viewer to the simulator requesting a temporary uploader capability + used to update a script contained in an agents inventory - An containing the data - + + The existing asset if of the script in the agents inventory to replace + + + The language of the script + Defaults to lsl version 2, "mono" might be another possible option + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - + A message containing either the request or response used in updating a script inside + an agents inventory - + + Object containing request or response + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + + Base class for Map Layers via Capabilities + + + + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - + - Event Queue message describing physics engine attributes of a list of objects - Sim sends these when object is selected + Sent by an agent to the capabilities server to request map layers - - Array with the list of physics properties - - + - Serializes the message + A message sent from the simulator to the viewer which contains an array of map images and their grid coordinates - Serialized OSD - - - Deseializes the message - - Incoming data to deserialize + + An array containing LayerData items - + - A message sent from the viewer to the simulator which - specifies that the user has changed current URL - of the specific media on a prim face + Serialize the object + An containing the objects data - + - New URL + Deserialize the message + An containing the data - + - Prim UUID where navigation occured + An object containing map location details - - - Face index - + + The Asset ID of the regions tile overlay - + + The grid location of the southern border of the map tile + + + The grid location of the western border of the map tile + + + The grid location of the eastern border of the map tile + + + The grid location of the northern border of the map tile + + + Object containing request or response + + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - Base class used for the ObjectMedia message - - + - Message used to retrive prim media data + New as of 1.23 RC1, no details yet. - + - Prim UUID + Serialize the object + An containing the objects data - + - Requested operation, either GET or UPDATE + Deserialize the message + An containing the data - + - Serialize object + Serialize the object - Serialized object as OSDMap + An containing the objects data - + Deserialize the message An containing the data - - - Message used to update prim media data - + + A string containing the method used - + - Prim UUID - + A request sent from an agent to the Simulator to begin a new conference. + Contains a list of Agents which will be included in the conference + - - - Array of media entries indexed by face number - + + An array containing the of the agents invited to this conference - - - Media version string - + + The conferences Session ID - + - Serialize object + Serialize the object - Serialized object as OSDMap + An containing the objects data - + Deserialize the message An containing the data - + - Message used to update prim media data + A moderation request sent from a conference moderator + Contains an agent and an optional action to take + + + + The Session ID + + + + + + A list containing Key/Value pairs, known valid values: + key: text value: true/false - allow/disallow specified agents ability to use text in session + key: voice value: true/false - allow/disallow specified agents ability to use voice in session + "text" or "voice" - + + + + - Prim UUID + Serialize the object + An containing the objects data - + - Array of media entries indexed by face number + Deserialize the message + An containing the data - + - Requested operation, either GET or UPDATE + A message sent from the agent to the simulator which tells the + simulator we've accepted a conference invitation - + + The conference SessionID + + - Serialize object + Serialize the object - Serialized object as OSDMap + An containing the objects data - + Deserialize the message An containing the data - + - Message for setting or getting per face MediaEntry + Serialize the object + An containing the objects data - - The request or response details block + + + Deserialize the message + + An containing the data - + Serialize the object An containing the objects data - + Deserialize the message An containing the data - - Details about object resource usage - - - Object UUID - - - Object name - - - Indicates if object is group owned - - - Locatio of the object - - - Object owner - - - Resource usage, keys are resource names, values are resource usage for that specific resource - - + - Deserializes object from OSD + Serialize the object - An containing the data + An containing the objects data - + - Makes an instance based on deserialized data + Deserialize the message - serialized data - Instance containg deserialized data + An containing the data - - Details about parcel resource usage + + Key of sender - - Parcel UUID + + Name of sender - - Parcel local ID + + Key of destination avatar - - Parcel name + + ID of originating estate - - Indicates if parcel is group owned + + Key of originating region + + + Coordinates in originating region + + + Instant message type - - Parcel owner + + Group IM session toggle - - Array of containing per object resource usage + + Key of IM session, for Group Messages, the groups UUID - - - Deserializes object from OSD - - An containing the data + + Timestamp of the instant message - - - Makes an instance based on deserialized data - - serialized data - Instance containg deserialized data + + Instant message text - - Resource usage base class, both agent and parcel resource - usage contains summary information + + Whether this message is held for offline avatars - - Summary of available resources, keys are resource names, - values are resource usage for that specific resource + + Context specific packed data - - Summary resource usage, keys are resource names, - values are resource usage for that specific resource + + Is this invitation for voice group/conference chat - + - Serializes object + Serialize the object - serialized data + An containing the objects data - + - Deserializes object from OSD + Deserialize the message An containing the data - - Agent resource usage - - - Per attachment point object resource usage - - + - Deserializes object from OSD + Sent from the simulator to the viewer. + + When an agent initially joins a session the AgentUpdatesBlock object will contain a list of session members including + a boolean indicating they can use voice chat in this session, a boolean indicating they are allowed to moderate + this session, and lastly a string which indicates another agent is entering the session with the Transition set to "ENTER" + + During the session lifetime updates on individuals are sent. During the update the booleans sent during the initial join are + excluded with the exception of the Transition field. This indicates a new user entering or exiting the session with + the string "ENTER" or "LEAVE" respectively. - An containing the data - + - Makes an instance based on deserialized data + Serialize the object - serialized data - Instance containg deserialized data + An containing the objects data - + - Detects which class handles deserialization of this message + Deserialize the message An containing the data - Object capable of decoding this message - - - Request message for parcel resource usage - - - UUID of the parel to request resource usage info - + - Serializes object + An EventQueue message sent when the agent is forcibly removed from a chatterbox session - serialized data - + - Deserializes object from OSD + A string containing the reason the agent was removed - An containing the data - - - Response message for parcel resource usage - - - URL where parcel resource usage details can be retrieved - - - URL where parcel resource usage summary can be retrieved - + - Serializes object + The ChatterBoxSession's SessionID - serialized data - + - Deserializes object from OSD + Serialize the object - An containing the data + An containing the objects data - + - Detects which class handles deserialization of this message + Deserialize the message An containing the data - Object capable of decoding this message - - Parcel resource usage - - - Array of containing per percal resource usage + + + Serialize the object + + An containing the objects data - + - Deserializes object from OSD + Deserialize the message An containing the data - + - Reply to request for bunch if display names + Serialize the object + An containing the objects data - - Current display name - - - Following UUIDs failed to return a valid display name - - + - Serializes the message + Deserialize the message - OSD containting the messaage + An containing the data - + - Message sent when requesting change of the display name + Serialize the object + An containing the objects data - - Current display name - - - Desired new display name - - + - Serializes the message + Deserialize the message - OSD containting the messaage + An containing the data - + - Message recieved in response to request to change display name + Serialize the object + An containing the objects data - - New display name - - - String message indicating the result of the operation - - - Numerical code of the result, 200 indicates success - - + - Serializes the message + Deserialize the message - OSD containting the messaage + An containing the data - + - Message recieved when someone nearby changes their display name + - - Previous display name, empty string if default - - - New display name - - + - Serializes the message + Serialize the object - OSD containting the messaage + An containing the objects data - + - Archives assets + Deserialize the message + An containing the data - + - Archive assets + Serialize the object + An containing the objects data - + - Archive the assets given to this archiver to the given archive. + Deserialize the message - + An containing the data - + - Write an assets metadata file to the given archive + Serialize the object - + An containing the objects data - + - Write asset data files to the given archive + Deserialize the message - + An containing the data - + - Constants for the archiving module + Event Queue message describing physics engine attributes of a list of objects + Sim sends these when object is selected - + + Array with the list of physics properties + + - The location of the archive control file + Serializes the message + Serialized OSD - + - Path for the assets held in an archive + Deseializes the message + Incoming data to deserialize - + - Path for the prims file + A message sent from the viewer to the simulator which + specifies that the user has changed current URL + of the specific media on a prim face - + - Path for terrains. Technically these may be assets, but I think it's quite nice to split them out. + New URL - + - Path for region settings. + Prim UUID where navigation occured - + - The character the separates the uuid from extension information in an archived asset filename + Face index - + - Extensions used for asset types in the archive + Serialize the object + An containing the objects data - + - + Deserialize the message + An containing the data - + + Base class used for the ObjectMedia message + + - An instance of DelegateWrapper which calls InvokeWrappedDelegate, - which in turn calls the DynamicInvoke method of the wrapped - delegate + Message used to retrive prim media data - + - Callback used to call EndInvoke on the asynchronously - invoked DelegateWrapper + Prim UUID - + - Executes the specified delegate with the specified arguments - asynchronously on a thread pool thread + Requested operation, either GET or UPDATE - - - + - Invokes the wrapped delegate synchronously + Serialize object - - + Serialized object as OSDMap - + - Calls EndInvoke on the wrapper and Close on the resulting WaitHandle - to prevent resource leaks + Deserialize the message - + An containing the data - + - Delegate to wrap another delegate and its arguments + Message used to update prim media data - - - - - 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 + Prim UUID - + - Create an allocated UDP packet buffer for sending a packet + Array of media entries indexed by face number - EndPoint of the remote host - + - Create an allocated UDP packet buffer for sending a packet + Media version string - 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 + Serialize object + Serialized object as OSDMap - + - Initialize the object pool in client mode + Deserialize the message - Server to connect to - - + An containing the data - + - Initialize the object pool in server mode + Message used to update prim media data - - - + - Returns a packet buffer with EndPoint set if the buffer is in - client mode, or with EndPoint set to null in server mode + Prim UUID - Initialized UDPPacketBuffer object - + - Default constructor + Array of media entries indexed by face number - + - Check a packet buffer out of the pool + Requested operation, either GET or UPDATE - A packet buffer object - + - + Serialize object - Looking direction, must be a normalized vector - Up direction, must be a normalized vector + Serialized object as OSDMap - + - Align the coordinate frame X and Y axis with a given rotation - around the Z axis in radians + Deserialize the message - Absolute rotation around the Z axis in - radians - - - Origin position of this coordinate frame + An containing the data - - X axis of this coordinate frame, or Forward/At in grid terms + + + Message for setting or getting per face MediaEntry + - - Y axis of this coordinate frame, or Left in grid terms + + The request or response details block - - Z axis of this coordinate frame, or Up in grid terms + + + Serialize the object + + An containing the objects data - + - Static pre-defined animations available to all agents + Deserialize the message + An containing the data - - Agent with afraid expression on face + + Details about object resource usage - - Agent aiming a bazooka (right handed) + + Object UUID - - Agent aiming a bow (left handed) + + Object name - - Agent aiming a hand gun (right handed) + + Indicates if object is group owned - - Agent aiming a rifle (right handed) + + Locatio of the object - - Agent with angry expression on face + + Object owner - - Agent hunched over (away) + + Resource usage, keys are resource names, values are resource usage for that specific resource - - Agent doing a backflip + + + Deserializes object from OSD + + An containing the data - - Agent laughing while holding belly + + + Makes an instance based on deserialized data + + serialized data + Instance containg deserialized data - - Agent blowing a kiss + + Details about parcel resource usage - - Agent with bored expression on face + + Parcel UUID - - Agent bowing to audience + + Parcel local ID - - Agent brushing himself/herself off + + Parcel name - - Agent in busy mode + + Indicates if parcel is group owned - - Agent clapping hands + + Parcel owner - - Agent doing a curtsey bow + + Array of containing per object resource usage - - Agent crouching + + + Deserializes object from OSD + + An containing the data - - Agent crouching while walking + + + Makes an instance based on deserialized data + + serialized data + Instance containg deserialized data - - Agent crying + + Resource usage base class, both agent and parcel resource + usage contains summary information - - Agent unanimated with arms out (e.g. setting appearance) + + Summary of available resources, keys are resource names, + values are resource usage for that specific resource - - Agent re-animated after set appearance finished + + Summary resource usage, keys are resource names, + values are resource usage for that specific resource - - Agent dancing + + + Serializes object + + serialized data - - Agent dancing + + + Deserializes object from OSD + + An containing the data - - Agent dancing + + Agent resource usage - - Agent dancing + + Per attachment point object resource usage - - Agent dancing + + + Deserializes object from OSD + + An containing the data - - Agent dancing + + + Makes an instance based on deserialized data + + serialized data + Instance containg deserialized data - - Agent dancing + + + Detects which class handles deserialization of this message + + An containing the data + Object capable of decoding this message - - Agent dancing + + Request message for parcel resource usage - - Agent on ground unanimated + + UUID of the parel to request resource usage info - - Agent boozing it up + + + Serializes object + + serialized data - - Agent with embarassed expression on face + + + Deserializes object from OSD + + An containing the data - - Agent with afraid expression on face + + Response message for parcel resource usage - - Agent with angry expression on face + + URL where parcel resource usage details can be retrieved - - Agent with bored expression on face + + URL where parcel resource usage summary can be retrieved - - Agent crying + + + Serializes object + + serialized data - - Agent showing disdain (dislike) for something + + + Deserializes object from OSD + + An containing the data - - Agent with embarassed expression on face + + + Detects which class handles deserialization of this message + + An containing the data + Object capable of decoding this message - - Agent with frowning expression on face + + Parcel resource usage - - Agent with kissy face + + Array of containing per percal resource usage - - Agent expressing laughgter + + + Deserializes object from OSD + + An containing the data - - Agent with open mouth + + + Reply to request for bunch if display names + - - Agent with repulsed expression on face + + Current display name - - Agent expressing sadness + + Following UUIDs failed to return a valid display name - - Agent shrugging shoulders + + + Serializes the message + + OSD containting the messaage - - Agent with a smile + + + Message sent when requesting change of the display name + - - Agent expressing surprise + + Current display name - - Agent sticking tongue out + + Desired new display name - - Agent with big toothy smile + + + Serializes the message + + OSD containting the messaage - - Agent winking + + + Message recieved in response to request to change display name + - - Agent expressing worry + + New display name - - Agent falling down + + String message indicating the result of the operation - - Agent walking (feminine version) + + Numerical code of the result, 200 indicates success - - Agent wagging finger (disapproval) + + + Serializes the message + + OSD containting the messaage - - I'm not sure I want to know + + + Message recieved when someone nearby changes their display name + - - Agent in superman position + + Previous display name, empty string if default - - Agent in superman position + + New display name - - Agent greeting another + + + Serializes the message + + OSD containting the messaage - - Agent holding bazooka (right handed) + + Sort by name - - Agent holding a bow (left handed) + + Sort by date - - Agent holding a handgun (right handed) + + Sort folders by name, regardless of whether items are + sorted by name or date - - Agent holding a rifle (right handed) + + Place system folders at the top - - Agent throwing an object (right handed) + + + Possible destinations for DeRezObject request + - - Agent in static hover + + - - Agent hovering downward + + Copy from in-world to agent inventory - - Agent hovering upward + + Derez to TaskInventory - - Agent being impatient + + - - Agent jumping + + Take Object - - Agent jumping with fervor + + - - Agent point to lips then rear end + + Delete Object - - Agent landing from jump, finished flight, etc + + Put an avatar attachment into agent inventory - - Agent laughing + + - - Agent landing from jump, finished flight, etc + + Return an object back to the owner's inventory - - Agent sitting on a motorcycle + + Return a deeded object back to the last owner's inventory - - + + + Upper half of the Flags field for inventory items + - - Agent moving head side to side + + 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 - - Agent moving head side to side with unhappy expression + + Indicates that the object sale information has been + changed - - Agent taunting another + + 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 - - Agent giving peace sign + + If set, and a slam bit is set, indicates GroupMask will be overwritten on Rez - - Agent pointing at self + + If set, and a slam bit is set, indicates EveryoneMask will be overwritten on Rez - - Agent pointing at another + + If set, and a slam bit is set, indicates NextOwnerMask will be overwritten on Rez - - Agent preparing for jump (bending knees) + + Indicates whether this object is composed of multiple + items or not - - Agent punching with left hand + + 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 - - Agent punching with right hand + + + Base Class for Inventory Items + - - Agent acting repulsed + + of item/folder - - Agent trying to be Chuck Norris + + of parent folder - - Rocks, Paper, Scissors 1, 2, 3 + + Name of item/folder - - Agent with hand flat over other hand + + Item/Folder Owners - - Agent with fist over other hand + + + Constructor, takes an itemID as a parameter + + The of the item - - Agent with two fingers spread over other hand + + + + + - - Agent running + + + + + - - Agent appearing sad + + + 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 - - Agent saluting + + + Determine whether the specified object is equal to the current object + + InventoryBase object to compare against + true if objects are the same - - Agent shooting bow (left handed) + + + Determine whether the specified object is equal to the current object + + InventoryBase object to compare against + true if objects are the same - - Agent cupping mouth as if shouting + + + Convert inventory to OSD + + OSD representation - - Agent shrugging shoulders + + + An Item in Inventory + - - Agent in sit position + + The of this item - - Agent in sit position (feminine) + + The combined of this item - - Agent in sit position (generic) + + The type of item from - - Agent sitting on ground + + The type of item from the enum - - Agent sitting on ground + + The of the creator of this item - - + + A Description of this item - - Agent sleeping on side + + The s this item is set to or owned by - - Agent smoking + + If true, item is owned by a group - - Agent inhaling smoke + + The price this item can be purchased for - - + + The type of sale from the enum - - Agent taking a picture + + Combined flags from - - Agent standing + + Time and date this inventory item was created, stored as + UTC (Coordinated Universal Time) - - Agent standing up + + Used to update the AssetID in requests sent to the server - - Agent standing + + The of the previous owner of the item - - Agent standing + + + Construct a new InventoryItem object + + The of the item - - Agent standing + + + Construct a new InventoryItem object of a specific Type + + The type of item from + of the item - - Agent standing + + + Indicates inventory item is a link + + True if inventory item is a link to another inventory item - - Agent stretching + + + + + - - Agent in stride (fast walk) + + + + + - - Agent surfing + + + 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 - - Agent acting surprised + + + Compares an object + + The object to compare + true if comparison object matches - - Agent striking with a sword + + + Determine whether the specified object is equal to the current object + + The object to compare against + true if objects are the same - - Agent talking (lips moving) + + + Determine whether the specified object is equal to the current object + + The object to compare against + true if objects are the same - - Agent throwing a tantrum + + + Create InventoryItem from OSD + + OSD Data that makes up InventoryItem + Inventory item created - - Agent throwing an object (right handed) + + + Convert InventoryItem to OSD + + OSD representation of InventoryItem - - Agent trying on a shirt + + + InventoryTexture Class representing a graphical image + + - - Agent turning to the left + + + Construct an InventoryTexture object + + A which becomes the + objects AssetUUID - - Agent turning to the right + + + Construct an InventoryTexture object from a serialization stream + - - Agent typing + + + InventorySound Class representing a playable sound + - - Agent walking + + + Construct an InventorySound object + + A which becomes the + objects AssetUUID - - Agent whispering + + + Construct an InventorySound object from a serialization stream + - - Agent whispering with fingers in mouth + + + InventoryCallingCard Class, contains information on another avatar + - - Agent winking + + + Construct an InventoryCallingCard object + + A which becomes the + objects AssetUUID - - Agent winking + + + Construct an InventoryCallingCard object from a serialization stream + - - Agent worried + + + InventoryLandmark Class, contains details on a specific location + - - Agent nodding yes + + + Construct an InventoryLandmark object + + A which becomes the + objects AssetUUID - - Agent nodding yes with happy face + + + Construct an InventoryLandmark object from a serialization stream + - - Agent floating with legs and arms crossed + + + Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited + - + - A dictionary containing all pre-defined animations + InventoryObject Class contains details on a primitive or coalesced set of primitives - A dictionary containing the pre-defined animations, - where the key is the animations ID, and the value is a string - containing a name to identify the purpose of the animation - + - Extract the avatar UUID encoded in a SIP URI + Construct an InventoryObject object - - + A which becomes the + objects AssetUUID - + - Permissions for control of object media + Construct an InventoryObject object from a serialization stream - + - Style of cotrols that shold be displayed to the user + Gets or sets the upper byte of the Flags value - + - Class representing media data for a single face + Gets or sets the object attachment point, the lower byte of the Flags value - - Is display of the alternative image enabled + + + InventoryNotecard Class, contains details on an encoded text document + - - Should media auto loop + + + Construct an InventoryNotecard object + + A which becomes the + objects AssetUUID - - Shoule media be auto played + + + Construct an InventoryNotecard object from a serialization stream + - - Auto scale media to prim face + + + InventoryCategory Class + + TODO: Is this even used for anything? - - Should viewer automatically zoom in on the face when clicked + + + Construct an InventoryCategory object + + A which becomes the + objects AssetUUID - - Should viewer interpret first click as interaction with the media - or when false should the first click be treated as zoom in commadn + + + Construct an InventoryCategory object from a serialization stream + - - Style of controls viewer should display when - viewer media on this face + + + InventoryLSL Class, represents a Linden Scripting Language object + - - Starting URL for the media + + + Construct an InventoryLSL object + + A which becomes the + objects AssetUUID - - Currently navigated URL + + + Construct an InventoryLSL object from a serialization stream + - - Media height in pixes + + + InventorySnapshot Class, an image taken with the viewer + - - Media width in pixels + + + Construct an InventorySnapshot object + + A which becomes the + objects AssetUUID - - Who can controls the media + + + Construct an InventorySnapshot object from a serialization stream + - - Who can interact with the media + + + InventoryAttachment Class, contains details on an attachable object + - - Is URL whitelist enabled + + + Construct an InventoryAttachment object + + A which becomes the + objects AssetUUID - - Array of URLs that are whitelisted + + + Construct an InventoryAttachment object from a serialization stream + - + - Serialize to OSD + Get the last AttachmentPoint this object was attached to - OSDMap with the serialized data - + - Deserialize from OSD data + InventoryWearable Class, details on a clothing item or body part - Serialized OSD data - Deserialized object - + - A Wrapper around openjpeg to encode and decode images to and from byte arrays + Construct an InventoryWearable object + A which becomes the + objects AssetUUID - - TGA Header size - - - OpenJPEG is not threadsafe, so this object is used to lock - during calls into unmanaged code - - + - Encode a object into a byte array + Construct an InventoryWearable object from a serialization stream - The object to encode - true to enable lossless conversion, only useful for small images ie: sculptmaps - A byte array containing the encoded Image object - + - Encode a object into a byte array + The , Skin, Shape, Skirt, Etc - The object to encode - a byte array of the encoded image - + - Decode JPEG2000 data to an and - + InventoryAnimation Class, A bvh encoded object which animates an avatar - JPEG2000 encoded data - ManagedImage object to decode to - Image object to decode to - True if the decode succeeds, otherwise false - + - + Construct an InventoryAnimation object - - - + A which becomes the + objects AssetUUID - + - + Construct an InventoryAnimation object from a serialization stream - - - - - + - Encode a object into a byte array + InventoryGesture Class, details on a series of animations, sounds, and actions - The source object to encode - 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 + Construct an InventoryGesture object + A which becomes the + objects AssetUUID - + - This structure is used to marshal both encoded and decoded images. - MUST MATCH THE STRUCT IN dotnet.h! + Construct an InventoryGesture object from a serialization stream - + - Information about a single packet in a JPEG2000 stream + A folder contains s and has certain attributes specific + to itself - - Packet start position + + The Preferred for a folder. - - Packet header end position + + The Version of this folder - - Packet end position + + Number of child items this folder contains. - + - Represents a texture + Constructor + UUID of the folder - - A object containing image data - - - - - - + + + + + - - Initializes a new instance of an AssetTexture object + + + Get Serilization data for this InventoryFolder object + - + - Initializes a new instance of an AssetTexture object + Construct an InventoryFolder object from a serialization stream - 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 + + + Create InventoryFolder from OSD + + OSD Data that makes up InventoryFolder + Inventory folder created - + - Represents an that represents an avatars body ie: Hair, Etc. + Convert InventoryItem to OSD + OSD representation of InventoryItem - - Initializes a new instance of an AssetBodyPart object + + + Tools for dealing with agents inventory + - - Initializes a new instance of an AssetBodyPart object with parameters - A unique specific to this asset - A byte array containing the raw asset data + + Used for converting shadow_id to asset_id - - Override the base classes AssetType + + 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 - - The avatar has no rights + + Thread sync lock object - - The avatar can see the online status of the target avatar + + The event subscribers, null of no subscribers - - The avatar can see the location of the target avatar on the map + + Raises the ScriptRunningReply Event + A ScriptRunningReplyEventArgs object containing + the data sent from the simulator - - The avatar can modify the ojects of the target avatar + + Thread sync lock object - + + Partial mapping of AssetTypes to folder names + + - 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 + Default constructor + Reference to the GridClient object - + - Used internally when building the initial list of friends at login time + Fetch an inventory item from the dataserver - 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 + 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 - + - FriendInfo represented as a string + Request A single inventory item - A string reprentation of both my rights and my friends rights + The items + The item Owners + - + - System ID of the avatar + Request inventory items + Inventory items to request + Owners of the inventory items + - + - full name of the avatar + Request inventory items via Capabilities + Inventory items to request + Owners of the inventory items + - + - True if the avatar is online + 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 - + - True if the friend can see if I am online + 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 + - + - True if the friend can see me on the map + 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 + - + - True if the freind can modify my objects + 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 - + - True if I can see if my friend is online + 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 - + - True if I can see if my friend is on the map + 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 - + - True if I can modify my friend's objects + 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 - + - My friend's rights represented as bitmapped flags + Move an inventory item or folder to a new location + The item or folder to move + The to move item or folder to - + - My rights represented as bitmapped flags + 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 - + - This class is used to add and remove avatars from your friends list and to manage their permission. + Move and rename a folder + The source folders + The destination folders + The name to change the folder to - - 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 + Update folder properties + of the folder to update + Sets folder's parent to + Folder name + Folder type - + - 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 + Move a folder + The source folders + The destination folders - + - Internal constructor + Move multiple folders, the keys in the Dictionary parameter, + to a new parents, the value of that folder's key. - A reference to the GridClient Object + A Dictionary containing the + of the source as the key, and the + of the destination as the value - + - Accept a friendship request + Move an inventory item to a new folder - agentID of avatatar to form friendship with - imSessionID of the friendship request message + The of the source item to move + The of the destination folder - + - Decline a friendship request + Move and rename an inventory item - of friend - imSessionID of the friendship request message + The of the source item to move + The of the destination folder + The name to change the folder to - + - Overload: Offer friendship to an avatar. + Move multiple inventory items to new locations - System ID of the avatar you are offering friendship to + A Dictionary containing the + of the source item as the key, and the + of the destination folder as the value - + - Offer friendship to an avatar. + Remove descendants of a folder - System ID of the avatar you are offering friendship to - A message to send with the request + The of the folder - + - Terminate a friendship with an avatar + Remove a single item from inventory - 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 + The of the inventory item to remove - + - Change the rights of a friend avatar. + Remove a folder from inventory - 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. + The of the folder to remove - + - Use to map a friends location on the grid. + Remove multiple items or folders from inventory - Friends UUID to find - + A List containing the s of items to remove + A List containing the s of the folders to remove - + - Use to track a friends movement on the grid + Empty the Lost and Found folder - Friends Key - + - Ask for a notification of friend's online status + Empty the Trash folder - 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 + + + + + Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. + + + - + - 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 + + + + + Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here. + + + + - + - Construct a new instance of the FriendInfoEventArgs class + Creates a new inventory folder - The FriendInfo - - - Get the FriendInfo - - - Contains Friend Names + ID of the folder to put this folder in + Name of the folder to create + The UUID of the newly created folder - + - Construct a new instance of the FriendNamesEventArgs class + Creates a new inventory folder - 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 + 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 - + - Construct a new instance of the FriendshipOfferedEventArgs class + Create an inventory item and upload asset data - 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 + 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 - + - Construct a new instance of the FriendShipResponseEventArgs class + Create an inventory item and upload asset data - 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 + 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 - + - Construct a new instance of the FrindshipTerminatedEventArgs class + Creates inventory link to another inventory item or folder - The ID of the friend who terminated the friendship with us - The name of the friend who terminated the friendship with us + Put newly created link in folder with this UUID + Inventory item or folder + Method to call upon creation of the link - - Get the ID of the agent that terminated the friendship with us + + + 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 - - Get the name of the agent that terminated the friendship with us + + + 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 - + - Data sent in response to a request which contains the information to allow us to map the friends location + 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 - + - 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 + + + 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 - + + - - OK - - - Transfer completed + + + + + - - + + + + + + - - + + + + + + + - - Unknown error occurred + + + 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 - - Equivalent to a 404 error + + + Upload new gesture asset for an inventory gesture item + + Encoded gesture asset + Gesture inventory UUID + Callback whick will be called when upload is complete - - Client does not have permission for that resource + + + 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 + - - Unknown status + + + 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 - - Unknown + + + 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 - - Virtually all asset transfers use this channel + + + 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 - - Asset from the asset server + + + Rez an item from inventory to its previous simulator location + + + + + - - Inventory item + + + 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 - - Estate asset, such as an estate covenant + + + 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 - - - - - - - - - - + - When requesting image download, type of the image requested + 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 - - Normal in-world object texture - - - Avatar texture + + + Request the contents of a tasks (primitives) inventory from the + current simulator + + The LocalID of the object + - - Server baked avatar texture + + + 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 + - + - Image file format + 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 - - Number of milliseconds passed since the last transfer - packet was received + + + 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 - - Number of milliseconds to wait for a transfer header packet if out of order data was received - - - The event subscribers. null if no subcribers - - - Raises the XferReceived event - A XferReceivedEventArgs object containing the - data returned from the simulator + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + + 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 - - Raises the AssetUploaded event - A AssetUploadedEventArgs object containing the - data returned from the simulator + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the UploadProgress event - A UploadProgressEventArgs object containing the - data returned from the simulator + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - The event subscribers. null if no subcribers + + Raised when the simulator sends us data containing + ... - - Raises the InitiateDownload event - A InitiateDownloadEventArgs object containing the - data returned from the simulator + + Raised when the simulator sends us data containing + an inventory object sent by another avatar or primitive - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - The event subscribers. null if no subcribers + + Raised when the simulator sends us data containing + ... - - Raises the ImageReceiveProgress event - A ImageReceiveProgressEventArgs object containing the - data returned from the simulator + + Raised when the simulator sends us data containing + ... - - Thread sync lock object + + Raised when the simulator sends us data containing + ... - - Texture download cache + + Raised when the simulator sends us data containing + ... - + - Default constructor + Get this agents Inventory data - A reference to the GridClient object - + - Request an asset download + Callback for inventory item creation finishing - Asset UUID - Asset type, must be correct for the transfer to succeed - Whether to give this transfer an elevated priority - The callback to fire when the simulator responds with the asset data + Whether the request to create an inventory + item succeeded or not + Inventory item being created. If success is + false this will be null - + - Request an asset download + Callback for an inventory item being create from an uploaded asset - Asset UUID - Asset type, must be correct for the transfer to succeed - Whether to give this transfer an elevated priority - Source location of the requested asset - The callback to fire when the simulator responds with the asset data + true if inventory item creation was successful + + + - + - Request an asset download + - Asset UUID - Asset type, must be correct for the transfer to succeed - Whether to give this transfer an elevated priority - Source location of the requested asset - UUID of the transaction - The callback to fire when the simulator responds with the asset data + - + - Request an asset download through the almost deprecated Xfer system + Reply received when uploading an inventory asset - Filename of the asset to request - Whether or not to delete the asset - off the server after it is retrieved - Use large transfer packets or not - UUID of the file to request, if filename is - left empty - Asset type of vFileID, or - AssetType.Unknown if filename is not empty - Sets the FilePath in the request to Cache - (4) if true, otherwise Unknown (0) is used - + Has upload been successful + Error message if upload failed + Inventory asset UUID + New asset UUID - + - + Delegate that is invoked when script upload is completed - Use UUID.Zero if you do not have the - asset ID but have all the necessary permissions - The item ID of this asset in the inventory - Use UUID.Zero if you are not requesting an - asset from an object inventory - The owner of this asset - Asset type - Whether to prioritize this asset download or not - + 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 + + - Used to force asset data into the PendingUpload property, ie: for raw terrain uploads + 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. - An AssetUpload object containing the data to upload to the simulator - + - Request an asset be uploaded to the simulator + Map layer request type - The Object containing the asset data - If True, the asset once uploaded will be stored on the simulator - in which the client was connected in addition to being stored on the asset server - The of the transfer, can be used to correlate the upload with - events being fired - + + Objects and terrain are shown + + + Only the terrain is shown, no objects + + + Overlay showing land for sale and for auction + + - Request an asset be uploaded to the simulator + Type of grid item, such as telehub, event, populator location, etc. - The of the asset being uploaded - A byte array containing the encoded asset data - If True, the asset once uploaded will be stored on the simulator - in which the client was connected in addition to being stored on the asset server - The of the transfer, can be used to correlate the upload with - events being fired - + + 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 + + - Request an asset be uploaded to the simulator + Information about a region on the grid map - - Asset type to upload this data as - A byte array containing the encoded asset data - If True, the asset once uploaded will be stored on the simulator - in which the client was connected in addition to being stored on the asset server - The of the transfer, can be used to correlate the upload with - events being fired - + + 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 + + - Initiate an asset upload + - The ID this asset will have if the - upload succeeds - Asset type to upload this data as - Raw asset data to upload - Whether to store this asset on the local - simulator or the grid-wide asset server - The tranaction id for the upload - The transaction ID of this transfer + - - - 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. Sending with value -1 combined with priority of 0 cancels an in-progress - transfer. - A bug exists in the Linden Simulator where a -1 will occasionally be sent with a non-zero priority - indicating an off-by-one error. - 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 - - Request an image and fire a callback when the request is complete - - Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); - - private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) - { - if(state == TextureRequestState.Finished) - { - Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", - asset.AssetID, - asset.AssetData.Length); - } - } - - Request an image and use an inline anonymous method to handle the downloaded texture data - - Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, delegate(TextureRequestState state, AssetTexture asset) - { - if(state == TextureRequestState.Finished) - { - Console.WriteLine("Texture {0} ({1} bytes) has been successfully downloaded", - asset.AssetID, - asset.AssetData.Length); - } - } - ); - - Request a texture, decode the texture to a bitmap image and apply it to a imagebox - - Client.Assets.RequestImage(UUID.Parse("c307629f-e3a1-4487-5e88-0d96ac9d4965"), ImageType.Normal, TextureDownloader_OnDownloadFinished); - - private void TextureDownloader_OnDownloadFinished(TextureRequestState state, AssetTexture asset) - { - if(state == TextureRequestState.Finished) - { - ManagedImage imgData; - Image bitmap; + + - if (state == TextureRequestState.Finished) - { - OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData, out bitmap); - picInsignia.Image = bitmap; - } - } - } - - + + - + - Overload: 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 callback to fire when the image is retrieved. The callback - will contain the result of the request and the texture asset data + + - + - Overload: 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 + Visual chunk of the grid map - The of the texture asset to download - The of the texture asset. - Use for most textures, or for baked layer texture assets - The callback to fire when the image is retrieved. The callback - will contain the result of the request and the texture asset data - + - Overload: 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 + Base class for Map Items - The of the texture asset to download - The of the texture asset. - Use for most textures, or for baked layer texture assets - 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 - + + 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 + + - Cancel a texture request + Represents an agent or group of agents location - The texture assets - + - Requests download of a mesh asset + Represents a Telehub location - UUID of the mesh asset - Callback when the request completes - + - Fetach avatar texture on a grid capable of server side baking + Represents a non-adult parcel of land for sale - ID of the avatar - ID of the texture - Name of the part of the avatar texture applies to - Callback invoked on operation completion - + - Lets TexturePipeline class fire the progress event + Represents an Adult parcel of land for sale - The texture ID currently being downloaded - the number of bytes transferred - the total number of bytes expected - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Represents a PG Event + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Represents a Mature event + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Represents an Adult event + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + + Manages grid-wide tasks such as the world map + - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + The event subscribers. null if no subcribers - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Raises the CoarseLocationUpdate event + A CoarseLocationUpdateEventArgs object containing the + data sent by simulator - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Thread sync lock object - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + The event subscribers. null if no subcribers - - Raised when the simulator responds sends + + Raises the GridRegion event + A GridRegionEventArgs object containing the + data sent by simulator - - Raised during upload completes + + Thread sync lock object - - Raised during upload with progres update + + The event subscribers. null if no subcribers - - Fired when the simulator sends an InitiateDownloadPacket, used to download terrain .raw files + + Raises the GridLayer event + A GridLayerEventArgs object containing the + data sent by simulator - - Fired when a texture is in the process of being downloaded by the TexturePipeline class + + 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 + + - Callback used for various asset download requests + Constructor - Transfer information - Downloaded asset, null on fail + Instance of GridClient object to associate with this GridManager instance - + - Callback used upon competition of baked texture upload + - Asset UUID of the newly uploaded baked texture + + + + + 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 - + - A callback that fires upon the completition of the RequestMesh call + Get grid region information using the region name, this function + will block until it can find the region or gives up - Was the download successfull - Resulting mesh or null on problems - - - Xfer data - - - Upload data - - - Filename used on the simulator + 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 - - Filename used by the client + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - UUID of the image that is in progress + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Number of bytes received so far + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Image size in bytes + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - The event subscribers. null if no subcribers + + Process an incoming packet and raise the appropriate events + The sender + The EventArgs object containing the packet data - - Raises the LandPatchReceived event - A LandPatchReceivedEventArgs object containing the - data returned from the simulator + + Raised when the simulator sends a + containing the location of agents in the simulator - - Thread sync lock object + + Raised when the simulator sends a Region Data in response to + a Map request - - - Default constructor - - + + Raised when the simulator sends GridLayer object containing + a map tile coordinates and texture information - - Raised when the simulator responds sends + + Raised when the simulator sends GridItems object containing + details on events, land sales at a specific location - - Simulator from that sent tha data + + Raised in response to a Region lookup - - Sim coordinate of the patch + + Unknown - - Sim coordinate of the patch + + Current direction of the sun - - Size of tha patch + + Current angular velocity of the sun - - Heightmap for the patch + + Microseconds since the start of SL 4-hour day - + - Registers, unregisters, and fires events generated by incoming packets + + Looking direction, must be a normalized vector + Up direction, must be a normalized vector - - Reference to the GridClient object - - + - Default constructor + 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 - - - 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 + + Origin position of this coordinate frame - - - Unregister an event handler - - Packet type to unregister the handler for - Callback to be unregistered + + X axis of this coordinate frame, or Forward/At in grid terms - - - Fire the events registered for this packet type - - Incoming packet type - Incoming packet - Simulator this packet was received from + + Y axis of this coordinate frame, or Left in grid terms - + + Z axis of this coordinate frame, or Up in grid terms + + - Object that is passed to worker threads in the ThreadPool for - firing packet callbacks + Represents a texture - - Callback to fire for this packet - - - Reference to the simulator that this packet came from - - - The packet that needs to be processed + + A object containing image data - - - Registers, unregisters, and fires events generated by the Capabilities - event queue - + + - - Reference to the GridClient object + + - - - Default constructor - - Reference to the GridClient object + + Initializes a new instance of an AssetTexture object - + - Register an new event handler for a capabilities event sent via the EventQueue + Initializes a new instance of an AssetTexture object - Use String.Empty to fire this event on every CAPS event - Capability event name to register the - handler for - Callback to fire + A unique specific to this asset + A byte array containing the raw asset data - + - Unregister a previously registered capabilities handler + Initializes a new instance of an AssetTexture object - Capability event name unregister the - handler for - Callback to unregister + A object containing texture data - + - Fire the events registered for this event type synchronously + Populates the byte array with a JPEG2000 + encoded image created from the data in - Capability name - Decoded event body - Reference to the simulator that - generated this event - + - Fire the events registered for this event type asynchronously + Decodes the JPEG2000 data in AssetData to the + object - Capability name - Decoded event body - Reference to the simulator that - generated this event + True if the decoding was successful, otherwise false - + - Object that is passed to worker threads in the ThreadPool for - firing CAPS callbacks + Decodes the begin and end byte positions for each quality layer in + the image + - - Callback to fire for this packet - - - Name of the CAPS event - - - Strongly typed decoded data - - - Reference to the simulator that generated this event - - - Describes tasks returned in LandStatReply + + Override the base classes AssetType - + - Estate level administration and utilities + 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 - - Textures for each of the four terrain height levels + + Main grid login server - - Upper/lower texture boundaries for each corner of the sim + + Beta grid login server - + - Constructor for EstateTools class + InventoryManager requests inventory information on login, + GridClient initializes an Inventory store for main inventory. - - - The event subscribers. null if no subcribers + + + InventoryManager requests library information on login, + GridClient initializes an Inventory store for the library. + - - Raises the TopCollidersReply event - A TopCollidersReplyEventArgs object containing the - data returned from the data server + + Number of milliseconds between sending pings to each sim - - Thread sync lock object + + Number of milliseconds between sending camera updates - - The event subscribers. null if no subcribers + + Number of milliseconds between updating the current + positions of moving, non-accelerating and non-colliding objects - - Raises the TopScriptsReply event - A TopScriptsReplyEventArgs object containing the - data returned from the data server + + Millisecond interval between ticks, where all ACKs are + sent out and the age of unACKed packets is checked - - Thread sync lock object + + The initial size of the packet inbox, where packets are + stored before processing - - The event subscribers. null if no subcribers + + Maximum size of packet that we want to send over the wire - - Raises the EstateUsersReply event - A EstateUsersReplyEventArgs object containing the - data returned from the data server + + The maximum value of a packet sequence number before it + rolls over back to one - - Thread sync lock object + + The relative directory where external resources are kept - - The event subscribers. null if no subcribers + + Login server to connect to - - Raises the EstateGroupsReply event - A EstateGroupsReplyEventArgs object containing the - data returned from the data server + + IP Address the client will bind to - - Thread sync lock object + + Use XML-RPC Login or LLSD Login, default is XML-RPC Login - - The event subscribers. null if no subcribers + + + Use Caps for fetching inventory where available + - - Raises the EstateManagersReply event - A EstateManagersReplyEventArgs object containing the - data returned from the data server + + Number of milliseconds before an asset transfer will time + out - - Thread sync lock object + + Number of milliseconds before a teleport attempt will time + out - - The event subscribers. null if no subcribers + + Number of milliseconds before NetworkManager.Logout() will + time out - - Raises the EstateBansReply event - A EstateBansReplyEventArgs object containing the - data returned from the data server + + Number of milliseconds before a CAPS call will time out + Setting this too low will cause web requests time out and + possibly retry repeatedly - - Thread sync lock object + + Number of milliseconds for xml-rpc to timeout - - The event subscribers. null if no subcribers + + Milliseconds before a packet is assumed lost and resent - - Raises the EstateCovenantReply event - A EstateCovenantReplyEventArgs object containing the - data returned from the data server + + Milliseconds without receiving a packet before the + connection to a simulator is assumed lost - - Thread sync lock object + + Milliseconds to wait for a simulator info request through + the grid interface - - The event subscribers. null if no subcribers + + The maximum size of the sequence number archive, used to + check for resent and/or duplicate packets - - Raises the EstateUpdateInfoReply event - A EstateUpdateInfoReplyEventArgs object containing the - data returned from the data server + + Maximum number of queued ACKs to be sent before SendAcks() + is forced - - Thread sync lock object + + Network stats queue length (seconds) - + - Requests estate information such as top scripts and colliders + 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 - - - - - - - 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 + Pool parcel data between clients (saves on requesting multiple times when all clients may need it) - 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 + 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 - 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 - - - - + + Enable/disable storing terrain heightmaps in the + TerrainManager - - - Used for setting and retrieving various estate panel settings - - EstateOwnerMessage Method field - List of parameters to include + + Enable/disable sending periodic camera updates - - - Kick an avatar from an estate - - Key of Agent to remove + + Enable/disable automatically setting agent appearance at + login and after sim crossing - - - Ban an avatar from an estate - Key of Agent to remove - Ban user from this estate and all others owned by the estate owner + + 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 - - Unban an avatar from an estate - Key of Agent to remove - /// Unban user from this estate and all others owned by the estate owner + + 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 - - - Send a message dialog to everyone in an entire estate - - Message to send all users in the estate + + 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 - + - Send a message dialog to everyone in a simulator + If true, utilization statistics will be tracked. There is a minor penalty + in CPU time for enabling this option. - Message to send all users in the simulator - + + If true, parcel details will be stored in the + Simulator.Parcels dictionary as they are received + + - Send an avatar back to their home location + If true, an incoming parcel properties reply will automatically send + a request for the parcel access list - Key of avatar to send home - + - Begin the region restart process + if true, an incoming parcel properties reply will automatically send + a request for the traffic count. - + - Cancels a region restart + If true, images, and other assets downloaded from the server + will be cached in a local directory - - Estate panel "Region" tab settings + + Path to store cached texture data - - Estate panel "Debug" tab settings + + Maximum size cached files are allowed to take on disk (bytes) - - Used for setting the region's terrain textures for its four height levels - - - - + + Default color used for viewer particle effects - - Used for setting sim terrain texture heights + + Maximum number of times to resend a failed packet - - Requests the estate covenant + + Throttle outgoing packet rate - - - 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 + + UUID of a texture used by some viewers to indentify type of client used - + - Teleports all users home in current Estate + Download textures using GetTexture capability when available - - - Remove estate manager - Key of Agent to Remove - removes manager to this estate and all others owned by the estate owner + + The maximum number of concurrent texture downloads allowed + Increasing this number will not necessarily increase texture retrieval times due to + simulator throttles - + - Add estate manager - Key of Agent to Add - Add agent as manager to this estate and all others owned by the estate owner + 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 - + - 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 + Textures taking longer than this value will be flagged as timed out and removed from the pipeline + - + - Removes an agent from the estate Allowed list - Key of Agent to Remove - Removes agent as an allowed reisdent from All estates if true - - + Get or set the minimum log level to output to the console by default - - 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 + 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 + - - - - Removes a group from the estate Allowed list - Key of Group to Remove - Removes Group as an allowed Group from All estates if true + + Attach avatar names to log messages - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + Log packet retransmission info - - Process an incoming packet and raise the appropriate events - The sender - The EventArgs object containing the packet data + + 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 - - 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. + + Cost of uploading an asset + Read-only since this value is dynamically fetched at login - - Raised when the data server responds to a request. + + + 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(); + } + } + } + + - - Used in the ReportType field of a LandStatRequest + + Networking subsystem - - Used by EstateOwnerMessage packets + + Settings class including constant values and changeable + parameters for everything - - Used by EstateOwnerMessage packets + + Parcel (subdivided simulator lots) subsystem - - - - + + Our own avatars subsystem - - No flags set + + Other avatars subsystem - - Only return targets scripted objects + + Estate subsystem - - Only return targets objects if on others land + + Friends list subsystem - - Returns target's scripted objects and objects on other parcels + + Grid (aka simulator group) subsystem - - Ground texture settings for each corner of the region + + Object subsystem - - Used by GroundTextureHeightSettings + + Group subsystem - - The high and low texture thresholds for each corner of the sim + + Asset subsystem - - Raised on LandStatReply when the report type is for "top colliders" + + Appearance subsystem - - Construct a new instance of the TopCollidersReplyEventArgs class - The number of returned items in LandStatReply - Dictionary of Object UUIDs to tasks returned in LandStatReply + + Inventory subsystem - - - The number of returned items in LandStatReply - + + Directory searches including classifieds, people, land + sales, etc - - - A Dictionary of Object UUIDs to tasks returned in LandStatReply - + + Handles land, wind, and cloud heightmaps - - Raised on LandStatReply when the report type is for "top Scripts" + + Handles sound-related networking - - Construct a new instance of the TopScriptsReplyEventArgs class - The number of returned items in LandStatReply - Dictionary of Object UUIDs to tasks returned in LandStatReply + + Throttling total bandwidth usage, or allocating bandwidth + for specific data stream types - + - The number of scripts returned in LandStatReply + Default constructor - + - A Dictionary of Object UUIDs to tasks returned in LandStatReply + Return the full name of this instance + Client avatars full name - - 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 + Class that handles the local asset cache - + - The number of returned itmes + Default constructor + A reference to the GridClient object - + - List of UUIDs of Banned Users + Disposes cleanup timer - - 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 + Only create timer when needed - + - The number of returned items + Return bytes read from the local asset cache, null if it does not exist + UUID of the asset we want to get + Raw bytes of the asset, or null on failure - + - List of UUIDs of Allowed Users + Returns ImageDownload object of the + image from the local image cache, null if it does not exist + UUID of the image we want to get + ImageDownload object containing the image, or null on failure - - 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 + Constructs a file name of the cached asset + UUID of the asset + String with the file name of the cahced asset - + - The number of returned items + Constructs a file name of the static cached asset + UUID of the asset + String with the file name of the static cached asset - + - List of UUIDs of Allowed Groups + Saves an asset to the local cache + UUID of the asset + Raw bytes the asset consists of + Weather the operation was successfull - - 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 + Get the file name of the asset stored with gived UUID + UUID of the asset + Null if we don't have that UUID cached on disk, file name if found in the cache folder - + - The number of returned items + Checks if the asset exists in the local cache + UUID of the asset + True is the asset is stored in the cache, otherwise false - + - List of UUIDs of the Estate's Managers + Wipes out entire cache - - 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 + Brings cache size to the 90% of the max size - + - The timestamp + Asynchronously brings cache size to the 90% of the max size - + - The Estate name + Adds up file sizes passes in a FileInfo array - + - The Estate Owner's ID (can be a GroupID) + Checks whether caching is enabled - - 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 + Periodically prune the cache - + - The Estate Owner's ID (can be a GroupID) + Nicely formats file sizes + Byte size we want to output + String with humanly readable file size - + - The identifier of the estate on the grid + Allows setting weather to periodicale prune the cache if it grows too big + Default is enabled, when caching is enabled - - - - + - Represends individual HTTP Download request + How long (in ms) between cache checks (default is 5 min.) - - 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 + Helper class for sorting files by their last accessed time - - Default constructor - - - Cleanup method - - - Setup http download request - - - Check the queue for pending work - - - Enqueue a new HTPP download - - - Maximum number of parallel downloads from a single endpoint - - - Client certificate - diff --git a/bin/OpenMetaverse.dll b/bin/OpenMetaverse.dll index 9054a99..59e8083 100755 Binary files a/bin/OpenMetaverse.dll and b/bin/OpenMetaverse.dll differ diff --git a/bin/OpenMetaverseTypes.XML b/bin/OpenMetaverseTypes.XML index 7d00b1b..56e3ac7 100644 --- a/bin/OpenMetaverseTypes.XML +++ b/bin/OpenMetaverseTypes.XML @@ -4,478 +4,735 @@ OpenMetaverseTypes - - - A thread-safe lockless queue that supports multiple readers and - multiple writers - + + Used for converting degrees to radians - - Queue head + + Used for converting radians to degrees - - Queue tail + + + Convert the first two bytes starting in the byte array in + little endian ordering to a signed short integer + + An array two bytes or longer + A signed short integer, will be zero if a short can't be + read at the given position - - Queue item count + + + Convert the first two bytes starting at the given position in + little endian ordering to a signed short integer + + An array two bytes or longer + Position in the array to start reading + A signed short integer, will be zero if a short can't be + read at the given position - + - Constructor + Convert the first four bytes starting at the given position in + little endian ordering to a signed integer + An array four bytes or longer + Position to start reading the int from + A signed integer, will be zero if an int can't be read + at the given position - + - Enqueue an item + Convert the first four bytes of the given array in little endian + ordering to a signed integer - Item to enqeue + An array four bytes or longer + A signed integer, will be zero if the array contains + less than four bytes - + - Try to dequeue an item + Convert the first eight bytes of the given array in little endian + ordering to a signed long integer - Dequeued item if the dequeue was successful - True if an item was successfully deqeued, otherwise false + An array eight bytes or longer + A signed long integer, will be zero if the array contains + less than eight bytes - - Gets the current number of items in the queue. Since this - is a lockless collection this value should be treated as a close - estimate + + + Convert the first eight bytes starting at the given position in + little endian ordering to a signed long integer + + An array eight bytes or longer + Position to start reading the long from + A signed long integer, will be zero if a long can't be read + at the given position - + - Provides a node container for data in a singly linked list + Convert the first two bytes starting at the given position in + little endian ordering to an unsigned short + Byte array containing the ushort + Position to start reading the ushort from + An unsigned short, will be zero if a ushort can't be read + at the given position - - Pointer to the next node in list + + + Convert two bytes in little endian ordering to an unsigned short + + Byte array containing the ushort + An unsigned short, will be zero if a ushort can't be + read - - The data contained by the node + + + Convert the first four bytes starting at the given position in + little endian ordering to an unsigned integer + + Byte array containing the uint + Position to start reading the uint from + An unsigned integer, will be zero if a uint can't be read + at the given position - + - Constructor + Convert the first four bytes of the given array in little endian + ordering to an unsigned integer + An array four bytes or longer + An unsigned integer, will be zero if the array contains + less than four bytes - + - Constructor + Convert the first eight bytes of the given array in little endian + ordering to an unsigned 64-bit integer + An array eight bytes or longer + An unsigned 64-bit integer, will be zero if the array + contains less than eight bytes - + - Attribute class that allows extra attributes to be attached to ENUMs + Convert four bytes in little endian ordering to a floating point + value + Byte array containing a little ending floating + point value + Starting position of the floating point value in + the byte array + Single precision value - - Text used when presenting ENUM to user + + + Convert an integer to a byte array in little endian format + + The integer to convert + A four byte little endian array - - Default initializer + + + Convert an integer to a byte array in big endian format + + The integer to convert + A four byte big endian array - - Text used when presenting ENUM to user + + + Convert a 64-bit integer to a byte array in little endian format + + The value to convert + An 8 byte little endian array - + - The different types of grid assets + Convert a 64-bit unsigned integer to a byte array in little endian + format + The value to convert + An 8 byte little endian array - - Unknown asset type + + + Convert a floating point value to four bytes in little endian + ordering + + A floating point value + A four byte array containing the value in little endian + ordering - - Texture asset, stores in JPEG2000 J2C stream format + + + Converts an unsigned integer to a hexadecimal string + + An unsigned integer to convert to a string + A hexadecimal string 10 characters long + 0x7fffffff - - Sound asset + + + Convert a variable length UTF8 byte array to a string + + The UTF8 encoded byte array to convert + The decoded string - - Calling card for another avatar + + + Converts a byte array to a string containing hexadecimal characters + + The byte array to convert to a string + The name of the field to prepend to each + line of the string + A string containing hexadecimal characters on multiple + lines. Each line is prepended with the field name - - Link to a location in world + + + Converts a byte array to a string containing hexadecimal characters + + The byte array to convert to a string + Number of bytes in the array to parse + A string to prepend to each line of the hex + dump + A string containing hexadecimal characters on multiple + lines. Each line is prepended with the field name - - Collection of textures and parameters that can be - worn by an avatar + + + Convert a string to a UTF8 encoded byte array + + The string to convert + A null-terminated UTF8 byte array - - Primitive that can contain textures, sounds, - scripts and more + + + Converts a string containing hexadecimal characters to a byte array + + String containing hexadecimal characters + If true, gracefully handles null, empty and + uneven strings as well as stripping unconvertable characters + The converted byte array - - Notecard asset + + + Returns true is c is a hexadecimal digit (A-F, a-f, 0-9) + + Character to test + true if hex digit, false if not - - Holds a collection of inventory items + + + Converts 1 or 2 character string into equivalant byte value + + 1 or 2 character string + byte - - Root inventory folder + + + Convert a float value to a byte given a minimum and maximum range + + Value to convert to a byte + Minimum value range + Maximum value range + A single byte representing the original float value - - Linden scripting language script - - - LSO bytecode for a script - - - Uncompressed TGA texture - - - Collection of textures and shape parameters that can - be worn - - - Trash folder - - - Snapshot folder - - - Lost and found folder - - - Uncompressed sound - - - Uncompressed TGA non-square image, not to be used as a - texture - - - Compressed JPEG non-square image, not to be used as a - texture + + + Convert a byte to a float value given a minimum and maximum range + + Byte array to get the byte from + Position in the byte array the desired byte is at + Minimum value range + Maximum value range + A float value inclusively between lower and upper - - Animation + + + Convert a byte to a float value given a minimum and maximum range + + Byte to convert to a float value + Minimum value range + Maximum value range + A float value inclusively between lower and upper - - Sequence of animations, sounds, chat, and pauses + + + Attempts to parse a floating point value from a string, using an + EN-US number format + + String to parse + Resulting floating point number + True if the parse was successful, otherwise false - - Simstate file + + + Attempts to parse a floating point value from a string, using an + EN-US number format + + String to parse + Resulting floating point number + True if the parse was successful, otherwise false - - Contains landmarks for favorites + + + Tries to parse an unsigned 32-bit integer from a hexadecimal string + + String to parse + Resulting integer + True if the parse was successful, otherwise false - - Asset is a link to another inventory item + + + Returns text specified in EnumInfo attribute of the enumerator + To add the text use [EnumInfo(Text = "Some nice text here")] before declaration + of enum values + + Enum value + Text representation of the enum - - Asset is a link to another inventory folder + + + Takes an AssetType and returns the string representation + + The source + The string version of the AssetType - - Beginning of the range reserved for ensembles + + + Translate a string name of an AssetType into the proper Type + + A string containing the AssetType name + The AssetType which matches the string name, or AssetType.Unknown if no match was found - - End of the range reserved for ensembles + + + Convert an InventoryType to a string + + The to convert + A string representation of the source - - Folder containing inventory links to wearables and attachments - that are part of the current outfit + + + Convert a string into a valid InventoryType + + A string representation of the InventoryType to convert + A InventoryType object which matched the type - - Folder containing inventory items or links to - inventory items of wearables and attachments - together make a full outfit + + + Convert a SaleType to a string + + The to convert + A string representation of the source - - Root folder for the folders of type OutfitFolder + + + Convert a string into a valid SaleType + + A string representation of the SaleType to convert + A SaleType object which matched the type - - Linden mesh format + + + Converts a string used in LLSD to AttachmentPoint type + + String representation of AttachmentPoint to convert + AttachmentPoint enum - - Marketplace direct delivery inbox ("Received Items") + + + Copy a byte array + + Byte array to copy + A copy of the given byte array - - Marketplace direct delivery outbox + + + Packs to 32-bit unsigned integers in to a 64-bit unsigned integer + + The left-hand (or X) value + The right-hand (or Y) value + A 64-bit integer containing the two 32-bit input values - - + + + Unpacks two 32-bit unsigned integers from a 64-bit unsigned integer + + The 64-bit input integer + The left-hand (or X) output value + The right-hand (or Y) output value - + - Inventory Item Types, eg Script, Notecard, Folder, etc + Convert an IP address object to an unsigned 32-bit integer + IP address to convert + 32-bit unsigned integer holding the IP address bits - - Unknown + + + Gets a unix timestamp for the current time + + An unsigned integer representing a unix timestamp for now - - Texture + + + Convert a UNIX timestamp to a native DateTime object + + An unsigned integer representing a UNIX + timestamp + A DateTime object containing the same time specified in + the given timestamp - - Sound + + + Convert a UNIX timestamp to a native DateTime object + + A signed integer representing a UNIX + timestamp + A DateTime object containing the same time specified in + the given timestamp - - Calling Card + + + Convert a native DateTime object to a UNIX timestamp + + A DateTime object you want to convert to a + timestamp + An unsigned integer representing a UNIX timestamp - - Landmark + + + Swap two values + + Type of the values to swap + First value + Second value - - Notecard + + + Try to parse an enumeration value from a string + + Enumeration type + String value to parse + Enumeration value on success + True if the parsing succeeded, otherwise false - - + + + Swaps the high and low words in a byte. Converts aaaabbbb to bbbbaaaa + + Byte to swap the words in + Byte value with the words swapped - - Folder + + + Attempts to convert a string representation of a hostname or IP + address to a + + Hostname to convert to an IPAddress + Converted IP address object, or null if the conversion + failed - - + + Provide a single instance of the CultureInfo class to + help parsing in situations where the grid assumes an en-us + culture - - an LSL Script + + UNIX epoch in DateTime format - - + + Provide a single instance of the MD5 class to avoid making + duplicate copies and handle thread safety - - + + Provide a single instance of the SHA-1 class to avoid + making duplicate copies and handle thread safety - - + + Provide a single instance of a random number generator + to avoid making duplicate copies and handle thread safety - - + + + Clamp a given value between a range + + Value to clamp + Minimum allowable value + Maximum allowable value + A value inclusively between lower and upper - - + + + Clamp a given value between a range + + Value to clamp + Minimum allowable value + Maximum allowable value + A value inclusively between lower and upper - - + + + Clamp a given value between a range + + Value to clamp + Minimum allowable value + Maximum allowable value + A value inclusively between lower and upper - + - Item Sale Status + Round a floating-point value to the nearest integer + Floating point number to round + Integer - - Not for sale + + + Test if a single precision float is a finite number + - - The original is for sale + + + Test if a double precision float is a finite number + - - Copies are for sale + + + Get the distance between two floating-point values + + First value + Second value + The distance between the two values - - The contents of the object are for sale + + + Compute the MD5 hash for a byte array + + Byte array to compute the hash for + MD5 hash of the input data - + - Types of wearable assets + Compute the SHA1 hash for a byte array + Byte array to compute the hash for + SHA1 hash of the input data - - Body shape + + + Calculate the SHA1 hash of a given string + + The string to hash + The SHA1 hash as a string - - Skin textures and attributes + + + Compute the SHA256 hash for a byte array + + Byte array to compute the hash for + SHA256 hash of the input data - - Hair + + + Calculate the SHA256 hash of a given string + + The string to hash + The SHA256 hash as a string - - Eyes + + + Calculate the MD5 hash of a given string + + The password to hash + An MD5 hash in string format, with $1$ prepended - - Shirt + + + Calculate the MD5 hash of a given string + + The string to hash + The MD5 hash as a string - - Pants + + + Generate a random double precision floating point value + + Random value of type double - - Shoes + + + Get the current running platform + + Enumeration of the current platform we are running on - - Socks + + + Get the current running runtime + + Enumeration of the current runtime we are running on - - Jacket + + + Operating system + - - Gloves + + Unknown - - Undershirt + + Microsoft Windows - - Underpants + + Microsoft Windows CE - - Skirt + + Linux - - Alpha mask to hide parts of the avatar + + Apple OSX - - Tattoo + + + Runtime platform + - - Physics + + .NET runtime - - Invalid wearable asset + + Mono runtime: http://www.mono-project.com/ - + - An 8-bit color structure including an alpha channel + Convert this matrix to euler rotations + X euler angle + Y euler angle + Z euler angle - - Red + + + Convert this matrix to a quaternion rotation + + A quaternion representation of this rotation matrix - - Green + + + Construct a matrix from euler rotation values in radians + + X euler angle in radians + Y euler angle in radians + Z euler angle in radians - - Blue + + + Get a formatted string representation of the vector + + A string representation of the vector - - Alpha + + A 4x4 matrix containing all zeroes - + + A 4x4 identity matrix + + - + Same as Queue except Dequeue function blocks until there is an object to return. + Note: This class does not need to be synchronized - - - - - + - Builds a color from a byte array + Create new BlockingQueue. - Byte array containing a 16 byte color - Beginning position in the byte array - True if the byte array stores inverted values, - otherwise false. For example the color black (fully opaque) inverted - would be 0xFF 0xFF 0xFF 0x00 + The System.Collections.ICollection to copy elements from - + - Returns the raw bytes for this vector + Create new BlockingQueue. - Byte array containing a 16 byte color - Beginning position in the byte array - True if the byte array stores inverted values, - otherwise false. For example the color black (fully opaque) inverted - would be 0xFF 0xFF 0xFF 0x00 - True if the alpha value is inverted in - addition to whatever the inverted parameter is. Setting inverted true - and alphaInverted true will flip the alpha value back to non-inverted, - but keep the other color bytes inverted - A 16 byte array containing R, G, B, and A + The initial number of elements that the queue can contain - + - Copy constructor + Create new BlockingQueue. - Color to copy - + - IComparable.CompareTo implementation + BlockingQueue Destructor (Close queue, resume any waiting thread). - Sorting ends up like this: |--Grayscale--||--Color--|. - Alpha is only used when the colors are otherwise equivalent - + - Builds a color from a byte array + Remove all objects from the Queue. - Byte array containing a 16 byte color - Beginning position in the byte array - True if the byte array stores inverted values, - otherwise false. For example the color black (fully opaque) inverted - would be 0xFF 0xFF 0xFF 0x00 - True if the alpha value is inverted in - addition to whatever the inverted parameter is. Setting inverted true - and alphaInverted true will flip the alpha value back to non-inverted, - but keep the other color bytes inverted - + - Writes the raw bytes for this color to a byte array + Remove all objects from the Queue, resume all dequeue threads. - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array - + - Serializes this color into four bytes in a byte array + Removes and returns the object at the beginning of the Queue. - Destination byte array - Position in the destination array to start - writing. Must be at least 4 bytes before the end of the array - True to invert the output (1.0 becomes 0 - instead of 255) + Object in queue. - + - Writes the raw bytes for this color to a byte array + Removes and returns the object at the beginning of the Queue. - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array + time to wait before returning + Object in queue. - + - Ensures that values are in range 0-1 + Removes and returns the object at the beginning of the Queue. + time to wait before returning (in milliseconds) + Object in queue. - + - Create an RGB color from a hue, saturation, value combination + Adds an object to the end of the Queue - Hue - Saturation - Value - An fully opaque RGB color (alpha is 1.0) + Object to put in queue - + - Performs linear interpolation between two colors + Open Queue. - Color to start at - Color to end at - Amount to interpolate - The interpolated color - - - A Color4 with zero RGB values and fully opaque (alpha 1.0) - - - A Color4 with full RGB values (1.0) and fully opaque (alpha 1.0) - + - A three-dimensional vector with doubleing-point values + Gets flag indicating if queue has been closed. - + X value - + Y value - + Z value - + + W value + + Constructor, builds a vector from a byte array - Byte array containing three eight-byte doubles + Byte array containing four four-byte floats Beginning position in the byte array - + Test if this vector is equal to another vector, within a given tolerance range @@ -486,1309 +743,1023 @@ True if the magnitude of difference between the two vectors is less than the given tolerance, otherwise false - + IComparable.CompareTo implementation - + Test if this vector is composed of all finite numbers - + Builds a vector from a byte array - Byte array containing a 24 byte vector + Byte array containing a 16 byte vector Beginning position in the byte array - + Returns the raw bytes for this vector - A 24 byte array containing X, Y, and Z + A 16 byte array containing X, Y, Z, and W - + Writes the raw bytes for this vector to a byte array Destination byte array Position in the destination array to start - writing. Must be at least 24 bytes before the end of the array - - - - Parse a vector from a string - - A string representation of a 3D vector, enclosed - in arrow brackets and separated by commas - - - - Interpolates between two vectors using a cubic equation - - - - - Get a formatted string representation of the vector - - A string representation of the vector + writing. Must be at least 16 bytes before the end of the array - + Get a string representation of the vector elements with up to three decimal digits and separated by spaces only Raw string representation of the vector - - - Cross product between two vectors - - - - - Implicit casting for Vector3 > Vector3d - - - - - - A vector with a value of 0,0,0 - - - A vector with a value of 1,1,1 + + A vector with a value of 0,0,0,0 - - A unit vector facing forward (X axis), value of 1,0,0 + + A vector with a value of 1,1,1,1 - - A unit vector facing left (Y axis), value of 0,1,0 + + A vector with a value of 1,0,0,0 - - A unit vector facing up (Z axis), value of 0,0,1 + + A vector with a value of 0,1,0,0 - - - Determines the appropriate events to set, leaves the locks, and sets the events. - + + A vector with a value of 0,0,1,0 - - - A routine for lazily creating a event outside the lock (so if errors - happen they are outside the lock and that we don't do much work - while holding a spin lock). If all goes well, reenter the lock and - set 'waitEvent' - + + A vector with a value of 0,0,0,1 - + - Waits on 'waitEvent' with a timeout of 'millisceondsTimeout. - Before the wait 'numWaiters' is incremented and is restored before leaving this routine. + A three-dimensional vector with doubleing-point values - + X value - + Y value - + Z value - - W value - - + - Build a quaternion from normalized float values + Constructor, builds a vector from a byte array - X value from -1.0 to 1.0 - Y value from -1.0 to 1.0 - Z value from -1.0 to 1.0 + Byte array containing three eight-byte doubles + Beginning position in the byte array - + - Constructor, builds a quaternion object from a byte array + Test if this vector is equal to another vector, within a given + tolerance range - Byte array containing four four-byte floats - Offset in the byte array to start reading at - Whether the source data is normalized or - not. If this is true 12 bytes will be read, otherwise 16 bytes will - be read. + Vector to test against + The acceptable magnitude of difference + between the two vectors + True if the magnitude of difference between the two vectors + is less than the given tolerance, otherwise false - + - Normalizes the quaternion + IComparable.CompareTo implementation - + - Builds a quaternion object from a byte array + Test if this vector is composed of all finite numbers - The source byte array - Offset in the byte array to start reading at - Whether the source data is normalized or - not. If this is true 12 bytes will be read, otherwise 16 bytes will - be read. - + - Normalize this quaternion and serialize it to a byte array + Builds a vector from a byte array - A 12 byte array containing normalized X, Y, and Z floating - point values in order using little endian byte ordering + Byte array containing a 24 byte vector + Beginning position in the byte array - + - Writes the raw bytes for this quaternion to a byte array + Returns the raw bytes for this vector - Destination byte array - Position in the destination array to start - writing. Must be at least 12 bytes before the end of the array + A 24 byte array containing X, Y, and Z - + - Convert this quaternion to euler angles + Writes the raw bytes for this vector to a byte array - X euler angle - Y euler angle - Z euler angle + Destination byte array + Position in the destination array to start + writing. Must be at least 24 bytes before the end of the array - + - Convert this quaternion to an angle around an axis + Parse a vector from a string - Unit vector describing the axis - Angle around the axis, in radians + A string representation of a 3D vector, enclosed + in arrow brackets and separated by commas - + - Returns the conjugate (spatial inverse) of a quaternion + Interpolates between two vectors using a cubic equation - + - Build a quaternion from an axis and an angle of rotation around - that axis + Get a formatted string representation of the vector + A string representation of the vector - + - Build a quaternion from an axis and an angle of rotation around - that axis + Get a string representation of the vector elements with up to three + decimal digits and separated by spaces only - Axis of rotation - Angle of rotation + Raw string representation of the vector - + - Creates a quaternion from a vector containing roll, pitch, and yaw - in radians + Cross product between two vectors - Vector representation of the euler angles in - radians - Quaternion representation of the euler angles - + - Creates a quaternion from roll, pitch, and yaw euler angles in - radians + Implicit casting for Vector3 > Vector3d - X angle in radians - Y angle in radians - Z angle in radians - Quaternion representation of the euler angles + + - + + A vector with a value of 0,0,0 + + + A vector with a value of 1,1,1 + + + A unit vector facing forward (X axis), value of 1,0,0 + + + A unit vector facing left (Y axis), value of 0,1,0 + + + A unit vector facing up (Z axis), value of 0,0,1 + + - Conjugates and renormalizes a vector + A three-dimensional vector with floating-point values - + + X value + + + Y value + + + Z value + + - Spherical linear interpolation between two quaternions + Constructor, builds a vector from a byte array + Byte array containing three four-byte floats + Beginning position in the byte array - + - Get a string representation of the quaternion elements with up to three - decimal digits and separated by spaces only + Test if this vector is equal to another vector, within a given + tolerance range - Raw string representation of the quaternion - - - A quaternion with a value of 0,0,0,1 + Vector to test against + The acceptable magnitude of difference + between the two vectors + True if the magnitude of difference between the two vectors + is less than the given tolerance, otherwise false - + - Copy constructor + IComparable.CompareTo implementation - Circular queue to copy - + - Same as Queue except Dequeue function blocks until there is an object to return. - Note: This class does not need to be synchronized + Test if this vector is composed of all finite numbers - + - Create new BlockingQueue. + Builds a vector from a byte array - The System.Collections.ICollection to copy elements from + Byte array containing a 12 byte vector + Beginning position in the byte array - + - Create new BlockingQueue. + Returns the raw bytes for this vector - The initial number of elements that the queue can contain + A 12 byte array containing X, Y, and Z - + - Create new BlockingQueue. + Writes the raw bytes for this vector to a byte array + Destination byte array + Position in the destination array to start + writing. Must be at least 12 bytes before the end of the array - + - BlockingQueue Destructor (Close queue, resume any waiting thread). + Parse a vector from a string + A string representation of a 3D vector, enclosed + in arrow brackets and separated by commas - + - Remove all objects from the Queue. + Calculate the rotation between two vectors + Normalized directional vector (such as 1,0,0 for forward facing) + Normalized target vector - + - Remove all objects from the Queue, resume all dequeue threads. + Interpolates between two vectors using a cubic equation - + - Removes and returns the object at the beginning of the Queue. + Get a formatted string representation of the vector - Object in queue. + A string representation of the vector - + - Removes and returns the object at the beginning of the Queue. + Get a string representation of the vector elements with up to three + decimal digits and separated by spaces only - time to wait before returning - Object in queue. + Raw string representation of the vector - + - Removes and returns the object at the beginning of the Queue. + Cross product between two vectors - time to wait before returning (in milliseconds) - Object in queue. - + - Adds an object to the end of the Queue + Explicit casting for Vector3d > Vector3 - Object to put in queue + + - + + A vector with a value of 0,0,0 + + + A vector with a value of 1,1,1 + + + A unit vector facing forward (X axis), value 1,0,0 + + + A unit vector facing left (Y axis), value 0,1,0 + + + A unit vector facing up (Z axis), value 0,0,1 + + - Open Queue. + Identifier code for primitive types - + + None + + + A Primitive + + + A Avatar + + + Linden grass + + + Linden tree + + + A primitive that acts as the source for a particle stream + + + A Linden tree + + - Gets flag indicating if queue has been closed. + Primary parameters for primitives such as Physics Enabled or Phantom - - Used for converting degrees to radians + + Deprecated + + + Whether physics are enabled for this object + + + + + + + + + + + + + + + + + + + + + Whether this object contains an active touch script + + + + + + Whether this object can receive payments + + + Whether this object is phantom (no collisions) + + + + + + + + + + + + + + + Deprecated - - Used for converting radians to degrees + + - - Provide a single instance of the CultureInfo class to - help parsing in situations where the grid assumes an en-us - culture + + - - UNIX epoch in DateTime format + + - - Provide a single instance of the MD5 class to avoid making - duplicate copies and handle thread safety + + Deprecated - - Provide a single instance of the SHA-1 class to avoid - making duplicate copies and handle thread safety + + - - Provide a single instance of a random number generator - to avoid making duplicate copies and handle thread safety + + - - - Clamp a given value between a range - - Value to clamp - Minimum allowable value - Maximum allowable value - A value inclusively between lower and upper + + - - - Clamp a given value between a range - - Value to clamp - Minimum allowable value - Maximum allowable value - A value inclusively between lower and upper + + - - - Clamp a given value between a range - - Value to clamp - Minimum allowable value - Maximum allowable value - A value inclusively between lower and upper + + Server flag, will not be sent to clients. Specifies that + the object is destroyed when it touches a simulator edge - - - Round a floating-point value to the nearest integer - - Floating point number to round - Integer + + Server flag, will not be sent to clients. Specifies that + the object will be returned to the owner's inventory when it + touches a simulator edge - - - Test if a single precision float is a finite number - + + Server flag, will not be sent to clients. - - - Test if a double precision float is a finite number - + + Server flag, will not be sent to client. Specifies that + the object is hovering/flying - - - Get the distance between two floating-point values - - First value - Second value - The distance between the two values + + - - - Compute the MD5 hash for a byte array - - Byte array to compute the hash for - MD5 hash of the input data + + - - - Compute the SHA1 hash for a byte array - - Byte array to compute the hash for - SHA1 hash of the input data + + - - - Calculate the SHA1 hash of a given string - - The string to hash - The SHA1 hash as a string + + - + - Compute the SHA256 hash for a byte array + Sound flags for sounds attached to primitives - Byte array to compute the hash for - SHA256 hash of the input data - - - Calculate the SHA256 hash of a given string - - The string to hash - The SHA256 hash as a string + + - - - Calculate the MD5 hash of a given string - - The password to hash - An MD5 hash in string format, with $1$ prepended + + - - - Calculate the MD5 hash of a given string - - The string to hash - The MD5 hash as a string + + - - - Generate a random double precision floating point value - - Random value of type double + + - - - Get the current running platform - - Enumeration of the current platform we are running on + + - - - Get the current running runtime - - Enumeration of the current runtime we are running on + + - - - Convert the first two bytes starting in the byte array in - little endian ordering to a signed short integer - - An array two bytes or longer - A signed short integer, will be zero if a short can't be - read at the given position + + - + - Convert the first two bytes starting at the given position in - little endian ordering to a signed short integer + Material type for a primitive - An array two bytes or longer - Position in the array to start reading - A signed short integer, will be zero if a short can't be - read at the given position - - - Convert the first four bytes starting at the given position in - little endian ordering to a signed integer - - An array four bytes or longer - Position to start reading the int from - A signed integer, will be zero if an int can't be read - at the given position + + - - - Convert the first four bytes of the given array in little endian - ordering to a signed integer - - An array four bytes or longer - A signed integer, will be zero if the array contains - less than four bytes + + - - - Convert the first eight bytes of the given array in little endian - ordering to a signed long integer - - An array eight bytes or longer - A signed long integer, will be zero if the array contains - less than eight bytes + + - - - Convert the first eight bytes starting at the given position in - little endian ordering to a signed long integer - - An array eight bytes or longer - Position to start reading the long from - A signed long integer, will be zero if a long can't be read - at the given position + + - - - Convert the first two bytes starting at the given position in - little endian ordering to an unsigned short - - Byte array containing the ushort - Position to start reading the ushort from - An unsigned short, will be zero if a ushort can't be read - at the given position + + - - - Convert two bytes in little endian ordering to an unsigned short - - Byte array containing the ushort - An unsigned short, will be zero if a ushort can't be - read + + + + + - - - Convert the first four bytes starting at the given position in - little endian ordering to an unsigned integer - - Byte array containing the uint - Position to start reading the uint from - An unsigned integer, will be zero if a uint can't be read - at the given position + + - + - Convert the first four bytes of the given array in little endian - ordering to an unsigned integer + Used in a helper function to roughly determine prim shape - An array four bytes or longer - An unsigned integer, will be zero if the array contains - less than four bytes - + - Convert the first eight bytes of the given array in little endian - ordering to an unsigned 64-bit integer + Extra parameters for primitives, these flags are for features that have + been added after the original ObjectFlags that has all eight bits + reserved already - An array eight bytes or longer - An unsigned 64-bit integer, will be zero if the array - contains less than eight bytes - - - Convert four bytes in little endian ordering to a floating point - value - - Byte array containing a little ending floating - point value - Starting position of the floating point value in - the byte array - Single precision value + + Whether this object has flexible parameters - - - Convert an integer to a byte array in little endian format - - The integer to convert - A four byte little endian array + + Whether this object has light parameters - - - Convert an integer to a byte array in big endian format - - The integer to convert - A four byte big endian array + + Whether this object is a sculpted prim - - - Convert a 64-bit integer to a byte array in little endian format - - The value to convert - An 8 byte little endian array + + Whether this object is a light image map - - - Convert a 64-bit unsigned integer to a byte array in little endian - format - - The value to convert - An 8 byte little endian array + + Whether this object is a mesh - + - Convert a floating point value to four bytes in little endian - ordering + - A floating point value - A four byte array containing the value in little endian - ordering - - - Converts an unsigned integer to a hexadecimal string - - An unsigned integer to convert to a string - A hexadecimal string 10 characters long - 0x7fffffff + + - - - Convert a variable length UTF8 byte array to a string - - The UTF8 encoded byte array to convert - The decoded string + + - - - Converts a byte array to a string containing hexadecimal characters - - The byte array to convert to a string - The name of the field to prepend to each - line of the string - A string containing hexadecimal characters on multiple - lines. Each line is prepended with the field name + + - + - Converts a byte array to a string containing hexadecimal characters + - The byte array to convert to a string - Number of bytes in the array to parse - A string to prepend to each line of the hex - dump - A string containing hexadecimal characters on multiple - lines. Each line is prepended with the field name - - - Convert a string to a UTF8 encoded byte array - - The string to convert - A null-terminated UTF8 byte array + + - - - Converts a string containing hexadecimal characters to a byte array - - String containing hexadecimal characters - If true, gracefully handles null, empty and - uneven strings as well as stripping unconvertable characters - The converted byte array + + - - - Returns true is c is a hexadecimal digit (A-F, a-f, 0-9) - - Character to test - true if hex digit, false if not + + - - - Converts 1 or 2 character string into equivalant byte value - - 1 or 2 character string - byte + + - - - Convert a float value to a byte given a minimum and maximum range - - Value to convert to a byte - Minimum value range - Maximum value range - A single byte representing the original float value + + - + + + + + + + + + + - Convert a byte to a float value given a minimum and maximum range + - Byte array to get the byte from - Position in the byte array the desired byte is at - Minimum value range - Maximum value range - A float value inclusively between lower and upper - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Convert a byte to a float value given a minimum and maximum range + - Byte to convert to a float value - Minimum value range - Maximum value range - A float value inclusively between lower and upper - - - Attempts to parse a floating point value from a string, using an - EN-US number format - - String to parse - Resulting floating point number - True if the parse was successful, otherwise false + + + + + + + + + + + + + + + + + + + + + + + + Attachment points for objects on avatar bodies + + + Both InventoryObject and InventoryAttachment types can be attached + + + + Right hand if object was not previously attached + + + Chest + + + Skull + + + Left shoulder - - - Attempts to parse a floating point value from a string, using an - EN-US number format - - String to parse - Resulting floating point number - True if the parse was successful, otherwise false + + Right shoulder - - - Tries to parse an unsigned 32-bit integer from a hexadecimal string - - String to parse - Resulting integer - True if the parse was successful, otherwise false + + Left hand - - - Returns text specified in EnumInfo attribute of the enumerator - To add the text use [EnumInfo(Text = "Some nice text here")] before declaration - of enum values - - Enum value - Text representation of the enum + + Right hand - - - Takes an AssetType and returns the string representation - - The source - The string version of the AssetType + + Left foot - - - Translate a string name of an AssetType into the proper Type - - A string containing the AssetType name - The AssetType which matches the string name, or AssetType.Unknown if no match was found + + Right foot - - - Convert an InventoryType to a string - - The to convert - A string representation of the source + + Spine - - - Convert a string into a valid InventoryType - - A string representation of the InventoryType to convert - A InventoryType object which matched the type + + Pelvis - - - Convert a SaleType to a string - - The to convert - A string representation of the source + + Mouth - - - Convert a string into a valid SaleType - - A string representation of the SaleType to convert - A SaleType object which matched the type + + Chin - - - Converts a string used in LLSD to AttachmentPoint type - - String representation of AttachmentPoint to convert - AttachmentPoint enum + + Left ear - - - Copy a byte array - - Byte array to copy - A copy of the given byte array + + Right ear - - - Packs to 32-bit unsigned integers in to a 64-bit unsigned integer - - The left-hand (or X) value - The right-hand (or Y) value - A 64-bit integer containing the two 32-bit input values + + Left eyeball - - - Unpacks two 32-bit unsigned integers from a 64-bit unsigned integer - - The 64-bit input integer - The left-hand (or X) output value - The right-hand (or Y) output value + + Right eyeball - - - Convert an IP address object to an unsigned 32-bit integer - - IP address to convert - 32-bit unsigned integer holding the IP address bits + + Nose - - - Gets a unix timestamp for the current time - - An unsigned integer representing a unix timestamp for now + + Right upper arm - - - Convert a UNIX timestamp to a native DateTime object - - An unsigned integer representing a UNIX - timestamp - A DateTime object containing the same time specified in - the given timestamp + + Right forearm - - - Convert a UNIX timestamp to a native DateTime object - - A signed integer representing a UNIX - timestamp - A DateTime object containing the same time specified in - the given timestamp + + Left upper arm - - - Convert a native DateTime object to a UNIX timestamp - - A DateTime object you want to convert to a - timestamp - An unsigned integer representing a UNIX timestamp + + Left forearm - - - Swap two values - - Type of the values to swap - First value - Second value + + Right hip - - - Try to parse an enumeration value from a string - - Enumeration type - String value to parse - Enumeration value on success - True if the parsing succeeded, otherwise false + + Right upper leg - - - Swaps the high and low words in a byte. Converts aaaabbbb to bbbbaaaa - - Byte to swap the words in - Byte value with the words swapped + + Right lower leg - - - Attempts to convert a string representation of a hostname or IP - address to a - - Hostname to convert to an IPAddress - Converted IP address object, or null if the conversion - failed + + Left hip - - - Operating system - + + Left upper leg - - Unknown + + Left lower leg - - Microsoft Windows + + Stomach - - Microsoft Windows CE + + Left pectoral - - Linux + + Right pectoral - - Apple OSX + + HUD Center position 2 - - - Runtime platform - + + HUD Top-right - - .NET runtime + + HUD Top - - Mono runtime: http://www.mono-project.com/ + + HUD Top-left - - For thread safety + + HUD Center - - For thread safety + + HUD Bottom-left - - - Purges expired objects from the cache. Called automatically by the purge timer. - + + HUD Bottom - - - Convert this matrix to euler rotations - - X euler angle - Y euler angle - Z euler angle + + HUD Bottom-right - - - Convert this matrix to a quaternion rotation - - A quaternion representation of this rotation matrix + + Neck - - - Construct a matrix from euler rotation values in radians - - X euler angle in radians - Y euler angle in radians - Z euler angle in radians + + Avatar Center - + - Get a formatted string representation of the vector + Tree foliage types - A string representation of the vector - - A 4x4 matrix containing all zeroes + + Pine1 tree - - A 4x4 identity matrix + + Oak tree - - - Provides helper methods for parallelizing loops - + + Tropical Bush1 - - - 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 + + Palm1 tree - - - 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 + + Dogwood tree - - - 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 + + Tropical Bush2 - - - 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 + + Palm2 tree - - - Executes a series of tasks in parallel - - A series of method bodies to execute + + Cypress1 tree - - - Executes a series of tasks in parallel - - The number of concurrent execution threads to run - A series of method bodies to execute + + Cypress2 tree - - X value + + Pine2 tree - - Y value + + Plumeria - - Z value + + Winter pinetree1 - - W value + + Winter Aspen tree - - - Constructor, builds a vector from a byte array - - Byte array containing four four-byte floats - Beginning position in the byte array + + Winter pinetree2 - - - Test if this vector is equal to another vector, within a given - tolerance range - - Vector to test against - The acceptable magnitude of difference - between the two vectors - True if the magnitude of difference between the two vectors - is less than the given tolerance, otherwise false + + Eucalyptus tree - - - IComparable.CompareTo implementation - + + Fern - - - Test if this vector is composed of all finite numbers - + + Eelgrass - - - Builds a vector from a byte array - - Byte array containing a 16 byte vector - Beginning position in the byte array + + Sea Sword - - - Returns the raw bytes for this vector - - A 16 byte array containing X, Y, Z, and W + + Kelp1 plant - - - Writes the raw bytes for this vector to a byte array - - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array + + Beach grass - + + Kelp2 plant + + - Get a string representation of the vector elements with up to three - decimal digits and separated by spaces only + Grass foliage types - Raw string representation of the vector - - A vector with a value of 0,0,0,0 + + - - A vector with a value of 1,1,1,1 + + - - A vector with a value of 1,0,0,0 + + - - A vector with a value of 0,1,0,0 + + - - A vector with a value of 0,0,1,0 + + - - A vector with a value of 0,0,0,1 + + - + - A 128-bit Universally Unique Identifier, used throughout the Second - Life networking protocol + Action associated with clicking on an object - - The System.Guid object this struct wraps around + + Touch object - - - Constructor that takes a string UUID representation - - A string representation of a UUID, case - insensitive and can either be hyphenated or non-hyphenated - UUID("11f8aa9c-b071-4242-836b-13b7abe0d489") + + Sit on object - - - Constructor that takes a System.Guid object - - A Guid object that contains the unique identifier - to be represented by this UUID + + Purchase object or contents - - - Constructor that takes a byte array containing a UUID - - Byte array containing a 16 byte UUID - Beginning offset in the array + + Pay the object - - - Constructor that takes an unsigned 64-bit unsigned integer to - convert to a UUID - - 64-bit unsigned integer to convert to a UUID + + Open task inventory - - - Copy constructor - - UUID to copy + + Play parcel media - - - IComparable.CompareTo implementation - + + Open parcel media - + - Assigns this UUID from 16 bytes out of a byte array + Type of physics representation used for this prim in the simulator - Byte array containing the UUID to assign this UUID to - Starting position of the UUID in the byte array - - - Returns a copy of the raw bytes for this UUID - - A 16 byte array containing this UUID + + Use prim physics form this object - - - Writes the raw bytes for this UUID to a byte array - - Destination byte array - Position in the destination array to start - writing. Must be at least 16 bytes before the end of the array + + No physics, prim doesn't collide - - - Calculate an LLCRC (cyclic redundancy check) for this UUID - - The CRC checksum for this UUID + + Use convex hull represantion of this prim - + - Create a 64-bit integer representation from the second half of this UUID + An 8-bit color structure including an alpha channel - An integer created from the last eight bytes of this UUID - + + Red + + + Green + + + Blue + + + Alpha + + - Generate a UUID from a string + - A string representation of a UUID, case - insensitive and can either be hyphenated or non-hyphenated - UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489") + + + + - + - Generate a UUID from a string + Builds a color from a byte array - A string representation of a UUID, case - insensitive and can either be hyphenated or non-hyphenated - Will contain the parsed UUID if successful, - otherwise null - True if the string was successfully parse, otherwise false - UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result) + Byte array containing a 16 byte color + Beginning position in the byte array + True if the byte array stores inverted values, + otherwise false. For example the color black (fully opaque) inverted + would be 0xFF 0xFF 0xFF 0x00 - + - Combine two UUIDs together by taking the MD5 hash of a byte array - containing both UUIDs + Returns the raw bytes for this vector - First UUID to combine - Second UUID to combine - The UUID product of the combination + Byte array containing a 16 byte color + Beginning position in the byte array + True if the byte array stores inverted values, + otherwise false. For example the color black (fully opaque) inverted + would be 0xFF 0xFF 0xFF 0x00 + True if the alpha value is inverted in + addition to whatever the inverted parameter is. Setting inverted true + and alphaInverted true will flip the alpha value back to non-inverted, + but keep the other color bytes inverted + A 16 byte array containing R, G, B, and A - + - + Copy constructor - + Color to copy - + - Return a hash code for this UUID, used by .NET for hash tables + IComparable.CompareTo implementation - An integer composed of all the UUID bytes XORed together + Sorting ends up like this: |--Grayscale--||--Color--|. + Alpha is only used when the colors are otherwise equivalent - + - Comparison function + Builds a color from a byte array - An object to compare to this UUID - True if the object is a UUID and both UUIDs are equal + Byte array containing a 16 byte color + Beginning position in the byte array + True if the byte array stores inverted values, + otherwise false. For example the color black (fully opaque) inverted + would be 0xFF 0xFF 0xFF 0x00 + True if the alpha value is inverted in + addition to whatever the inverted parameter is. Setting inverted true + and alphaInverted true will flip the alpha value back to non-inverted, + but keep the other color bytes inverted - + - Comparison function + Writes the raw bytes for this color to a byte array - UUID to compare to - True if the UUIDs are equal, otherwise false + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - + - Get a hyphenated string representation of this UUID + Serializes this color into four bytes in a byte array - A string representation of this UUID, lowercase and - with hyphens - 11f8aa9c-b071-4242-836b-13b7abe0d489 + Destination byte array + Position in the destination array to start + writing. Must be at least 4 bytes before the end of the array + True to invert the output (1.0 becomes 0 + instead of 255) - + - Equals operator + Writes the raw bytes for this color to a byte array - First UUID for comparison - Second UUID for comparison - True if the UUIDs are byte for byte equal, otherwise false + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - + - Not equals operator + Ensures that values are in range 0-1 - First UUID for comparison - Second UUID for comparison - True if the UUIDs are not equal, otherwise true - + - XOR operator + Create an RGB color from a hue, saturation, value combination - First UUID - Second UUID - A UUID that is a XOR combination of the two input UUIDs + Hue + Saturation + Value + An fully opaque RGB color (alpha is 1.0) - + - String typecasting operator + Performs linear interpolation between two colors - A UUID in string form. Case insensitive, - hyphenated or non-hyphenated - A UUID built from the string representation + Color to start at + Color to end at + Amount to interpolate + The interpolated color - - An UUID with a value of all zeroes + + A Color4 with zero RGB values and fully opaque (alpha 1.0) - - A cache of UUID.Zero as a string to optimize a common path + + A Color4 with full RGB values (1.0) and fully opaque (alpha 1.0) - + - A three-dimensional vector with floating-point values + A two-dimensional vector with floating-point values - + X value - + Y value - - Z value - - - - Constructor, builds a vector from a byte array - - Byte array containing three four-byte floats - Beginning position in the byte array - - + Test if this vector is equal to another vector, within a given tolerance range @@ -1799,95 +1770,73 @@ True if the magnitude of difference between the two vectors is less than the given tolerance, otherwise false - + - IComparable.CompareTo implementation + Test if this vector is composed of all finite numbers - + - Test if this vector is composed of all finite numbers + IComparable.CompareTo implementation - + Builds a vector from a byte array - Byte array containing a 12 byte vector + Byte array containing two four-byte floats Beginning position in the byte array - + Returns the raw bytes for this vector - A 12 byte array containing X, Y, and Z + An eight-byte array containing X and Y - + Writes the raw bytes for this vector to a byte array Destination byte array Position in the destination array to start - writing. Must be at least 12 bytes before the end of the array + writing. Must be at least 8 bytes before the end of the array - + Parse a vector from a string - A string representation of a 3D vector, enclosed + A string representation of a 2D vector, enclosed in arrow brackets and separated by commas - - - Calculate the rotation between two vectors - - Normalized directional vector (such as 1,0,0 for forward facing) - Normalized target vector - - + Interpolates between two vectors using a cubic equation - + Get a formatted string representation of the vector A string representation of the vector - - - Get a string representation of the vector elements with up to three - decimal digits and separated by spaces only - - Raw string representation of the vector - - - - Cross product between two vectors - - - + - Explicit casting for Vector3d > Vector3 + Get a string representation of the vector elements with up to three + decimal digits and separated by spaces only - - - - - A vector with a value of 0,0,0 + Raw string representation of the vector - - A vector with a value of 1,1,1 + + A vector with a value of 0,0 - - A unit vector facing forward (X axis), value 1,0,0 + + A vector with a value of 1,1 - - A unit vector facing left (Y axis), value 0,1,0 + + A vector with a value of 1,0 - - A unit vector facing up (Z axis), value 0,0,1 + + A vector with a value of 0,1 @@ -1981,674 +1930,725 @@ return false regardless of the content of this bucket - - - Identifier code for primitive types - - - - None - - - A Primitive - - - A Avatar - - - Linden grass + + X value - - Linden tree + + Y value - - A primitive that acts as the source for a particle stream + + Z value - - A Linden tree + + W value - + - Primary parameters for primitives such as Physics Enabled or Phantom + Build a quaternion from normalized float values + X value from -1.0 to 1.0 + Y value from -1.0 to 1.0 + Z value from -1.0 to 1.0 - - Deprecated - - - Whether physics are enabled for this object - - - - - - - - - - - - - - - - - - - - - Whether this object contains an active touch script - - - - - - Whether this object can receive payments - - - Whether this object is phantom (no collisions) - - - - - - - - - - - - - - - Deprecated - - - - - - - - - - - - Deprecated - - - - - - - - - - - - - - - Server flag, will not be sent to clients. Specifies that - the object is destroyed when it touches a simulator edge - - - Server flag, will not be sent to clients. Specifies that - the object will be returned to the owner's inventory when it - touches a simulator edge - - - Server flag, will not be sent to clients. - - - Server flag, will not be sent to client. Specifies that - the object is hovering/flying - - - + + + Constructor, builds a quaternion object from a byte array + + Byte array containing four four-byte floats + Offset in the byte array to start reading at + Whether the source data is normalized or + not. If this is true 12 bytes will be read, otherwise 16 bytes will + be read. - - + + + Normalizes the quaternion + - - + + + Builds a quaternion object from a byte array + + The source byte array + Offset in the byte array to start reading at + Whether the source data is normalized or + not. If this is true 12 bytes will be read, otherwise 16 bytes will + be read. - - + + + Normalize this quaternion and serialize it to a byte array + + A 12 byte array containing normalized X, Y, and Z floating + point values in order using little endian byte ordering - + - Sound flags for sounds attached to primitives + Writes the raw bytes for this quaternion to a byte array + Destination byte array + Position in the destination array to start + writing. Must be at least 12 bytes before the end of the array - - + + + Convert this quaternion to euler angles + + X euler angle + Y euler angle + Z euler angle - - + + + Convert this quaternion to an angle around an axis + + Unit vector describing the axis + Angle around the axis, in radians - - + + + Returns the conjugate (spatial inverse) of a quaternion + - - + + + Build a quaternion from an axis and an angle of rotation around + that axis + - - + + + Build a quaternion from an axis and an angle of rotation around + that axis + + Axis of rotation + Angle of rotation - - + + + Creates a quaternion from a vector containing roll, pitch, and yaw + in radians + + Vector representation of the euler angles in + radians + Quaternion representation of the euler angles - - + + + Creates a quaternion from roll, pitch, and yaw euler angles in + radians + + X angle in radians + Y angle in radians + Z angle in radians + Quaternion representation of the euler angles - + - Material type for a primitive + Conjugates and renormalizes a vector - - - - - - - - - - - + + + Spherical linear interpolation between two quaternions + - - + + + Get a string representation of the quaternion elements with up to three + decimal digits and separated by spaces only + + Raw string representation of the quaternion - - + + A quaternion with a value of 0,0,0,1 - - + + For thread safety - - + + For thread safety - + - Used in a helper function to roughly determine prim shape + Purges expired objects from the cache. Called automatically by the purge timer. - + - Extra parameters for primitives, these flags are for features that have - been added after the original ObjectFlags that has all eight bits - reserved already + Attribute class that allows extra attributes to be attached to ENUMs - - Whether this object has flexible parameters - - - Whether this object has light parameters - - - Whether this object is a sculpted prim + + Text used when presenting ENUM to user - - Whether this object is a light image map + + Default initializer - - Whether this object is a mesh + + Text used when presenting ENUM to user - + - + The different types of grid assets - - + + Unknown asset type - - + + Texture asset, stores in JPEG2000 J2C stream format - - + + Sound asset - - - - + + Calling card for another avatar - - + + Link to a location in world - - + + Collection of textures and parameters that can be + worn by an avatar - - + + Primitive that can contain textures, sounds, + scripts and more - - + + Notecard asset - - + + Holds a collection of inventory items - - + + Root inventory folder - - + + Linden scripting language script - - + + LSO bytecode for a script - - - - + + Uncompressed TGA texture - - + + Collection of textures and shape parameters that can + be worn - - + + Trash folder - - + + Snapshot folder - - + + Lost and found folder - - + + Uncompressed sound - - + + Uncompressed TGA non-square image, not to be used as a + texture - - + + Compressed JPEG non-square image, not to be used as a + texture - - + + Animation - - + + Sequence of animations, sounds, chat, and pauses - - - - + + 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 - - - Attachment points for objects on avatar bodies - - - Both InventoryObject and InventoryAttachment types can be attached - + + Root folder for the folders of type OutfitFolder - - Right hand if object was not previously attached + + Linden mesh format - - Chest + + Marketplace direct delivery inbox ("Received Items") - - Skull + + Marketplace direct delivery outbox - - Left shoulder + + - - Right shoulder + + + Inventory Item Types, eg Script, Notecard, Folder, etc + - - Left hand + + Unknown - - Right hand + + Texture - - Left foot + + Sound - - Right foot + + Calling Card - - Spine + + Landmark - - Pelvis + + Notecard - - Mouth + + - - Chin + + Folder - - Left ear + + - - Right ear + + an LSL Script - - Left eyeball + + - - Right eyeball + + - - Nose + + - - Right upper arm + + - - Right forearm + + - - Left upper arm + + - - Left forearm + + + Item Sale Status + - - Right hip + + Not for sale - - Right upper leg + + The original is for sale - - Right lower leg + + Copies are for sale - - Left hip + + The contents of the object are for sale - - Left upper leg + + + Types of wearable assets + - - Left lower leg + + Body shape - - Stomach + + Skin textures and attributes - - Left pectoral + + Hair - - Right pectoral + + Eyes - - HUD Center position 2 + + Shirt - - HUD Top-right + + Pants - - HUD Top + + Shoes - - HUD Top-left + + Socks - - HUD Center + + Jacket - - HUD Bottom-left + + Gloves - - HUD Bottom + + Undershirt - - HUD Bottom-right + + Underpants - - Neck + + Skirt - - Avatar Center + + Alpha mask to hide parts of the avatar - - - Tree foliage types - + + Tattoo - - Pine1 tree + + Physics - - Oak tree + + Invalid wearable asset - - Tropical Bush1 + + + A thread-safe lockless queue that supports multiple readers and + multiple writers + - - Palm1 tree + + Queue head - - Dogwood tree + + Queue tail - - Tropical Bush2 + + Queue item count - - Palm2 tree + + + Constructor + - - Cypress1 tree + + + Enqueue an item + + Item to enqeue - - Cypress2 tree + + + Try to dequeue an item + + Dequeued item if the dequeue was successful + True if an item was successfully deqeued, otherwise false - - Pine2 tree + + Gets the current number of items in the queue. Since this + is a lockless collection this value should be treated as a close + estimate - - Plumeria + + + Provides a node container for data in a singly linked list + - - Winter pinetree1 + + Pointer to the next node in list - - Winter Aspen tree + + The data contained by the node - - Winter pinetree2 + + + Constructor + - - Eucalyptus tree + + + Constructor + - - Fern + + + A 128-bit Universally Unique Identifier, used throughout the Second + Life networking protocol + - - Eelgrass + + The System.Guid object this struct wraps around - - Sea Sword + + + Constructor that takes a string UUID representation + + A string representation of a UUID, case + insensitive and can either be hyphenated or non-hyphenated + UUID("11f8aa9c-b071-4242-836b-13b7abe0d489") - - Kelp1 plant + + + Constructor that takes a System.Guid object + + A Guid object that contains the unique identifier + to be represented by this UUID - - Beach grass + + + Constructor that takes a byte array containing a UUID + + Byte array containing a 16 byte UUID + Beginning offset in the array - - Kelp2 plant + + + Constructor that takes an unsigned 64-bit unsigned integer to + convert to a UUID + + 64-bit unsigned integer to convert to a UUID - + - Grass foliage types + Copy constructor + UUID to copy - - - - - + + + IComparable.CompareTo implementation + - - + + + Assigns this UUID from 16 bytes out of a byte array + + Byte array containing the UUID to assign this UUID to + Starting position of the UUID in the byte array - - + + + Returns a copy of the raw bytes for this UUID + + A 16 byte array containing this UUID - - + + + Writes the raw bytes for this UUID to a byte array + + Destination byte array + Position in the destination array to start + writing. Must be at least 16 bytes before the end of the array - - + + + Calculate an LLCRC (cyclic redundancy check) for this UUID + + The CRC checksum for this UUID - + - Action associated with clicking on an object + Create a 64-bit integer representation from the second half of this UUID + An integer created from the last eight bytes of this UUID - - Touch object + + + Generate a UUID from a string + + A string representation of a UUID, case + insensitive and can either be hyphenated or non-hyphenated + UUID.Parse("11f8aa9c-b071-4242-836b-13b7abe0d489") - - Sit on object + + + Generate a UUID from a string + + A string representation of a UUID, case + insensitive and can either be hyphenated or non-hyphenated + Will contain the parsed UUID if successful, + otherwise null + True if the string was successfully parse, otherwise false + UUID.TryParse("11f8aa9c-b071-4242-836b-13b7abe0d489", result) - - Purchase object or contents + + + Combine two UUIDs together by taking the MD5 hash of a byte array + containing both UUIDs + + First UUID to combine + Second UUID to combine + The UUID product of the combination - - Pay the object + + + + + - - Open task inventory + + + Return a hash code for this UUID, used by .NET for hash tables + + An integer composed of all the UUID bytes XORed together - - Play parcel media + + + Comparison function + + An object to compare to this UUID + True if the object is a UUID and both UUIDs are equal - - Open parcel media + + + Comparison function + + UUID to compare to + True if the UUIDs are equal, otherwise false - + - Type of physics representation used for this prim in the simulator + Get a hyphenated string representation of this UUID + A string representation of this UUID, lowercase and + with hyphens + 11f8aa9c-b071-4242-836b-13b7abe0d489 - - Use prim physics form this object + + + Equals operator + + First UUID for comparison + Second UUID for comparison + True if the UUIDs are byte for byte equal, otherwise false - - No physics, prim doesn't collide + + + Not equals operator + + First UUID for comparison + Second UUID for comparison + True if the UUIDs are not equal, otherwise true - - Use convex hull represantion of this prim + + + XOR operator + + First UUID + Second UUID + A UUID that is a XOR combination of the two input UUIDs - + - A two-dimensional vector with floating-point values + String typecasting operator + A UUID in string form. Case insensitive, + hyphenated or non-hyphenated + A UUID built from the string representation - - X value + + An UUID with a value of all zeroes - - Y value + + A cache of UUID.Zero as a string to optimize a common path - + - Test if this vector is equal to another vector, within a given - tolerance range + Provides helper methods for parallelizing loops - Vector to test against - The acceptable magnitude of difference - between the two vectors - True if the magnitude of difference between the two vectors - is less than the given tolerance, otherwise false - + - Test if this vector is composed of all finite numbers + 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 - + - IComparable.CompareTo implementation + 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 - + - Builds a vector from a byte array + Executes a foreach loop in which iterations may run in parallel - Byte array containing two four-byte floats - Beginning position in the byte array + Object type that the collection wraps + An enumerable collection to iterate over + Method body to run for each object in the collection - + - Returns the raw bytes for this vector + Executes a foreach loop in which iterations may run in parallel - An eight-byte array containing X and Y + 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 - + - Writes the raw bytes for this vector to a byte array + Executes a series of tasks in parallel - Destination byte array - Position in the destination array to start - writing. Must be at least 8 bytes before the end of the array + A series of method bodies to execute - + - Parse a vector from a string + Executes a series of tasks in parallel - A string representation of a 2D vector, enclosed - in arrow brackets and separated by commas + The number of concurrent execution threads to run + A series of method bodies to execute - + - Interpolates between two vectors using a cubic equation + Copy constructor + Circular queue to copy - + - Get a formatted string representation of the vector + Determines the appropriate events to set, leaves the locks, and sets the events. - A string representation of the vector - + - Get a string representation of the vector elements with up to three - decimal digits and separated by spaces only + A routine for lazily creating a event outside the lock (so if errors + happen they are outside the lock and that we don't do much work + while holding a spin lock). If all goes well, reenter the lock and + set 'waitEvent' - Raw string representation of the vector - - A vector with a value of 0,0 - - - A vector with a value of 1,1 - - - A vector with a value of 1,0 - - - A vector with a value of 0,1 + + + Waits on 'waitEvent' with a timeout of 'millisceondsTimeout. + Before the wait 'numWaiters' is incremented and is restored before leaving this routine. + diff --git a/bin/OpenMetaverseTypes.dll b/bin/OpenMetaverseTypes.dll index 00397a9..7ee907b 100755 Binary files a/bin/OpenMetaverseTypes.dll and b/bin/OpenMetaverseTypes.dll differ -- cgit v1.1 From 46eb8465a01b7dd923b962035562c953d4eb78e4 Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 15 May 2013 17:12:17 -0700 Subject: fall back to using a display mesh for physics proxy if no physics_mesh entry was wound in a mesh asset --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 8145d61..2d102de 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -358,6 +358,10 @@ namespace OpenSim.Region.Physics.Meshing physicsParms = (OSDMap)map["physics_shape"]; // old asset format else if (map.ContainsKey("physics_mesh")) physicsParms = (OSDMap)map["physics_mesh"]; // new asset format + else if (map.ContainsKey("medium_lod")) + physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh + else if (map.ContainsKey("high_lod")) + physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) if (physicsParms == null) { -- cgit v1.1 From bd31821792a940709ff1355a91b9b60302cc1a17 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 16 May 2013 16:37:21 +0100 Subject: On logout, send close child agent requests to neighbours asynchronously, so user is not prevented from relogging if many neighbours are present but not responsive. The symptom here is that previous user connections are still present but are labelled active == false --- OpenSim/Region/Framework/Scenes/Scene.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 6bbcbd7..50bea6f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3435,16 +3435,13 @@ namespace OpenSim.Region.Framework.Scenes if (closeChildAgents && CapsModule != null) CapsModule.RemoveCaps(agentID); -// // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever -// // this method is doing is HORRIBLE!!! - // Commented pending deletion since this method no longer appears to do anything at all -// avatar.Scene.NeedSceneCacheClear(avatar.UUID); - if (closeChildAgents && !isChildAgent) { List regions = avatar.KnownRegionHandles; regions.Remove(RegionInfo.RegionHandle); - m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); + + // We must do this asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. + Util.FireAndForget(delegate { m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); }); } m_eventManager.TriggerClientClosed(agentID, this); -- cgit v1.1 From d214e2d0c4b8e1ea5e0d69e2ba94cd668be610bd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 16 May 2013 17:12:02 +0100 Subject: On closing child agents, send separate asynchronous requests to each neighbour rather than sending all closes concurrently on a separate thread. This is to reduce race conditions where neighbours may be responding erratically, thus mixing up create and close agent requests in time. This mirrors OpenSimulator behaviour on enabling child agents where each region is contacted separately. --- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++-- OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs | 4 +--- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 50bea6f..8fe9b66 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3440,8 +3440,8 @@ namespace OpenSim.Region.Framework.Scenes List regions = avatar.KnownRegionHandles; regions.Remove(RegionInfo.RegionHandle); - // We must do this asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. - Util.FireAndForget(delegate { m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); }); + // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. + m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); } m_eventManager.TriggerClientClosed(agentID, this); diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index 305f8a4..8c84c98 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -222,9 +222,7 @@ namespace OpenSim.Region.Framework.Scenes public void SendCloseChildAgentConnections(UUID agentID, List regionslst) { foreach (ulong handle in regionslst) - { - SendCloseChildAgent(agentID, handle); - } + Util.FireAndForget(delegate { SendCloseChildAgent(agentID, handle); }); } public List RequestNamedRegions(string name, int maxNumber) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2a265db..9e9089b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3135,10 +3135,8 @@ namespace OpenSim.Region.Framework.Scenes if (byebyeRegions.Count > 0) { m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); - Util.FireAndForget(delegate - { - m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); - }); + + m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); } foreach (ulong handle in byebyeRegions) -- cgit v1.1 From 3bc8cf65a4e933cfdd0597affc1685c74fb29dba Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 16 May 2013 17:30:30 +0100 Subject: Where this is not already happening, trigger asychoronous calls to CloseChildAgent() above the LocalSimulationConnector level. This is so that other callers (such as SceneCommunicationService.SendCloseChildAgentConnections() can perform all closes asynchronously without pointlessly firing another thread for local closes). No functional change apart from elimination of unnecessary chaining of new threads. --- .../Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 1 + .../ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | 2 +- OpenSim/Server/Handlers/Simulation/AgentHandlers.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index eac0da7..9579449 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -937,6 +937,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer EnableChildAgents(sp); // Finally, kill the agent we just created at the destination. + // XXX: Possibly this should be done asynchronously. Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index a413546..9427961 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -317,7 +317,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // s.RegionInfo.RegionName, destination.RegionHandle); - Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id, false); }); + m_scenes[destination.RegionID].IncomingCloseAgent(id, false); return true; } diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 012b14e..ae37ca7 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -218,7 +218,7 @@ namespace OpenSim.Server.Handlers.Simulation if (action.Equals("release")) ReleaseAgent(regionID, id); else - m_SimulationService.CloseAgent(destination, id); + Util.FireAndForget(delegate { m_SimulationService.CloseAgent(destination, id); }); responsedata["int_response_code"] = HttpStatusCode.OK; responsedata["str_response_string"] = "OpenSim agent " + id.ToString(); -- cgit v1.1 From 61f4ab667447da953018b9e63821777ec5f144b0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 16 May 2013 18:25:04 +0100 Subject: minor: Remove completely unused IClientAPI.RequestClientInfo() call from EntityTransferModule.CrossAgentToNewRegionAsync() --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 9579449..4f693c6 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1482,9 +1482,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return agent; } - //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo(); - agent.ControllingClient.RequestClientInfo(); - //m_log.Debug("BEFORE CROSS"); //Scene.DumpChildrenSeeds(UUID); //DumpKnownRegions(); -- cgit v1.1 From ec818a506bd125b1a89b2ff04f15108521a0f2e9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 16 May 2013 18:26:22 +0100 Subject: minor: remove long commented out scene cache clearing code in EntityTransferModule.CrossAgentToNewRegionAsync() --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 4f693c6..f58a24f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1541,15 +1541,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.CloseChildAgents(neighbourx, neighboury); AgentHasMovedAway(agent, false); - -// // the user may change their profile information in other region, -// // so the userinfo in UserProfileCache is not reliable any more, delete it -// // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! -// if (agent.Scene.NeedSceneCacheClear(agent.UUID)) -// { -// m_log.DebugFormat( -// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); -// } //m_log.Debug("AFTER CROSS"); //Scene.DumpChildrenSeeds(UUID); -- cgit v1.1 From 214bae14799c05c12595b067ff2eb0e2e5b4eeb2 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 17 May 2013 14:43:53 -0700 Subject: BulletSim: fix BulletSim crashing if there is no [BulletSim] section in any INI file. Update TODO list. --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 6 ++++++ OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | 14 ++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 3f407ce..9ed2d06 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -268,6 +268,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // Do any replacements in the parameters m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); } + else + { + BulletEngineName = "BulletUnmanaged"; + m_physicsLoggingEnabled = false; + VehicleLoggingEnabled = false; + } // The material characteristics. BSMaterials.InitializeFromDefaults(Params); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 5792ae6..df1da63 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -1,16 +1,12 @@ -PROBLEMS TO LOOK INTO +CURRENT PROBLEMS TO FIX AND/OR LOOK AT ================================================= -Nebadon vehicle ride, get up, ride again. Second time vehicle does not act correctly. +Script changing rotation of child prim while vehicle moving (eg turning wheel) causes + the wheel to appear to jump back. Looks like sending position from previous update. +Vehicle ride, get up, ride again. Second time vehicle does not act correctly. Have to rez new vehicle and delete the old to fix situation. Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd position state where it will not settle onto ground properly, etc Two of Nebadon vehicles in a sim max the CPU. This is new. -A sitting, active vehicle bobs up and down a small amount. - -CURRENT PRIORITIES -================================================= -Use the HACD convex hull routine in Bullet rather than the C# version. - Speed up hullifying large meshes. Enable vehicle border crossings (at least as poorly as ODE) Terrain skirts Avatar created in previous region and not new region when crossing border @@ -361,4 +357,6 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. Nebadon vehicles turning funny in arena (DONE) Lock axis (DONE 20130401) Terrain detail: double terrain mesh detail (DONE) +Use the HACD convex hull routine in Bullet rather than the C# version. + Speed up hullifying large meshes. (DONE) -- cgit v1.1 From fa8f5bafb225624fe4a0df88acf1f4c227632fe0 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 18 May 2013 01:23:09 -0700 Subject: add prototype code to decode convex hulls from mesh assets. Please do not use yet; the interface will be defined in a later commit. --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 131 +++++++++++++++++++++----- 1 file changed, 110 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 2d102de..825e622 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -79,6 +79,8 @@ namespace OpenSim.Region.Physics.Meshing private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh + private List> mConvexHulls = null; + private Dictionary m_uniqueMeshes = new Dictionary(); public Meshmerizer(IConfigSource config) @@ -363,6 +365,57 @@ namespace OpenSim.Region.Physics.Meshing else if (map.ContainsKey("high_lod")) physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) + if (map.ContainsKey("physics_convex")) + { // pull this out also in case physics engine can use it + try + { + OSDMap convexBlock = (OSDMap)map["physics_convex"]; + if (convexBlock.ContainsKey("HullList")) + { + byte[] hullList = convexBlock["HullList"].AsBinary(); + Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); + if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); + Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); + if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); + + // decompress and decode hull points + byte[] posBytes = DecompressOsd(convexBlock["Positions"].AsBinary()).AsBinary(); + + List> hulls = new List>(); + int posNdx = 0; + + foreach (byte cnt in hullList) + { + int count = cnt == 0 ? 256 : cnt; + List hull = new List(); + + for (int i = 0; i < cnt; i++) + { + ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + + Vector3 pos = new Vector3( + Utils.UInt16ToFloat(uX, min.X, max.X) * size.X, + Utils.UInt16ToFloat(uY, min.Y, max.Y) * size.Y, + Utils.UInt16ToFloat(uZ, min.Z, max.Z) * size.Z + ); + + hull.Add(pos); + } + + hulls.Add(hull); + } + + mConvexHulls = hulls; + } + } + catch (Exception e) + { + m_log.WarnFormat("[MESH]: exception decoding convex block: {0}", e.Message); + } + } + if (physicsParms == null) { m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName); @@ -381,27 +434,7 @@ namespace OpenSim.Region.Physics.Meshing // byte[] decompressed = new byte[physSize * 5]; try { - using (MemoryStream inMs = new MemoryStream(meshBytes)) - { - using (MemoryStream outMs = new MemoryStream()) - { - using (ZOutputStream zOut = new ZOutputStream(outMs)) - { - byte[] readBuffer = new byte[2048]; - int readLen = 0; - while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) - { - zOut.Write(readBuffer, 0, readLen); - } - zOut.Flush(); - outMs.Seek(0, SeekOrigin.Begin); - - byte[] decompressedBuf = outMs.GetBuffer(); - - decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); - } - } - } + decodedMeshOsd = DecompressOsd(meshBytes); } catch (Exception e) { @@ -428,6 +461,41 @@ namespace OpenSim.Region.Physics.Meshing return true; } + + /// + /// decompresses a gzipped OSD object + /// + /// the OSD object + /// + /// + private static OSD DecompressOsd(byte[] meshBytes) + { + OSD decodedOsd = null; + + using (MemoryStream inMs = new MemoryStream(meshBytes)) + { + using (MemoryStream outMs = new MemoryStream()) + { + using (ZOutputStream zOut = new ZOutputStream(outMs)) + { + byte[] readBuffer = new byte[2048]; + int readLen = 0; + while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) + { + zOut.Write(readBuffer, 0, readLen); + } + zOut.Flush(); + outMs.Seek(0, SeekOrigin.Begin); + + byte[] decompressedBuf = outMs.GetBuffer(); + + decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); + } + } + } + return decodedOsd; + } + /// /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. /// @@ -704,6 +772,27 @@ namespace OpenSim.Region.Physics.Meshing return true; } + /// + /// temporary prototype code - please do not use until the interface has been finalized! + /// + /// value to scale the hull points by + /// a list of hulls if they exist and have been successfully decoded, otherwise null + public List> GetConvexHulls(Vector3 size) + { + if (mConvexHulls == null) + return null; + + List> hulls = new List>(); + foreach (var hull in mConvexHulls) + { + List verts = new List(); + foreach (var vert in hull) + verts.Add(vert * size); + } + + return hulls; + } + public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) { return CreateMesh(primName, primShape, size, lod, false, true); -- cgit v1.1 From 477bee6468f35ca9264fc8f752a9124e32503901 Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 18 May 2013 11:15:05 -0700 Subject: remove duplicate hull scaling --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 825e622..a57146c 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -396,9 +396,9 @@ namespace OpenSim.Region.Physics.Meshing ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; Vector3 pos = new Vector3( - Utils.UInt16ToFloat(uX, min.X, max.X) * size.X, - Utils.UInt16ToFloat(uY, min.Y, max.Y) * size.Y, - Utils.UInt16ToFloat(uZ, min.Z, max.Z) * size.Z + Utils.UInt16ToFloat(uX, min.X, max.X), + Utils.UInt16ToFloat(uY, min.Y, max.Y), + Utils.UInt16ToFloat(uZ, min.Z, max.Z) ); hull.Add(pos); -- cgit v1.1 From e65d1e459eb875cb2d0d5f9aa6042c640daa19fd Mon Sep 17 00:00:00 2001 From: dahlia Date: Sat, 18 May 2013 13:11:22 -0700 Subject: fix error in hull point indexing --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index a57146c..79edc12 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -389,7 +389,7 @@ namespace OpenSim.Region.Physics.Meshing int count = cnt == 0 ? 256 : cnt; List hull = new List(); - for (int i = 0; i < cnt; i++) + for (int i = 0; i < count; i++) { ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; -- cgit v1.1 From 26904cc5a16d0bbbd9984bfc36354680b0ee27fb Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 20 May 2013 09:25:50 -0700 Subject: Add comment --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2a265db..1b81985 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1348,7 +1348,9 @@ namespace OpenSim.Region.Framework.Scenes // Create child agents in neighbouring regions if (openChildAgents && !IsChildAgent) { + // Remember in HandleUseCircuitCode, we delayed this to here SendInitialDataToMe(); + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); if (m_agentTransfer != null) Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); -- cgit v1.1 From 6ae426c96ba0bfdad9e884364f5b6be5b4cd61a9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 17:25:06 +0100 Subject: Lock m_UserCache whilst iterating over it in UserManagementModule.GetUserData() to avoid concurrency exceptions --- .../Framework/UserManagement/UserManagementModule.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 6847e57..d99c8eb 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -246,10 +246,15 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // search the local cache - foreach (UserData data in m_UserCache.Values) - if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && - (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) - users.Add(data); + lock (m_UserCache) + { + foreach (UserData data in m_UserCache.Values) + { + if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && + (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) + users.Add(data); + } + } AddAdditionalUsers(query, users); -- cgit v1.1 From c47de9878dd8af19fa9b4322a8a49646712ebf9b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 17:45:15 +0100 Subject: Log when "Unknown User" is sent to a user because the UMM had no binding for that UUID and when a binding replaces a previous "Unknown User" entry. This is a temporary measure to hunt down issues where some but not all users see others as "Unknown user" in text chat, etc. http://opensimulator.org/mantis/view.php?id=6625 --- .../UserManagement/UserManagementModule.cs | 49 ++++++++++++++-------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index d99c8eb..06f1712 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -157,13 +157,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } else { - string[] names = GetUserNames(uuid); + string[] names; + bool foundRealName = TryGetUserNames(uuid, out names); + if (names.Length == 2) { - //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]); + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, remote_client.Name); + remote_client.SendNameReply(uuid, names[0], names[1]); } - } } @@ -277,17 +280,24 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - private string[] GetUserNames(UUID uuid) + /// + /// Try to get the names bound to the given uuid. + /// + /// True if the name was found, false if not. + /// + /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" + private bool TryGetUserNames(UUID uuid, out string[] names) { - string[] returnstring = new string[2]; + names = new string[2]; lock (m_UserCache) { if (m_UserCache.ContainsKey(uuid)) { - returnstring[0] = m_UserCache[uuid].FirstName; - returnstring[1] = m_UserCache[uuid].LastName; - return returnstring; + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; + + return true; } } @@ -295,8 +305,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (account != null) { - returnstring[0] = account.FirstName; - returnstring[1] = account.LastName; + names[0] = account.FirstName; + names[1] = account.LastName; UserData user = new UserData(); user.FirstName = account.FirstName; @@ -304,14 +314,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement lock (m_UserCache) m_UserCache[uuid] = user; + + return true; } else { - returnstring[0] = "Unknown"; - returnstring[1] = "User"; - } + names[0] = "Unknown"; + names[1] = "User"; - return returnstring; + return false; + } } #region IUserManagement @@ -347,15 +359,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public string GetUserName(UUID uuid) { - string[] names = GetUserNames(uuid); + string[] names; + TryGetUserNames(uuid, out names); + if (names.Length == 2) { string firstname = names[0]; string lastname = names[1]; return firstname + " " + lastname; - } + return "(hippos)"; } @@ -471,12 +485,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement //ignore updates without creator data return; } + //try update unknown users //and creator's home URL's if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) { m_UserCache.Remove (id); -// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL); + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); } else { -- cgit v1.1 From 6edecd5d94949873411b0625928b4f0ad0e01f9a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 18:00:41 +0100 Subject: Add "show name" console command to make it possible to show a single binding of a UUID to a name. --- .../UserManagement/UserManagementModule.cs | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 06f1712..48ec12f 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -568,6 +568,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected void RegisterConsoleCmds() { MainConsole.Instance.Commands.AddCommand("Users", true, + "show name", + "show name ", + "Show the bindings between a single user UUID and a user name", + String.Empty, + HandleShowUser); + + MainConsole.Instance.Commands.AddCommand("Users", true, "show names", "show names", "Show the bindings between user UUIDs and user names", @@ -575,6 +582,33 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement HandleShowUsers); } + private void HandleShowUser(string module, string[] cmd) + { + if (cmd.Length < 3) + { + MainConsole.Instance.OutputFormat("Usage: show name "); + return; + } + + UUID userId; + if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId)) + return; + + string[] names; + if (!TryGetUserNames(userId, out names)) + { + MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId); + return; + } + + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("UUID", 36); + cdt.AddColumn("Name", 60); + cdt.AddRow(userId, string.Join(" ", names)); + + MainConsole.Instance.Output(cdt.ToString()); + } + private void HandleShowUsers(string module, string[] cmd) { lock (m_UserCache) -- cgit v1.1 From 5c8d38d6cf00ea8e53ff52ac5eafde40ee94b68e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 18:10:42 +0100 Subject: minor: Change "show names" command to use consistent console display table --- .../UserManagement/UserManagementModule.cs | 24 ++++++++-------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 48ec12f..d75a85f 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -603,7 +603,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("UUID", 36); - cdt.AddColumn("Name", 60); + cdt.AddColumn("Name", 30); cdt.AddRow(userId, string.Join(" ", names)); MainConsole.Instance.Output(cdt.ToString()); @@ -611,24 +611,18 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement private void HandleShowUsers(string module, string[] cmd) { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("UUID", 36); + cdt.AddColumn("Name", 30); + cdt.AddColumn("HomeURL", 40); + lock (m_UserCache) { - if (m_UserCache.Count == 0) - { - MainConsole.Instance.Output("No users found"); - return; - } - - MainConsole.Instance.Output("UUID User Name"); - MainConsole.Instance.Output("-----------------------------------------------------------------------------"); foreach (KeyValuePair kvp in m_UserCache) - { - MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})", - kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL)); - } - - return; + cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL); } + + MainConsole.Instance.Output(cdt.ToString()); } } } \ No newline at end of file -- cgit v1.1 From 434c3cf83b09fbbf4b3d20b079597a40d63bae2f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 18:15:22 +0100 Subject: Make "show name" command display HomeURL like "show names" --- .../Framework/UserManagement/UserManagementModule.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index d75a85f..f8f4235 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -595,16 +595,23 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return; string[] names; - if (!TryGetUserNames(userId, out names)) + + UserData ud; + + lock (m_UserCache) { - MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId); - return; + if (!m_UserCache.TryGetValue(userId, out ud)) + { + MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId); + return; + } } ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("UUID", 36); cdt.AddColumn("Name", 30); - cdt.AddRow(userId, string.Join(" ", names)); + cdt.AddColumn("HomeURL", 40); + cdt.AddRow(userId, string.Join(" ", ud.FirstName, ud.LastName), ud.HomeURL); MainConsole.Instance.Output(cdt.ToString()); } -- cgit v1.1 From ba6a6b2d4021160a68dec906b3a0b3930e870a51 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 18:18:16 +0100 Subject: Fix compile failure from recent git master 434c3cf --- .../Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index f8f4235..806f5e5 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -611,7 +611,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement cdt.AddColumn("UUID", 36); cdt.AddColumn("Name", 30); cdt.AddColumn("HomeURL", 40); - cdt.AddRow(userId, string.Join(" ", ud.FirstName, ud.LastName), ud.HomeURL); + cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL); MainConsole.Instance.Output(cdt.ToString()); } -- cgit v1.1 From 06ab16889744ab3f3cef7d698b19408368711194 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 22:26:15 +0100 Subject: To further help with tracking down the apperance of too much "Unknown User" in chatlogs, etc. temporarily change each instance of this in OpenSimulator so we can identify where it's coming from For instance, the "Unknown User" in Util.ParseUniversalUserIdenitifer becaomes "Unknown UserUPUUI (class initials + method initials) This is to help with http://opensimulator.org/mantis/view.php?id=6625 --- OpenSim/Framework/Util.cs | 2 +- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 4 ++-- OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | 2 +- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a3602e9..ada4e89 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2136,7 +2136,7 @@ namespace OpenSim.Framework /// the secret part public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty; string[] parts = value.Split(';'); if (parts.Length >= 1) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 8056030..4613344 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -371,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends foreach (string fid in outstanding) { UUID fromAgentID; - string firstname = "Unknown", lastname = "User"; + string firstname = "Unknown", lastname = "UserFMSFOIN"; if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname)) { m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid); @@ -397,7 +397,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) { - first = "Unknown"; last = "User"; + first = "Unknown"; last = "UserFMGAI"; if (!UUID.TryParse(fid, out agentID)) return false; diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index bf5c0bb..b3e3aa2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -293,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) { - first = "Unknown"; last = "User"; + first = "Unknown"; last = "UserHGGAI"; if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) return true; diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 806f5e5..a720d7b 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -320,7 +320,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { names[0] = "Unknown"; - names[1] = "User"; + names[1] = "UserUMMTGUN"; return false; } @@ -536,7 +536,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { user.FirstName = "Unknown"; - user.LastName = "User"; + user.LastName = "UserUMMAU"; } AddUserInternal (user); -- cgit v1.1 From 9de3979f5b91ae4bf9b05b89ec59999c43514f90 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 17 May 2013 21:17:54 -0700 Subject: BulletSim: add gImpact shape type. Add logic to use gImpact shape for prims that have cuts or holes. Default logic to 'off' as it needs debugging. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 15 +++ OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 11 +- .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 5 + OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 + OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 2 + .../Physics/BulletSPlugin/BSShapeCollection.cs | 15 ++- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 130 +++++++++++++++++++-- 7 files changed, 167 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 231f0f8..12a0c17 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -251,6 +251,16 @@ public override BulletShape CreateMeshShape(BulletWorld world, BSPhysicsShapeType.SHAPE_MESH); } +public override BulletShape CreateGImpactShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_GIMPACT); +} + public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) { BulletWorldUnman worldu = world as BulletWorldUnman; @@ -1426,6 +1436,11 @@ public static extern IntPtr CreateMeshShape2(IntPtr world, int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern IntPtr CreateGImpactShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateHullShape2(IntPtr world, int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 59780ae..6db5f5e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -1475,7 +1475,7 @@ private sealed class BulletConstraintXNA : BulletConstraint ret = BSPhysicsShapeType.SHAPE_UNKNOWN; break; case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; + ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; break; case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: ret = BSPhysicsShapeType.SHAPE_HULL; @@ -1503,7 +1503,7 @@ private sealed class BulletConstraintXNA : BulletConstraint ret = BSPhysicsShapeType.SHAPE_CONE; break; case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; break; case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: ret = BSPhysicsShapeType.SHAPE_CYLINDER; @@ -1547,7 +1547,7 @@ private sealed class BulletConstraintXNA : BulletConstraint break; ///Used for GIMPACT Trimesh integration case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; + ret = BSPhysicsShapeType.SHAPE_GIMPACT; break; ///Multimaterial mesh case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: @@ -1820,6 +1820,11 @@ private sealed class BulletConstraintXNA : BulletConstraint return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); } + public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + // TODO: + return null; + } public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 3378c93..6cdc112 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -71,6 +71,7 @@ public enum BSPhysicsShapeType SHAPE_HEIGHTMAP = 23, SHAPE_AVATAR = 24, SHAPE_CONVEXHULL= 25, + SHAPE_GIMPACT = 26, }; // The native shapes have predefined shape hash keys @@ -321,6 +322,10 @@ public abstract BulletShape CreateMeshShape(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); +public abstract BulletShape CreateGImpactShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + public abstract BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index d33292f..9a9e527 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -89,6 +89,7 @@ public static class BSParam public static bool ShouldRemoveZeroWidthTriangles { get; private set; } public static bool ShouldUseBulletHACD { get; set; } public static bool ShouldUseSingleConvexHullForPrims { get; set; } + public static bool ShouldUseGImpactShapeForPrims { get; set; } public static float TerrainImplementation { get; set; } public static int TerrainMeshMagnification { get; private set; } @@ -369,6 +370,8 @@ public static class BSParam false ), new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", true ), + new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", + false ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5 ), diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 9ed2d06..39f5b0a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -328,6 +328,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters BSParam.ShouldUseBulletHACD = false; m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); BSParam.ShouldUseSingleConvexHullForPrims = false; + m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader); + BSParam.ShouldUseGImpactShapeForPrims = false; m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 64aaa15..32bbc8f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -230,6 +230,7 @@ public sealed class BSShapeCollection : IDisposable BSShape potentialHull = null; PrimitiveBaseShape pbs = prim.BaseShape; + // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) if (BSParam.ShouldUseSingleConvexHullForPrims && pbs != null && !pbs.SculptEntry @@ -238,7 +239,17 @@ public sealed class BSShapeCollection : IDisposable { potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); } - else + // Use the GImpact shape if it is a prim that has some concaveness + if (potentialHull == null + && BSParam.ShouldUseGImpactShapeForPrims + && pbs != null + && !pbs.SculptEntry + ) + { + potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); + } + // If not any of the simple cases, just make a hull + if (potentialHull == null) { potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); } @@ -261,7 +272,7 @@ public sealed class BSShapeCollection : IDisposable } else { - // Update prim.BSShape to reference a mesh of this shape. + // Non-physical objects should be just meshes. BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); // If the current shape is not what is on the prim at the moment, time to change. if (!prim.PhysShape.HasPhysicalShape diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 72d039b..0152233 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -422,9 +422,22 @@ public class BSShapeMesh : BSShape outMesh = foundDesc; return ret; } + + public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { + return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, + (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) ); + } + + // Code that uses the mesher to create the index/vertices info for a trimesh shape. + // This is used by the passed 'makeShape' call to create the Bullet mesh shape. + // The actual build call is passed so this logic can be used by several of the shapes that use a + // simple mesh as their base shape. + public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) + { BulletShape newShape = new BulletShape(); IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, @@ -482,8 +495,7 @@ public class BSShapeMesh : BSShape if (realIndicesIndex != 0) { - newShape = physicsScene.PE.CreateMeshShape(physicsScene.World, - realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); + newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); } else { @@ -803,6 +815,7 @@ public class BSShapeCompound : BSShape // Called at taint-time. private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) { + // TODO: figure a better way to go through all the shape types and find a possible instance. BSShapeMesh meshDesc; if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) { @@ -824,17 +837,25 @@ public class BSShapeCompound : BSShape } else { - if (physicsScene.PE.IsCompound(pShape)) + BSShapeGImpact gImpactDesc; + if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) { - BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); - recursiveCompound.Dereference(physicsScene); + gImpactDesc.Dereference(physicsScene); } else { - if (physicsScene.PE.IsNativeShape(pShape)) + if (physicsScene.PE.IsCompound(pShape)) + { + BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); + recursiveCompound.Dereference(physicsScene); + } + else { - BSShapeNative nativeShape = new BSShapeNative(pShape); - nativeShape.Dereference(physicsScene); + if (physicsScene.PE.IsNativeShape(pShape)) + { + BSShapeNative nativeShape = new BSShapeNative(pShape); + nativeShape.Dereference(physicsScene); + } } } } @@ -857,7 +878,7 @@ public class BSShapeConvexHull : BSShape float lod; System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}", + physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); BSShapeConvexHull retConvexHull = null; @@ -937,6 +958,97 @@ public class BSShapeConvexHull : BSShape return ret; } } +// ============================================================================================================ +public class BSShapeGImpact : BSShape +{ + private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; + public static Dictionary GImpacts = new Dictionary(); + + public BSShapeGImpact(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeGImpact retGImpact = null; + lock (GImpacts) + { + if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) + { + // The mesh has already been created. Return a new reference to same. + retGImpact.IncrementReference(); + } + else + { + retGImpact = new BSShapeGImpact(new BulletShape()); + BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + + // Check to see if mesh was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + { + // If a mesh was what was created, remember the built shape for later sharing. + // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. + GImpacts.Add(newMeshKey, retGImpact); + } + + retGImpact.physShapeInfo = newShape; + } + } + return retGImpact; + } + + private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, + (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) ); + } + + public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + { + // Calling this reference means we want another handle to an existing shape + // (usually linksets) so return this copy. + IncrementReference(); + return this; + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + lock (GImpacts) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) + { + bool ret = false; + BSShapeGImpact foundDesc = null; + lock (GImpacts) + { + foreach (BSShapeGImpact sh in GImpacts.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; + return ret; + } +} // ============================================================================================================ public class BSShapeAvatar : BSShape -- cgit v1.1 From 2fd8819a043269f9308cb46c71893e6eb35a426e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 21 May 2013 21:32:30 -0700 Subject: BulletSim: add code to experimentally use asset hull data. Default to 'off' as it needs debugging. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 ++ OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 55 ++++++++++++++++++++++-- prebuild.xml | 1 + 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 9a9e527..5cff668 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -90,6 +90,7 @@ public static class BSParam public static bool ShouldUseBulletHACD { get; set; } public static bool ShouldUseSingleConvexHullForPrims { get; set; } public static bool ShouldUseGImpactShapeForPrims { get; set; } + public static bool ShouldUseAssetHulls { get; set; } public static float TerrainImplementation { get; set; } public static int TerrainMeshMagnification { get; private set; } @@ -372,6 +373,8 @@ public static class BSParam true ), new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", false ), + new ParameterDefn("UseAssetHulls", "If true, use hull if specified in the mesh asset info", + false ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5 ), diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 0152233..b7f7e6c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -31,6 +31,7 @@ using System.Text; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Physics.Meshing; using OpenSim.Region.Physics.ConvexDecompositionDotNet; using OMV = OpenMetaverse; @@ -573,9 +574,56 @@ public class BSShapeHull : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = new BulletShape(); - IntPtr hullPtr = IntPtr.Zero; + newShape.shapeKey = newHullKey; - if (BSParam.ShouldUseBulletHACD) + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); + + // If there is hull data in the mesh asset, build the hull from that + if (meshData != null && BSParam.ShouldUseAssetHulls) + { + Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; + if (realMesher != null) + { + List> allHulls = realMesher.GetConvexHulls(size); + if (allHulls != null) + { + int hullCount = allHulls.Count; + int totalVertices = 1; // include one for the count of the hulls + // Using the structure described for HACD hulls, create the memory sturcture + // to pass the hull data to the creater. + foreach (List hullVerts in allHulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += hullVerts.Count * 3; // one vertex is three dimensions + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (List hullVerts in allHulls) + { + convHulls[jj + 0] = hullVerts.Count; + convHulls[jj + 1] = 0f; // centroid x,y,z + convHulls[jj + 2] = 0f; + convHulls[jj + 3] = 0f; + jj += 4; + foreach (OMV.Vector3 oneVert in hullVerts) + { + convHulls[jj + 0] = oneVert.X; + convHulls[jj + 1] = oneVert.Y; + convHulls[jj + 2] = oneVert.Z; + jj += 3; + } + } + + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + } + } + } + // If no hull specified in the asset and we should use Bullet's HACD approximation... + if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) { // Build the hull shape from an existing mesh shape. // The mesh should have already been created in Bullet. @@ -604,11 +652,10 @@ public class BSShapeHull : BSShape } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } + // If no hull specified, use our HACD hull approximation. if (!newShape.HasPhysicalShape) { // Build a new hull in the physical world using the C# HACD algorigthm. - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); if (meshData != null) { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) diff --git a/prebuild.xml b/prebuild.xml index 9fbe08b..f51e8f0 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1753,6 +1753,7 @@ + -- cgit v1.1 From 10097f13aa21356a08fcf60a4e36c4c6471167ef Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 21 May 2013 21:40:26 -0700 Subject: BulletSim: update DLLs and SOs with version containing gImpact code. --- bin/lib32/BulletSim.dll | Bin 1010176 -> 982528 bytes bin/lib32/libBulletSim.so | Bin 2096576 -> 2271520 bytes bin/lib64/BulletSim.dll | Bin 1142272 -> 1222656 bytes bin/lib64/libBulletSim.so | Bin 2265980 -> 2454504 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 1e94d05..d63ee1d 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 6216a65..03de631 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 68cfcc4..e155f0e 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 08c00af..ac64a40 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From 6596a1de806d1ec509f3a570a0944ab9aff5947c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 21 May 2013 22:16:18 -0700 Subject: Revert "BulletSim: add code to experimentally use asset hull data." This reverts commit 2fd8819a043269f9308cb46c71893e6eb35a426e. Remove this code until I can figure out why the references that are clearly in prebuild.xml doesn't work for the 'using OpenSim.Region.Physics.Meshing' in BSShape.cs. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 -- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 55 ++---------------------- prebuild.xml | 1 - 3 files changed, 4 insertions(+), 55 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 5cff668..9a9e527 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -90,7 +90,6 @@ public static class BSParam public static bool ShouldUseBulletHACD { get; set; } public static bool ShouldUseSingleConvexHullForPrims { get; set; } public static bool ShouldUseGImpactShapeForPrims { get; set; } - public static bool ShouldUseAssetHulls { get; set; } public static float TerrainImplementation { get; set; } public static int TerrainMeshMagnification { get; private set; } @@ -373,8 +372,6 @@ public static class BSParam true ), new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", false ), - new ParameterDefn("UseAssetHulls", "If true, use hull if specified in the mesh asset info", - false ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5 ), diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index b7f7e6c..0152233 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -31,7 +31,6 @@ using System.Text; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; -using OpenSim.Region.Physics.Meshing; using OpenSim.Region.Physics.ConvexDecompositionDotNet; using OMV = OpenMetaverse; @@ -574,56 +573,9 @@ public class BSShapeHull : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = new BulletShape(); - newShape.shapeKey = newHullKey; + IntPtr hullPtr = IntPtr.Zero; - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); - - // If there is hull data in the mesh asset, build the hull from that - if (meshData != null && BSParam.ShouldUseAssetHulls) - { - Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; - if (realMesher != null) - { - List> allHulls = realMesher.GetConvexHulls(size); - if (allHulls != null) - { - int hullCount = allHulls.Count; - int totalVertices = 1; // include one for the count of the hulls - // Using the structure described for HACD hulls, create the memory sturcture - // to pass the hull data to the creater. - foreach (List hullVerts in allHulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += hullVerts.Count * 3; // one vertex is three dimensions - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (List hullVerts in allHulls) - { - convHulls[jj + 0] = hullVerts.Count; - convHulls[jj + 1] = 0f; // centroid x,y,z - convHulls[jj + 2] = 0f; - convHulls[jj + 3] = 0f; - jj += 4; - foreach (OMV.Vector3 oneVert in hullVerts) - { - convHulls[jj + 0] = oneVert.X; - convHulls[jj + 1] = oneVert.Y; - convHulls[jj + 2] = oneVert.Z; - jj += 3; - } - } - - // create the hull data structure in Bullet - newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); - } - } - } - // If no hull specified in the asset and we should use Bullet's HACD approximation... - if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) + if (BSParam.ShouldUseBulletHACD) { // Build the hull shape from an existing mesh shape. // The mesh should have already been created in Bullet. @@ -652,10 +604,11 @@ public class BSShapeHull : BSShape } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } - // If no hull specified, use our HACD hull approximation. if (!newShape.HasPhysicalShape) { // Build a new hull in the physical world using the C# HACD algorigthm. + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); if (meshData != null) { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) diff --git a/prebuild.xml b/prebuild.xml index f51e8f0..9fbe08b 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1753,7 +1753,6 @@ - -- cgit v1.1 From 7d38f4940c39b217bcf6b90b7811933099916de9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 22 May 2013 20:01:57 +0100 Subject: Implement llSetSoundQueueing(). This is controlled by the viewer, not the server. So as per http://wiki.secondlife.com/wiki/LlSetSoundQueueing, only two sounds can be queued per prim. You probably need to use llPreloadSound() for best results --- OpenSim/Region/CoreModules/World/Sound/SoundModule.cs | 9 +++++++++ OpenSim/Region/Framework/Interfaces/ISoundModule.cs | 8 +++++++- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 10 +++++++++- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 12 ++++++++---- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 883045a..d093224 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs @@ -369,6 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Sound }); } + public void SetSoundQueueing(UUID objectID, bool shouldQueue) + { + SceneObjectPart part; + if (!m_scene.TryGetSceneObjectPart(objectID, out part)) + return; + + part.SoundQueueing = shouldQueue; + } + #endregion } } diff --git a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs index 68af492..8372ddd 100644 --- a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs @@ -104,7 +104,6 @@ namespace OpenSim.Region.Framework.Interfaces /// Sound asset ID /// Sound volume /// Triggered or not. - /// /// Sound radius /// Play using sound master /// Play as sound master @@ -123,5 +122,12 @@ namespace OpenSim.Region.Framework.Interfaces /// AABB top north-east corner void TriggerSoundLimited(UUID objectID, UUID sound, double volume, Vector3 min, Vector3 max); + + /// + /// Set whether sounds on the given prim should be queued. + /// + /// + /// + void SetSoundQueueing(UUID objectID, bool shouldQueue); } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 347a2b5..b1c1cbb 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -219,6 +219,14 @@ namespace OpenSim.Region.Framework.Scenes public double SoundRadius; + /// + /// Should sounds played from this prim be queued? + /// + /// + /// This should only be changed by sound modules. It is up to sound modules as to how they interpret this setting. + /// + public bool SoundQueueing { get; set; } + public uint TimeStampFull; public uint TimeStampLastActivity; // Will be used for AutoReturn @@ -2429,7 +2437,7 @@ namespace OpenSim.Region.Framework.Scenes if (soundModule != null) { soundModule.SendSound(UUID, CollisionSound, - CollisionSoundVolume, true, (byte)0, 0, false, + CollisionSoundVolume, true, 0, 0, false, false); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 969243c..0b4b043 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2474,9 +2474,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // send the sound, once, to all clients in range if (m_SoundModule != null) { - m_SoundModule.SendSound(m_host.UUID, - ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0, - 0, false, false); + m_SoundModule.SendSound( + m_host.UUID, + ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), + volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None, + 0, false, false); } } @@ -11822,7 +11824,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llSetSoundQueueing(int queue) { m_host.AddScriptLPS(1); - NotImplemented("llSetSoundQueueing"); + + if (m_SoundModule != null) + m_SoundModule.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value); } public void llCollisionSprite(string impact_sprite) -- cgit v1.1 From 61cdf9390d8dc124b0ef3afabb5bcb63328686eb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 22 May 2013 16:06:06 -0700 Subject: BulletSim: fix problem with walking up stairs that are oriented in certain directions. The problem was really that the avatar capsule orientation was being set incorrectly. --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index ff5b6ab..48f842e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -483,8 +483,15 @@ public sealed class BSCharacter : BSPhysObject { // Bullet assumes we know what we are doing when forcing orientation // so it lets us go against all the rules and just compensates for them later. - // This keeps us from flipping the capsule over which the veiwer does not understand. - ForceOrientation = new OMV.Quaternion(0, 0, _orientation.Z,0); + // This forces rotation to be only around the Z axis and doesn't change any of the other axis. + // This keeps us from flipping the capsule over which the veiwer does not understand. + float oRoll, oPitch, oYaw; + _orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); + OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); + // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", + // LocalID, _orientation, OMV.Vector3.UnitX * _orientation, + // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); + ForceOrientation = trimmedOrientation; }); } } -- cgit v1.1 From ffc9b3dda766c15e053b9296d15356533f7e99f8 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 21 May 2013 21:32:30 -0700 Subject: BulletSim: add code to experimentally use asset hull data. Default to 'off' as it needs debugging. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 ++ OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 55 ++++++++++++++++++++++-- prebuild.xml | 1 + 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 9a9e527..5cff668 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -90,6 +90,7 @@ public static class BSParam public static bool ShouldUseBulletHACD { get; set; } public static bool ShouldUseSingleConvexHullForPrims { get; set; } public static bool ShouldUseGImpactShapeForPrims { get; set; } + public static bool ShouldUseAssetHulls { get; set; } public static float TerrainImplementation { get; set; } public static int TerrainMeshMagnification { get; private set; } @@ -372,6 +373,8 @@ public static class BSParam true ), new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", false ), + new ParameterDefn("UseAssetHulls", "If true, use hull if specified in the mesh asset info", + false ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5 ), diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 0152233..b7f7e6c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -31,6 +31,7 @@ using System.Text; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Physics.Meshing; using OpenSim.Region.Physics.ConvexDecompositionDotNet; using OMV = OpenMetaverse; @@ -573,9 +574,56 @@ public class BSShapeHull : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = new BulletShape(); - IntPtr hullPtr = IntPtr.Zero; + newShape.shapeKey = newHullKey; - if (BSParam.ShouldUseBulletHACD) + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); + + // If there is hull data in the mesh asset, build the hull from that + if (meshData != null && BSParam.ShouldUseAssetHulls) + { + Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; + if (realMesher != null) + { + List> allHulls = realMesher.GetConvexHulls(size); + if (allHulls != null) + { + int hullCount = allHulls.Count; + int totalVertices = 1; // include one for the count of the hulls + // Using the structure described for HACD hulls, create the memory sturcture + // to pass the hull data to the creater. + foreach (List hullVerts in allHulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += hullVerts.Count * 3; // one vertex is three dimensions + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (List hullVerts in allHulls) + { + convHulls[jj + 0] = hullVerts.Count; + convHulls[jj + 1] = 0f; // centroid x,y,z + convHulls[jj + 2] = 0f; + convHulls[jj + 3] = 0f; + jj += 4; + foreach (OMV.Vector3 oneVert in hullVerts) + { + convHulls[jj + 0] = oneVert.X; + convHulls[jj + 1] = oneVert.Y; + convHulls[jj + 2] = oneVert.Z; + jj += 3; + } + } + + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + } + } + } + // If no hull specified in the asset and we should use Bullet's HACD approximation... + if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) { // Build the hull shape from an existing mesh shape. // The mesh should have already been created in Bullet. @@ -604,11 +652,10 @@ public class BSShapeHull : BSShape } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } + // If no hull specified, use our HACD hull approximation. if (!newShape.HasPhysicalShape) { // Build a new hull in the physical world using the C# HACD algorigthm. - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); if (meshData != null) { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) diff --git a/prebuild.xml b/prebuild.xml index 9fbe08b..f51e8f0 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1753,6 +1753,7 @@ + -- cgit v1.1 From f4905220821671f91cb830e9932a0b9ed5d3da49 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 22 May 2013 21:09:37 -0700 Subject: BulletSim: specify directory for OpenSim.Region.Physics.Meshing DLL file in prebuild.xml since that file ends up in bin/Physics directory. --- prebuild.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prebuild.xml b/prebuild.xml index f51e8f0..25c287e 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1753,7 +1753,7 @@ - + -- cgit v1.1 From 5efce21abc92fa1005fa8651a5622fe72cf83ff3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 22 May 2013 21:57:07 -0700 Subject: BulletSim: correct errors caused by misspelled INI parameter spec. Add debugging messages for hull asset use. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 5cff668..c19eda1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -373,7 +373,7 @@ public static class BSParam true ), new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", false ), - new ParameterDefn("UseAssetHulls", "If true, use hull if specified in the mesh asset info", + new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", false ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index b7f7e6c..6729d6b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -619,6 +619,9 @@ public class BSShapeHull : BSShape // create the hull data structure in Bullet newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", + prim.LocalID, hullCount, totalVertices, newShape); } } } @@ -627,7 +630,7 @@ public class BSShapeHull : BSShape { // Build the hull shape from an existing mesh shape. // The mesh should have already been created in Bullet. - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); if (meshShape.physShapeInfo.HasPhysicalShape) @@ -645,12 +648,12 @@ public class BSShapeHull : BSShape physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); // Now done with the mesh shape. meshShape.Dereference(physicsScene); } - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } // If no hull specified, use our HACD hull approximation. if (!newShape.HasPhysicalShape) -- cgit v1.1 From 29b3b44fab46a44f911e582ab284025086cf3692 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 23 May 2013 14:40:16 -0700 Subject: BulletSim: add locking around Meshmerizer use to eliminate possible race condition when extracting the convex hulls. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 302 ++++++++++++----------- 1 file changed, 157 insertions(+), 145 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 6729d6b..48f1394 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -441,10 +441,14 @@ public class BSShapeMesh : BSShape { BulletShape newShape = new BulletShape(); - IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, - false, // say it is not physical so a bounding box is not built - false // do not cache the mesh and do not use previously built versions - ); + IMesh meshData = null; + lock (physicsScene.mesher) + { + meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, + false, // say it is not physical so a bounding box is not built + false // do not cache the mesh and do not use previously built versions + ); + } if (meshData != null) { @@ -576,55 +580,67 @@ public class BSShapeHull : BSShape BulletShape newShape = new BulletShape(); newShape.shapeKey = newHullKey; - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); - - // If there is hull data in the mesh asset, build the hull from that - if (meshData != null && BSParam.ShouldUseAssetHulls) + IMesh meshData = null; + List> allHulls = null; + lock (physicsScene.mesher) { - Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; - if (realMesher != null) + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); + + // If we should use the asset's hull info, fetch it out of the locked mesher + if (meshData != null && BSParam.ShouldUseAssetHulls) { - List> allHulls = realMesher.GetConvexHulls(size); - if (allHulls != null) + Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; + if (realMesher != null) { - int hullCount = allHulls.Count; - int totalVertices = 1; // include one for the count of the hulls - // Using the structure described for HACD hulls, create the memory sturcture - // to pass the hull data to the creater. - foreach (List hullVerts in allHulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += hullVerts.Count * 3; // one vertex is three dimensions - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (List hullVerts in allHulls) - { - convHulls[jj + 0] = hullVerts.Count; - convHulls[jj + 1] = 0f; // centroid x,y,z - convHulls[jj + 2] = 0f; - convHulls[jj + 3] = 0f; - jj += 4; - foreach (OMV.Vector3 oneVert in hullVerts) - { - convHulls[jj + 0] = oneVert.X; - convHulls[jj + 1] = oneVert.Y; - convHulls[jj + 2] = oneVert.Z; - jj += 3; - } - } + allHulls = realMesher.GetConvexHulls(size); + } + if (allHulls == null) + { + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); + } + } + } - // create the hull data structure in Bullet - newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + // If there is hull data in the mesh asset, build the hull from that + if (allHulls != null && BSParam.ShouldUseAssetHulls) + { + int hullCount = allHulls.Count; + int totalVertices = 1; // include one for the count of the hulls + // Using the structure described for HACD hulls, create the memory sturcture + // to pass the hull data to the creater. + foreach (List hullVerts in allHulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += hullVerts.Count * 3; // one vertex is three dimensions + } + float[] convHulls = new float[totalVertices]; - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", - prim.LocalID, hullCount, totalVertices, newShape); + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (List hullVerts in allHulls) + { + convHulls[jj + 0] = hullVerts.Count; + convHulls[jj + 1] = 0f; // centroid x,y,z + convHulls[jj + 2] = 0f; + convHulls[jj + 3] = 0f; + jj += 4; + foreach (OMV.Vector3 oneVert in hullVerts) + { + convHulls[jj + 0] = oneVert.X; + convHulls[jj + 1] = oneVert.Y; + convHulls[jj + 2] = oneVert.Z; + jj += 3; } } + + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", + prim.LocalID, hullCount, totalVertices, newShape); } + // If no hull specified in the asset and we should use Bullet's HACD approximation... if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) { @@ -655,120 +671,116 @@ public class BSShapeHull : BSShape } physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); } - // If no hull specified, use our HACD hull approximation. - if (!newShape.HasPhysicalShape) + + // If no other hull specifications, use our HACD hull approximation. + if (!newShape.HasPhysicalShape && meshData != null) { - // Build a new hull in the physical world using the C# HACD algorigthm. - if (meshData != null) + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) - { - // Release the fetched asset data once it has been used. - pbs.SculptData = new byte[0]; - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; - } + // Release the fetched asset data once it has been used. + pbs.SculptData = new byte[0]; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); + int[] indices = meshData.getIndexListAsInt(); + List vertices = meshData.getVertexList(); - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) - { - convIndices.Add(indices[ii]); - } - foreach (OMV.Vector3 vv in vertices) - { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); - } + //format conversion from IMesh format to DecompDesc format + List convIndices = new List(); + List convVertices = new List(); + for (int ii = 0; ii < indices.GetLength(0); ii++) + { + convIndices.Add(indices[ii]); + } + foreach (OMV.Vector3 vv in vertices) + { + convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + } - uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; - if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; + if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + { + // Simple primitive shapes we know are convex so they are better implemented with + // fewer hulls. + // Check for simple shape (prim without cuts) and reduce split parameter if so. + if (BSShapeCollection.PrimHasNoCuts(pbs)) { - // Simple primitive shapes we know are convex so they are better implemented with - // fewer hulls. - // Check for simple shape (prim without cuts) and reduce split parameter if so. - if (BSShapeCollection.PrimHasNoCuts(pbs)) - { - maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; - } + maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; } + } + + // setup and do convex hull conversion + m_hulls = new List(); + DecompDesc dcomp = new DecompDesc(); + dcomp.mIndices = convIndices; + dcomp.mVertices = convVertices; + dcomp.mDepth = maxDepthSplit; + dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; + dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; + dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; + dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; + ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); + // create the hull into the _hulls variable + convexBuilder.process(dcomp); + + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", + BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); + + // Convert the vertices and indices for passing to unmanaged. + // The hull information is passed as a large floating point array. + // The format is: + // convHulls[0] = number of hulls + // convHulls[1] = number of vertices in first hull + // convHulls[2] = hull centroid X coordinate + // convHulls[3] = hull centroid Y coordinate + // convHulls[4] = hull centroid Z coordinate + // convHulls[5] = first hull vertex X + // convHulls[6] = first hull vertex Y + // convHulls[7] = first hull vertex Z + // convHulls[8] = second hull vertex X + // ... + // convHulls[n] = number of vertices in second hull + // convHulls[n+1] = second hull centroid X coordinate + // ... + // + // TODO: is is very inefficient. Someday change the convex hull generator to return + // data structures that do not need to be converted in order to pass to Bullet. + // And maybe put the values directly into pinned memory rather than marshaling. + int hullCount = m_hulls.Count; + int totalVertices = 1; // include one for the count of the hulls + foreach (ConvexResult cr in m_hulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + } + float[] convHulls = new float[totalVertices]; - // setup and do convex hull conversion - m_hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - dcomp.mDepth = maxDepthSplit; - dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; - dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; - dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; - dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", - BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); - - // Convert the vertices and indices for passing to unmanaged. - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = m_hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in m_hulls) + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (ConvexResult cr in m_hulls) + { + // copy vertices for index access + float3[] verts = new float3[cr.HullVertices.Count]; + int kk = 0; + foreach (float3 ff in cr.HullVertices) { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + verts[kk++] = ff; } - float[] convHulls = new float[totalVertices]; - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in m_hulls) + // add to the array one hull's worth of data + convHulls[jj++] = cr.HullIndices.Count; + convHulls[jj++] = 0f; // centroid x,y,z + convHulls[jj++] = 0f; + convHulls[jj++] = 0f; + foreach (int ind in cr.HullIndices) { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) - { - verts[kk++] = ff; - } - - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) - { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; - } + convHulls[jj++] = verts[ind].x; + convHulls[jj++] = verts[ind].y; + convHulls[jj++] = verts[ind].z; } - // create the hull data structure in Bullet - newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); } - newShape.shapeKey = newHullKey; + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); } return newShape; } -- cgit v1.1 From 0e002e369339719204f26c07157713bfc40fecca Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 23 May 2013 14:41:05 -0700 Subject: Add DEBUG level logging in Meshmerizer for mesh parsing. There is a compile time variable to turn this logging off if it is too spammy. --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 79edc12..adc0dc9 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -64,6 +64,7 @@ namespace OpenSim.Region.Physics.Meshing public class Meshmerizer : IMesher { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static string LogHeader = "[MESH]"; // Setting baseDir to a path will enable the dumping of raw files // raw files can be imported by blender so a visual inspection of the results can be done @@ -72,6 +73,8 @@ namespace OpenSim.Region.Physics.Meshing #else private const string baseDir = null; //"rawFiles"; #endif + // If 'true', lots of DEBUG logging of asset parsing details + private bool debugDetail = true; private bool cacheSculptMaps = true; private string decodedSculptMapPath = null; @@ -357,13 +360,25 @@ namespace OpenSim.Region.Physics.Meshing OSDMap physicsParms = null; OSDMap map = (OSDMap)meshOsd; if (map.ContainsKey("physics_shape")) + { physicsParms = (OSDMap)map["physics_shape"]; // old asset format + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName); + } else if (map.ContainsKey("physics_mesh")) + { physicsParms = (OSDMap)map["physics_mesh"]; // new asset format + if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName); + } else if (map.ContainsKey("medium_lod")) + { physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh + if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName); + } else if (map.ContainsKey("high_lod")) + { physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) + if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName); + } if (map.ContainsKey("physics_convex")) { // pull this out also in case physics engine can use it @@ -408,11 +423,16 @@ namespace OpenSim.Region.Physics.Meshing } mConvexHulls = hulls; + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count); + } + else + { + if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName); } } catch (Exception e) { - m_log.WarnFormat("[MESH]: exception decoding convex block: {0}", e.Message); + m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e); } } @@ -438,7 +458,7 @@ namespace OpenSim.Region.Physics.Meshing } catch (Exception e) { - m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); + m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e); return false; } @@ -455,6 +475,9 @@ namespace OpenSim.Region.Physics.Meshing if (subMeshOsd is OSDMap) AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); } + if (debugDetail) + m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}", + LogHeader, primName, physOffset, physSize, coords.Count, faces.Count); } } -- cgit v1.1 From 28548ab347487b1ed4e6cf50af30a6eacf963f7d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 23 May 2013 23:05:56 +0100 Subject: Fix bug where both ordinary UserManagementModule and HGUserManagementModules were being added to scenes if no UserManagementModule was specified. Without explicit config non-hg UMM is used - this is in common with other HG modules. This was causing a non-HG module to unpredictably use the UMM or HGUMM, though lack of bug reports suggest either UMM was always used or it didn't matter in this case. --- .../CoreModules/Framework/UserManagement/HGUserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index fac93e6..ad3cf15 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs @@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public new void Initialise(IConfigSource config) { - string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name); + string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null); if (umanmod == Name) { m_Enabled = true; -- cgit v1.1 From c5549d27306c71cd5ed96e7cba68bd28d5e6d9b0 Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 23 May 2013 15:47:47 -0700 Subject: add decoder for bounding convex hull --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 57 +++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index adc0dc9..fd45efe 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -83,6 +83,7 @@ namespace OpenSim.Region.Physics.Meshing private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh private List> mConvexHulls = null; + private List mBoundingHull = null; private Dictionary m_uniqueMeshes = new Dictionary(); @@ -324,6 +325,9 @@ namespace OpenSim.Region.Physics.Meshing faces = new List(); OSD meshOsd = null; + mConvexHulls = null; + mBoundingHull = null; + if (primShape.SculptData.Length <= 0) { // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this @@ -385,13 +389,41 @@ namespace OpenSim.Region.Physics.Meshing try { OSDMap convexBlock = (OSDMap)map["physics_convex"]; + + Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); + if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); + Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); + if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); + + List boundingHull = null; + + if (convexBlock.ContainsKey("BoundingVerts")) + { + // decompress and decode bounding hull points + byte[] boundingVertsBytes = DecompressOsd(convexBlock["BoundingVerts"].AsBinary()).AsBinary(); + boundingHull = new List(); + for (int i = 0; i < boundingVertsBytes.Length;) + { + ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + + Vector3 pos = new Vector3( + Utils.UInt16ToFloat(uX, min.X, max.X), + Utils.UInt16ToFloat(uY, min.Y, max.Y), + Utils.UInt16ToFloat(uZ, min.Z, max.Z) + ); + + boundingHull.Add(pos); + } + + mBoundingHull = boundingHull; + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nHulls={2}", LogHeader, primName, mBoundingHull.Count); + } + if (convexBlock.ContainsKey("HullList")) { byte[] hullList = convexBlock["HullList"].AsBinary(); - Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); - if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); - Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); - if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); // decompress and decode hull points byte[] posBytes = DecompressOsd(convexBlock["Positions"].AsBinary()).AsBinary(); @@ -799,6 +831,23 @@ namespace OpenSim.Region.Physics.Meshing /// temporary prototype code - please do not use until the interface has been finalized! /// /// value to scale the hull points by + /// a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null + public List GetBoundingHull(Vector3 size) + { + if (mBoundingHull == null) + return null; + + List verts = new List(); + foreach (var vert in mBoundingHull) + verts.Add(vert * size); + + return verts; + } + + /// + /// temporary prototype code - please do not use until the interface has been finalized! + /// + /// value to scale the hull points by /// a list of hulls if they exist and have been successfully decoded, otherwise null public List> GetConvexHulls(Vector3 size) { -- cgit v1.1 From 9b56f993261954fe9918bd0c9205a41e058183a1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 23 May 2013 23:52:07 +0100 Subject: Fix bug where a cloned object would report the wrong llGetNumberOfPrims() when avatars had been sitting on the original and a different avatar sat on the copy within the same opensim session. This was because the sitting avatars list was being cloned rather than reset. Addresses http://opensimulator.org/mantis/view.php?id=6649 --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 38fa26a..2d4218d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1500,6 +1500,7 @@ namespace OpenSim.Region.Framework.Scenes dupe.IsAttachment = true; dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); + dupe.m_sittingAvatars = new List(); if (!userExposed) { -- cgit v1.1 From 02fe05f346f3c4acad0116e702ed197a52b3fb4d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 24 May 2013 00:41:47 +0100 Subject: Fix issue where llSetPayPrice on either one of a clone prim in the same OpenSimulator session would change the prices on both prims. This is because the PayPrice array refernence was being memberwise cloned and not the array itself. Addresses http://opensimulator.org/mantis/view.php?id=6639 --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index b1c1cbb..ea8c3c5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1799,6 +1799,8 @@ namespace OpenSim.Region.Framework.Scenes Array.Copy(Shape.ExtraParams, extraP, extraP.Length); dupe.Shape.ExtraParams = extraP; + dupe.PayPrice = (int[])PayPrice.Clone(); + dupe.DynAttrs.CopyFrom(DynAttrs); if (userExposed) -- cgit v1.1 From eb2bd9d203dbc9d202ae62594fcbdb53d38031ac Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 24 May 2013 00:46:58 +0100 Subject: minor: Remove unnecessary duplication of AbsolutePosition Vector3 in SOG.Copy() As a struct, Vector3 has already been cloned by MemberwiseClone() --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 2d4218d..df23cc5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1499,7 +1499,6 @@ namespace OpenSim.Region.Framework.Scenes if (!userExposed) dupe.IsAttachment = true; - dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); dupe.m_sittingAvatars = new List(); if (!userExposed) -- cgit v1.1 From 0cdea5c2f302ece2d37357b7e7b8c1d3f6ed8f94 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 24 May 2013 01:53:37 -0700 Subject: correct some errors in decoding of mesh asset convex decomposition data --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 136 ++++++++++++++++---------- 1 file changed, 83 insertions(+), 53 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index fd45efe..3e2b663 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -386,61 +386,57 @@ namespace OpenSim.Region.Physics.Meshing if (map.ContainsKey("physics_convex")) { // pull this out also in case physics engine can use it + OSD convexBlockOsd = null; try { OSDMap convexBlock = (OSDMap)map["physics_convex"]; - - Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); - if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); - Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); - if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); - - List boundingHull = null; - - if (convexBlock.ContainsKey("BoundingVerts")) { - // decompress and decode bounding hull points - byte[] boundingVertsBytes = DecompressOsd(convexBlock["BoundingVerts"].AsBinary()).AsBinary(); - boundingHull = new List(); - for (int i = 0; i < boundingVertsBytes.Length;) - { - ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; - ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; - ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; - - Vector3 pos = new Vector3( - Utils.UInt16ToFloat(uX, min.X, max.X), - Utils.UInt16ToFloat(uY, min.Y, max.Y), - Utils.UInt16ToFloat(uZ, min.Z, max.Z) - ); + int convexOffset = convexBlock["offset"].AsInteger() + (int)start; + int convexSize = convexBlock["size"].AsInteger(); - boundingHull.Add(pos); + byte[] convexBytes = new byte[convexSize]; + + System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize); + + try + { + convexBlockOsd = DecompressOsd(convexBytes); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e); + //return false; } - - mBoundingHull = boundingHull; - if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nHulls={2}", LogHeader, primName, mBoundingHull.Count); } - - if (convexBlock.ContainsKey("HullList")) + + if (convexBlockOsd != null && convexBlockOsd is OSDMap) { - byte[] hullList = convexBlock["HullList"].AsBinary(); + convexBlock = convexBlockOsd as OSDMap; - // decompress and decode hull points - byte[] posBytes = DecompressOsd(convexBlock["Positions"].AsBinary()).AsBinary(); - - List> hulls = new List>(); - int posNdx = 0; + if (debugDetail) + { + string keys = "[MESH]: keys found in convexBlock: "; + foreach (KeyValuePair kvp in convexBlock) + keys += "'" + kvp.Key + "' "; + m_log.Info(keys); + } + + Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); + if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); + Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); + if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); + + List boundingHull = null; - foreach (byte cnt in hullList) + if (convexBlock.ContainsKey("BoundingVerts")) { - int count = cnt == 0 ? 256 : cnt; - List hull = new List(); - - for (int i = 0; i < count; i++) + byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary(); + boundingHull = new List(); + for (int i = 0; i < boundingVertsBytes.Length; ) { - ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; - ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; - ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; + ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; Vector3 pos = new Vector3( Utils.UInt16ToFloat(uX, min.X, max.X), @@ -448,18 +444,52 @@ namespace OpenSim.Region.Physics.Meshing Utils.UInt16ToFloat(uZ, min.Z, max.Z) ); - hull.Add(pos); + boundingHull.Add(pos); } - hulls.Add(hull); + mBoundingHull = boundingHull; + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count); } - mConvexHulls = hulls; - if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count); - } - else - { - if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName); + if (convexBlock.ContainsKey("HullList")) + { + byte[] hullList = convexBlock["HullList"].AsBinary(); + + byte[] posBytes = convexBlock["Positions"].AsBinary(); + + List> hulls = new List>(); + int posNdx = 0; + + foreach (byte cnt in hullList) + { + int count = cnt == 0 ? 256 : cnt; + List hull = new List(); + + for (int i = 0; i < count; i++) + { + ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; + + Vector3 pos = new Vector3( + Utils.UInt16ToFloat(uX, min.X, max.X), + Utils.UInt16ToFloat(uY, min.Y, max.Y), + Utils.UInt16ToFloat(uZ, min.Z, max.Z) + ); + + hull.Add(pos); + } + + hulls.Add(hull); + } + + mConvexHulls = hulls; + if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count); + } + else + { + if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName); + } } } catch (Exception e) @@ -483,7 +513,7 @@ namespace OpenSim.Region.Physics.Meshing OSD decodedMeshOsd = new OSD(); byte[] meshBytes = new byte[physSize]; System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); -// byte[] decompressed = new byte[physSize * 5]; + // byte[] decompressed = new byte[physSize * 5]; try { decodedMeshOsd = DecompressOsd(meshBytes); @@ -499,7 +529,7 @@ namespace OpenSim.Region.Physics.Meshing // physics_shape is an array of OSDMaps, one for each submesh if (decodedMeshOsd is OSDArray) { -// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); + // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); decodedMeshOsdArray = (OSDArray)decodedMeshOsd; foreach (OSD subMeshOsd in decodedMeshOsdArray) -- cgit v1.1 From 440905ad14d4261df9da0fd2ce7e20a350982af1 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 24 May 2013 10:31:14 -0700 Subject: change a hull debugging message to Debug instead of Info --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 3e2b663..2c10568 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -418,7 +418,7 @@ namespace OpenSim.Region.Physics.Meshing string keys = "[MESH]: keys found in convexBlock: "; foreach (KeyValuePair kvp in convexBlock) keys += "'" + kvp.Key + "' "; - m_log.Info(keys); + m_log.Debug(keys); } Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); -- cgit v1.1 From 681fbda4b6b9700421b82dc639f954c60871542e Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 24 May 2013 13:18:16 -0700 Subject: This is an experimental patch that adds support for comparing texture hashes for the purpose of accurately responding to AgentTextureCached packets. There is a change to IClientAPI to report the wearbles hashes that come in through the SetAppearance packet. Added storage of the texture hashes in the appearance. While these are added to the Pack/Unpack (with support for missing values) routines (which means Simian will store them properly), they are not currently persisted in Robust. --- OpenSim/Framework/AvatarAppearance.cs | 98 +++++++++++++------- OpenSim/Framework/IClientAPI.cs | 2 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 27 +++++- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 102 ++++++++++++--------- .../Server/IRCClientView.cs | 2 +- 5 files changed, 147 insertions(+), 84 deletions(-) diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 494ae5e..157feb5 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -53,6 +53,7 @@ namespace OpenSim.Framework protected AvatarWearable[] m_wearables; protected Dictionary> m_attachments; protected float m_avatarHeight = 0; + protected UUID[] m_texturehashes; public virtual int Serial { @@ -98,6 +99,8 @@ namespace OpenSim.Framework SetDefaultParams(); SetHeight(); m_attachments = new Dictionary>(); + + ResetTextureHashes(); } public AvatarAppearance(OSDMap map) @@ -108,32 +111,6 @@ namespace OpenSim.Framework SetHeight(); } - public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams) - { -// m_log.WarnFormat("[AVATAR APPEARANCE] create initialized appearance"); - - m_serial = 0; - - if (wearables != null) - m_wearables = wearables; - else - SetDefaultWearables(); - - if (textureEntry != null) - m_texture = textureEntry; - else - SetDefaultTexture(); - - if (visualParams != null) - m_visualparams = visualParams; - else - SetDefaultParams(); - - SetHeight(); - - m_attachments = new Dictionary>(); - } - public AvatarAppearance(AvatarAppearance appearance) : this(appearance, true) { } @@ -151,6 +128,8 @@ namespace OpenSim.Framework SetHeight(); m_attachments = new Dictionary>(); + ResetTextureHashes(); + return; } @@ -166,6 +145,10 @@ namespace OpenSim.Framework SetWearable(i,appearance.Wearables[i]); } + m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT]; + for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) + m_texturehashes[i] = new UUID(appearance.m_texturehashes[i]); + m_texture = null; if (appearance.Texture != null) { @@ -200,6 +183,37 @@ namespace OpenSim.Framework } } + public void ResetTextureHashes() + { + m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT]; + for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) + m_texturehashes[i] = UUID.Zero; + } + + public UUID GetTextureHash(int textureIndex) + { + return m_texturehashes[NormalizeBakedTextureIndex(textureIndex)]; + } + + public void SetTextureHash(int textureIndex, UUID textureHash) + { + m_texturehashes[NormalizeBakedTextureIndex(textureIndex)] = new UUID(textureHash); + } + + /// + /// Normalizes the texture index to the actual bake index, this is done to + /// accommodate older viewers that send the BAKE_INDICES index rather than + /// the actual texture index + /// + private int NormalizeBakedTextureIndex(int textureIndex) + { + // Earlier viewer send the index into the baked index array, just trying to be careful here + if (textureIndex < BAKE_INDICES.Length) + return BAKE_INDICES[textureIndex]; + + return textureIndex; + } + public void ClearWearables() { m_wearables = new AvatarWearable[AvatarWearable.MAX_WEARABLES]; @@ -223,12 +237,7 @@ namespace OpenSim.Framework 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; - // } + ResetTextureHashes(); } protected virtual void SetDefaultParams() @@ -598,6 +607,12 @@ namespace OpenSim.Framework data["serial"] = OSD.FromInteger(m_serial); data["height"] = OSD.FromReal(m_avatarHeight); + // Hashes + OSDArray hashes = new OSDArray(AvatarAppearance.TEXTURE_COUNT); + for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) + hashes.Add(OSD.FromUUID(m_texturehashes[i])); + data["hashes"] = hashes; + // Wearables OSDArray wears = new OSDArray(AvatarWearable.MAX_WEARABLES); for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) @@ -642,6 +657,25 @@ namespace OpenSim.Framework try { + // Hashes + m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT]; + if ((data != null) && (data["hashes"] != null) && (data["hashes"]).Type == OSDType.Array) + { + OSDArray hashes = (OSDArray)(data["hashes"]); + for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) + { + UUID hashID = UUID.Zero; + if (i < hashes.Count && hashes[i] != null) + hashID = hashes[i].AsUUID(); + m_texturehashes[i] = hashID; + } + } + else + { + for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) + m_texturehashes[i] = UUID.Zero; + } + // Wearables SetDefaultWearables(); if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 59ce2c4..1fffeff 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -66,7 +66,7 @@ namespace OpenSim.Framework public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List cachedTextureRequest); - public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams); + public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, List cachedTextureData); public delegate void StartAnim(IClientAPI remoteClient, UUID animID); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index e014471..dd8ef9c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -6214,7 +6214,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (appear.ObjectData.TextureEntry.Length > 1) te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length); - handlerSetAppearance(sender, te, visualparams); + List hashes = new List(); + for (int i = 0; i < appear.WearableData.Length; i++) + { + CachedTextureRequestArg arg = new CachedTextureRequestArg(); + arg.BakedTextureIndex = appear.WearableData[i].TextureIndex; + arg.WearableHashID = appear.WearableData[i].CacheID; + hashes.Add(arg); + } + + handlerSetAppearance(sender, te, visualparams, hashes); } catch (Exception e) { @@ -11487,12 +11496,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP requestArgs.Add(arg); } - CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; - if (handlerCachedTextureRequest != null) + try + { + CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; + if (handlerCachedTextureRequest != null) + { + handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); + } + } + catch (Exception e) { - handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); + m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e); + return false; } - + return true; } diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index b640b48..482bf6f 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -147,7 +147,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IScenePresence sp, AvatarAppearance appearance) { - SetAppearance(sp, appearance.Texture, appearance.VisualParams); + DoSetAppearance(sp, appearance.Texture, appearance.VisualParams, new List()); } /// @@ -158,9 +158,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) { -// m_log.DebugFormat( -// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", -// sp.Name, textureEntry, visualParams); + DoSetAppearance(sp, textureEntry, visualParams, new List()); + } + + /// + /// Set appearance data (texture asset IDs and slider settings) + /// + /// + /// + /// + protected void DoSetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, List hashes) + { + // m_log.DebugFormat( + // "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", + // sp.Name, textureEntry, visualParams); // TODO: This is probably not necessary any longer, just assume the // textureEntry set implies that the appearance transaction is complete @@ -190,18 +201,22 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Process the baked texture array if (textureEntry != null) { -// m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); - -// WriteBakedTexturesReport(sp, m_log.DebugFormat); + // m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); + // WriteBakedTexturesReport(sp, m_log.DebugFormat); changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; -// WriteBakedTexturesReport(sp, m_log.DebugFormat); + // WriteBakedTexturesReport(sp, m_log.DebugFormat); // If bake textures are missing and this is not an NPC, request a rebake from client if (!ValidateBakedTextureCache(sp) && (((ScenePresence)sp).PresenceType != PresenceType.Npc)) RequestRebake(sp, true); + // Save the wearble hashes in the appearance + sp.Appearance.ResetTextureHashes(); + foreach (CachedTextureRequestArg arg in hashes) + sp.Appearance.SetTextureHash(arg.BakedTextureIndex,arg.WearableHashID); + // This appears to be set only in the final stage of the appearance // update transaction. In theory, we should be able to do an immediate // appearance send and save here. @@ -235,13 +250,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory public bool SendAppearance(UUID agentId) { -// m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId); + // m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId); ScenePresence sp = m_scene.GetScenePresence(agentId); if (sp == null) { // This is expected if the user has gone away. -// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); + // m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); return false; } @@ -318,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void QueueAppearanceSend(UUID agentid) { -// m_log.DebugFormat("[AVFACTORY]: Queue appearance send for {0}", agentid); + // m_log.DebugFormat("[AVFACTORY]: Queue appearance send for {0}", agentid); // 10000 ticks per millisecond, 1000 milliseconds per second long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000); @@ -331,7 +346,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory public void QueueAppearanceSave(UUID agentid) { -// m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid); + // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid); // 10000 ticks per millisecond, 1000 milliseconds per second long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); @@ -356,9 +371,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (face == null) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", -// face.TextureID, idx, client.Name, client.AgentId); + // m_log.DebugFormat( + // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", + // face.TextureID, idx, client.Name, client.AgentId); // if the texture is one of the "defaults" then skip it // this should probably be more intelligent (skirt texture doesnt matter @@ -373,7 +388,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return false; } -// m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); + // m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); // If we only found default textures, then the appearance is not cached return (defonly ? false : true); @@ -392,9 +407,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (face == null) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", -// face.TextureID, idx, client.Name, client.AgentId); + // m_log.DebugFormat( + // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", + // face.TextureID, idx, client.Name, client.AgentId); // if the texture is one of the "defaults" then skip it // this should probably be more intelligent (skirt texture doesnt matter @@ -458,9 +473,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (bakeType == BakeType.Unknown) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", -// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); + // m_log.DebugFormat( + // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", + // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture @@ -484,7 +499,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory UUID avatarID = kvp.Key; long sendTime = kvp.Value; -// m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now); + // m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now); if (sendTime < now) { @@ -530,11 +545,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (sp == null) { // This is expected if the user has gone away. -// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); + // m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); return; } -// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); + // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); // This could take awhile since it needs to pull inventory // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape @@ -622,12 +637,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// /// /// - private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) + private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, List hashes) { // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); ScenePresence sp = m_scene.GetScenePresence(client.AgentId); if (sp != null) - SetAppearance(sp, textureEntry, visualParams); + DoSetAppearance(sp, textureEntry, visualParams, hashes); else m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); } @@ -684,7 +699,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List cachedTextureRequest) { - // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); + // m_log.DebugFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); ScenePresence sp = m_scene.GetScenePresence(client.AgentId); List cachedTextureResponse = new List(); @@ -695,23 +710,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (m_reusetextures) { - // this is the most insanely dumb way to do this... however it seems to - // actually work. if the appearance has been reset because wearables have - // changed then the texture entries are zero'd out until the bakes are - // uploaded. on login, if the textures exist in the cache (eg if you logged - // into the simulator recently, then the appearance will pull those and send - // them back in the packet and you won't have to rebake. if the textures aren't - // in the cache then the intial makeroot() call in scenepresence will zero - // them out. - // - // a better solution (though how much better is an open question) is to - // store the hashes in the appearance and compare them. Thats's coming. - - Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; - if (face != null) - texture = face.TextureID; - - // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); + if (sp.Appearance.GetTextureHash(index) == request.WearableHashID) + { + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; + if (face != null) + texture = face.TextureID; + } + else + { + // We know that that hash is wrong, null it out + // and wait for the setappearance call + sp.Appearance.SetTextureHash(index,UUID.Zero); + } + + // m_log.WarnFormat("[AVFACTORY]: use texture {0} for index {1}; hash={2}",texture,index,request.WearableHashID); } CachedTextureResponseArg response = new CachedTextureResponseArg(); diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 384eb1f..118635d 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -907,7 +907,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server // Mimicking LLClientView which gets always set appearance from client. AvatarAppearance appearance; m_scene.GetAvatarAppearance(this, out appearance); - OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone()); + OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone(), new List()); } public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) -- cgit v1.1 From bb0ea250907e24fe22490406e855cdcd958ba148 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 24 May 2013 13:25:25 -0700 Subject: Protect one more update of the baked texture hashes. --- .../Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 482bf6f..aea768e 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -214,8 +214,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Save the wearble hashes in the appearance sp.Appearance.ResetTextureHashes(); - foreach (CachedTextureRequestArg arg in hashes) - sp.Appearance.SetTextureHash(arg.BakedTextureIndex,arg.WearableHashID); + if (m_reusetextures) + { + foreach (CachedTextureRequestArg arg in hashes) + sp.Appearance.SetTextureHash(arg.BakedTextureIndex,arg.WearableHashID); + } // This appears to be set only in the final stage of the appearance // update transaction. In theory, we should be able to do an immediate -- cgit v1.1 From a087dbed7f57f3ec431782dd51ba43110a0f4ae3 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 24 May 2013 13:26:07 -0700 Subject: One more appearance change: drop sending the SendAppearance packet to avatar when it becomes root. This packet shows up in the viewer logs as an error and appears to cause problems for completing the texture rebake process for v1 viewers in some cases. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9e9089b..e1a8941 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2711,7 +2711,9 @@ namespace OpenSim.Region.Framework.Scenes // again here... this comes after the cached appearance check because the avatars // appearance goes into the avatar update packet SendAvatarDataToAllAgents(); - SendAppearanceToAgent(this); + + // This invocation always shows up in the viewer logs as an error. + // SendAppearanceToAgent(this); // If we are using the the cached appearance then send it out to everyone if (cachedappearance) -- cgit v1.1 From 81a6c397811c587cd97b5bb0f186fe6e799f865b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 24 May 2013 16:20:26 -0700 Subject: Meshmerizer: add INI parameter to enable DEBUG mesh detail logging. Default to off. To turn mesh parsing DEBUG detail logging on, add [Mesh] LogMeshDetail=true to the INI file. --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 2c10568..1b499d0 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -74,7 +74,7 @@ namespace OpenSim.Region.Physics.Meshing private const string baseDir = null; //"rawFiles"; #endif // If 'true', lots of DEBUG logging of asset parsing details - private bool debugDetail = true; + private bool debugDetail = false; private bool cacheSculptMaps = true; private string decodedSculptMapPath = null; @@ -94,8 +94,11 @@ namespace OpenSim.Region.Physics.Meshing decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); - if(mesh_config != null) + if (mesh_config != null) + { useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); + debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail); + } try { @@ -415,7 +418,7 @@ namespace OpenSim.Region.Physics.Meshing if (debugDetail) { - string keys = "[MESH]: keys found in convexBlock: "; + string keys = LogHeader + " keys found in convexBlock: "; foreach (KeyValuePair kvp in convexBlock) keys += "'" + kvp.Key + "' "; m_log.Debug(keys); -- cgit v1.1 From 4979940def5561015cb56bc660c6ec721722b9fc Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 24 May 2013 16:23:10 -0700 Subject: BulletSim: properly set mesh hash key in use tracking structure. Shouldn't see any functional difference. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 48f1394..81edc12 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -578,7 +578,6 @@ public class BSShapeHull : BSShape PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) { BulletShape newShape = new BulletShape(); - newShape.shapeKey = newHullKey; IMesh meshData = null; List> allHulls = null; @@ -782,6 +781,7 @@ public class BSShapeHull : BSShape // create the hull data structure in Bullet newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); } + newShape.shapeKey = newHullKey; return newShape; } // Callback from convex hull creater with a newly created hull. @@ -906,6 +906,7 @@ public class BSShapeCompound : BSShape } else { + // Didn't find it in the lists of specific types. It could be compound. if (physicsScene.PE.IsCompound(pShape)) { BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); @@ -913,6 +914,7 @@ public class BSShapeCompound : BSShape } else { + // If none of the above, maybe it is a simple native shape. if (physicsScene.PE.IsNativeShape(pShape)) { BSShapeNative nativeShape = new BSShapeNative(pShape); @@ -1052,6 +1054,7 @@ public class BSShapeGImpact : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); + newShape.shapeKey = newMeshKey; if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) { // If a mesh was what was created, remember the built shape for later sharing. -- cgit v1.1 From 5f1f5ea5ab5badf5944471fefe0a45f7b4f41b91 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 24 May 2013 16:24:16 -0700 Subject: BulletSim: add VehicleInertiaFactor to allow modifying inertia. Another parameter for vehicle operation tuning. Default to <1,1,1> which means nothing is different under normal use. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 3 ++- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index c16b7d3..311cf4f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -617,7 +617,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Vehicles report collision events so we know when it's on the ground m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); + Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); + ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index c19eda1..e98a7fb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -148,6 +148,7 @@ public static class BSParam public static float VehicleRestitution { get; private set; } public static Vector3 VehicleLinearFactor { get; private set; } public static Vector3 VehicleAngularFactor { get; private set; } + public static Vector3 VehicleInertiaFactor { get; private set; } public static float VehicleGroundGravityFudge { get; private set; } public static float VehicleAngularBankingTimescaleFudge { get; private set; } public static bool VehicleDebuggingEnable { get; private set; } @@ -583,6 +584,8 @@ public static class BSParam new Vector3(1f, 1f, 1f) ), new ParameterDefn("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), new ParameterDefn("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", 0.0f ), new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", -- cgit v1.1 From 182137263412fb23f9bdb250afbe1b1509280aac Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 24 May 2013 16:32:19 -0700 Subject: Meshmerizer: remember to add the copied hull verts to the list of hulls. --- OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 1b499d0..fc679e7 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -893,6 +893,7 @@ namespace OpenSim.Region.Physics.Meshing List verts = new List(); foreach (var vert in hull) verts.Add(vert * size); + hulls.Add(verts); } return hulls; -- cgit v1.1 From 533bbf033df88fd231eb0e7d2b0aa5a0058163ea Mon Sep 17 00:00:00 2001 From: Melanie Date: Sat, 25 May 2013 02:08:54 +0100 Subject: Update the money framework to allow sending the new style linden "serverside is now viewerside" messages regarding currency This will require all money modules to be refactored! --- OpenSim/Addons/Groups/GroupsModule.cs | 2 +- OpenSim/Framework/IClientAPI.cs | 5 ++-- OpenSim/Framework/IMoneyModule.cs | 3 ++- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 30 ++++++++++------------ .../Server/IRCClientView.cs | 7 +---- .../Avatar/XmlRpcGroups/GroupsModule.cs | 2 +- .../World/MoneyModule/SampleMoneyModule.cs | 13 +++++++--- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 7 +---- OpenSim/Tests/Common/Mock/TestClient.cs | 7 +---- 9 files changed, 32 insertions(+), 44 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 10bfa8f..f805d69 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -766,7 +766,7 @@ namespace OpenSim.Groups remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group."); return UUID.Zero; } - money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, "Group Creation"); + money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate); } string reason = string.Empty; UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment, diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 1fffeff..65f8395 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1159,7 +1159,8 @@ namespace OpenSim.Framework void SendTeleportStart(uint flags); void SendTeleportProgress(uint flags, string message); - void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance); + void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item); + void SendPayPrice(UUID objectID, int[] payPrice); void SendCoarseLocationUpdate(List users, List CoarseLocations); @@ -1254,8 +1255,6 @@ namespace OpenSim.Framework void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, string[] buttonlabels); - bool AddMoney(int debit); - /// /// Update the client as to where the sun is currently located. /// diff --git a/OpenSim/Framework/IMoneyModule.cs b/OpenSim/Framework/IMoneyModule.cs index 1e09728..52f3e83 100644 --- a/OpenSim/Framework/IMoneyModule.cs +++ b/OpenSim/Framework/IMoneyModule.cs @@ -38,7 +38,8 @@ namespace OpenSim.Framework int GetBalance(UUID agentID); bool UploadCovered(UUID agentID, int amount); bool AmountCovered(UUID agentID, int amount); - void ApplyCharge(UUID agentID, int amount, string text); + void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type); + void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData); void ApplyUploadCharge(UUID agentID, int amount, string text); int UploadCharge { get; } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index dd8ef9c..e47397d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -345,7 +345,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // protected HashSet m_attachmentsSent; - private int m_moneyBalance; private int m_animationSequenceNumber = 1; private bool m_SendLogoutPacketWhenClosing = true; @@ -420,7 +419,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP public string Name { get { return FirstName + " " + LastName; } } public uint CircuitCode { get { return m_circuitCode; } } - public int MoneyBalance { get { return m_moneyBalance; } } public int NextAnimationSequenceNumber { get { return m_animationSequenceNumber++; } } /// @@ -483,7 +481,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_firstName = sessionInfo.LoginInfo.First; m_lastName = sessionInfo.LoginInfo.Last; m_startpos = sessionInfo.LoginInfo.StartPos; - m_moneyBalance = 1000; m_udpServer = udpServer; m_udpClient = udpClient; @@ -1538,7 +1535,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(tpProgress, ThrottleOutPacketType.Unknown); } - public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) + public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) { MoneyBalanceReplyPacket money = (MoneyBalanceReplyPacket)PacketPool.Instance.GetPacket(PacketType.MoneyBalanceReply); money.MoneyData.AgentID = AgentId; @@ -1546,7 +1543,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP money.MoneyData.TransactionSuccess = success; money.MoneyData.Description = description; money.MoneyData.MoneyBalance = balance; - money.TransactionInfo.ItemDescription = Util.StringToBytes256("NONE"); + money.TransactionInfo.TransactionType = transactionType; + money.TransactionInfo.SourceID = sourceID; + money.TransactionInfo.IsSourceGroup = sourceIsGroup; + money.TransactionInfo.DestID = destID; + money.TransactionInfo.IsDestGroup = destIsGroup; + money.TransactionInfo.Amount = amount; + money.TransactionInfo.ItemDescription = Util.StringToBytes256(item); + OutPacket(money, ThrottleOutPacketType.Task); } @@ -2279,6 +2283,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public AgentAlertMessagePacket BuildAgentAlertPacket(string message, bool modal) { + // Prepend a slash to make the message come up in the top right + // again. + // Allow special formats to be sent from aware modules. + if (!modal && !message.StartsWith("ALERT: ") && !message.StartsWith("NOTIFY: ") && message != "Home position set." && message != "You died and have been teleported to your home location") + message = "/" + message; AgentAlertMessagePacket alertPack = (AgentAlertMessagePacket)PacketPool.Instance.GetPacket(PacketType.AgentAlertMessage); alertPack.AgentData.AgentID = AgentId; alertPack.AlertData.Message = Util.StringToBytes256(message); @@ -11933,17 +11942,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); } - public bool AddMoney(int debit) - { - if (m_moneyBalance + debit >= 0) - { - m_moneyBalance += debit; - SendMoneyBalance(UUID.Zero, true, Util.StringToBytes256("Poof Poof!"), m_moneyBalance); - return true; - } - return false; - } - protected void HandleAutopilot(Object sender, string method, List args) { float locx = 0; diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 118635d..3726191 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1056,7 +1056,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server { } - public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) + public void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) { } @@ -1196,11 +1196,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public bool AddMoney(int debit) - { - return true; - } - public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition) { diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs index 29f9591..32fb54b 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs @@ -764,7 +764,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got insufficient funds to create a group."); return UUID.Zero; } - money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, "Group Creation"); + money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, MoneyTransactionType.GroupCreate); } UUID groupID = m_groupData.CreateGroup(GetRequestingAgentID(remoteClient), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, GetRequestingAgentID(remoteClient)); diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index 35f44d0..1345db9 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs @@ -191,9 +191,14 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule // Please do not refactor these to be just one method // Existing implementations need the distinction // - public void ApplyCharge(UUID agentID, int amount, string text) + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData) { } + + public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type) + { + } + public void ApplyUploadCharge(UUID agentID, int amount, string text) { } @@ -322,7 +327,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule client.SendAlertMessage(e.Message + " "); } - client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds); + client.SendMoneyBalance(TransactionID, true, new byte[0], returnfunds, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } else { @@ -385,12 +390,12 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule { if (sender != null) { - sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID)); + sender.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(senderID), 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } if (receiver != null) { - receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID)); + receiver.SendMoneyBalance(UUID.Random(), transactionresult, Utils.StringToBytes(description), GetFundsForAgentID(receiverID), 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty); } } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 553443f..592e4e1 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -694,7 +694,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) + public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) { } @@ -866,11 +866,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public bool AddMoney(int debit) - { - return false; - } - public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 09e751a..c660501 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -651,7 +651,7 @@ namespace OpenSim.Tests.Common.Mock { } - public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) + public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item) { } @@ -875,11 +875,6 @@ namespace OpenSim.Tests.Common.Mock } - public bool AddMoney(int debit) - { - return false; - } - public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase) { } -- cgit v1.1 From 0c35d28933ddb2cae7b4f095b35ed4e386a1b71b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 26 May 2013 17:35:12 -0700 Subject: BulletSim: enable GImpact shape for prims with cuts. Include DLLs and SOs which recompute GImpact shape bounding box after creation as Bullet doesn't do that itself (something it does for nearly every other shape). Now, physical prims without cuts become single mesh convex meshes. Physical prims with cuts become GImpact meshes. Meshes become a set of convex hulls approximated from the mesh unless the hulls are specified in the mesh asset data. The use of GImpact shapes should make some mechanical physics more stable. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 2 +- bin/lib32/BulletSim.dll | Bin 982528 -> 982528 bytes bin/lib32/libBulletSim.so | Bin 2271520 -> 2271724 bytes bin/lib64/BulletSim.dll | Bin 1222656 -> 1222656 bytes bin/lib64/libBulletSim.so | Bin 2454504 -> 2454796 bytes 5 files changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index e98a7fb..0f0a494 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -373,7 +373,7 @@ public static class BSParam new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", true ), new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", - false ), + true ), new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", false ), diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index d63ee1d..bc0e222 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 03de631..e09dd27 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index e155f0e..5fc09f6 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index ac64a40..925269d 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From 7c3a46cceaf9dac694b1c387f37adc2c51c6ee40 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 27 May 2013 14:38:59 -0700 Subject: BulletSim: default using mesh asset hulls to 'true'. This means that, if the mesh asset specifies physics hulls, BulletSim will fetch and use same rather than approximating the hulls. If physics hulls are not specified, the representation will fall back to the regular physics mesh. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 0f0a494..2651e3b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -373,9 +373,9 @@ public static class BSParam new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", true ), new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", - true ), - new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", false ), + new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", + true ), new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 5 ), -- cgit v1.1 From ae0d6ab28a03ec23c91eaf6a8ac94b890916a1ca Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 28 May 2013 09:19:08 -0700 Subject: BulletSim: don't zero motion when changing vehicle type. Some vehicle scripts change type on the fly as an easy way of setting all the parameters (like a plane changing to a car when on the ground). --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index f5b0361..e11e365 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -511,7 +511,10 @@ public class BSPrim : BSPhysObject PhysScene.TaintedObject("setVehicleType", delegate() { - ZeroMotion(true /* inTaintTime */); + // Some vehicle scripts change vehicle type on the fly as an easy way to + // change all the parameters. Like a plane changing to CAR when on the + // ground. In this case, don't want to zero motion. + // ZeroMotion(true /* inTaintTime */); VehicleActor.ProcessTypeChange(type); ActivateIfPhysical(false); }); -- cgit v1.1 From 7e1c7f54c719910145a88bfebf16435b9f142901 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 28 May 2013 20:59:25 -0700 Subject: First change in Vivox for ages! -- added a lock to serialize calls to vivox servers. This may ameliorate things when lots of avies arrive in a sim at about the same time. Turns out that there are 4 http requests per avie to Vivox. --- .../Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | 39 ++++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs index cb69411..db4869d 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs @@ -117,6 +117,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice private IConfig m_config; + private object m_Lock; + public void Initialise(IConfigSource config) { @@ -128,6 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice if (!m_config.GetBoolean("enabled", false)) return; + m_Lock = new object(); + try { // retrieve configuration variables @@ -1111,25 +1115,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice doc = new XmlDocument(); - try + // Let's serialize all calls to Vivox. Most of these are driven by + // the clients (CAPs), when the user arrives at the region. We don't + // want to issue many simultaneous http requests to Vivox, because mono + // doesn't like that + lock (m_Lock) { - // Otherwise prepare the request - m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); + try + { + // Otherwise prepare the request + m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); - HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); - // We are sending just parameters, no content - req.ContentLength = 0; + // We are sending just parameters, no content + req.ContentLength = 0; - // Send request and retrieve the response - using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) + // Send request and retrieve the response + using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) using (Stream s = rsp.GetResponseStream()) - using (XmlTextReader rdr = new XmlTextReader(s)) - doc.Load(rdr); - } - catch (Exception e) - { - m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); + using (XmlTextReader rdr = new XmlTextReader(s)) + doc.Load(rdr); + } + catch (Exception e) + { + m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); + } } // If we're debugging server responses, dump the whole -- cgit v1.1 From 4898f18f89c104e74fa37793671231118d75e3ae Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 29 May 2013 21:28:38 +0100 Subject: Add HG regression TestCachedUserNameForNewAgent() --- .../Tests/HGUserManagementModuleTests.cs | 76 ++++++++++++++++++++++ prebuild.xml | 1 + 2 files changed, 77 insertions(+) create mode 100644 OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs new file mode 100644 index 0000000..9259a83 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs @@ -0,0 +1,76 @@ +/* + * 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 Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Framework.UserManagement; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests +{ + [TestFixture] + public class HGUserManagementModuleTests : OpenSimTestCase + { + /// + /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation. + /// + [Test] + public void TestCachedUserNameForNewAgent() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + HGUserManagementModule hgumm = new HGUserManagementModule(); + UUID userId = TestHelpers.ParseStem("11"); + string firstName = "Fred"; + string lastName = "Astaire"; + string homeUri = "example.com"; + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("UserManagementModule", hgumm.Name); + + SceneHelpers sceneHelpers = new SceneHelpers(); + TestScene scene = sceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, hgumm); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + acd.firstname = firstName; + acd.lastname = lastName; + acd.ServiceURLs["HomeURI"] = "http://" + homeUri; + + SceneHelpers.AddScenePresence(scene, acd); + + string name = hgumm.GetUserName(userId); + Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri))); + } + } +} \ No newline at end of file diff --git a/prebuild.xml b/prebuild.xml index 25c287e..5967ef6 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3058,6 +3058,7 @@ + -- cgit v1.1 From cc7aa88b264cd5fa35591b9768ebc230b1814824 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 29 May 2013 23:08:54 +0100 Subject: Try caching the user name for a new agent earlier on in the process of establishing a connection, to see if this helps with "Unknown UserUMMTGUN" issues. The UMMTGUN form of Unknown User seems to appear because a viewer sometimes sends a UUIDNameRequest UDP request that fails to find a binding. However, in theory the incoming agent should have made that binding before any such request is triggered. So moving this binding to an earlier point in the process to see if this makes a difference. Unknown user name is also updated to UserUMMTGUN2 - if you see the old name then you need to clear your viewer cache. This relates to http://opensimulator.org/mantis/view.php?id=6625 --- .../UserManagement/Tests/HGUserManagementModuleTests.cs | 2 +- .../Framework/UserManagement/UserManagementModule.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 12 +++++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs index 9259a83..9d36aa5 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs @@ -46,7 +46,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests public void TestCachedUserNameForNewAgent() { TestHelpers.InMethod(); - TestHelpers.EnableLogging(); +// TestHelpers.EnableLogging(); HGUserManagementModule hgumm = new HGUserManagementModule(); UUID userId = TestHelpers.ParseStem("11"); diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index a720d7b..1e70b84 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -320,7 +320,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { names[0] = "Unknown"; - names[1] = "UserUMMTGUN"; + names[1] = "UserUMMTGUN2"; return false; } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 8fe9b66..5dea634 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2847,7 +2847,9 @@ namespace OpenSim.Region.Framework.Scenes // client is for a root or child agent. client.SceneAgent = sp; - // Cache the user's name + // This is currently also being done earlier in NewUserConnection for real users to see if this + // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other + // places. However, we still need to do it here for NPCs. CacheUserName(sp, aCircuit); EventManager.TriggerOnNewClient(client); @@ -2871,7 +2873,7 @@ namespace OpenSim.Region.Framework.Scenes { string first = aCircuit.firstname, last = aCircuit.lastname; - if (sp.PresenceType == PresenceType.Npc) + if (sp != null && sp.PresenceType == PresenceType.Npc) { UserManagementModule.AddUser(aCircuit.AgentID, first, last); } @@ -3766,8 +3768,12 @@ namespace OpenSim.Region.Framework.Scenes CapsModule.SetAgentCapsSeeds(agent); } } - } + // Try caching an incoming user name much earlier on to see if this helps with an issue + // where HG users are occasionally seen by others as "Unknown User" because their UUIDName + // request for the HG avatar appears to trigger before the user name is cached. + CacheUserName(null, agent); + } if (vialogin) { -- cgit v1.1 From 8f9a726465c5bb7528d6ae7d74f20818d4ee3094 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 30 May 2013 19:27:20 +0100 Subject: If on a sit request we sit the avatar on a different prim in a linkset for some reason (e.g. because it has a sit target), then send the actual sit prim UUID to the viewer rather than the requested one. This purports to fix the issue described in http://opensimulator.org/mantis/view.php?id=6653 where the camera can end up following the requested sit prim rather than the actual. The original spot was by Vegaslon, this commit just goes about it in a slightly different way This commit also makes m_requestedSitTargetUUID to be the actual UUID, which is consistent with m_requestedSitTargetID which was already doing this. However, this adjustment has no practical effect since we only currently need to know that there's any requested sit UUID at all, not which one it is. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index ab7fd5b..e8aa52e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2138,9 +2138,9 @@ namespace OpenSim.Region.Framework.Scenes forceMouselook = part.GetForceMouselook(); ControllingClient.SendSitResponse( - targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); + part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); - m_requestedSitTargetUUID = targetID; + m_requestedSitTargetUUID = part.UUID; HandleAgentSit(ControllingClient, UUID); @@ -2165,7 +2165,7 @@ namespace OpenSim.Region.Framework.Scenes if (part != null) { m_requestedSitTargetID = part.LocalId; - m_requestedSitTargetUUID = targetID; + m_requestedSitTargetUUID = part.UUID; // m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset); -- cgit v1.1 From 12a3b855619735b2e36a67ab99027029c8b57260 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 30 May 2013 22:20:02 +0100 Subject: Fix passing of voice distance attenuation to the Vivox voice server. Because of a typo, this wasn't being done at all - now the 'default' value as described in OpenSimDefaults.ini of 10m is passed (vivox_channel_clamping_distance) Thanks to Ai Austin for spotting this. --- .../Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs index db4869d..2d65530 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs @@ -836,7 +836,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); - requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); + requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance); XmlElement resp = VivoxCall(requrl, true); if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) -- cgit v1.1 From 6b88a665d3a3196288b5aa16eb23f7673c2433ac Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 30 May 2013 22:43:52 +0100 Subject: minor: fix warnings in GodsModule that were due to duplicate using statements --- OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index 16673ec..a542d62 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -26,29 +26,25 @@ */ using System; -using System.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.Framework.Interfaces; -using System; -using System.Reflection; using System.Collections; +using System.Collections.Generic; using System.Collections.Specialized; -using System.Reflection; using System.IO; +using System.Reflection; using System.Web; using System.Xml; using log4net; - using Mono.Addins; - +using Nini.Config; +using OpenMetaverse; using OpenMetaverse.Messages.Linden; using OpenMetaverse.StructuredData; +using OpenSim.Framework; using OpenSim.Framework.Capabilities; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OSDArray = OpenMetaverse.StructuredData.OSDArray; using OSDMap = OpenMetaverse.StructuredData.OSDMap; -- cgit v1.1 From 328883700a15e4216bf7b251ac099d38f413375e Mon Sep 17 00:00:00 2001 From: BlueWall Date: Mon, 13 May 2013 22:11:28 -0400 Subject: UserProfiles UserProfiles for Robust and Standalone. Includes service and connectors for Robust and standalone opensim plus matching region module. --- OpenSim/Data/IProfilesData.cs | 29 + OpenSim/Data/MySQL/MySQLUserProfilesData.cs | 1023 +++++++++++++++ .../Data/MySQL/Resources/UserProfiles.migrations | 83 ++ OpenSim/Framework/UserProfiles.cs | 90 ++ .../Avatar/Profile/BasicProfileModule.cs | 176 --- .../Avatar/UserProfiles/UserProfileModule.cs | 1386 ++++++++++++++++++++ .../LocalUserProfilesServiceConnector.cs | 226 ++++ .../Grid/LocalGridServiceConnector.cs | 1 + .../Handlers/Profiles/UserProfilesConnector.cs | 92 ++ .../Handlers/Profiles/UserProfilesHandlers.cs | 434 ++++++ .../Services/Interfaces/IUserProfilesService.cs | 48 + .../UserProfilesService/UserProfilesService.cs | 160 +++ .../UserProfilesService/UserProfilesServiceBase.cs | 59 + bin/OpenSim.ini.example | 6 + bin/OpenSimDefaults.ini | 13 + bin/Robust.HG.ini.example | 12 +- bin/Robust.ini.example | 11 + bin/config-include/StandaloneCommon.ini.example | 16 + bin/config-include/StandaloneHypergrid.ini | 2 +- prebuild.xml | 38 + 20 files changed, 3727 insertions(+), 178 deletions(-) create mode 100644 OpenSim/Data/IProfilesData.cs create mode 100644 OpenSim/Data/MySQL/MySQLUserProfilesData.cs create mode 100644 OpenSim/Data/MySQL/Resources/UserProfiles.migrations create mode 100644 OpenSim/Framework/UserProfiles.cs delete mode 100644 OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs create mode 100644 OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs create mode 100644 OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs create mode 100644 OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs create mode 100644 OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs create mode 100644 OpenSim/Services/Interfaces/IUserProfilesService.cs create mode 100644 OpenSim/Services/UserProfilesService/UserProfilesService.cs create mode 100644 OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs diff --git a/OpenSim/Data/IProfilesData.cs b/OpenSim/Data/IProfilesData.cs new file mode 100644 index 0000000..eeccbf6 --- /dev/null +++ b/OpenSim/Data/IProfilesData.cs @@ -0,0 +1,29 @@ +using System; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + + public interface IProfilesData + { + OSDArray GetClassifiedRecords(UUID creatorId); + bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result); + bool DeleteClassifiedRecord(UUID recordId); + OSDArray GetAvatarPicks(UUID avatarId); + UserProfilePick GetPickInfo(UUID avatarId, UUID pickId); + bool UpdatePicksRecord(UserProfilePick pick); + bool DeletePicksRecord(UUID pickId); + bool GetAvatarNotes(ref UserProfileNotes note); + bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result); + bool GetAvatarProperties(ref UserProfileProperties props, ref string result); + bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result); + bool UpdateAvatarInterests(UserProfileProperties up, ref string result); + bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result); + bool GetUserAppData(ref UserAppData props, ref string result); + bool SetUserAppData(UserAppData props, ref string result); + OSDArray GetUserImageAssets(UUID avatarId); + } +} + diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs new file mode 100644 index 0000000..09bd448 --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs @@ -0,0 +1,1023 @@ +using System; +using System.Data; +using System.Reflection; +using OpenSim.Data; +using OpenSim.Framework; +using MySql.Data.MySqlClient; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; + +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 object Lock + { + 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. + /// + /// + /// Array of classified records + /// + /// + /// Creator identifier. + /// + 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"; + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", creatorId); + using( MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default)) + { + if(reader.HasRows) + { + while (reader.Read()) + { + OSDMap n = new OSDMap(); + UUID Id = UUID.Zero; + + string Name = null; + try + { + UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id); + Name = Convert.ToString(reader["name"]); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UserAccount exception {0}", e.Message); + } + n.Add("classifieduuid", OSD.FromUUID(Id)); + n.Add("name", OSD.FromString(Name)); + data.Add(n); + } + } + } + } + } + return data; + } + + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + + query += "INSERT INTO classifieds ("; + query += "`classifieduuid`,"; + query += "`creatoruuid`,"; + query += "`creationdate`,"; + query += "`expirationdate`,"; + query += "`category`,"; + query += "`name`,"; + query += "`description`,"; + query += "`parceluuid`,"; + query += "`parentestate`,"; + query += "`snapshotuuid`,"; + query += "`simname`,"; + query += "`posglobal`,"; + query += "`parcelname`,"; + query += "`classifiedflags`,"; + query += "`priceforlisting`) "; + query += "VALUES ("; + query += "?ClassifiedId,"; + query += "?CreatorId,"; + query += "?CreatedDate,"; + query += "?ExpirationDate,"; + query += "?Category,"; + query += "?Name,"; + query += "?Description,"; + query += "?ParcelId,"; + query += "?ParentEstate,"; + query += "?SnapshotId,"; + query += "?SimName,"; + query += "?GlobalPos,"; + query += "?ParcelName,"; + query += "?Flags,"; + query += "?ListingPrice ) "; + query += "ON DUPLICATE KEY UPDATE "; + query += "category=?Category, "; + query += "expirationdate=?ExpirationDate, "; + query += "name=?Name, "; + query += "description=?Description, "; + query += "parentestate=?ParentEstate, "; + query += "posglobal=?GlobalPos, "; + query += "parcelname=?ParcelName, "; + 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); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + else + { + duration = new TimeSpan(365,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + ad.CreationDate = (int)epochnow.TotalSeconds; + ad.ExpirationDate = (int)epochexp.TotalSeconds; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?ClassifiedId", ad.ClassifiedId.ToString()); + cmd.Parameters.AddWithValue("?CreatorId", ad.CreatorId.ToString()); + cmd.Parameters.AddWithValue("?CreatedDate", ad.CreationDate.ToString()); + cmd.Parameters.AddWithValue("?ExpirationDate", ad.ExpirationDate.ToString()); + cmd.Parameters.AddWithValue("?Category", ad.Category.ToString()); + cmd.Parameters.AddWithValue("?Name", ad.Name.ToString()); + cmd.Parameters.AddWithValue("?Description", ad.Description.ToString()); + cmd.Parameters.AddWithValue("?ParcelId", ad.ParcelId.ToString()); + cmd.Parameters.AddWithValue("?ParentEstate", ad.ParentEstate.ToString()); + cmd.Parameters.AddWithValue("?SnapshotId", ad.SnapshotId.ToString ()); + cmd.Parameters.AddWithValue("?SimName", ad.SimName.ToString()); + cmd.Parameters.AddWithValue("?GlobalPos", ad.GlobalPos.ToString()); + cmd.Parameters.AddWithValue("?ParcelName", ad.ParcelName.ToString()); + cmd.Parameters.AddWithValue("?Flags", ad.Flags.ToString()); + cmd.Parameters.AddWithValue("?ListingPrice", ad.Price.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": ClassifiedesUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + + public bool DeleteClassifiedRecord(UUID recordId) + { + string query = string.Empty; + + query += "DELETE FROM classifieds WHERE "; + query += "classifieduuid = ?ClasifiedId"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?ClassifiedId", recordId.ToString()); + + lock(Lock) + { + cmd.ExecuteNonQuery(); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": DeleteClassifiedRecord exception {0}", e.Message); + return false; + } + 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)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?AdId", ad.ClassifiedId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.Read ()) + { + ad.CreatorId = new UUID(reader.GetGuid("creatoruuid")); + ad.ParcelId = new UUID(reader.GetGuid("parceluuid")); + ad.SnapshotId = new UUID(reader.GetGuid("snapshotuuid")); + ad.CreationDate = Convert.ToInt32(reader["creationdate"]); + ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]); + ad.ParentEstate = Convert.ToInt32(reader["parentestate"]); + ad.Flags = (byte)reader.GetUInt32("classifiedflags"); + ad.Category = reader.GetInt32("category"); + ad.Price = reader.GetInt16("priceforlisting"); + ad.Name = reader.GetString("name"); + ad.Description = reader.GetString("description"); + ad.SimName = reader.GetString("simname"); + ad.GlobalPos = reader.GetString("posglobal"); + ad.ParcelName = reader.GetString("parcelname"); + + } + } + } + dbcon.Close(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + 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)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.HasRows) + { + 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); + } + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarPicks exception {0}", e.Message); + } + 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)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + 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); + UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId); + pick.GlobalPos = (string)reader["posglobal"]; + bool.TryParse((string)reader["toppick"], out pick.TopPick); + bool.TryParse((string)reader["enabled"], out pick.Enabled); + pick.Name = (string)reader["name"]; + pick.Desc = description; + pick.User = (string)reader["user"]; + pick.OriginalName = (string)reader["originalname"]; + pick.SimName = (string)reader["simname"]; + pick.SortOrder = (int)reader["sortorder"]; + } + } + } + dbcon.Close(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return pick; + } + + public bool UpdatePicksRecord(UserProfilePick pick) + { + string query = string.Empty; + + query += "INSERT INTO userpicks VALUES ("; + query += "?PickId,"; + query += "?CreatorId,"; + query += "?TopPick,"; + query += "?ParcelId,"; + query += "?Name,"; + query += "?Desc,"; + query += "?SnapshotId,"; + query += "?User,"; + query += "?Original,"; + query += "?SimName,"; + query += "?GlobalPos,"; + query += "?SortOrder,"; + query += "?Enabled) "; + query += "ON DUPLICATE KEY UPDATE "; + query += "parceluuid=?ParcelId,"; + query += "name=?Name,"; + query += "description=?Desc,"; + query += "snapshotuuid=?SnapshotId,"; + query += "pickuuid=?PickId,"; + query += "posglobal=?GlobalPos"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?PickId", pick.PickId.ToString()); + cmd.Parameters.AddWithValue("?CreatorId", pick.CreatorId.ToString()); + cmd.Parameters.AddWithValue("?TopPick", pick.TopPick.ToString()); + cmd.Parameters.AddWithValue("?ParcelId", pick.ParcelId.ToString()); + cmd.Parameters.AddWithValue("?Name", pick.Name.ToString()); + cmd.Parameters.AddWithValue("?Desc", pick.Desc.ToString()); + cmd.Parameters.AddWithValue("?SnapshotId", pick.SnapshotId.ToString()); + cmd.Parameters.AddWithValue("?User", pick.User.ToString()); + cmd.Parameters.AddWithValue("?Original", pick.OriginalName.ToString()); + cmd.Parameters.AddWithValue("?SimName",pick.SimName.ToString()); + cmd.Parameters.AddWithValue("?GlobalPos", pick.GlobalPos); + cmd.Parameters.AddWithValue("?SortOrder", pick.SortOrder.ToString ()); + cmd.Parameters.AddWithValue("?Enabled", pick.Enabled.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + 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(); + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": DeleteUserPickRecord exception {0}", e.Message); + return false; + } + 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"; + OSDArray data = new OSDArray(); + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", notes.UserId.ToString()); + cmd.Parameters.AddWithValue("?TargetId", notes.TargetId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + reader.Read(); + notes.Notes = OSD.FromString((string)reader["notes"]); + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return true; + } + + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) + { + string query = string.Empty; + bool remove; + + if(string.IsNullOrEmpty(note.Notes)) + { + remove = true; + query += "DELETE FROM usernotes WHERE "; + query += "useruuid=?UserId AND "; + query += "targetuuid=?TargetId"; + } + else + { + remove = false; + query += "INSERT INTO usernotes VALUES ( "; + query += "?UserId,"; + query += "?TargetId,"; + query += "?Notes )"; + query += "ON DUPLICATE KEY "; + query += "UPDATE "; + query += "notes=?Notes"; + } + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + if(!remove) + cmd.Parameters.AddWithValue("?Notes", note.Notes); + cmd.Parameters.AddWithValue("?TargetId", note.TargetId.ToString ()); + cmd.Parameters.AddWithValue("?UserId", note.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + 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)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", props.UserId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Getting data for {0}.", props.UserId); + reader.Read(); + props.WebUrl = (string)reader["profileURL"]; + UUID.TryParse((string)reader["profileImage"], out props.ImageId); + props.AboutText = (string)reader["profileAboutText"]; + UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId); + props.FirstLifeText = (string)reader["profileFirstText"]; + UUID.TryParse((string)reader["profilePartner"], out props.PartnerId); + props.WantToMask = (int)reader["profileWantToMask"]; + props.WantToText = (string)reader["profileWantToText"]; + props.SkillsMask = (int)reader["profileSkillsMask"]; + props.SkillsText = (string)reader["profileSkillsText"]; + props.Language = (string)reader["profileLanguages"]; + } + else + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": No data for {0}", props.UserId); + + props.WebUrl = string.Empty; + props.ImageId = UUID.Zero; + props.AboutText = string.Empty; + props.FirstLifeImageId = UUID.Zero; + props.FirstLifeText = string.Empty; + props.PartnerId = UUID.Zero; + props.WantToMask = 0; + props.WantToText = string.Empty; + props.SkillsMask = 0; + props.SkillsText = string.Empty; + props.Language = string.Empty; + + query = "INSERT INTO userprofile (`useruuid`) VALUES (?userId)"; + + dbcon.Close(); + dbcon.Open(); + + using (MySqlCommand put = new MySqlCommand(query, dbcon)) + { + put.Parameters.AddWithValue("?userId", props.UserId.ToString()); + put.ExecuteNonQuery(); + } + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Requst properties exception {0}", e.Message); + result = e.Message; + return false; + } + 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, "; + query += "profileAboutText=?abouttext,"; + query += "profileFirstImage=?firstlifeimage,"; + query += "profileFirstText=?firstlifetext "; + query += "WHERE useruuid=?uuid"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?profileURL", props.WebUrl); + cmd.Parameters.AddWithValue("?image", props.ImageId.ToString()); + cmd.Parameters.AddWithValue("?abouttext", props.AboutText); + cmd.Parameters.AddWithValue("?firstlifeimage", props.FirstLifeImageId.ToString()); + cmd.Parameters.AddWithValue("?firstlifetext", props.FirstLifeText); + cmd.Parameters.AddWithValue("?uuid", props.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[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,"; + query += "profileSkillsMask=?SkillsMask,"; + query += "profileSkillsText=?SkillsText, "; + query += "profileLanguages=?Languages "; + query += "WHERE useruuid=?uuid"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?WantMask", up.WantToMask); + cmd.Parameters.AddWithValue("?WantText", up.WantToText); + cmd.Parameters.AddWithValue("?SkillsMask", up.SkillsMask); + cmd.Parameters.AddWithValue("?SkillsText", up.SkillsText); + cmd.Parameters.AddWithValue("?Languages", up.Language); + cmd.Parameters.AddWithValue("?uuid", up.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + #endregion Avatar Interests + + public OSDArray GetUserImageAssets(UUID avatarId) + { + OSDArray data = new OSDArray(); + string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = ?Id"; + + // Get classified image assets + + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + + 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) + { + while (reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + } + + dbcon.Close(); + dbcon.Open(); + + 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) + { + while (reader.Read()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + } + + dbcon.Close(); + dbcon.Open(); + + query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = ?Id"; + + 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) + { + while (reader.Read()) + { + data.Add(new OSDString((string)reader["profileImage"].ToString ())); + data.Add(new OSDString((string)reader["profileFirstImage"].ToString ())); + } + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return data; + } + + #region User Preferences + public OSDArray GetUserPreferences(UUID avatarId) + { + string query = string.Empty; + + query += "SELECT imviaemail,visible,email FROM "; + query += "usersettings WHERE "; + query += "useruuid = ?Id"; + + OSDArray data = new OSDArray(); + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", avatarId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if(reader.HasRows) + { + reader.Read(); + OSDMap record = new OSDMap(); + + record.Add("imviaemail",OSD.FromString((string)reader["imviaemail"])); + record.Add("visible",OSD.FromString((string)reader["visible"])); + record.Add("email",OSD.FromString((string)reader["email"])); + data.Add(record); + } + else + { + using (MySqlCommand put = new MySqlCommand(query, dbcon)) + { + query = "INSERT INTO usersettings VALUES "; + query += "(?Id,'false','false', '')"; + + lock(Lock) + { + put.ExecuteNonQuery(); + } + } + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Get preferences exception {0}", e.Message); + } + return data; + } + + public bool UpdateUserPreferences(bool emailIm, bool visible, UUID avatarId ) + { + string query = string.Empty; + + query += "UPDATE userpsettings SET "; + query += "imviaemail=?ImViaEmail, "; + query += "visible=?Visible,"; + query += "WHERE useruuid=?uuid"; + + try + { + using (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?ImViaEmail", emailIm.ToString().ToLower ()); + cmd.Parameters.AddWithValue("?WantText", visible.ToString().ToLower ()); + cmd.Parameters.AddWithValue("?uuid", avatarId.ToString()); + + lock(Lock) + { + cmd.ExecuteNonQuery(); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + return false; + } + 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)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?Id", props.UserId.ToString()); + cmd.Parameters.AddWithValue ("?TagId", props.TagId.ToString()); + + using (MySqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow)) + { + if(reader.HasRows) + { + reader.Read(); + props.DataKey = (string)reader["DataKey"]; + props.DataVal = (string)reader["DataVal"]; + } + else + { + query += "INSERT INTO userdata VALUES ( "; + query += "?UserId,"; + query += "?TagId,"; + query += "?DataKey,"; + query += "?DataVal) "; + + using (MySqlCommand put = new MySqlCommand(query, dbcon)) + { + put.Parameters.AddWithValue("?Id", props.UserId.ToString()); + put.Parameters.AddWithValue("?TagId", props.TagId.ToString()); + put.Parameters.AddWithValue("?DataKey", props.DataKey.ToString()); + put.Parameters.AddWithValue("?DataVal", props.DataVal.ToString()); + + lock(Lock) + { + put.ExecuteNonQuery(); + } + } + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Requst application data exception {0}", e.Message); + result = e.Message; + return false; + } + 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 (MySqlConnection dbcon = new MySqlConnection(ConnectionString)) + { + dbcon.Open(); + using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) + { + cmd.Parameters.AddWithValue("?UserId", props.UserId.ToString()); + cmd.Parameters.AddWithValue("?TagId", props.TagId.ToString ()); + cmd.Parameters.AddWithValue("?DataKey", props.DataKey.ToString ()); + cmd.Parameters.AddWithValue("?DataVal", props.DataKey.ToString ()); + + lock(Lock) + { + cmd.ExecuteNonQuery(); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": SetUserData exception {0}", e.Message); + return false; + } + return true; + } + #endregion Integration + } +} + diff --git a/OpenSim/Data/MySQL/Resources/UserProfiles.migrations b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations new file mode 100644 index 0000000..c29f1ab --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/UserProfiles.migrations @@ -0,0 +1,83 @@ +:VERSION 1 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS `classifieds` ( + `classifieduuid` char(36) NOT NULL, + `creatoruuid` char(36) NOT NULL, + `creationdate` int(20) NOT NULL, + `expirationdate` int(20) NOT NULL, + `category` varchar(20) NOT NULL, + `name` varchar(255) NOT NULL, + `description` text NOT NULL, + `parceluuid` char(36) NOT NULL, + `parentestate` int(11) NOT NULL, + `snapshotuuid` char(36) NOT NULL, + `simname` varchar(255) NOT NULL, + `posglobal` varchar(255) NOT NULL, + `parcelname` varchar(255) NOT NULL, + `classifiedflags` int(8) NOT NULL, + `priceforlisting` int(5) NOT NULL, + PRIMARY KEY (`classifieduuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + + +CREATE TABLE IF NOT EXISTS `usernotes` ( + `useruuid` varchar(36) NOT NULL, + `targetuuid` varchar(36) NOT NULL, + `notes` text NOT NULL, + UNIQUE KEY `useruuid` (`useruuid`,`targetuuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +CREATE TABLE IF NOT EXISTS `userpicks` ( + `pickuuid` varchar(36) NOT NULL, + `creatoruuid` varchar(36) NOT NULL, + `toppick` enum('true','false') NOT NULL, + `parceluuid` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `description` text NOT NULL, + `snapshotuuid` varchar(36) NOT NULL, + `user` varchar(255) NOT NULL, + `originalname` varchar(255) NOT NULL, + `simname` varchar(255) NOT NULL, + `posglobal` varchar(255) NOT NULL, + `sortorder` int(2) NOT NULL, + `enabled` enum('true','false') NOT NULL, + PRIMARY KEY (`pickuuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +CREATE TABLE IF NOT EXISTS `userprofile` ( + `useruuid` varchar(36) NOT NULL, + `profilePartner` varchar(36) NOT NULL, + `profileAllowPublish` binary(1) NOT NULL, + `profileMaturePublish` binary(1) NOT NULL, + `profileURL` varchar(255) NOT NULL, + `profileWantToMask` int(3) NOT NULL, + `profileWantToText` text NOT NULL, + `profileSkillsMask` int(3) NOT NULL, + `profileSkillsText` text NOT NULL, + `profileLanguages` text NOT NULL, + `profileImage` varchar(36) NOT NULL, + `profileAboutText` text NOT NULL, + `profileFirstImage` varchar(36) NOT NULL, + `profileFirstText` text NOT NULL, + PRIMARY KEY (`useruuid`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +commit; + +:VERSION 2 # ------------------------------- + +begin; +CREATE TABLE IF NOT EXISTS `userdata` ( + `UserId` char(36) NOT NULL, + `TagId` varchar(64) NOT NULL, + `DataKey` varchar(255), + `DataVal` varchar(255), + PRIMARY KEY (`UserId`,`TagId`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +commit; + diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs new file mode 100644 index 0000000..aabbb84 --- /dev/null +++ b/OpenSim/Framework/UserProfiles.cs @@ -0,0 +1,90 @@ +using System; +using OpenMetaverse; + +namespace OpenSim.Framework +{ + public class UserClassifiedAdd + { + public UUID ClassifiedId = UUID.Zero; + public UUID CreatorId = UUID.Zero; + public int CreationDate = 0; + public int ExpirationDate = 0; + public int Category = 0; + public string Name = string.Empty; + public string Description = string.Empty; + public UUID ParcelId = UUID.Zero; + public int ParentEstate = 0; + public UUID SnapshotId = UUID.Zero; + public string SimName = string.Empty; + public string GlobalPos = "<0,0,0>"; + public string ParcelName = string.Empty; + public byte Flags = 0; + public int Price = 0; + } + + public class UserProfileProperties + { + public UUID UserId = UUID.Zero; + public UUID PartnerId = UUID.Zero; + public bool PublishProfile = false; + public bool PublishMature = false; + public string WebUrl = string.Empty; + public int WantToMask = 0; + public string WantToText = string.Empty; + public int SkillsMask = 0; + public string SkillsText = string.Empty; + public string Language = string.Empty; + public UUID ImageId = UUID.Zero; + public string AboutText = string.Empty; + public UUID FirstLifeImageId = UUID.Zero; + public string FirstLifeText = string.Empty; + } + + public class UserProfilePick + { + public UUID PickId = UUID.Zero; + public UUID CreatorId = UUID.Zero; + public bool TopPick = false; + public string Name = string.Empty; + public string OriginalName = string.Empty; + public string Desc = string.Empty; + public UUID ParcelId = UUID.Zero; + public UUID SnapshotId = UUID.Zero; + public string User = string.Empty; + public string SimName = string.Empty; + public string GlobalPos = "<0,0,0>"; + public int SortOrder = 0; + public bool Enabled = false; + } + + public class UserProfileNotes + { + public UUID UserId; + public UUID TargetId; + public string Notes; + } + + public class UserAccountProperties + { + public string EmailAddress = string.Empty; + public string Firstname = string.Empty; + public string LastName = string.Empty; + 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; + public string DataKey = string.Empty; + public string UserId = UUID.Zero.ToString(); + public string DataVal = string.Empty; + } +} + diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs deleted file mode 100644 index bf24030..0000000 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ /dev/null @@ -1,176 +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.Generic; -using System.Globalization; -using System.Reflection; - -using OpenMetaverse; -using log4net; -using Nini.Config; -using Mono.Addins; - -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; -using OpenSim.Services.Interfaces; - -namespace OpenSim.Region.CoreModules.Avatar.Profile -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicProfileModule")] - public class BasicProfileModule : IProfileModule, ISharedRegionModule - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // - // Module vars - // - private List m_Scenes = new List(); - private bool m_Enabled = false; - - #region ISharedRegionModule - - public void Initialise(IConfigSource config) - { - m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); - m_Enabled = true; - } - - public void AddRegion(Scene scene) - { - if (!m_Enabled) - return; - - lock (m_Scenes) - { - if (!m_Scenes.Contains(scene)) - { - m_Scenes.Add(scene); - // Hook up events - scene.EventManager.OnNewClient += OnNewClient; - scene.RegisterModuleInterface(this); - } - } - } - - public void RegionLoaded(Scene scene) - { - if (!m_Enabled) - return; - } - - public void RemoveRegion(Scene scene) - { - if (!m_Enabled) - return; - - lock (m_Scenes) - { - m_Scenes.Remove(scene); - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "BasicProfileModule"; } - } - - public Type ReplaceableInterface - { - get { return typeof(IProfileModule); } - } - - #endregion - - /// New Client Event Handler - private void OnNewClient(IClientAPI client) - { - //Profile - client.OnRequestAvatarProperties += RequestAvatarProperties; - } - - public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) - { - IScene s = remoteClient.Scene; - if (!(s is Scene)) - return; - -// Scene scene = (Scene)s; - - string profileUrl = String.Empty; - string aboutText = String.Empty; - string firstLifeAboutText = String.Empty; - UUID image = UUID.Zero; - UUID firstLifeImage = UUID.Zero; - UUID partner = UUID.Zero; - uint wantMask = 0; - string wantText = String.Empty; - uint skillsMask = 0; - string skillsText = String.Empty; - string languages = String.Empty; - - UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, avatarID); - - string name = "Avatar"; - int created = 0; - if (account != null) - { - name = account.FirstName + " " + account.LastName; - created = account.Created; - } - Byte[] charterMember = Utils.StringToBytes(name); - - profileUrl = "No profile data"; - aboutText = string.Empty; - firstLifeAboutText = string.Empty; - image = UUID.Zero; - firstLifeImage = UUID.Zero; - partner = UUID.Zero; - - remoteClient.SendAvatarProperties(avatarID, aboutText, - Util.ToDateTime(created).ToString( - "M/d/yyyy", CultureInfo.InvariantCulture), - charterMember, firstLifeAboutText, - (uint)(0 & 0xff), - firstLifeImage, image, profileUrl, partner); - - //Viewer expects interest data when it asks for properties. - remoteClient.SendAvatarInterestsReply(avatarID, wantMask, wantText, - skillsMask, skillsText, languages); - } - - } -} diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs new file mode 100644 index 0000000..563617d --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -0,0 +1,1386 @@ +/* + * 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.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Xml; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using Mono.Addins; +using OpenSim.Services.Connectors.Hypergrid; + +namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")] + public class UserProfileModule : IProfileModule, INonSharedRegionModule + { + /// + /// Logging + /// + static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // The pair of Dictionaries are used to handle the switching of classified ads + // by maintaining a cache of classified id to creator id mappings and an interest + // count. The entries are removed when the interest count reaches 0. + Dictionary classifiedCache = new Dictionary(); + Dictionary classifiedInterest = new Dictionary(); + + public Scene Scene + { + get; private set; + } + + /// + /// Gets or sets the ConfigSource. + /// + /// + /// The configuration + /// + public IConfigSource Config { + get; + set; + } + + /// + /// Gets or sets the URI to the profile server. + /// + /// + /// The profile server URI. + /// + public string ProfileServerUri { + get; + set; + } + + IProfileModule ProfileModule + { + get; set; + } + + IUserManagement UserManagementModule + { + get; set; + } + + /// + /// Gets or sets a value indicating whether this + /// is enabled. + /// + /// + /// true if enabled; otherwise, false. + /// + public bool Enabled { + get; + set; + } + + #region IRegionModuleBase implementation + /// + /// This is called to initialize the region module. For shared modules, this is called exactly once, after + /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after + /// the instace for the region has been created. + /// + /// + /// Source. + /// + public void Initialise(IConfigSource source) + { + Config = source; + + IConfig profileConfig = Config.Configs["Profile"]; + + if (profileConfig == null) + { + Enabled = false; + return; + } + + // If we find ProfileURL then we configure for FULL support + // else we setup for BASIC support + ProfileServerUri = profileConfig.GetString("ProfileURL", ""); + if (ProfileServerUri == "") + { + m_log.Info("[PROFILES] UserProfiles module is activated in BASIC mode"); + Enabled = false; + return; + } + else + { + m_log.Info("[PROFILES] UserProfiles module is activated in FULL mode"); + Enabled = true; + } + } + + /// + /// Adds the region. + /// + /// + /// Scene. + /// + public void AddRegion(Scene scene) + { + Scene = scene; + Scene.RegisterModuleInterface(this); + Scene.EventManager.OnNewClient += OnNewClient; + Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent; + + UserManagementModule = Scene.RequestModuleInterface(); + } + + void HandleOnMakeRootAgent (ScenePresence obj) + { + GetImageAssets(((IScenePresence)obj).UUID); + } + + /// + /// Removes the region. + /// + /// + /// Scene. + /// + public void RemoveRegion(Scene scene) + { + } + + /// + /// This will be called once for every scene loaded. In a shared module this will be multiple times in one + /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion + /// has been called in all modules for that scene, providing an opportunity to request another module's + /// interface, or hook an event from another module. + /// + /// + /// Scene. + /// + public void RegionLoaded(Scene scene) + { + } + + /// + /// If this returns non-null, it is the type of an interface that this module intends to register. This will + /// cause the loader to defer loading of this module until all other modules have been loaded. If no other + /// module has registered the interface by then, this module will be activated, else it will remain inactive, + /// letting the other module take over. This should return non-null ONLY in modules that are intended to be + /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party + /// provided modules. + /// + /// + /// The replaceable interface. + /// + public Type ReplaceableInterface + { + get { return typeof(IProfileModule); } + } + + /// + /// Called as the instance is closed. + /// + public void Close() + { + } + + /// + /// The name of the module + /// + /// + /// Gets the module name. + /// + public string Name + { + get { return "UserProfileModule"; } + } + #endregion IRegionModuleBase implementation + + #region Region Event Handlers + /// + /// Raises the new client event. + /// + /// + /// Client. + /// + void OnNewClient(IClientAPI client) + { + // Basic or Full module? + if(!Enabled) + { + client.OnRequestAvatarProperties += BasicRequestProperties; + return; + } + + //Profile + client.OnRequestAvatarProperties += RequestAvatarProperties; + client.OnUpdateAvatarProperties += AvatarPropertiesUpdate; + client.OnAvatarInterestUpdate += AvatarInterestsUpdate; + + // Classifieds + client.AddGenericPacketHandler("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; + } + #endregion Region Event Handlers + + #region Classified + /// + /// + /// Handles the avatar classifieds request. + /// + /// + /// Sender. + /// + /// + /// Method. + /// + /// + /// Arguments. + /// + public void ClassifiedsRequest(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + + IClientAPI remoteClient = (IClientAPI)sender; + + UUID targetID; + UUID.TryParse(args[0], out targetID); + + // Can't handle NPC yet... + ScenePresence p = FindPresence(targetID); + + if (null != p) + { + if (p.PresenceType == PresenceType.Npc) + return; + } + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(targetID, out serverURI); + UUID creatorId = UUID.Zero; + + OSDMap parameters= new OSDMap(); + UUID.TryParse(args[0], out creatorId); + parameters.Add("creatorId", OSD.FromUUID(creatorId)); + OSD Params = (OSD)parameters; + if(!JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) + { + // Error Handling here! + // if(parameters.ContainsKey("message") + } + + parameters = (OSDMap)Params; + + OSDArray list = (OSDArray)parameters["result"]; + + Dictionary classifieds = new Dictionary(); + + foreach(OSD map in list) + { + OSDMap m = (OSDMap)map; + UUID cid = m["classifieduuid"].AsUUID(); + string name = m["name"].AsString(); + + classifieds[cid] = name; + + if(!classifiedCache.ContainsKey(cid)) + { + classifiedCache.Add(cid,creatorId); + classifiedInterest.Add(cid, 0); + } + + classifiedInterest[cid] ++; + } + + remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); + } + + public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient) + { + UUID target = remoteClient.AgentId; + UserClassifiedAdd ad = new UserClassifiedAdd(); + ad.ClassifiedId = queryClassifiedID; + + if(classifiedCache.ContainsKey(queryClassifiedID)) + { + target = classifiedCache[queryClassifiedID]; + + if(classifiedInterest[queryClassifiedID] -- == 0) + { + lock(classifiedCache) + { + lock(classifiedInterest) + { + classifiedInterest.Remove(queryClassifiedID); + } + classifiedCache.Remove(queryClassifiedID); + } + } + } + + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(target, out serverURI); + + object Ad = (object)ad; + if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error getting classified info", false); + return; + } + ad = (UserClassifiedAdd) Ad; + + if(ad.CreatorId == UUID.Zero) + return; + + Vector3 globalPos = new Vector3(); + Vector3.TryParse(ad.GlobalPos, out globalPos); + + 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, globalPos, ad.ParcelName, ad.Flags, ad.Price); + + } + + /// + /// Classifieds info update. + /// + /// + /// Queryclassified I. + /// + /// + /// Query category. + /// + /// + /// Query name. + /// + /// + /// Query description. + /// + /// + /// Query parcel I. + /// + /// + /// Query parent estate. + /// + /// + /// Query snapshot I. + /// + /// + /// Query global position. + /// + /// + /// Queryclassified flags. + /// + /// + /// Queryclassified price. + /// + /// + /// Remote client. + /// + public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID, + uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags, + int queryclassifiedPrice, IClientAPI remoteClient) + { + UserClassifiedAdd ad = new UserClassifiedAdd(); + + Scene s = (Scene) remoteClient.Scene; + Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; + ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); + ScenePresence p = FindPresence(remoteClient.AgentId); + Vector3 avaPos = p.AbsolutePosition; + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + + if (land == null) + { + ad.ParcelName = string.Empty; + } + else + { + ad.ParcelName = land.LandData.Name; + } + + ad.CreatorId = remoteClient.AgentId; + ad.ClassifiedId = queryclassifiedID; + ad.Category = Convert.ToInt32(queryCategory); + ad.Name = queryName; + ad.Description = queryDescription; + ad.ParentEstate = Convert.ToInt32(queryParentEstate); + ad.SnapshotId = querySnapshotID; + ad.SimName = remoteClient.Scene.RegionInfo.RegionName; + ad.GlobalPos = queryGlobalPos.ToString (); + ad.Flags = queryclassifiedFlags; + ad.Price = queryclassifiedPrice; + ad.ParcelId = p.currentParcelUUID; + + object Ad = ad; + + OSD X = OSD.SerializeMembers(Ad); + + if(!JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error updating classified", false); + } + } + + /// + /// Classifieds delete. + /// + /// + /// Query classified I. + /// + /// + /// Remote client. + /// + public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) + { + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + + UUID classifiedId; + OSDMap parameters= new OSDMap(); + UUID.TryParse(queryClassifiedID.ToString(), out classifiedId); + parameters.Add("classifiedId", OSD.FromUUID(classifiedId)); + OSD Params = (OSD)parameters; + if(!JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error classified delete", false); + } + + parameters = (OSDMap)Params; + } + #endregion Classified + + #region Picks + /// + /// Handles the avatar picks request. + /// + /// + /// Sender. + /// + /// + /// Method. + /// + /// + /// Arguments. + /// + public void PicksRequest(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + + IClientAPI remoteClient = (IClientAPI)sender; + + UUID targetId; + UUID.TryParse(args[0], out targetId); + + // Can't handle NPC yet... + ScenePresence p = FindPresence(targetId); + + if (null != p) + { + if (p.PresenceType == PresenceType.Npc) + return; + } + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(targetId, out serverURI); + + OSDMap parameters= new OSDMap(); + parameters.Add("creatorId", OSD.FromUUID(targetId)); + OSD Params = (OSD)parameters; + if(!JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error requesting picks", false); + return; + } + + parameters = (OSDMap)Params; + + OSDArray list = (OSDArray)parameters["result"]; + + Dictionary picks = new Dictionary(); + + foreach(OSD map in list) + { + 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); + } + + /// + /// Handles the pick info request. + /// + /// + /// Sender. + /// + /// + /// Method. + /// + /// + /// Arguments. + /// + public void PickInfoRequest(Object sender, string method, List args) + { + if (!(sender is IClientAPI)) + return; + + UUID targetID; + UUID.TryParse(args[0], out targetID); + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(targetID, out serverURI); + 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(!JsonRpcRequest(ref Pick, "pickinforequest", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error selecting pick", false); + } + pick = (UserProfilePick) Pick; + if(pick.SnapshotId == UUID.Zero) + { + // In case of a new UserPick, the data may not be ready and we would send wrong data, skip it... + m_log.DebugFormat("[PROFILES]: PickInfoRequest: SnapshotID is {0}", UUID.Zero.ToString()); + return; + } + + Vector3 globalPos; + Vector3.TryParse(pick.GlobalPos,out globalPos); + + m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); + + remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, + pick.Desc,pick.SnapshotId,pick.User,pick.OriginalName,pick.SimName, + globalPos,pick.SortOrder,pick.Enabled); + } + + /// + /// Updates the userpicks + /// + /// + /// Remote client. + /// + /// + /// Pick I. + /// + /// + /// the creator of the pick + /// + /// + /// Top pick. + /// + /// + /// Name. + /// + /// + /// Desc. + /// + /// + /// Snapshot I. + /// + /// + /// Sort order. + /// + /// + /// Enabled. + /// + public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled) + { + + m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); + UserProfilePick pick = new UserProfilePick(); + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + ScenePresence p = FindPresence(remoteClient.AgentId); + + Vector3 avaPos = p.AbsolutePosition; + // Getting the global position for the Avatar + Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X, + remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y, + avaPos.Z); + + string landOwnerName = string.Empty; + ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y); + if(land.LandData.IsGroupOwned) + { + IGroupsModule groupMod = p.Scene.RequestModuleInterface(); + UUID groupId = land.LandData.GroupID; + GroupRecord groupRecord = groupMod.GetGroupRecord(groupId); + landOwnerName = groupRecord.GroupName; + } + else + { + IUserAccountService accounts = p.Scene.RequestModuleInterface(); + UserAccount user = accounts.GetUserAccount(p.Scene.RegionInfo.ScopeID, land.LandData.OwnerID); + landOwnerName = user.Name; + } + + pick.PickId = pickID; + pick.CreatorId = creatorID; + pick.TopPick = topPick; + pick.Name = name; + pick.Desc = desc; + pick.ParcelId = p.currentParcelUUID; + pick.SnapshotId = snapshotID; + pick.User = landOwnerName; + pick.SimName = remoteClient.Scene.RegionInfo.RegionName; + pick.GlobalPos = posGlobal.ToString(); + pick.SortOrder = sortOrder; + pick.Enabled = enabled; + + object Pick = (object)pick; + if(!JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error updating pick", false); + } + + m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString()); + } + + /// + /// Delete a Pick + /// + /// + /// Remote client. + /// + /// + /// Query pick I. + /// + public void PickDelete(IClientAPI remoteClient, UUID queryPickID) + { + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + + OSDMap parameters= new OSDMap(); + parameters.Add("pickId", OSD.FromUUID(queryPickID)); + OSD Params = (OSD)parameters; + if(!JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error picks delete", false); + } + } + #endregion Picks + + #region Notes + /// + /// Handles the avatar notes request. + /// + /// + /// Sender. + /// + /// + /// Method. + /// + /// + /// Arguments. + /// + public void NotesRequest(Object sender, string method, List args) + { + UserProfileNotes note = new UserProfileNotes(); + + if (!(sender is IClientAPI)) + return; + + IClientAPI remoteClient = (IClientAPI)sender; + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + note.TargetId = remoteClient.AgentId; + UUID.TryParse(args[0], out note.UserId); + + object Note = (object)note; + if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error requesting note", false); + } + note = (UserProfileNotes) Note; + + remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); + } + + /// + /// Avatars the notes update. + /// + /// + /// Remote client. + /// + /// + /// Query target I. + /// + /// + /// Query notes. + /// + public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes) + { + UserProfileNotes note = new UserProfileNotes(); + + note.UserId = remoteClient.AgentId; + note.TargetId = queryTargetID; + note.Notes = queryNotes; + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + + object Note = note; + if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error updating note", false); + } + } + #endregion Notes + + #region Avatar Properties + /// + /// Update the avatars interests . + /// + /// + /// Remote client. + /// + /// + /// Wantmask. + /// + /// + /// Wanttext. + /// + /// + /// Skillsmask. + /// + /// + /// Skillstext. + /// + /// + /// Languages. + /// + public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages) + { + UserProfileProperties prop = new UserProfileProperties(); + + prop.UserId = remoteClient.AgentId; + prop.WantToMask = (int)wantmask; + prop.WantToText = wanttext; + prop.SkillsMask = (int)skillsmask; + prop.SkillsText = skillstext; + prop.Language = languages; + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + + object Param = prop; + if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error updating interests", false); + } + } + + public void BasicRequestProperties(IClientAPI remoteClient, UUID avatarID) + { + IScene s = remoteClient.Scene; + if (!(s is Scene)) + return; + + string profileUrl = String.Empty; + string aboutText = String.Empty; + string firstLifeAboutText = String.Empty; + UUID image = UUID.Zero; + UUID firstLifeImage = UUID.Zero; + UUID partner = UUID.Zero; + uint wantMask = 0; + string wantText = String.Empty; + uint skillsMask = 0; + string skillsText = String.Empty; + string languages = String.Empty; + + UserAccount account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID); + + string name = "Avatar"; + int created = 0; + if (account != null) + { + name = account.FirstName + " " + account.LastName; + created = account.Created; + } + Byte[] charterMember = Utils.StringToBytes(name); + + profileUrl = "No profile data"; + aboutText = string.Empty; + firstLifeAboutText = string.Empty; + image = UUID.Zero; + firstLifeImage = UUID.Zero; + partner = UUID.Zero; + + remoteClient.SendAvatarProperties(avatarID, aboutText, + Util.ToDateTime(created).ToString( + "M/d/yyyy", CultureInfo.InvariantCulture), + charterMember, firstLifeAboutText, + (uint)(0 & 0xff), + firstLifeImage, image, profileUrl, partner); + + //Viewer expects interest data when it asks for properties. + remoteClient.SendAvatarInterestsReply(avatarID, wantMask, wantText, + skillsMask, skillsText, languages); + } + + /// + /// Requests the avatar properties. + /// + /// + /// Remote client. + /// + /// + /// Avatar I. + /// + public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) + { + if ( String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString())) + { + // Looking for a reason that some viewers are sending null Id's + m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID); + return; + } + + // Can't handle NPC yet... + ScenePresence p = FindPresence(avatarID); + + if (null != p) + { + if (p.PresenceType == PresenceType.Npc) + return; + } + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(avatarID, out serverURI); + + UserAccount account = null; + Dictionary userInfo; + + if (!foreign) + { + account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID); + } + else + { + userInfo = new Dictionary(); + } + + Byte[] charterMember = new Byte[1]; + string born = String.Empty; + uint flags = 0x00; + + if (null != account) + { + if (account.UserTitle == "") + { + charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8); + } + else + { + charterMember = Utils.StringToBytes(account.UserTitle); + } + + born = Util.ToDateTime(account.Created).ToString( + "M/d/yyyy", CultureInfo.InvariantCulture); + flags = (uint)(account.UserFlags & 0xff); + } + else + { + if (GetUserAccountData(avatarID, out userInfo) == true) + { + if ((string)userInfo["user_title"] == "") + { + charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); + } + else + { + charterMember = Utils.StringToBytes((string)userInfo["user_title"]); + } + + int val_born = (int)userInfo["user_created"]; + born = Util.ToDateTime(val_born).ToString( + "M/d/yyyy", CultureInfo.InvariantCulture); + + // picky, picky + int val_flags = (int)userInfo["user_flags"]; + flags = (uint)(val_flags & 0xff); + } + } + + UserProfileProperties props = new UserProfileProperties(); + string result = string.Empty; + + props.UserId = avatarID; + GetProfileData(ref props, out result); + + remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , 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); + } + + /// + /// Updates the avatar properties. + /// + /// + /// Remote client. + /// + /// + /// New profile. + /// + public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile) + { + if (remoteClient.AgentId == newProfile.ID) + { + UserProfileProperties prop = new UserProfileProperties(); + + prop.UserId = remoteClient.AgentId; + prop.WebUrl = newProfile.ProfileUrl; + prop.ImageId = newProfile.Image; + prop.AboutText = newProfile.AboutText; + prop.FirstLifeImageId = newProfile.FirstLifeImage; + prop.FirstLifeText = newProfile.FirstLifeAboutText; + + string serverURI = string.Empty; + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + + object Prop = prop; + + if(!JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString())) + { + remoteClient.SendAgentAlertMessage( + "Error updating properties", false); + } + + RequestAvatarProperties(remoteClient, newProfile.ID); + } + } + + + /// + /// Gets the profile data. + /// + /// + /// The profile data. + /// + /// + /// User I. + /// + bool GetProfileData(ref UserProfileProperties properties, 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; + bool foreign = 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"; + return false; + } + + object Prop = (object)properties; + JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()); + properties = (UserProfileProperties)Prop; + + message = "Success"; + return true; + } + #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"); + + OSDMap parameters= new OSDMap(); + parameters.Add("avatarId", OSD.FromUUID(avatarId)); + OSD Params = (OSD)parameters; + if(!JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString())) + { + // Error Handling here! + // if(parameters.ContainsKey("message") + return false; + } + + parameters = (OSDMap)Params; + + OSDArray list = (OSDArray)parameters["result"]; + + foreach(OSD asset in list) + { + OSDString assetId = (OSDString)asset; + + Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString()), this, + delegate (string assetID, Object s, AssetBase a) + { + // m_log.DebugFormat("[PROFILES]: Getting Image Assets {0}", assetID); + return; + }); + } + return true; + } + + /// + /// Gets the user account data. + /// + /// + /// The user profile data. + /// + /// + /// If set to true user I. + /// + /// + /// If set to true user info. + /// + bool GetUserAccountData(UUID userID, out Dictionary userInfo) + { + Dictionary info = new Dictionary(); + + if (UserManagementModule.IsLocalGridUser(userID)) + { + // Is local + IUserAccountService uas = Scene.UserAccountService; + UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID); + + info["user_flags"] = account.UserFlags; + info["user_created"] = account.Created; + + if (!String.IsNullOrEmpty(account.UserTitle)) + info["user_title"] = account.UserTitle; + else + info["user_title"] = ""; + + userInfo = info; + + return false; + } + else + { + // Is Foreign + string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI"); + + if (String.IsNullOrEmpty(home_url)) + { + info["user_flags"] = 0; + info["user_created"] = 0; + info["user_title"] = "Unavailable"; + + userInfo = info; + return true; + } + + UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url); + + Dictionary account = uConn.GetUserInfo(userID); + + if (account.Count > 0) + { + if (account.ContainsKey("user_flags")) + info["user_flags"] = account["user_flags"]; + else + info["user_flags"] = ""; + + if (account.ContainsKey("user_created")) + info["user_created"] = account["user_created"]; + else + info["user_created"] = ""; + + info["user_title"] = "HG Visitor"; + } + else + { + info["user_flags"] = 0; + info["user_created"] = 0; + info["user_title"] = "HG Visitor"; + } + userInfo = info; + return true; + } + } + + /// + /// Gets the user profile server UR. + /// + /// + /// The user profile server UR. + /// + /// + /// If set to true user I. + /// + /// + /// If set to true server UR. + /// + bool GetUserProfileServerURI(UUID userID, out string serverURI) + { + bool local; + local = UserManagementModule.IsLocalGridUser(userID); + + if (!local) + { + serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI"); + // Is Foreign + return true; + } + else + { + serverURI = ProfileServerUri; + // Is local + return false; + } + } + + /// + /// Finds the presence. + /// + /// + /// The presence. + /// + /// + /// Client I. + /// + ScenePresence FindPresence(UUID clientID) + { + ScenePresence p; + + p = Scene.GetScenePresence(clientID); + if (p != null && !p.IsChildAgent) + return p; + + return null; + } + #endregion Util + + #region Web Util + /// + /// Sends json-rpc request with a serializable type. + /// + /// + /// OSD Map. + /// + /// + /// Serializable type . + /// + /// + /// Json-rpc method to call. + /// + /// + /// URI of json-rpc service. + /// + /// + /// Id for our call. + /// + bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId) + { + if (jsonId == null) + throw new ArgumentNullException ("jsonId"); + if (uri == null) + throw new ArgumentNullException ("uri"); + if (method == null) + throw new ArgumentNullException ("method"); + if (parameters == null) + throw new ArgumentNullException ("parameters"); + + // Prep our payload + OSDMap json = new OSDMap(); + + json.Add("jsonrpc", OSD.FromString("2.0")); + json.Add("id", OSD.FromString(jsonId)); + json.Add("method", OSD.FromString(method)); + // Experiment + json.Add("params", OSD.SerializeMembers(parameters)); + + string jsonRequestData = OSDParser.SerializeJsonString(json); + byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); + + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + // webRequest.Credentials = new NetworkCredential(rpcUser, rpcPass); + webRequest.ContentType = "application/json-rpc"; + webRequest.Method = "POST"; + + Stream dataStream = webRequest.GetRequestStream(); + dataStream.Write(content, 0, content.Length); + dataStream.Close(); + + WebResponse webResponse = null; + try + { + webResponse = webRequest.GetResponse(); + } + catch (WebException e) + { + Console.WriteLine("Web Error" + e.Message); + Console.WriteLine ("Please check input"); + return false; + } + + byte[] buf = new byte[8192]; + Stream rstream = webResponse.GetResponseStream(); + OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); + + if(mret.ContainsKey("error")) + return false; + + // get params... + OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]); + return true; + } + + /// + /// Sends json-rpc request with OSD parameter. + /// + /// + /// The rpc request. + /// + /// + /// data - incoming as parameters, outgong as result/error + /// + /// + /// Json-rpc method to call. + /// + /// + /// URI of json-rpc service. + /// + /// + /// If set to true json identifier. + /// + bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId) + { + OSDMap map = new OSDMap(); + + map["jsonrpc"] = "2.0"; + if(string.IsNullOrEmpty(jsonId)) + map["id"] = UUID.Random().ToString(); + else + map["id"] = jsonId; + + map["method"] = method; + map["params"] = data; + + string jsonRequestData = OSDParser.SerializeJsonString(map); + byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); + + HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + webRequest.ContentType = "application/json-rpc"; + webRequest.Method = "POST"; + + Stream dataStream = webRequest.GetRequestStream(); + dataStream.Write(content, 0, content.Length); + dataStream.Close(); + + WebResponse webResponse = null; + try + { + webResponse = webRequest.GetResponse(); + } + catch (WebException e) + { + Console.WriteLine("Web Error" + e.Message); + Console.WriteLine ("Please check input"); + return false; + } + + byte[] buf = new byte[8192]; + Stream rstream = webResponse.GetResponseStream(); + + OSDMap response = new OSDMap(); + response = (OSDMap)OSDParser.DeserializeJson(rstream); + if(response.ContainsKey("error")) + { + data = response["error"]; + return false; + } + + data = response; + + return true; + } + #endregion Web Util + } +} diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs new file mode 100644 index 0000000..323535a --- /dev/null +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs @@ -0,0 +1,226 @@ + +/* + * 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 log4net; +using Mono.Addins; +using Nini.Config; +using System; +using System.Collections.Generic; +using System.Reflection; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Server.Base; +using OpenSim.Server.Handlers; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.Servers; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; +using OpenMetaverse; + +namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalUserProfilesServicesConnector")] + public class LocalUserProfilesServicesConnector : ISharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private Dictionary regions = new Dictionary(); + + public IUserProfilesService ServiceModule + { + get; private set; + } + + public bool Enabled + { + get; private set; + } + + public string Name + { + get + { + return "LocalUserProfilesServicesConnector"; + } + } + + public string ConfigName + { + get; private set; + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public LocalUserProfilesServicesConnector() + { + m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params"); + } + + public LocalUserProfilesServicesConnector(IConfigSource source) + { + m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly."); + InitialiseService(source); + } + + public void InitialiseService(IConfigSource source) + { + ConfigName = "UserProfilesService"; + + // Instantiate the request handler + IHttpServer Server = MainServer.Instance; + + IConfig config = source.Configs[ConfigName]; + if (config == null) + { + m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini"); + return; + } + + if(!config.GetBoolean("Enabled",false)) + { + Enabled = false; + return; + } + + Enabled = true; + + string serviceDll = config.GetString("LocalServiceModule", + String.Empty); + + if (serviceDll == String.Empty) + { + m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService"); + return; + } + + Object[] args = new Object[] { source, ConfigName }; + ServiceModule = + ServerUtils.LoadPlugin(serviceDll, + args); + + if (ServiceModule == null) + { + m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service"); + return; + } + + Enabled = true; + + JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule); + + Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest); + Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate); + Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest); + Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete); + Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest); + Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest); + Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate); + Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete); + Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest); + Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate); + Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); + Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); + Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); + Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); + Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); + Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); + + } + + #region ISharedRegionModule implementation + + void ISharedRegionModule.PostInitialise() + { + if(!Enabled) + return; + } + + #endregion + + #region IRegionModuleBase implementation + + void IRegionModuleBase.Initialise(IConfigSource source) + { + IConfig moduleConfig = source.Configs["Modules"]; + if (moduleConfig != null) + { + string name = moduleConfig.GetString("UserProfilesServices", ""); + if (name == Name) + { + InitialiseService(source); + m_log.Info("[LOCAL USERPROFILES SERVICE CONNECTOR]: Local user profiles connector enabled"); + } + } + } + + void IRegionModuleBase.Close() + { + return; + } + + void IRegionModuleBase.AddRegion(Scene scene) + { + if (!Enabled) + return; + + lock (regions) + { + if (regions.ContainsKey(scene.RegionInfo.RegionID)) + m_log.ErrorFormat("[LOCAL USERPROFILES SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); + else + regions.Add(scene.RegionInfo.RegionID, scene); + } + } + + void IRegionModuleBase.RemoveRegion(Scene scene) + { + if (!Enabled) + return; + + lock (regions) + { + if (regions.ContainsKey(scene.RegionInfo.RegionID)) + regions.Remove(scene.RegionInfo.RegionID); + } + } + + void IRegionModuleBase.RegionLoaded(Scene scene) + { + if (!Enabled) + return; + } + #endregion + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index c32820e..3849a3f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs @@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public LocalGridServicesConnector() { + m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms."); } public LocalGridServicesConnector(IConfigSource source) diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs new file mode 100644 index 0000000..4ad7297 --- /dev/null +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs @@ -0,0 +1,92 @@ +using System; +using System.Reflection; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; +using OpenSim.Server.Handlers.Base; +using log4net; + +namespace OpenSim.Server.Handlers.Profiles +{ + public class UserProfilesConnector: ServiceConnector + { + static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + + // Our Local Module + public IUserProfilesService ServiceModule + { + get; private set; + } + + // The HTTP server. + public IHttpServer Server + { + get; private set; + } + + public string ConfigName + { + get; private set; + } + + public bool Enabled + { + get; private set; + } + + public UserProfilesConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + ConfigName = "UserProfilesService"; + if(!string.IsNullOrEmpty(configName)) + ConfigName = configName; + + IConfig serverConfig = config.Configs[ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section {0} in config file", ConfigName)); + + if(!serverConfig.GetBoolean("Enabled",false)) + { + Enabled = false; + return; + } + + Enabled = true; + + Server = server; + + string service = serverConfig.GetString("LocalServiceModule", String.Empty); + + Object[] args = new Object[] { config, ConfigName }; + ServiceModule = ServerUtils.LoadPlugin(service, args); + + JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule); + + Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest); + Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate); + Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest); + Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete); + Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest); + Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest); + Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate); + Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete); + Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest); + Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate); + Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); + Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); + Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); + Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); +// Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest); +// Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferencesUpdate); +// Server.AddJsonRPCHandler("user_account_create", handler.UserAccountCreate); +// Server.AddJsonRPCHandler("user_account_auth", handler.UserAccountAuth); +// Server.AddJsonRPCHandler("user_account_test", handler.UserAccountTest); + Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); + Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); + } + } +} + diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs new file mode 100644 index 0000000..93da102 --- /dev/null +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs @@ -0,0 +1,434 @@ +using System; +using System.Reflection; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using log4net; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; + +namespace OpenSim.Server.Handlers +{ + public class UserProfilesHandlers + { + public UserProfilesHandlers () + { + } + } + + public class JsonRpcProfileHandlers + { + static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + public IUserProfilesService Service + { + get; private set; + } + + public JsonRpcProfileHandlers(IUserProfilesService service) + { + Service = service; + } + + #region Classifieds + /// + /// Request avatar's classified ads. + /// + /// + /// An array containing all the calassified uuid and it's name created by the creator id + /// + /// + /// Our parameters are in the OSDMap json["params"] + /// + /// + /// If set to true response. + /// + public bool AvatarClassifiedsRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Classified Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID creatorId = new UUID(request["creatorId"].AsString()); + + + OSDArray data = (OSDArray) Service.AvatarClassifiedsRequest(creatorId); + response.Result = data; + + return true; + } + + public bool ClassifiedUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "Error parsing classified update request"; + m_log.DebugFormat ("Classified Update Request"); + return false; + } + + string result = string.Empty; + UserClassifiedAdd ad = new UserClassifiedAdd(); + object Ad = (object)ad; + OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]); + if(Service.ClassifiedUpdate(ad, ref result)) + { + response.Result = OSD.SerializeMembers(ad); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool ClassifiedDelete(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Classified Delete Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID classifiedId = new UUID(request["classifiedID"].AsString()); + + OSDMap res = new OSDMap(); + res["result"] = OSD.FromString("success"); + response.Result = res; + + return true; + + } + + public bool ClassifiedInfoRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Classified Info Request"); + return false; + } + + string result = string.Empty; + UserClassifiedAdd ad = new UserClassifiedAdd(); + object Ad = (object)ad; + OSD.DeserializeMembers(ref Ad, (OSDMap)json["params"]); + if(Service.ClassifiedInfoRequest(ref ad, ref result)) + { + response.Result = OSD.SerializeMembers(ad); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion Classifieds + + #region Picks + public bool AvatarPicksRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Avatar Picks Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID creatorId = new UUID(request["creatorId"].AsString()); + + + OSDArray data = (OSDArray) Service.AvatarPicksRequest(creatorId); + response.Result = data; + + return true; + } + + public bool PickInfoRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Picks Info Request"); + return false; + } + + string result = string.Empty; + UserProfilePick pick = new UserProfilePick(); + object Pick = (object)pick; + OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]); + if(Service.PickInfoRequest(ref pick, ref result)) + { + response.Result = OSD.SerializeMembers(pick); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool PicksUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Picks Update Request"); + return false; + } + + string result = string.Empty; + UserProfilePick pick = new UserProfilePick(); + object Pick = (object)pick; + OSD.DeserializeMembers(ref Pick, (OSDMap)json["params"]); + if(Service.PicksUpdate(ref pick, ref result)) + { + response.Result = OSD.SerializeMembers(pick); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = "unable to update pick"; + + return false; + } + + public bool PicksDelete(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Avatar Picks Delete Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID pickId = new UUID(request["pickId"].AsString()); + if(Service.PicksDelete(pickId)) + return true; + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = "data error removing record"; + return false; + } + #endregion Picks + + #region Notes + public bool AvatarNotesRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "Params missing"; + m_log.DebugFormat ("Avatar Notes Request"); + return false; + } + + string result = string.Empty; + UserProfileNotes note = new UserProfileNotes(); + object Note = (object)note; + OSD.DeserializeMembers(ref Note, (OSDMap)json["params"]); + if(Service.AvatarNotesRequest(ref note)) + { + response.Result = OSD.SerializeMembers(note); + return true; + } + + object Notes = (object) note; + OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]); + return true; + } + + public bool NotesUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "No parameters"; + m_log.DebugFormat ("Avatar Notes Update Request"); + return false; + } + + string result = string.Empty; + UserProfileNotes note = new UserProfileNotes(); + object Notes = (object) note; + OSD.DeserializeMembers(ref Notes, (OSDMap)json["params"]); + if(Service.NotesUpdate(ref note, ref result)) + { + response.Result = OSD.SerializeMembers(note); + return true; + } + return true; + } + #endregion Notes + + #region Profile Properties + public bool AvatarPropertiesRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Properties Request"); + return false; + } + + string result = string.Empty; + UserProfileProperties props = new UserProfileProperties(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.AvatarPropertiesRequest(ref props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool AvatarPropertiesUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Properties Update Request"); + return false; + } + + string result = string.Empty; + UserProfileProperties props = new UserProfileProperties(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.AvatarPropertiesUpdate(ref props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion Profile Properties + + #region Interests + public bool AvatarInterestsUpdate(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("Avatar Interests Update Request"); + return false; + } + + string result = string.Empty; + UserProfileProperties props = new UserProfileProperties(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.AvatarInterestsUpdate(props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion Interests + + #region Utility + public bool AvatarImageAssetsRequest(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + m_log.DebugFormat ("Avatar Image Assets Request"); + return false; + } + + OSDMap request = (OSDMap)json["params"]; + UUID avatarId = new UUID(request["avatarId"].AsString()); + + OSDArray data = (OSDArray) Service.AvatarImageAssetsRequest(avatarId); + response.Result = data; + + return true; + } + #endregion Utiltiy + + #region UserData + public bool RequestUserAppData(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("User Application Service URL Request: No Parameters!"); + return false; + } + + string result = string.Empty; + UserAppData props = new UserAppData(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.RequestUserAppData(ref props, ref result)) + { + OSDMap res = new OSDMap(); + res["result"] = OSD.FromString("success"); + res["token"] = OSD.FromString (result); + response.Result = res; + + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + + public bool UpdateUserAppData(OSDMap json, ref JsonRpcResponse response) + { + if(!json.ContainsKey("params")) + { + response.Error.Code = ErrorCode.ParseError; + response.Error.Message = "no parameters supplied"; + m_log.DebugFormat ("User App Data Update Request"); + return false; + } + + string result = string.Empty; + UserAppData props = new UserAppData(); + object Props = (object)props; + OSD.DeserializeMembers(ref Props, (OSDMap)json["params"]); + if(Service.SetUserAppData(props, ref result)) + { + response.Result = OSD.SerializeMembers(props); + return true; + } + + response.Error.Code = ErrorCode.InternalError; + response.Error.Message = string.Format("{0}", result); + return false; + } + #endregion UserData + } +} + diff --git a/OpenSim/Services/Interfaces/IUserProfilesService.cs b/OpenSim/Services/Interfaces/IUserProfilesService.cs new file mode 100644 index 0000000..12fc986 --- /dev/null +++ b/OpenSim/Services/Interfaces/IUserProfilesService.cs @@ -0,0 +1,48 @@ +using System; +using OpenSim.Framework; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +namespace OpenSim.Services.Interfaces +{ + public interface IUserProfilesService + { + #region Classifieds + OSD AvatarClassifiedsRequest(UUID creatorId); + bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result); + bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result); + bool ClassifiedDelete(UUID recordId); + #endregion Classifieds + + #region Picks + OSD AvatarPicksRequest(UUID creatorId); + bool PickInfoRequest(ref UserProfilePick pick, ref string result); + bool PicksUpdate(ref UserProfilePick pick, ref string result); + bool PicksDelete(UUID pickId); + #endregion Picks + + #region Notes + bool AvatarNotesRequest(ref UserProfileNotes note); + bool NotesUpdate(ref UserProfileNotes note, ref string result); + #endregion Notes + + #region Profile Properties + bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result); + bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result); + #endregion Profile Properties + + #region Interests + bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result); + #endregion Interests + + #region Utility + OSD AvatarImageAssetsRequest(UUID avatarId); + #endregion Utility + + #region UserData + bool RequestUserAppData(ref UserAppData prop, ref string result); + bool SetUserAppData(UserAppData prop, ref string result); + #endregion UserData + } +} + diff --git a/OpenSim/Services/UserProfilesService/UserProfilesService.cs b/OpenSim/Services/UserProfilesService/UserProfilesService.cs new file mode 100644 index 0000000..959c661 --- /dev/null +++ b/OpenSim/Services/UserProfilesService/UserProfilesService.cs @@ -0,0 +1,160 @@ +using System; +using System.Reflection; +using System.Text; +using Nini.Config; +using log4net; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Services.UserAccountService; +using OpenSim.Data; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Services.ProfilesService +{ + public class UserProfilesService: UserProfilesServiceBase, IUserProfilesService + { + static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + IUserAccountService userAccounts; + IAuthenticationService authService; + + public UserProfilesService(IConfigSource config, string configName): + base(config, configName) + { + IConfig Config = config.Configs[configName]; + if (Config == null) + { + m_log.Warn("[PROFILES]: No configuration found!"); + return; + } + Object[] args = null; + + args = new Object[] { config }; + string accountService = Config.GetString("UserAccountService", String.Empty); + if (accountService != string.Empty) + userAccounts = ServerUtils.LoadPlugin(accountService, args); + + args = new Object[] { config }; + string authServiceConfig = Config.GetString("AuthenticationServiceModule", String.Empty); + if (accountService != string.Empty) + authService = ServerUtils.LoadPlugin(authServiceConfig, args); + } + + #region Classifieds + public OSD AvatarClassifiedsRequest(UUID creatorId) + { + OSDArray records = ProfilesData.GetClassifiedRecords(creatorId); + + return records; + } + + public bool ClassifiedUpdate(UserClassifiedAdd ad, ref string result) + { + if(!ProfilesData.UpdateClassifiedRecord(ad, ref result)) + { + return false; + } + result = "success"; + return true; + } + + public bool ClassifiedDelete(UUID recordId) + { + if(ProfilesData.DeleteClassifiedRecord(recordId)) + return true; + + return false; + } + + public bool ClassifiedInfoRequest(ref UserClassifiedAdd ad, ref string result) + { + if(ProfilesData.GetClassifiedInfo(ref ad, ref result)) + return true; + + return false; + } + #endregion Classifieds + + #region Picks + public OSD AvatarPicksRequest(UUID creatorId) + { + OSDArray records = ProfilesData.GetAvatarPicks(creatorId); + + return records; + } + + public bool PickInfoRequest(ref UserProfilePick pick, ref string result) + { + pick = ProfilesData.GetPickInfo(pick.CreatorId, pick.PickId); + result = "OK"; + return true; + } + + public bool PicksUpdate(ref UserProfilePick pick, ref string result) + { + return ProfilesData.UpdatePicksRecord(pick); + } + + public bool PicksDelete(UUID pickId) + { + return ProfilesData.DeletePicksRecord(pickId); + } + #endregion Picks + + #region Notes + public bool AvatarNotesRequest(ref UserProfileNotes note) + { + return ProfilesData.GetAvatarNotes(ref note); + } + + public bool NotesUpdate(ref UserProfileNotes note, ref string result) + { + return ProfilesData.UpdateAvatarNotes(ref note, ref result); + } + #endregion Notes + + #region Profile Properties + public bool AvatarPropertiesRequest(ref UserProfileProperties prop, ref string result) + { + return ProfilesData.GetAvatarProperties(ref prop, ref result); + } + + public bool AvatarPropertiesUpdate(ref UserProfileProperties prop, ref string result) + { + return ProfilesData.UpdateAvatarProperties(ref prop, ref result); + } + #endregion Profile Properties + + #region Interests + public bool AvatarInterestsUpdate(UserProfileProperties prop, ref string result) + { + return ProfilesData.UpdateAvatarInterests(prop, ref result); + } + #endregion Interests + + #region Utility + public OSD AvatarImageAssetsRequest(UUID avatarId) + { + OSDArray records = ProfilesData.GetUserImageAssets(avatarId); + return records; + } + #endregion Utility + + #region UserData + public bool RequestUserAppData(ref UserAppData prop, ref string result) + { + return ProfilesData.GetUserAppData(ref prop, ref result); + } + + public bool SetUserAppData(UserAppData prop, ref string result) + { + return true; + } + #endregion UserData + } +} + diff --git a/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs new file mode 100644 index 0000000..dc0be03 --- /dev/null +++ b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs @@ -0,0 +1,59 @@ +using System; +using System.Reflection; +using Nini.Config; +using log4net; +using OpenSim.Services.Base; +using OpenSim.Data; + +namespace OpenSim.Services.ProfilesService +{ + public class UserProfilesServiceBase: ServiceBase + { + static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + public IProfilesData ProfilesData; + + public string ConfigName + { + get; private set; + } + + public UserProfilesServiceBase(IConfigSource config, string configName): + base(config) + { + if(string.IsNullOrEmpty(configName)) + { + m_log.WarnFormat("[PROFILES]: Configuration section not given!"); + return; + } + + string dllName = String.Empty; + string connString = null; + string realm = String.Empty; + + IConfig dbConfig = config.Configs["DatabaseService"]; + if (dbConfig != null) + { + if (dllName == String.Empty) + dllName = dbConfig.GetString("StorageProvider", String.Empty); + if (string.IsNullOrEmpty(connString)) + connString = dbConfig.GetString("ConnectionString", String.Empty); + } + + IConfig ProfilesConfig = config.Configs[configName]; + if (ProfilesConfig != null) + { + connString = ProfilesConfig.GetString("ConnectionString", connString); + realm = ProfilesConfig.GetString("Realm", realm); + } + + ProfilesData = LoadPlugin(dllName, new Object[] { connString }); + if (ProfilesData == null) + throw new Exception("Could not find a storage interface in the given module"); + + } + } +} + diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 5e486d4..38e2a07 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1032,6 +1032,12 @@ ;# {InitialTerrain} {} {Initial terrain type} {pinhead-island flat} pinhead-island ; InitialTerrain = "pinhead-island" +[Profile] + ;# {ProfileURL} {} {Set url to UserProfilesService} {} + ;; Set the value of the url to your UserProfilesService + ;; If un-set / "" the module is disabled + ;; ProfileURL = http://127.0.0.1:8002 + [Architecture] ;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini ;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim, diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 81843b1..237f684 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -377,6 +377,19 @@ AllowRegionRestartFromClient = true +[UserProfiles] + ;# {ProfileURL} {} {Set url to UserProfilesService} {} + ;; Set the value of the url to your UserProfilesService + ;; If un-set / "" the module is disabled + ;; If the ProfileURL is not set, then very BASIC + ;; profile support will be configured. If the ProfileURL is set to a + ;; valid URL, then full profile support will be configured. The URL + ;; points to your grid's Robust user profiles service + ;; + ; ProfileURL = http://127.0.0.1:9000 + + + [SMTP] enabled = false diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index bc2b4cf..d9f1ca1 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -71,10 +71,12 @@ HGInventoryServiceConnector = "HGInventoryService@8002/OpenSim.Server.Handlers.d HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:AssetServiceConnector" ;; Uncomment this if you want Groups V2, HG to work ; HGGroupsServiceConnector = "8002/OpenSim.Addons.Groups.dll:HGGroupsServiceRobustConnector" - ;; Additions for other add-on modules. For example: ;; WifiServerConnector = "8002/Diva.Wifi.dll:WifiServerConnector" +;; Uncomment for UserProfiles see [UserProfilesService] to configure... +; UserProfilesServiceConnector = "8002/OpenSim.Server.Handlers.dll:UserProfilesConnector" + ; * This is common for all services, it's the network setup for the entire ; * server instance, if none is specified above ; * @@ -595,4 +597,12 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ;; Can overwrite the default in [Hypergrid], but probably shouldn't ; HomeURI = "http://127.0.0.1:8002" +[UserProfilesService] + LocalServiceModule = "OpenSim.Services.UserProfilesService.dll:UserProfilesService" + Enabled = false + ;; Configure this for separate profiles database + ;; ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=*****;Old Guids=true;" + ;; Realm = UserProfiles + UserAccountService = OpenSim.Services.UserAccountService.dll:UserAccountService + AuthenticationServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 1d66b7f..7d6492b 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -51,6 +51,8 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ;; Uncomment this if you want Groups V2 to work ;GroupsServiceConnector = "8003/OpenSim.Addons.Groups.dll:GroupsServiceRobustConnector" +;; Uncomment for UserProfiles see [UserProfilesService] to configure... +; UserProfilesServiceConnector = "8002/OpenSim.Server.Handlers.dll:UserProfilesConnector" ; * This is common for all services, it's the network setup for the entire ; * server instance, if none is specified above @@ -391,4 +393,13 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; password help: optional: page providing password assistance for users of your grid ;password = http://127.0.0.1/password +[UserProfilesService] + LocalServiceModule = "OpenSim.Services.UserProfilesService.dll:UserProfilesService" + Enabled = false + ;; Configure this for separate profiles database + ;; ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=*****;Old Guids=true;" + ;; Realm = UserProfiles + UserAccountService = OpenSim.Services.UserAccountService.dll:UserAccountService + AuthenticationServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" + diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 2547244..8c23c41 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -352,3 +352,19 @@ ;; If appearance is restricted, which accounts' appearances are allowed to be exported? ;; Comma-separated list of account names AccountForAppearance = "Test User, Astronaut Smith" + +;; UserProfiles Service +;; +;; To use, set Enabled to true then configure for your site... +[UserProfilesService] + LocalServiceModule = "OpenSim.Services.UserProfilesService.dll:UserProfilesService" + Enabled = false + + ;; Configure this for separate databse + ; ConnectionString = "Data Source=localhost;Database=opensim;User ID=opensim;Password=***;Old Guids=true;" + ; Realm = UserProfiles + + UserAccountService = OpenSim.Services.UserAccountService.dll:UserAccountService + AuthenticationServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" + + diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index ba92030..39c33e8 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -19,6 +19,7 @@ GridUserServices = "LocalGridUserServicesConnector" SimulationServices = "RemoteSimulationConnectorModule" AvatarServices = "LocalAvatarServicesConnector" + UserProfilesServices = "LocalUserProfilesServicesConnector" MapImageService = "MapImageServiceModule" EntityTransferModule = "HGEntityTransferModule" InventoryAccessModule = "HGInventoryAccessModule" @@ -184,7 +185,6 @@ UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" InGatekeeper = True - ;; This should always be the very last thing on this file [Includes] Include-Common = "config-include/StandaloneCommon.ini" diff --git a/prebuild.xml b/prebuild.xml index 5967ef6..03cac76 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -281,6 +281,7 @@ + @@ -1239,6 +1240,42 @@ + + + + ../../../bin/ + + + + + ../../../bin/ + + + + ../../../bin/ + + + + + + + + + + + + + + + + + + + + + + + @@ -1977,6 +2014,7 @@ + -- cgit v1.1 From 46335b103e1f993c6aa77e46f89e5ee0d6d7497e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 30 May 2013 23:51:35 +0100 Subject: If an exception occurs in the AsyncCommandManager loop, spit it out to log rather than silently swallowing it. This might help diagnose the cause of http://opensimulator.org/mantis/view.php?id=6651 where sometimes scripts fail to start on region start. --- .../Shared/Api/Implementation/AsyncCommandManager.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 1c59624..352e316 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public class AsyncCommandManager { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static Thread cmdHandlerThread; private static int cmdHandlerThreadCycleSleepms; @@ -183,17 +183,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { try { - while (true) - { - Thread.Sleep(cmdHandlerThreadCycleSleepms); + Thread.Sleep(cmdHandlerThreadCycleSleepms); - DoOneCmdHandlerPass(); + DoOneCmdHandlerPass(); - Watchdog.UpdateThread(); - } + Watchdog.UpdateThread(); } - catch + catch (Exception e) { + m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e); } } } -- cgit v1.1 From 3aa2fb99289162b4338b7550a39411bebd74d97b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 30 May 2013 09:19:42 -0700 Subject: BulletSim: remove unuseful BulletSim parameters from OpenSimDefaults.ini and replace with things someone might actually want to tune (avatar height, ...). --- bin/OpenSimDefaults.ini | 57 ++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 81843b1..6cdf146 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -921,56 +921,49 @@ ;force_simple_prim_meshing = true [BulletSim] - ; World parameters + ; All the BulletSim parameters can be displayed with the console command "physics get all" + ; and all are defined in the source file OpenSim/Regions/Physics/BulletSPlugin/BSParam.cs. ; There are two bullet physics libraries, bulletunmanaged is the default and is a native c++ dll - ; bulletxna is a managed C# dll. They have comparible functionality.. the c++ is much faster. - + ; bulletxna is a managed C# dll. They have comparible functionality but the c++ one is much faster. BulletEngine = "bulletunmanaged" ; BulletEngine = "bulletxna" - ; Terrain Implementation {1|0} 0 for HeightField, 1 for Mesh terrain. If you're using the bulletxna engine, - ; you will want to switch to the heightfield option - TerrainImplementation = 1 - ; TerrainImplementation = 0 - - Gravity = -9.80665 - - TerrainFriction = 0.30 - TerrainHitFraction = 0.8 - TerrainRestitution = 0 - TerrainCollisionMargin = 0.04 + ; Terrain Implementation + TerrainImplementation = 1 ; 0=Heightfield, 1=mesh + ; For mesh terrain, the detail of the created mesh. '1' gives 256x256 (heightfield resolution). '2' + ; gives 512x512. Etc. Cannot be larger than '4'. Higher magnification uses lots of memory. + TerrainMeshMagnification = 2 - AvatarFriction = 0.2 - AvatarStandingFriction = 0.95 - AvatarRestitution = 0.0 - AvatarDensity = 3.5 - AvatarCapsuleWidth = 0.6 - AvatarCapsuleDepth = 0.45 - AvatarCapsuleHeight = 1.5 - AvatarContactProcessingThreshold = 0.1 + ; Avatar physics height adjustments. http://opensimulator.org/wiki/BulletSim#Adjusting_Avatar_Height + AvatarHeightLowFudge = -0.2 ; Adjustment at low end of height range + AvatarHeightMidFudge = 0.1 ; Adjustment at mid point of avatar height range + AvatarHeightHighFudge = 0.1 ; Adjustment at high end of height range - MaxObjectMass = 10000.01 - - CollisionMargin = 0.04 - - ; Linkset implmentation + ; Default linkset implmentation + ; 'Constraint' uses physics constraints to hold linkset together. 'Compound' builds a compound + ; shape from the children shapes to create a single physical shape. 'Compound' uses a lot less CPU time. LinkImplementation = 1 ; 0=constraint, 1=compound - ; Whether to mesh sculpties + ; If 'true', turn scuplties into meshes MeshSculptedPrim = true ; If 'true', force simple prims (box and sphere) to be meshed + ; If 'false', the Bullet native special case shape is used for square rectangles and even dimensioned spheres ForceSimplePrimMeshing = false - ; Bullet step parameters - MaxSubSteps = 10 - FixedTimeStep = .01667 + ; If 'true', when creating meshes, remove all triangles that have two equal vertexes. + ; Happens often in sculpties. If turned off, there will be some doorways that cannot be walked through. + ShouldRemoveZeroWidthTriangles = true + + ; If 'true', use convex hull definition in mesh asset if present. + ShouldUseAssetHulls = true + ; If there are thousands of physical objects, these maximums should be increased. MaxCollisionsPerFrame = 2048 MaxUpdatesPerFrame = 8192 - ; Detailed physics debug logging + ; Detailed physics debug logging. Very verbose. PhysicsLoggingEnabled = False PhysicsLoggingDir = "." VehicleLoggingEnabled = False -- cgit v1.1 From 439f11cc3cf2ab8f7fdc1d8746f1d8ab44c911eb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 30 May 2013 09:21:58 -0700 Subject: Add region heartbeat start event to complement heartbeat end event. This allows object modification before the usual heartbeat operation. --- OpenSim/Region/Framework/Scenes/EventManager.cs | 23 +++++++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 2 ++ 2 files changed, 25 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 59d0148..a246319 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -969,6 +969,8 @@ namespace OpenSim.Region.Framework.Scenes public delegate void RegionStarted(Scene scene); public event RegionStarted OnRegionStarted; + public delegate void RegionHeartbeatStart(Scene scene); + public event RegionHeartbeatStart OnRegionHeartbeatStart; public delegate void RegionHeartbeatEnd(Scene scene); public event RegionHeartbeatEnd OnRegionHeartbeatEnd; @@ -3068,6 +3070,27 @@ namespace OpenSim.Region.Framework.Scenes } } + public void TriggerRegionHeartbeatStart(Scene scene) + { + RegionHeartbeatStart handler = OnRegionHeartbeatStart; + + if (handler != null) + { + foreach (RegionHeartbeatStart d in handler.GetInvocationList()) + { + try + { + d(scene); + } + catch (Exception e) + { + m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}", + e.Message, e.StackTrace); + } + } + } + } + public void TriggerRegionHeartbeatEnd(Scene scene) { RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 5dea634..0743ce7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1517,6 +1517,8 @@ namespace OpenSim.Region.Framework.Scenes try { + EventManager.TriggerRegionHeartbeatStart(this); + // Apply taints in terrain module to terrain in physics scene if (Frame % m_update_terrain == 0) { -- cgit v1.1 From 48a175eff760e04f8096acd404058755d7c2919c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 30 May 2013 14:30:45 -0700 Subject: Add methods to Animation and AnimationSet for easier manipulation and display of groups of animations (Equal(), ToString(), FromOSDArray(), ...). No functional change to animations. --- OpenSim/Framework/Animation.cs | 20 ++++ .../Framework/Scenes/Animation/AnimationSet.cs | 110 +++++++++++++++++++++ .../Scenes/Animation/DefaultAvatarAnimations.cs | 26 +++++ 3 files changed, 156 insertions(+) diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs index 232f5a1..8bdf8f4 100644 --- a/OpenSim/Framework/Animation.cs +++ b/OpenSim/Framework/Animation.cs @@ -120,5 +120,25 @@ namespace OpenSim.Framework sequenceNum = args["seq_num"].AsInteger(); } + public override bool Equals(object obj) + { + Animation other = obj as Animation; + if (other != null) + { + return (other.AnimID == this.AnimID + && other.SequenceNum == this.SequenceNum + && other.ObjectID == this.ObjectID); + } + + return base.Equals(obj); + } + + public override string ToString() + { + return "AnimID=" + AnimID.ToString() + + "/seq=" + SequenceNum.ToString() + + "/objID=" + ObjectID.ToString(); + } + } } diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index 66edfed..5dee64d 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs @@ -28,8 +28,11 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Text; using log4net; using OpenMetaverse; +using OpenMetaverse.StructuredData; + using OpenSim.Framework; using Animation = OpenSim.Framework.Animation; @@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation ResetDefaultAnimation(); } + public AnimationSet(OSDArray pArray) + { + ResetDefaultAnimation(); + FromOSDArray(pArray); + } + public bool HasAnimation(UUID animID) { if (m_defaultAnimation.AnimID == animID) @@ -218,5 +227,106 @@ namespace OpenSim.Region.Framework.Scenes.Animation foreach (OpenSim.Framework.Animation anim in theArray) m_animations.Add(anim); } + + // Create representation of this AnimationSet as an OSDArray. + // First two entries in the array are the default and implicitDefault animations + // followed by the other animations. + public OSDArray ToOSDArray() + { + OSDArray ret = new OSDArray(); + ret.Add(DefaultAnimation.PackUpdateMessage()); + ret.Add(ImplicitDefaultAnimation.PackUpdateMessage()); + + foreach (OpenSim.Framework.Animation anim in m_animations) + ret.Add(anim.PackUpdateMessage()); + + return ret; + } + + public void FromOSDArray(OSDArray pArray) + { + this.Clear(); + + if (pArray.Count >= 1) + { + m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]); + } + if (pArray.Count >= 2) + { + m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]); + } + for (int ii = 2; ii < pArray.Count; ii++) + { + m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii])); + } + } + + // Compare two AnimationSets and return 'true' if the default animations are the same + // and all of the animations in the list are equal. + public override bool Equals(object obj) + { + AnimationSet other = obj as AnimationSet; + if (other != null) + { + if (this.DefaultAnimation.Equals(other.DefaultAnimation) + && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation)) + { + // The defaults are the same. Is the list of animations the same? + OpenSim.Framework.Animation[] thisAnims = this.ToArray(); + OpenSim.Framework.Animation[] otherAnims = other.ToArray(); + if (thisAnims.Length == 0 && otherAnims.Length == 0) + return true; // the common case + if (thisAnims.Length == otherAnims.Length) + { + // Do this the hard way but since the list is usually short this won't take long. + foreach (OpenSim.Framework.Animation thisAnim in thisAnims) + { + bool found = false; + foreach (OpenSim.Framework.Animation otherAnim in otherAnims) + { + if (thisAnim.Equals(otherAnim)) + { + found = true; + break; + } + } + if (!found) + { + // If anything is not in the other list, these are not equal + return false; + } + } + // Found everything in the other list. Since lists are equal length, they must be equal. + return true; + } + } + return false; + } + // Don't know what was passed, but the base system will figure it out for me. + return base.Equals(obj); + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append("dflt="); + buff.Append(DefaultAnimation.ToString()); + buff.Append(",iDflt="); + if (DefaultAnimation == ImplicitDefaultAnimation) + buff.Append("same"); + else + buff.Append(ImplicitDefaultAnimation.ToString()); + if (m_animations.Count > 0) + { + buff.Append(",anims="); + foreach (OpenSim.Framework.Animation anim in m_animations) + { + buff.Append("<"); + buff.Append(anim.ToString()); + buff.Append(">,"); + } + } + return buff.ToString(); + } } } diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs index c2b0468..b79dd8f 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs @@ -104,5 +104,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation return UUID.Zero; } + + /// + /// Get the name of the animation given a UUID. If there is no matching animation + /// return the UUID as a string. + /// + public static string GetDefaultAnimationName(UUID uuid) + { + string ret = "unknown"; + if (AnimsUUID.ContainsValue(uuid)) + { + foreach (KeyValuePair kvp in AnimsUUID) + { + if (kvp.Value == uuid) + { + ret = kvp.Key; + break; + } + } + } + else + { + ret = uuid.ToString(); + } + + return ret; + } } } \ No newline at end of file -- cgit v1.1 From 4d32ca19bf27048105aeb01c67f0f9647ed3e700 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 30 May 2013 19:15:14 -0700 Subject: Trigger OnScenePresenceUpdated when the avatar's animations change. --- .../Framework/Scenes/Animation/ScenePresenceAnimator.cs | 17 ++++++++++++++--- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 8 +++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index e92a087..a701a79 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -92,7 +92,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation GetAnimName(animID), animID, m_scenePresence.Name); if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) + { SendAnimPack(); + } } // Called from scripts @@ -131,7 +133,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation GetAnimName(animID), animID, m_scenePresence.Name); if (m_animations.Remove(animID, allowNoDefault)) + { SendAnimPack(); + } } // Called from scripts @@ -163,8 +167,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// The movement animation is reserved for "main" animations /// that are mutually exclusive, e.g. flying and sitting. /// - public void TrySetMovementAnimation(string anim) + /// 'true' if the animation was updated + public bool TrySetMovementAnimation(string anim) { + bool ret = false; if (!m_scenePresence.IsChildAgent) { // m_log.DebugFormat( @@ -181,6 +187,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation // 16384 is CHANGED_ANIMATION m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); SendAnimPack(); + ret = true; } } else @@ -189,6 +196,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", anim, m_scenePresence.Name); } + return ret; } /// @@ -422,8 +430,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// /// Update the movement animation of this avatar according to its current state /// - public void UpdateMovementAnimations() + /// 'true' if the animation was changed + public bool UpdateMovementAnimations() { + bool ret = false; lock (m_animations) { string newMovementAnimation = DetermineMovementAnimation(); @@ -437,9 +447,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation // Only set it if it's actually changed, give a script // a chance to stop a default animation - TrySetMovementAnimation(CurrentMovementAnimation); + ret = TrySetMovementAnimation(CurrentMovementAnimation); } } + return ret; } public UUID[] GetAnimationArray() diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index e8aa52e..b8ff7f7 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2039,6 +2039,7 @@ namespace OpenSim.Region.Framework.Scenes } Animator.TrySetMovementAnimation("STAND"); + TriggerScenePresenceUpdated(); } private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) @@ -2432,6 +2433,7 @@ namespace OpenSim.Region.Framework.Scenes } Animator.TrySetMovementAnimation(sitAnimation); SendAvatarDataToAllAgents(); + TriggerScenePresenceUpdated(); } } @@ -2440,6 +2442,7 @@ namespace OpenSim.Region.Framework.Scenes // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. m_AngularVelocity = Vector3.Zero; Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); + TriggerScenePresenceUpdated(); SitGround = true; RemoveFromPhysicalScene(); } @@ -2456,11 +2459,13 @@ namespace OpenSim.Region.Framework.Scenes public void HandleStartAnim(IClientAPI remoteClient, UUID animID) { Animator.AddAnimation(animID, UUID.Zero); + TriggerScenePresenceUpdated(); } public void HandleStopAnim(IClientAPI remoteClient, UUID animID) { Animator.RemoveAnimation(animID, false); + TriggerScenePresenceUpdated(); } /// @@ -3465,7 +3470,8 @@ namespace OpenSim.Region.Framework.Scenes // if (m_updateCount > 0) // { - Animator.UpdateMovementAnimations(); + if (Animator.UpdateMovementAnimations()) + TriggerScenePresenceUpdated(); // m_updateCount--; // } -- cgit v1.1 From 5b3a443125e19d9cda0b6ce5f8b6a44116c9d50a Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 30 May 2013 22:52:17 -0400 Subject: Trigger Jenkins build --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 552cdef..118fe71 100644 --- a/README.md +++ b/README.md @@ -111,3 +111,4 @@ project can always be found at http://opensimulator.org. Thanks for trying OpenSim, we hope it is a pleasant experience. + -- cgit v1.1 From bf035233232885b798a56a1687319ba167e4bf60 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Fri, 31 May 2013 10:40:47 -0400 Subject: Fill in fields with default values on profile creation --- OpenSim/Data/MySQL/MySQLUserProfilesData.cs | 50 +++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs index 09bd448..5d7149b 100644 --- a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs +++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs @@ -622,7 +622,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; @@ -634,8 +634,38 @@ namespace OpenSim.Data.MySQL props.SkillsMask = 0; props.SkillsText = string.Empty; props.Language = string.Empty; + props.PublishProfile = false; + props.PublishMature = false; - query = "INSERT INTO userprofile (`useruuid`) VALUES (?userId)"; + query = "INSERT INTO userprofile ("; + query += "useruuid, "; + query += "profilePartner, "; + query += "profileAllowPublish, "; + query += "profileMaturePublish, "; + query += "profileURL, "; + query += "profileWantToMask, "; + query += "profileWantToText, "; + query += "profileSkillsMask, "; + query += "profileSkillsText, "; + query += "profileLanguages, "; + query += "profileImage, "; + query += "profileAboutText, "; + query += "profileFirstImage, "; + query += "profileFirstText) VALUES ("; + query += "?userId, "; + query += "?profilePartner, "; + query += "?profileAllowPublish, "; + query += "?profileMaturePublish, "; + query += "?profileURL, "; + query += "?profileWantToMask, "; + query += "?profileWantToText, "; + query += "?profileSkillsMask, "; + query += "?profileSkillsText, "; + query += "?profileLanguages, "; + query += "?profileImage, "; + query += "?profileAboutText, "; + query += "?profileFirstImage, "; + query += "?profileFirstText)"; dbcon.Close(); dbcon.Open(); @@ -643,6 +673,20 @@ namespace OpenSim.Data.MySQL using (MySqlCommand put = new MySqlCommand(query, dbcon)) { put.Parameters.AddWithValue("?userId", props.UserId.ToString()); + put.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString()); + put.Parameters.AddWithValue("?profileAllowPublish", props.PublishProfile); + put.Parameters.AddWithValue("?profileMaturePublish", props.PublishMature); + put.Parameters.AddWithValue("?profileURL", props.WebUrl); + put.Parameters.AddWithValue("?profileWantToMask", props.WantToMask); + put.Parameters.AddWithValue("?profileWantToText", props.WantToText); + put.Parameters.AddWithValue("?profileSkillsMask", props.SkillsMask); + put.Parameters.AddWithValue("?profileSkillsText", props.SkillsText); + put.Parameters.AddWithValue("?profileLanguages", props.Language); + put.Parameters.AddWithValue("?profileImage", props.ImageId.ToString()); + put.Parameters.AddWithValue("?profileAboutText", props.AboutText); + put.Parameters.AddWithValue("?profileFirstImage", props.FirstLifeImageId.ToString()); + put.Parameters.AddWithValue("?profileFirstText", props.FirstLifeText); + put.ExecuteNonQuery(); } } @@ -665,6 +709,7 @@ namespace OpenSim.Data.MySQL string query = string.Empty; query += "UPDATE userprofile SET "; + query += "profilePartner=?profilePartner, "; query += "profileURL=?profileURL, "; query += "profileImage=?image, "; query += "profileAboutText=?abouttext,"; @@ -680,6 +725,7 @@ namespace OpenSim.Data.MySQL using (MySqlCommand cmd = new MySqlCommand(query, dbcon)) { cmd.Parameters.AddWithValue("?profileURL", props.WebUrl); + cmd.Parameters.AddWithValue("?profilePartner", props.PartnerId.ToString()); cmd.Parameters.AddWithValue("?image", props.ImageId.ToString()); cmd.Parameters.AddWithValue("?abouttext", props.AboutText); cmd.Parameters.AddWithValue("?firstlifeimage", props.FirstLifeImageId.ToString()); -- cgit v1.1 From 00c1586ff8cd0abb2270a109087857adefe3b5c2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 31 May 2013 18:12:36 +0100 Subject: refactor: Remove unused AsyncCommandManager.PleaseShutdown --- .../Shared/Api/Implementation/AsyncCommandManager.cs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 352e316..c71b571 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -377,23 +377,5 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - - #region Check llRemoteData channels - - #endregion - - #region Check llListeners - - #endregion - - /// - /// If set to true then threads and stuff should try to make a graceful exit - /// - public bool PleaseShutdown - { - get { return _PleaseShutdown; } - set { _PleaseShutdown = value; } - } - private bool _PleaseShutdown = false; } -} +} \ No newline at end of file -- cgit v1.1 From 921ad8704e08fccc994f7907e7cb1e9372e355b9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 31 May 2013 22:50:15 +0100 Subject: Lock areas of AsyncCommandManager where multiple threads could try to access/update the same static structures simultaneously. This is possible where there is more than one scene (multiple copies of the same script engine) and/or more than one script engine being used. These operations are not thread safe and could be leading to the exceptions/problems seen in http://opensimulator.org/mantis/view.php?id=6651 This also prevents a small race condition where more than one AsyncLSLCmdHandlerThread could be started. --- .../Api/Implementation/AsyncCommandManager.cs | 288 +++++++++++++-------- 1 file changed, 177 insertions(+), 111 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index c71b571..72e8415 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -52,6 +52,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private static Thread cmdHandlerThread; private static int cmdHandlerThreadCycleSleepms; + /// + /// Lock for reading/writing static components of AsyncCommandManager. + /// + /// + /// This lock exists so that multiple threads from different engines and/or different copies of the same engine + /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently. + /// + private static object staticLock = new object(); + private static List m_Scenes = new List(); private static List m_ScriptEngines = new List(); @@ -74,37 +83,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public Dataserver DataserverPlugin { - get { return m_Dataserver[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_Dataserver[m_ScriptEngine]; + } } public Timer TimerPlugin { - get { return m_Timer[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_Timer[m_ScriptEngine]; + } } public HttpRequest HttpRequestPlugin { - get { return m_HttpRequest[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_HttpRequest[m_ScriptEngine]; + } } public Listener ListenerPlugin { - get { return m_Listener[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_Listener[m_ScriptEngine]; + } } public SensorRepeat SensorRepeatPlugin { - get { return m_SensorRepeat[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_SensorRepeat[m_ScriptEngine]; + } } public XmlRequest XmlRequestPlugin { - get { return m_XmlRequest[m_ScriptEngine]; } + get + { + lock (staticLock) + return m_XmlRequest[m_ScriptEngine]; + } } public IScriptEngine[] ScriptEngines { - get { return m_ScriptEngines.ToArray(); } + get + { + lock (staticLock) + return m_ScriptEngines.ToArray(); + } } public AsyncCommandManager(IScriptEngine _ScriptEngine) @@ -112,29 +149,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine = _ScriptEngine; m_Scene = m_ScriptEngine.World; - if (m_Scenes.Count == 0) - ReadConfig(); - - if (!m_Scenes.Contains(m_Scene)) - m_Scenes.Add(m_Scene); - if (!m_ScriptEngines.Contains(m_ScriptEngine)) - m_ScriptEngines.Add(m_ScriptEngine); - - // Create instances of all plugins - if (!m_Dataserver.ContainsKey(m_ScriptEngine)) - m_Dataserver[m_ScriptEngine] = new Dataserver(this); - if (!m_Timer.ContainsKey(m_ScriptEngine)) - m_Timer[m_ScriptEngine] = new Timer(this); - if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) - m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); - if (!m_Listener.ContainsKey(m_ScriptEngine)) - m_Listener[m_ScriptEngine] = new Listener(this); - if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) - m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); - if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) - m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); - - StartThread(); + // If there is more than one scene in the simulator or multiple script engines are used on the same region + // then more than one thread could arrive at this block of code simultaneously. However, it cannot be + // executed concurrently both because concurrent list operations are not thread-safe and because of other + // race conditions such as the later check of cmdHandlerThread == null. + lock (staticLock) + { + if (m_Scenes.Count == 0) + ReadConfig(); + + if (!m_Scenes.Contains(m_Scene)) + m_Scenes.Add(m_Scene); + if (!m_ScriptEngines.Contains(m_ScriptEngine)) + m_ScriptEngines.Add(m_ScriptEngine); + + // Create instances of all plugins + if (!m_Dataserver.ContainsKey(m_ScriptEngine)) + m_Dataserver[m_ScriptEngine] = new Dataserver(this); + if (!m_Timer.ContainsKey(m_ScriptEngine)) + m_Timer[m_ScriptEngine] = new Timer(this); + if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) + m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); + if (!m_Listener.ContainsKey(m_ScriptEngine)) + m_Listener[m_ScriptEngine] = new Listener(this); + if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) + m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); + if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) + m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); + + StartThread(); + } } private static void StartThread() @@ -198,25 +242,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private static void DoOneCmdHandlerPass() { - // Check HttpRequests - m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); + lock (staticLock) + { + // Check HttpRequests + m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); - // Check XMLRPCRequests - m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); + // Check XMLRPCRequests + m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); - foreach (IScriptEngine s in m_ScriptEngines) - { - // Check Listeners - m_Listener[s].CheckListeners(); + foreach (IScriptEngine s in m_ScriptEngines) + { + // Check Listeners + m_Listener[s].CheckListeners(); - // Check timers - m_Timer[s].CheckTimerEvents(); + // Check timers + m_Timer[s].CheckTimerEvents(); - // Check Sensors - m_SensorRepeat[s].CheckSenseRepeaterEvents(); + // Check Sensors + m_SensorRepeat[s].CheckSenseRepeaterEvents(); - // Check dataserver - m_Dataserver[s].ExpireRequests(); + // Check dataserver + m_Dataserver[s].ExpireRequests(); + } } } @@ -229,32 +276,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); - // Remove a specific script + lock (staticLock) + { + // Remove dataserver events + m_Dataserver[engine].RemoveEvents(localID, itemID); - // Remove dataserver events - m_Dataserver[engine].RemoveEvents(localID, itemID); + // Remove from: Timers + m_Timer[engine].UnSetTimerEvents(localID, itemID); - // Remove from: Timers - m_Timer[engine].UnSetTimerEvents(localID, itemID); + // Remove from: HttpRequest + IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); + if (iHttpReq != null) + iHttpReq.StopHttpRequestsForScript(itemID); - // Remove from: HttpRequest - IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); - if (iHttpReq != null) - iHttpReq.StopHttpRequestsForScript(itemID); + IWorldComm comms = engine.World.RequestModuleInterface(); + if (comms != null) + comms.DeleteListener(itemID); - IWorldComm comms = engine.World.RequestModuleInterface(); - if (comms != null) - comms.DeleteListener(itemID); + IXMLRPC xmlrpc = engine.World.RequestModuleInterface(); + if (xmlrpc != null) + { + xmlrpc.DeleteChannels(itemID); + xmlrpc.CancelSRDRequests(itemID); + } - IXMLRPC xmlrpc = engine.World.RequestModuleInterface(); - if (xmlrpc != null) - { - xmlrpc.DeleteChannels(itemID); - xmlrpc.CancelSRDRequests(itemID); + // Remove Sensors + m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); } - - // Remove Sensors - m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); } /// @@ -264,10 +312,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) { - if (m_SensorRepeat.ContainsKey(engine)) - return m_SensorRepeat[engine]; - else - return null; + lock (staticLock) + { + if (m_SensorRepeat.ContainsKey(engine)) + return m_SensorRepeat[engine]; + else + return null; + } } /// @@ -277,10 +328,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static Dataserver GetDataserverPlugin(IScriptEngine engine) { - if (m_Dataserver.ContainsKey(engine)) - return m_Dataserver[engine]; - else - return null; + lock (staticLock) + { + if (m_Dataserver.ContainsKey(engine)) + return m_Dataserver[engine]; + else + return null; + } } /// @@ -290,10 +344,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static Timer GetTimerPlugin(IScriptEngine engine) { - if (m_Timer.ContainsKey(engine)) - return m_Timer[engine]; - else - return null; + lock (staticLock) + { + if (m_Timer.ContainsKey(engine)) + return m_Timer[engine]; + else + return null; + } } /// @@ -303,38 +360,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// public static Listener GetListenerPlugin(IScriptEngine engine) { - if (m_Listener.ContainsKey(engine)) - return m_Listener[engine]; - else - return null; + lock (staticLock) + { + if (m_Listener.ContainsKey(engine)) + return m_Listener[engine]; + else + return null; + } } public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID) { List data = new List(); - Object[] listeners = m_Listener[engine].GetSerializationData(itemID); - if (listeners.Length > 0) + lock (staticLock) { - data.Add("listener"); - data.Add(listeners.Length); - data.AddRange(listeners); - } + Object[] listeners = m_Listener[engine].GetSerializationData(itemID); + if (listeners.Length > 0) + { + data.Add("listener"); + data.Add(listeners.Length); + data.AddRange(listeners); + } - Object[] timers=m_Timer[engine].GetSerializationData(itemID); - if (timers.Length > 0) - { - data.Add("timer"); - data.Add(timers.Length); - data.AddRange(timers); - } + Object[] timers=m_Timer[engine].GetSerializationData(itemID); + if (timers.Length > 0) + { + data.Add("timer"); + data.Add(timers.Length); + data.AddRange(timers); + } - Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); - if (sensors.Length > 0) - { - data.Add("sensor"); - data.Add(sensors.Length); - data.AddRange(sensors); + Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); + if (sensors.Length > 0) + { + data.Add("sensor"); + data.Add(sensors.Length); + data.AddRange(sensors); + } } return data.ToArray(); @@ -359,20 +422,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api idx+=len; + lock (staticLock) + { switch (type) { - case "listener": - m_Listener[engine].CreateFromData(localID, itemID, - hostID, item); - break; - case "timer": - m_Timer[engine].CreateFromData(localID, itemID, - hostID, item); - break; - case "sensor": - m_SensorRepeat[engine].CreateFromData(localID, - itemID, hostID, item); - break; + case "listener": + m_Listener[engine].CreateFromData(localID, itemID, + hostID, item); + break; + case "timer": + m_Timer[engine].CreateFromData(localID, itemID, + hostID, item); + break; + case "sensor": + m_SensorRepeat[engine].CreateFromData(localID, + itemID, hostID, item); + break; + } } } } -- cgit v1.1 From 217c7d11401dbf15ada3de750e7ad0df85a02894 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 31 May 2013 23:00:10 +0100 Subject: Remove unnecessary m_scenes and m_scene from AsyncCommandManager. These were private and the sole point of use (to know when to load config for the first time) can be done by looking at script engines instead. --- .../ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 72e8415..998f40b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -61,12 +61,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// private static object staticLock = new object(); - private static List m_Scenes = new List(); private static List m_ScriptEngines = new List(); public IScriptEngine m_ScriptEngine; - private IScene m_Scene; private static Dictionary m_Dataserver = new Dictionary(); @@ -147,7 +145,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public AsyncCommandManager(IScriptEngine _ScriptEngine) { m_ScriptEngine = _ScriptEngine; - m_Scene = m_ScriptEngine.World; // If there is more than one scene in the simulator or multiple script engines are used on the same region // then more than one thread could arrive at this block of code simultaneously. However, it cannot be @@ -155,11 +152,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // race conditions such as the later check of cmdHandlerThread == null. lock (staticLock) { - if (m_Scenes.Count == 0) + if (m_ScriptEngines.Count == 0) ReadConfig(); - if (!m_Scenes.Contains(m_Scene)) - m_Scenes.Add(m_Scene); if (!m_ScriptEngines.Contains(m_ScriptEngine)) m_ScriptEngines.Add(m_ScriptEngine); -- cgit v1.1 From ba2f13db63a58698ca47e9ba51a1a1509b838a77 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Fri, 31 May 2013 18:48:01 -0400 Subject: Adding back the BasicProfileModule --- .../Avatar/Profile/BasicProfileModule.cs | 176 +++++++++++++++++++++ .../Avatar/UserProfiles/UserProfileModule.cs | 88 ++--------- bin/OpenSim.ini.example | 4 +- 3 files changed, 193 insertions(+), 75 deletions(-) create mode 100644 OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs new file mode 100644 index 0000000..bf24030 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs @@ -0,0 +1,176 @@ +/* + * 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.Generic; +using System.Globalization; +using System.Reflection; + +using OpenMetaverse; +using log4net; +using Nini.Config; +using Mono.Addins; + +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Region.CoreModules.Avatar.Profile +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicProfileModule")] + public class BasicProfileModule : IProfileModule, ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // + // Module vars + // + private List m_Scenes = new List(); + private bool m_Enabled = false; + + #region ISharedRegionModule + + public void Initialise(IConfigSource config) + { + m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); + m_Enabled = true; + } + + public void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock (m_Scenes) + { + if (!m_Scenes.Contains(scene)) + { + m_Scenes.Add(scene); + // Hook up events + scene.EventManager.OnNewClient += OnNewClient; + scene.RegisterModuleInterface(this); + } + } + } + + public void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + } + + public void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + lock (m_Scenes) + { + m_Scenes.Remove(scene); + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "BasicProfileModule"; } + } + + public Type ReplaceableInterface + { + get { return typeof(IProfileModule); } + } + + #endregion + + /// New Client Event Handler + private void OnNewClient(IClientAPI client) + { + //Profile + client.OnRequestAvatarProperties += RequestAvatarProperties; + } + + public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) + { + IScene s = remoteClient.Scene; + if (!(s is Scene)) + return; + +// Scene scene = (Scene)s; + + string profileUrl = String.Empty; + string aboutText = String.Empty; + string firstLifeAboutText = String.Empty; + UUID image = UUID.Zero; + UUID firstLifeImage = UUID.Zero; + UUID partner = UUID.Zero; + uint wantMask = 0; + string wantText = String.Empty; + uint skillsMask = 0; + string skillsText = String.Empty; + string languages = String.Empty; + + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, avatarID); + + string name = "Avatar"; + int created = 0; + if (account != null) + { + name = account.FirstName + " " + account.LastName; + created = account.Created; + } + Byte[] charterMember = Utils.StringToBytes(name); + + profileUrl = "No profile data"; + aboutText = string.Empty; + firstLifeAboutText = string.Empty; + image = UUID.Zero; + firstLifeImage = UUID.Zero; + partner = UUID.Zero; + + remoteClient.SendAvatarProperties(avatarID, aboutText, + Util.ToDateTime(created).ToString( + "M/d/yyyy", CultureInfo.InvariantCulture), + charterMember, firstLifeAboutText, + (uint)(0 & 0xff), + firstLifeImage, image, profileUrl, partner); + + //Viewer expects interest data when it asks for properties. + remoteClient.SendAvatarInterestsReply(avatarID, wantMask, wantText, + skillsMask, skillsText, languages); + } + + } +} diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 563617d..5b228ee 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -124,8 +124,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void Initialise(IConfigSource source) { Config = source; + ReplaceableInterface = typeof(IProfileModule); - IConfig profileConfig = Config.Configs["Profile"]; + IConfig profileConfig = Config.Configs["UserProfiles"]; if (profileConfig == null) { @@ -135,18 +136,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles // If we find ProfileURL then we configure for FULL support // else we setup for BASIC support - ProfileServerUri = profileConfig.GetString("ProfileURL", ""); + ProfileServerUri = profileConfig.GetString("ProfileServiceURL", ""); if (ProfileServerUri == "") { - m_log.Info("[PROFILES] UserProfiles module is activated in BASIC mode"); Enabled = false; return; } - else - { - m_log.Info("[PROFILES] UserProfiles module is activated in FULL mode"); - Enabled = true; - } + + m_log.Debug("[PROFILES]: Full Profiles Enabled"); + ReplaceableInterface = null; + Enabled = true; } /// @@ -157,6 +156,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles /// public void AddRegion(Scene scene) { + if(!Enabled) + return; + Scene = scene; Scene.RegisterModuleInterface(this); Scene.EventManager.OnNewClient += OnNewClient; @@ -178,6 +180,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles /// public void RemoveRegion(Scene scene) { + if(!Enabled) + return; } /// @@ -191,6 +195,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles /// public void RegionLoaded(Scene scene) { + if(!Enabled) + return; } /// @@ -206,7 +212,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles /// public Type ReplaceableInterface { - get { return typeof(IProfileModule); } + get; private set; } /// @@ -237,13 +243,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles /// void OnNewClient(IClientAPI client) { - // Basic or Full module? - if(!Enabled) - { - client.OnRequestAvatarProperties += BasicRequestProperties; - return; - } - //Profile client.OnRequestAvatarProperties += RequestAvatarProperties; client.OnUpdateAvatarProperties += AvatarPropertiesUpdate; @@ -839,63 +838,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } } - public void BasicRequestProperties(IClientAPI remoteClient, UUID avatarID) - { - IScene s = remoteClient.Scene; - if (!(s is Scene)) - return; - - string profileUrl = String.Empty; - string aboutText = String.Empty; - string firstLifeAboutText = String.Empty; - UUID image = UUID.Zero; - UUID firstLifeImage = UUID.Zero; - UUID partner = UUID.Zero; - uint wantMask = 0; - string wantText = String.Empty; - uint skillsMask = 0; - string skillsText = String.Empty; - string languages = String.Empty; - - UserAccount account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID); - - string name = "Avatar"; - int created = 0; - if (account != null) - { - name = account.FirstName + " " + account.LastName; - created = account.Created; - } - Byte[] charterMember = Utils.StringToBytes(name); - - profileUrl = "No profile data"; - aboutText = string.Empty; - firstLifeAboutText = string.Empty; - image = UUID.Zero; - firstLifeImage = UUID.Zero; - partner = UUID.Zero; - - remoteClient.SendAvatarProperties(avatarID, aboutText, - Util.ToDateTime(created).ToString( - "M/d/yyyy", CultureInfo.InvariantCulture), - charterMember, firstLifeAboutText, - (uint)(0 & 0xff), - firstLifeImage, image, profileUrl, partner); - - //Viewer expects interest data when it asks for properties. - remoteClient.SendAvatarInterestsReply(avatarID, wantMask, wantText, - skillsMask, skillsText, languages); - } - - /// - /// Requests the avatar properties. - /// - /// - /// Remote client. - /// - /// - /// Avatar I. - /// public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) { if ( String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString())) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 38e2a07..3015c08 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1032,11 +1032,11 @@ ;# {InitialTerrain} {} {Initial terrain type} {pinhead-island flat} pinhead-island ; InitialTerrain = "pinhead-island" -[Profile] +[UserProfiles] ;# {ProfileURL} {} {Set url to UserProfilesService} {} ;; Set the value of the url to your UserProfilesService ;; If un-set / "" the module is disabled - ;; ProfileURL = http://127.0.0.1:8002 + ;; ProfileServiceURL = http://127.0.0.1:8002 [Architecture] ;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini -- cgit v1.1 From d7fa9f671eefebd49c0e8f56e56088b0c0b3d93c Mon Sep 17 00:00:00 2001 From: BlueWall Date: Fri, 31 May 2013 22:03:27 -0400 Subject: Adding standard OpenSim header to source files --- OpenSim/Data/IProfilesData.cs | 27 ++++++++++++++++++++++ OpenSim/Data/MySQL/MySQLUserProfilesData.cs | 27 ++++++++++++++++++++++ OpenSim/Framework/UserProfiles.cs | 27 ++++++++++++++++++++++ .../Handlers/Profiles/UserProfilesConnector.cs | 27 ++++++++++++++++++++++ .../Handlers/Profiles/UserProfilesHandlers.cs | 27 ++++++++++++++++++++++ .../Services/Interfaces/IUserProfilesService.cs | 27 ++++++++++++++++++++++ .../UserProfilesService/UserProfilesService.cs | 27 ++++++++++++++++++++++ .../UserProfilesService/UserProfilesServiceBase.cs | 27 ++++++++++++++++++++++ 8 files changed, 216 insertions(+) diff --git a/OpenSim/Data/IProfilesData.cs b/OpenSim/Data/IProfilesData.cs index eeccbf6..0de7f68 100644 --- a/OpenSim/Data/IProfilesData.cs +++ b/OpenSim/Data/IProfilesData.cs @@ -1,3 +1,30 @@ +/* + * 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 OpenMetaverse; using OpenMetaverse.StructuredData; diff --git a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs index 5d7149b..4c6c8e3 100644 --- a/OpenSim/Data/MySQL/MySQLUserProfilesData.cs +++ b/OpenSim/Data/MySQL/MySQLUserProfilesData.cs @@ -1,3 +1,30 @@ +/* + * 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.Data; using System.Reflection; diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs index aabbb84..6133591 100644 --- a/OpenSim/Framework/UserProfiles.cs +++ b/OpenSim/Framework/UserProfiles.cs @@ -1,3 +1,30 @@ +/* + * 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 OpenMetaverse; diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs index 4ad7297..5a24ee3 100644 --- a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs @@ -1,3 +1,30 @@ +/* + * 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.Reflection; using Nini.Config; diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs index 93da102..f5f0794 100644 --- a/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesHandlers.cs @@ -1,3 +1,30 @@ +/* + * 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.Reflection; using OpenMetaverse; diff --git a/OpenSim/Services/Interfaces/IUserProfilesService.cs b/OpenSim/Services/Interfaces/IUserProfilesService.cs index 12fc986..319d307 100644 --- a/OpenSim/Services/Interfaces/IUserProfilesService.cs +++ b/OpenSim/Services/Interfaces/IUserProfilesService.cs @@ -1,3 +1,30 @@ +/* + * 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 OpenSim.Framework; using OpenMetaverse; diff --git a/OpenSim/Services/UserProfilesService/UserProfilesService.cs b/OpenSim/Services/UserProfilesService/UserProfilesService.cs index 959c661..d00f34d 100644 --- a/OpenSim/Services/UserProfilesService/UserProfilesService.cs +++ b/OpenSim/Services/UserProfilesService/UserProfilesService.cs @@ -1,3 +1,30 @@ +/* + * 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.Reflection; using System.Text; diff --git a/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs index dc0be03..927f7c9 100644 --- a/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs +++ b/OpenSim/Services/UserProfilesService/UserProfilesServiceBase.cs @@ -1,3 +1,30 @@ +/* + * 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.Reflection; using Nini.Config; -- cgit v1.1 From 07058b044be59b6e07efedeca36b2b464e984195 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 1 Jun 2013 14:52:44 -0700 Subject: BulletSim: experimental movement of physics execution off of heartbeat thread. Off by default until more testing. Setting "[BulletSim]UseSeparatePhysicsThread=true" causes the physics engine to be called on its own thread and the heartbeat thread only handles the reporting of property updates and collisions. Physics frame rate is about right but physics execution time goes to zero as accounted by the heartbeat loop. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 8 + OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 3 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 271 +++++++++++++++++------- 3 files changed, 209 insertions(+), 73 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 2651e3b..afd547a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -54,6 +54,9 @@ public static class BSParam // =================== // From: + public static bool UseSeparatePhysicsThread { get; private set; } + public static float PhysicsTimeStep { get; private set; } + // Level of Detail values kept as float because that's what the Meshmerizer wants public static float MeshLOD { get; private set; } public static float MeshCircularLOD { get; private set; } @@ -354,6 +357,11 @@ public static class BSParam // v = value (appropriate type) private static ParameterDefnBase[] ParameterDefinitions = { + new ParameterDefn("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", + false ), + new ParameterDefn("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", + 0.1f ), + new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", true, (s) => { return ShouldMeshSculptedPrim; }, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e11e365..95bdc7b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -1513,7 +1513,8 @@ public class BSPrim : BSPhysObject CurrentEntityProperties = entprop; // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. - base.RequestPhysicsterseUpdate(); + + PhysScene.PostUpdate(this); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 39f5b0a..423c389 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public string BulletEngineName { get; private set; } public BSAPITemplate PE; + // If the physics engine is running on a separate thread + public Thread m_physicsThread; + public Dictionary PhysObjects; public BSShapeCollection Shapes; // Keeping track of the objects with collisions so we can report begin and end of a collision public HashSet ObjectsWithCollisions = new HashSet(); public HashSet ObjectsWithNoMoreCollisions = new HashSet(); + + // All the collision processing is protected with this lock object + public Object CollisionLock = new Object(); + + // Properties are updated here + public Object UpdateLock = new Object(); + public HashSet ObjectsWithUpdates = new HashSet(); + // Keep track of all the avatars so we can send them a collision event // every tick so OpenSim will update its animation. private HashSet m_avatars = new HashSet(); @@ -77,12 +88,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public BSConstraintCollection Constraints { get; private set; } // Simulation parameters + internal float m_physicsStepTime; // if running independently, the interval simulated by default + internal int m_maxSubSteps; internal float m_fixedTimeStep; - internal long m_simulationStep = 0; - internal float NominalFrameRate { get; set; } + + internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc. + + internal long m_simulationStep = 0; // The current simulation step. public long SimulationStep { get { return m_simulationStep; } } - internal float LastTimeStep { get; private set; } + + internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() + + internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to // Physical objects can register for prestep or poststep events public delegate void PreStepAction(float timeStep); @@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public event PreStepAction BeforeStep; public event PostStepAction AfterStep; - // A value of the time now so all the collision and update routines do not have to get their own + // A value of the time 'now' so all the collision and update routines do not have to get their own // Set to 'now' just before all the prims and actors are called for collisions and updates public int SimulationNowTime { get; private set; } @@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters PhysObjects = new Dictionary(); Shapes = new BSShapeCollection(this); + m_simulatedTime = 0f; + LastTimeStep = 0.1f; + // Allocate pinned memory to pass parameters. UnmanagedParams = new ConfigurationParameters[1]; @@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters TerrainManager = new BSTerrainManager(this); TerrainManager.CreateInitialGroundPlaneAndTerrain(); + // Put some informational messages into the log file. m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); InTaintTime = false; m_initialized = true; + + // If the physics engine runs on its own thread, start same. + if (BSParam.UseSeparatePhysicsThread) + { + // The physics simulation should happen independently of the heartbeat loop + m_physicsThread = new Thread(BulletSPluginPhysicsThread); + m_physicsThread.Name = BulletEngineName; + m_physicsThread.Start(); + } } // All default parameter values are set here. There should be no values set in the @@ -270,6 +301,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters } else { + // Nothing in the configuration INI file so assume unmanaged and other defaults. BulletEngineName = "BulletUnmanaged"; m_physicsLoggingEnabled = false; VehicleLoggingEnabled = false; @@ -317,6 +349,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters switch (selectionName) { + case "bullet": case "bulletunmanaged": ret = new BSAPIUnman(engineName, this); break; @@ -494,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters #endregion // Prim and Avatar addition and removal #region Simulation - // Simulate one timestep + + // Call from the simulator to send physics information to the simulator objects. + // This pushes all the collision and property update events into the objects in + // the simulator and, since it is on the heartbeat thread, there is an implicit + // locking of those data structures from other heartbeat events. + // If the physics engine is running on a separate thread, the update information + // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. public override float Simulate(float timeStep) { + if (!BSParam.UseSeparatePhysicsThread) + { + DoPhysicsStep(timeStep); + } + return SendUpdatesToSimulator(timeStep); + } + + // Call the physics engine to do one 'timeStep' and collect collisions and updates + // into ObjectsWithCollisions and ObjectsWithUpdates data structures. + private void DoPhysicsStep(float timeStep) + { // prevent simulation until we've been initialized - if (!m_initialized) return 5.0f; + if (!m_initialized) return; LastTimeStep = timeStep; int updatedEntityCount = 0; int collidersCount = 0; - int beforeTime = 0; + int beforeTime = Util.EnvironmentTickCount(); int simTime = 0; - // update the prim states while we know the physics engine is not busy int numTaints = _taintOperations.Count; - InTaintTime = true; // Only used for debugging so locking is not necessary. + // update the prim states while we know the physics engine is not busy ProcessTaints(); // Some of the physical objects requre individual, pre-step calls @@ -535,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters int numSubSteps = 0; try { - if (PhysicsLogging.Enabled) - beforeTime = Util.EnvironmentTickCount(); - numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); - if (PhysicsLogging.Enabled) - { - simTime = Util.EnvironmentTickCountSubtract(beforeTime); - DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", - DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, - updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); - } } catch (Exception e) { @@ -558,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters collidersCount = 0; } + // Make the physics engine dump useful statistics periodically if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) PE.DumpPhysicsStatistics(World); // Get a value for 'now' so all the collision and update routines don't have to get their own. SimulationNowTime = Util.EnvironmentTickCount(); - // If there were collisions, process them by sending the event to the prim. - // Collisions must be processed before updates. - if (collidersCount > 0) + // Send collision information to the colliding objects. The objects decide if the collision + // is 'real' (like linksets don't collide with themselves) and the individual objects + // know if the simulator has subscribed to collisions. + lock (CollisionLock) { - for (int ii = 0; ii < collidersCount; ii++) + if (collidersCount > 0) { - uint cA = m_collisionArray[ii].aID; - uint cB = m_collisionArray[ii].bID; - Vector3 point = m_collisionArray[ii].point; - Vector3 normal = m_collisionArray[ii].normal; - float penetration = m_collisionArray[ii].penetration; - SendCollision(cA, cB, point, normal, penetration); - SendCollision(cB, cA, point, -normal, penetration); - } - } - - // The above SendCollision's batch up the collisions on the objects. - // Now push the collisions into the simulator. - if (ObjectsWithCollisions.Count > 0) - { - foreach (BSPhysObject bsp in ObjectsWithCollisions) - if (!bsp.SendCollisions()) + for (int ii = 0; ii < collidersCount; ii++) { - // If the object is done colliding, see that it's removed from the colliding list - ObjectsWithNoMoreCollisions.Add(bsp); + uint cA = m_collisionArray[ii].aID; + uint cB = m_collisionArray[ii].bID; + Vector3 point = m_collisionArray[ii].point; + Vector3 normal = m_collisionArray[ii].normal; + float penetration = m_collisionArray[ii].penetration; + SendCollision(cA, cB, point, normal, penetration); + SendCollision(cB, cA, point, -normal, penetration); } + } } - // This is a kludge to get avatar movement updates. - // The simulator expects collisions for avatars even if there are have been no collisions. - // The event updates avatar animations and stuff. - // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. - foreach (BSPhysObject bsp in m_avatars) - if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice - bsp.SendCollisions(); - - // Objects that are done colliding are removed from the ObjectsWithCollisions list. - // Not done above because it is inside an iteration of ObjectWithCollisions. - // This complex collision processing is required to create an empty collision - // event call after all real collisions have happened on an object. This enables - // the simulator to generate the 'collision end' event. - if (ObjectsWithNoMoreCollisions.Count > 0) - { - foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) - ObjectsWithCollisions.Remove(po); - ObjectsWithNoMoreCollisions.Clear(); - } - // Done with collisions. - - // If any of the objects had updated properties, tell the object it has been changed by the physics engine - if (updatedEntityCount > 0) + // If any of the objects had updated properties, tell the managed objects about the update + // and remember that there was a change so it will be passed to the simulator. + lock (UpdateLock) { - for (int ii = 0; ii < updatedEntityCount; ii++) + if (updatedEntityCount > 0) { - EntityProperties entprop = m_updateArray[ii]; - BSPhysObject pobj; - if (PhysObjects.TryGetValue(entprop.ID, out pobj)) + for (int ii = 0; ii < updatedEntityCount; ii++) { - pobj.UpdateProperties(entprop); + EntityProperties entprop = m_updateArray[ii]; + BSPhysObject pobj; + if (PhysObjects.TryGetValue(entprop.ID, out pobj)) + { + pobj.UpdateProperties(entprop); + } } } } + // Some actors want to know when the simulation step is complete. TriggerPostStepEvent(timeStep); + simTime = Util.EnvironmentTickCountSubtract(beforeTime); + if (PhysicsLogging.Enabled) + { + DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", + DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, + updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); + } + // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. // Only enable this in a limited test world with few objects. if (m_physicsPhysicalDumpEnabled) @@ -637,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // The physics engine returns the number of milliseconds it simulated this call. // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). - return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; + m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; + } + + // Called by a BSPhysObject to note that it has changed properties and this information + // should be passed up to the simulator at the proper time. + // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so + // this is is under UpdateLock. + public void PostUpdate(BSPhysObject updatee) + { + ObjectsWithUpdates.Add(updatee); + } + + // The simulator thinks it is physics time so return all the collisions and position + // updates that were collected in actual physics simulation. + private float SendUpdatesToSimulator(float timeStep) + { + if (!m_initialized) return 5.0f; + + DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", + BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); + // Push the collisions into the simulator. + lock (CollisionLock) + { + if (ObjectsWithCollisions.Count > 0) + { + foreach (BSPhysObject bsp in ObjectsWithCollisions) + if (!bsp.SendCollisions()) + { + // If the object is done colliding, see that it's removed from the colliding list + ObjectsWithNoMoreCollisions.Add(bsp); + } + } + + // This is a kludge to get avatar movement updates. + // The simulator expects collisions for avatars even if there are have been no collisions. + // The event updates avatar animations and stuff. + // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. + foreach (BSPhysObject bsp in m_avatars) + if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice + bsp.SendCollisions(); + + // Objects that are done colliding are removed from the ObjectsWithCollisions list. + // Not done above because it is inside an iteration of ObjectWithCollisions. + // This complex collision processing is required to create an empty collision + // event call after all real collisions have happened on an object. This allows + // the simulator to generate the 'collision end' event. + if (ObjectsWithNoMoreCollisions.Count > 0) + { + foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) + ObjectsWithCollisions.Remove(po); + ObjectsWithNoMoreCollisions.Clear(); + } + } + + // Call the simulator for each object that has physics property updates. + HashSet updatedObjects = null; + lock (UpdateLock) + { + if (ObjectsWithUpdates.Count > 0) + { + updatedObjects = ObjectsWithUpdates; + ObjectsWithUpdates = new HashSet(); + } + } + if (updatedObjects != null) + { + foreach (BSPhysObject obj in updatedObjects) + { + obj.RequestPhysicsterseUpdate(); + } + updatedObjects.Clear(); + } + + // Return the framerate simulated to give the above returned results. + // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). + float simTime = m_simulatedTime; + m_simulatedTime = 0f; + return simTime; } // Something has collided @@ -656,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters return; } - // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. + // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. BSPhysObject collidee = null; PhysObjects.TryGetValue(collidingWith, out collidee); @@ -664,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) { - // If a collision was posted, remember to send it to the simulator + // If a collision was 'good', remember to send it to the simulator ObjectsWithCollisions.Add(collider); } return; } + public void BulletSPluginPhysicsThread() + { + while (m_initialized) + { + int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); + DoPhysicsStep(BSParam.PhysicsTimeStep); + int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); + int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; + + if (simulationTimeVsRealtimeDifferenceMS > 0) + { + // The simulation of the time interval took less than realtime. + // Do a sleep for the rest of realtime. + DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); + Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); + } + else + { + // The simulation took longer than realtime. + // Do some scaling of simulation time. + // TODO. + DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); + } + } + } + #endregion // Simulation public override void GetResults() { } -- cgit v1.1 From 43d804b998e6f37bbae771711af0ae1ffcc84cbd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 4 Jun 2013 12:27:22 -0700 Subject: New HttpServer_OpenSim.dll with increased limits on number of connections, requests, etc. --- bin/HttpServer_OpenSim.dll | Bin 119808 -> 116224 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/HttpServer_OpenSim.dll b/bin/HttpServer_OpenSim.dll index e15493d..38a4cb7 100755 Binary files a/bin/HttpServer_OpenSim.dll and b/bin/HttpServer_OpenSim.dll differ -- cgit v1.1 From 0c971d148cbee691136a8e6f6c0b3dd40ba4e78a Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 5 Jun 2013 07:09:43 -0700 Subject: BulletSim: fix corner case when rebuilding a compound linkset while a mesh/hull while a mesh or hull is being rebuilt when its asset is fetched. This fixes a 'pure virtual function' crash when changing physical state of complex linksets that include many meshes. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 57 +++++++++++++++++++----- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 81edc12..867d2ab 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -389,9 +389,21 @@ public class BSShapeMesh : BSShape } public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { - // Another reference to this shape is just counted. - IncrementReference(); - return this; + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; } public override void Dereference(BSScene physicsScene) { @@ -560,9 +572,21 @@ public class BSShapeHull : BSShape } public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { - // Another reference to this shape is just counted. - IncrementReference(); - return this; + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; } public override void Dereference(BSScene physicsScene) { @@ -1075,12 +1099,23 @@ public class BSShapeGImpact : BSShape (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) ); } - public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { - // Calling this reference means we want another handle to an existing shape - // (usually linksets) so return this copy. - IncrementReference(); - return this; + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; } // Dereferencing a compound shape releases the hold on all the child shapes. public override void Dereference(BSScene physicsScene) -- cgit v1.1 From b5d0ac4c42629812523f5af4384f61dee00ef495 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 5 Jun 2013 07:12:14 -0700 Subject: BulletSim: default PhysicsTimeStep to same as the simulator's heartbeat timestep when running the physics engine on a separate thread. This reduces the occurance of heartbeats that happen when there is no physics step which is seen as vehicle jerkyness. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index afd547a..aad1108 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -360,7 +360,7 @@ public static class BSParam new ParameterDefn("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", false ), new ParameterDefn("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", - 0.1f ), + 0.089f ), new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", true, -- cgit v1.1 From b4f472c4fab5c1b3fda0f86bba330d5bf0800e22 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 5 Jun 2013 15:08:25 -0400 Subject: Make locking more uniform --- .../Avatar/UserProfiles/UserProfileModule.cs | 33 +++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 5b228ee..7165cb6 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -62,6 +62,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles // count. The entries are removed when the interest count reaches 0. Dictionary classifiedCache = new Dictionary(); Dictionary classifiedInterest = new Dictionary(); + Object classifiedLock; public Scene Scene { @@ -326,14 +327,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles string name = m["name"].AsString(); classifieds[cid] = name; - + if(!classifiedCache.ContainsKey(cid)) { - classifiedCache.Add(cid,creatorId); - classifiedInterest.Add(cid, 0); +// lock(classifiedLock) +// { + lock(classifiedCache) + classifiedCache.Add(cid,creatorId); + lock(classifiedInterest) + classifiedInterest.Add(cid, 0); +// } } - classifiedInterest[cid] ++; + lock(classifiedInterest) + classifiedInterest[cid] ++; } remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); @@ -346,22 +353,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles ad.ClassifiedId = queryClassifiedID; if(classifiedCache.ContainsKey(queryClassifiedID)) - { + { target = classifiedCache[queryClassifiedID]; - if(classifiedInterest[queryClassifiedID] -- == 0) + lock(classifiedInterest) + classifiedInterest[queryClassifiedID] --; + + if(classifiedInterest[queryClassifiedID] == 0) { + lock(classifiedInterest) + classifiedInterest.Remove(queryClassifiedID); lock(classifiedCache) - { - lock(classifiedInterest) - { - classifiedInterest.Remove(queryClassifiedID); - } classifiedCache.Remove(queryClassifiedID); - } } - } - + } string serverURI = string.Empty; bool foreign = GetUserProfileServerURI(target, out serverURI); -- cgit v1.1 From 10572b78f8d726ff07fd37dca4bb4f27f38563cb Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 5 Jun 2013 15:10:53 -0400 Subject: Remove a couple of orphaned lines --- OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 7165cb6..13f0167 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -330,13 +330,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles if(!classifiedCache.ContainsKey(cid)) { -// lock(classifiedLock) -// { lock(classifiedCache) classifiedCache.Add(cid,creatorId); lock(classifiedInterest) classifiedInterest.Add(cid, 0); -// } } lock(classifiedInterest) -- cgit v1.1 From f41fc4eb25ade48a358511564f3911a4605c1c31 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 5 Jun 2013 22:20:48 +0100 Subject: Avoid a deadlock where a script can attempt to take a ScriptInstance.m_Scripts lock then a lock on SP.m_attachments whilst SP.MakeRootAgent() attempts to take in the opposite order. This is because scripts (at least on XEngine) start unsuspended - deceptively the ResumeScripts() calls in various places in the code are actually completely redundant (and useless). The solution chosen here is to use a copy of the SP attachments and not have the list locked whilst creating the scripts when an avatar enters the region. This looks to address http://opensimulator.org/mantis/view.php?id=6557 --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 32 ++++++++++++++++-------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index b8ff7f7..bab14dd 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -121,6 +121,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// TODO: For some reason, we effectively have a list both here and in Appearance. Need to work out if this is /// necessary. + /// NOTE: To avoid deadlocks, do not lock m_attachments and then perform other tasks under that lock. Take a copy + /// of the list and act on that instead. /// private List m_attachments = new List(); @@ -971,19 +973,27 @@ namespace OpenSim.Region.Framework.Scenes // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are // not transporting the required data. - lock (m_attachments) + // + // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of + // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here + // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status. + // + // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts(). + // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing + // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the + // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine. + List attachments = GetAttachments(); + + if (attachments.Count > 0) { - if (HasAttachments()) - { - m_log.DebugFormat( - "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); + m_log.DebugFormat( + "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); - // Resume scripts - foreach (SceneObjectGroup sog in m_attachments) - { - sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); - sog.ResumeScripts(); - } + // Resume scripts + foreach (SceneObjectGroup sog in attachments) + { + sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); + sog.ResumeScripts(); } } } -- cgit v1.1 From cd64da87461937b2a46ff6f5e8250ee9a8d15889 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 5 Jun 2013 18:41:55 -0400 Subject: Cleanup --- OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs index 5a24ee3..f9a520a 100644 --- a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs @@ -106,11 +106,6 @@ namespace OpenSim.Server.Handlers.Profiles Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); -// Server.AddJsonRPCHandler("user_preferences_request", handler.UserPreferencesRequest); -// Server.AddJsonRPCHandler("user_preferences_update", handler.UserPreferencesUpdate); -// Server.AddJsonRPCHandler("user_account_create", handler.UserAccountCreate); -// Server.AddJsonRPCHandler("user_account_auth", handler.UserAccountAuth); -// Server.AddJsonRPCHandler("user_account_test", handler.UserAccountTest); Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); } -- cgit v1.1 From e449950030decf7e65e7d9b334ddaed25c1bd629 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Wed, 5 Jun 2013 18:42:15 -0400 Subject: Prevent processing for Npc --- OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 13f0167..a97c9b4 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -62,7 +62,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles // count. The entries are removed when the interest count reaches 0. Dictionary classifiedCache = new Dictionary(); Dictionary classifiedInterest = new Dictionary(); - Object classifiedLock; public Scene Scene { @@ -170,6 +169,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles void HandleOnMakeRootAgent (ScenePresence obj) { + if(obj.PresenceType == PresenceType.Npc) + return; + GetImageAssets(((IScenePresence)obj).UUID); } -- cgit v1.1 From a7dbafb0e383ca5043a71284cdc35569acc5e2be Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 5 Jun 2013 23:42:50 +0100 Subject: Port Avination's inventory send throttling --- OpenSim/Framework/Util.cs | 108 +++++++++ .../Linden/Caps/WebFetchInvDescModule.cs | 265 +++++++++++++++++---- prebuild.xml | 1 + 3 files changed, 322 insertions(+), 52 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ada4e89..7f0850f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2233,4 +2233,112 @@ namespace OpenSim.Framework return str.Replace("_", "\\_").Replace("%", "\\%"); } } + + public class DoubleQueue where T:class + { + private Queue m_lowQueue = new Queue(); + private Queue m_highQueue = new Queue(); + + private object m_syncRoot = new object(); + private Semaphore m_s = new Semaphore(0, 1); + + public DoubleQueue() + { + } + + public virtual int Count + { + get { return m_highQueue.Count + m_lowQueue.Count; } + } + + public virtual void Enqueue(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueLow(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueHigh(T data) + { + Enqueue(m_highQueue, data); + } + + private void Enqueue(Queue q, T data) + { + lock (m_syncRoot) + { + m_lowQueue.Enqueue(data); + m_s.WaitOne(0); + m_s.Release(); + } + } + + public virtual T Dequeue() + { + return Dequeue(Timeout.Infinite); + } + + public virtual T Dequeue(int tmo) + { + return Dequeue(TimeSpan.FromMilliseconds(tmo)); + } + + public virtual T Dequeue(TimeSpan wait) + { + T res = null; + + if (!Dequeue(wait, ref res)) + return null; + + return res; + } + + public bool Dequeue(int timeout, ref T res) + { + return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); + } + + public bool Dequeue(TimeSpan wait, ref T res) + { + if (!m_s.WaitOne(wait)) + return false; + + lock (m_syncRoot) + { + if (m_highQueue.Count > 0) + res = m_highQueue.Dequeue(); + else + res = m_lowQueue.Dequeue(); + + if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) + return true; + + try + { + m_s.Release(); + } + catch + { + } + + return true; + } + } + + public virtual void Clear() + { + + lock (m_syncRoot) + { + // Make sure sem count is 0 + m_s.WaitOne(0); + + m_lowQueue.Clear(); + m_highQueue.Clear(); + } + } + } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 6890f4a..7dd9770 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -27,18 +27,25 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Reflection; +using System.Threading; using log4net; using Nini.Config; using Mono.Addins; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; +using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Framework.Capabilities; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OpenSim.Capabilities.Handlers; +using OpenMetaverse; +using OpenMetaverse.StructuredData; namespace OpenSim.Region.ClientStack.Linden { @@ -48,67 +55,74 @@ namespace OpenSim.Region.ClientStack.Linden [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] public class WebFetchInvDescModule : INonSharedRegionModule { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + class aPollRequest + { + public PollServiceInventoryEventArgs thepoll; + public UUID reqID; + public Hashtable request; + public ScenePresence presence; + public List folders; + } + + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; private IInventoryService m_InventoryService; private ILibraryService m_LibraryService; - private bool m_Enabled; + private static WebFetchInvDescHandler m_webFetchHandler; - private string m_fetchInventoryDescendents2Url; - private string m_webFetchInventoryDescendentsUrl; + private Dictionary m_capsDict = new Dictionary(); + private static Thread[] m_workerThreads = null; - private WebFetchInvDescHandler m_webFetchHandler; + private static DoubleQueue m_queue = + new DoubleQueue(); #region ISharedRegionModule Members public void Initialise(IConfigSource source) { - IConfig config = source.Configs["ClientStack.LindenCaps"]; - if (config == null) - return; - - m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); - m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); - - if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) - { - m_Enabled = true; - } } public void AddRegion(Scene s) { - if (!m_Enabled) - return; - m_scene = s; } public void RemoveRegion(Scene s) { - if (!m_Enabled) - return; - m_scene.EventManager.OnRegisterCaps -= RegisterCaps; + m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; m_scene = null; } public void RegionLoaded(Scene s) { - if (!m_Enabled) - return; - m_InventoryService = m_scene.InventoryService; m_LibraryService = m_scene.LibraryService; // We'll reuse the same handler for all requests. - if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") - m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); + m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); m_scene.EventManager.OnRegisterCaps += RegisterCaps; + m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; + + if (m_workerThreads == null) + { + m_workerThreads = new Thread[2]; + + for (uint i = 0; i < 2; i++) + { + m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests, + String.Format("InventoryWorkerThread{0}", i), + ThreadPriority.Normal, + false, + true, + null, + int.MaxValue); + } + } } public void PostInitialise() @@ -126,43 +140,190 @@ namespace OpenSim.Region.ClientStack.Linden #endregion - private void RegisterCaps(UUID agentID, Caps caps) + ~WebFetchInvDescModule() { - if (m_webFetchInventoryDescendentsUrl != "") - RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); - - if (m_fetchInventoryDescendents2Url != "") - RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url); + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); } - private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) + private class PollServiceInventoryEventArgs : PollServiceEventArgs { - string capUrl; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Dictionary responses = + new Dictionary(); + + private Scene m_scene; - if (url == "localhost") + public PollServiceInventoryEventArgs(Scene scene, UUID pId) : + base(null, null, null, null, pId) { - capUrl = "/CAPS/" + UUID.Random(); + m_scene = scene; + + HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; + GetEvents = (x, y, z) => + { + lock (responses) + { + try + { + return responses[x]; + } + finally + { + responses.Remove(x); + } + } + }; + + Request = (x, y) => + { + ScenePresence sp = m_scene.GetScenePresence(Id); + if (sp == null) + { + m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id); + return; + } + + aPollRequest reqinfo = new aPollRequest(); + reqinfo.thepoll = this; + reqinfo.reqID = x; + reqinfo.request = y; + reqinfo.presence = sp; + reqinfo.folders = new List(); + + // Decode the request here + string request = y["body"].ToString(); + + request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); + + request = request.Replace("fetch_folders0", "fetch_folders0"); + request = request.Replace("fetch_folders1", "fetch_folders1"); + + Hashtable hash = new Hashtable(); + try + { + hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); + } + catch (LLSD.LLSDParseException e) + { + m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace); + m_log.Error("Request: " + request); + return; + } + catch (System.Xml.XmlException) + { + m_log.ErrorFormat("[INVENTORY]: XML Format error"); + } + + ArrayList foldersrequested = (ArrayList)hash["folders"]; + + bool highPriority = false; + + for (int i = 0; i < foldersrequested.Count; i++) + { + Hashtable inventoryhash = (Hashtable)foldersrequested[i]; + string folder = inventoryhash["folder_id"].ToString(); + UUID folderID; + if (UUID.TryParse(folder, out folderID)) + { + if (!reqinfo.folders.Contains(folderID)) + { + //TODO: Port COF handling from Avination + reqinfo.folders.Add(folderID); + } + } + } + + if (highPriority) + m_queue.EnqueueHigh(reqinfo); + else + m_queue.EnqueueLow(reqinfo); + }; + + NoEvents = (x, y) => + { +/* + lock (requests) + { + Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString()); + requests.Remove(request); + } +*/ + Hashtable response = new Hashtable(); + + response["int_response_code"] = 500; + response["str_response_string"] = "Script timeout"; + response["content_type"] = "text/plain"; + response["keepalive"] = false; + response["reusecontext"] = false; + + return response; + }; + } - IRequestHandler reqHandler - = new RestStreamHandler( - "POST", - capUrl, - m_webFetchHandler.FetchInventoryDescendentsRequest, - "FetchInventoryDescendents2", - agentID.ToString()); + public void Process(aPollRequest requestinfo) + { + UUID requestID = requestinfo.reqID; + + Hashtable response = new Hashtable(); + + response["int_response_code"] = 200; + response["content_type"] = "text/plain"; + response["keepalive"] = false; + response["reusecontext"] = false; - caps.RegisterHandler(capName, reqHandler); + response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest( + requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); + + lock (responses) + responses[requestID] = response; } - else + } + + private void RegisterCaps(UUID agentID, Caps caps) + { + string capUrl = "/CAPS/" + UUID.Random() + "/"; + + // Register this as a poll service + PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); + + MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); + + string hostName = m_scene.RegionInfo.ExternalHostName; + uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; + string protocol = "http"; + + if (MainServer.Instance.UseSSL) { - capUrl = url; + hostName = MainServer.Instance.SSLCommonName; + port = MainServer.Instance.SSLPort; + protocol = "https"; + } + caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + + m_capsDict[agentID] = capUrl; + } - caps.RegisterHandler(capName, capUrl); + private void DeregisterCaps(UUID agentID, Caps caps) + { + string capUrl; + + if (m_capsDict.TryGetValue(agentID, out capUrl)) + { + MainServer.Instance.RemoveHTTPHandler("", capUrl); + m_capsDict.Remove(agentID); } + } -// m_log.DebugFormat( -// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", -// capName, capUrl, m_scene.RegionInfo.RegionName, agentID); + private void DoInventoryRequests() + { + while (true) + { + aPollRequest poolreq = m_queue.Dequeue(); + + poolreq.thepoll.Process(poolreq); + } } } -} \ No newline at end of file +} diff --git a/prebuild.xml b/prebuild.xml index 03cac76..5531558 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1531,6 +1531,7 @@ + -- cgit v1.1 From e1d98c9e4c579c9feb6bcc4e7473e2372f496fdb Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 6 Jun 2013 02:25:19 +0100 Subject: Committing Avination's Keyframe module. This is not hooked up yet and will do nothing. More commits to follow. --- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 766 ++++++++++++++++++++++ 1 file changed, 766 insertions(+) create mode 100644 OpenSim/Region/Framework/Scenes/KeyframeMotion.cs diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs new file mode 100644 index 0000000..d773ee7 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -0,0 +1,766 @@ +// Proprietary code of Avination Virtual Limited +// (c) 2012 Melanie Thielker +// + +using System; +using System.Timers; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Physics.Manager; +using OpenSim.Region.Framework.Scenes.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; +using Timer = System.Timers.Timer; +using log4net; + +namespace OpenSim.Region.Framework.Scenes +{ + public class KeyframeTimer + { + private static Dictionarym_timers = + new Dictionary(); + + private Timer m_timer; + private Dictionary m_motions = new Dictionary(); + private object m_lockObject = new object(); + private object m_timerLock = new object(); + private const double m_tickDuration = 50.0; + private Scene m_scene; + + public double TickDuration + { + get { return m_tickDuration; } + } + + public KeyframeTimer(Scene scene) + { + m_timer = new Timer(); + m_timer.Interval = TickDuration; + m_timer.AutoReset = true; + m_timer.Elapsed += OnTimer; + + m_scene = scene; + + m_timer.Start(); + } + + private void OnTimer(object sender, ElapsedEventArgs ea) + { + if (!Monitor.TryEnter(m_timerLock)) + return; + + try + { + List motions; + + lock (m_lockObject) + { + motions = new List(m_motions.Keys); + } + + foreach (KeyframeMotion m in motions) + { + try + { + m.OnTimer(TickDuration); + } + catch (Exception inner) + { + // Don't stop processing + } + } + } + catch (Exception e) + { + // Keep running no matter what + } + finally + { + Monitor.Exit(m_timerLock); + } + } + + public static void Add(KeyframeMotion motion) + { + KeyframeTimer timer; + + if (motion.Scene == null) + return; + + lock (m_timers) + { + if (!m_timers.TryGetValue(motion.Scene, out timer)) + { + timer = new KeyframeTimer(motion.Scene); + m_timers[motion.Scene] = timer; + } + } + + lock (timer.m_lockObject) + { + timer.m_motions[motion] = null; + } + } + + public static void Remove(KeyframeMotion motion) + { + KeyframeTimer timer; + + if (motion.Scene == null) + return; + + lock (m_timers) + { + if (!m_timers.TryGetValue(motion.Scene, out timer)) + { + return; + } + } + + lock (timer.m_lockObject) + { + timer.m_motions.Remove(motion); + } + } + } + + [Serializable] + public class KeyframeMotion + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public enum PlayMode : int + { + Forward = 0, + Reverse = 1, + Loop = 2, + PingPong = 3 + }; + + [Flags] + public enum DataFormat : int + { + Translation = 2, + Rotation = 1 + } + + [Serializable] + public struct Keyframe + { + public Vector3? Position; + public Quaternion? Rotation; + public Quaternion StartRotation; + public int TimeMS; + public int TimeTotal; + public Vector3 AngularVelocity; + }; + + private Vector3 m_serializedPosition; + private Vector3 m_basePosition; + private Quaternion m_baseRotation; + + private Keyframe m_currentFrame; + + private List m_frames = new List(); + + private Keyframe[] m_keyframes; + + // skip timer events. + //timer.stop doesn't assure there aren't event threads still being fired + [NonSerialized()] + private bool m_timerStopped; + + [NonSerialized()] + private bool m_isCrossing; + + [NonSerialized()] + private bool m_waitingCrossing; + + // retry position for cross fail + [NonSerialized()] + private Vector3 m_nextPosition; + + [NonSerialized()] + private SceneObjectGroup m_group; + + private PlayMode m_mode = PlayMode.Forward; + private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation; + + private bool m_running = false; + + [NonSerialized()] + private bool m_selected = false; + + private int m_iterations = 0; + + private int m_skipLoops = 0; + + [NonSerialized()] + private Scene m_scene; + + public Scene Scene + { + get { return m_scene; } + } + + public DataFormat Data + { + get { return m_data; } + } + + public bool Selected + { + set + { + if (m_group != null) + { + if (!value) + { + // Once we're let go, recompute positions + if (m_selected) + UpdateSceneObject(m_group); + } + else + { + // Save selection position in case we get moved + if (!m_selected) + { + StopTimer(); + m_serializedPosition = m_group.AbsolutePosition; + } + } + } + m_isCrossing = false; + m_waitingCrossing = false; + m_selected = value; + } + } + + private void StartTimer() + { + KeyframeTimer.Add(this); + m_timerStopped = false; + } + + private void StopTimer() + { + m_timerStopped = true; + KeyframeTimer.Remove(this); + } + + public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) + { + KeyframeMotion newMotion = null; + + try + { + MemoryStream ms = new MemoryStream(data); + BinaryFormatter fmt = new BinaryFormatter(); + + newMotion = (KeyframeMotion)fmt.Deserialize(ms); + + newMotion.m_group = grp; + + if (grp != null) + { + newMotion.m_scene = grp.Scene; + if (grp.IsSelected) + newMotion.m_selected = true; + } + + newMotion.m_timerStopped = false; + newMotion.m_running = true; + newMotion.m_isCrossing = false; + newMotion.m_waitingCrossing = false; + } + catch + { + newMotion = null; + } + + return newMotion; + } + + public void UpdateSceneObject(SceneObjectGroup grp) + { + m_isCrossing = false; + m_waitingCrossing = false; + StopTimer(); + + if (grp == null) + return; + + m_group = grp; + m_scene = grp.Scene; + + Vector3 grppos = grp.AbsolutePosition; + Vector3 offset = grppos - m_serializedPosition; + // avoid doing it more than once + // current this will happen draging a prim to other region + m_serializedPosition = grppos; + + m_basePosition += offset; + m_currentFrame.Position += offset; + + m_nextPosition += offset; + + for (int i = 0; i < m_frames.Count; i++) + { + Keyframe k = m_frames[i]; + k.Position += offset; + m_frames[i]=k; + } + + if (m_running) + Start(); + } + + public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) + { + m_mode = mode; + m_data = data; + + m_group = grp; + if (grp != null) + { + m_basePosition = grp.AbsolutePosition; + m_baseRotation = grp.GroupRotation; + m_scene = grp.Scene; + } + + m_timerStopped = true; + m_isCrossing = false; + m_waitingCrossing = false; + } + + public void SetKeyframes(Keyframe[] frames) + { + m_keyframes = frames; + } + + public KeyframeMotion Copy(SceneObjectGroup newgrp) + { + StopTimer(); + + KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data); + + newmotion.m_group = newgrp; + newmotion.m_scene = newgrp.Scene; + + if (m_keyframes != null) + { + newmotion.m_keyframes = new Keyframe[m_keyframes.Length]; + m_keyframes.CopyTo(newmotion.m_keyframes, 0); + } + + newmotion.m_frames = new List(m_frames); + + newmotion.m_basePosition = m_basePosition; + newmotion.m_baseRotation = m_baseRotation; + + if (m_selected) + newmotion.m_serializedPosition = m_serializedPosition; + else + { + if (m_group != null) + newmotion.m_serializedPosition = m_group.AbsolutePosition; + else + newmotion.m_serializedPosition = m_serializedPosition; + } + + newmotion.m_currentFrame = m_currentFrame; + + newmotion.m_iterations = m_iterations; + newmotion.m_running = m_running; + + if (m_running && !m_waitingCrossing) + StartTimer(); + + return newmotion; + } + + public void Delete() + { + m_running = false; + StopTimer(); + m_isCrossing = false; + m_waitingCrossing = false; + m_frames.Clear(); + m_keyframes = null; + } + + public void Start() + { + m_isCrossing = false; + m_waitingCrossing = false; + if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) + { + StartTimer(); + m_running = true; + } + else + { + m_running = false; + StopTimer(); + } + } + + public void Stop() + { + m_running = false; + m_isCrossing = false; + m_waitingCrossing = false; + + StopTimer(); + + m_basePosition = m_group.AbsolutePosition; + m_baseRotation = m_group.GroupRotation; + + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.AngularVelocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); +// m_group.RootPart.ScheduleTerseUpdate(); + m_frames.Clear(); + } + + public void Pause() + { + m_running = false; + StopTimer(); + + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.AngularVelocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); +// m_group.RootPart.ScheduleTerseUpdate(); + + } + + private void GetNextList() + { + m_frames.Clear(); + Vector3 pos = m_basePosition; + Quaternion rot = m_baseRotation; + + if (m_mode == PlayMode.Loop || m_mode == PlayMode.PingPong || m_iterations == 0) + { + int direction = 1; + if (m_mode == PlayMode.Reverse || ((m_mode == PlayMode.PingPong) && ((m_iterations & 1) != 0))) + direction = -1; + + int start = 0; + int end = m_keyframes.Length; + + if (direction < 0) + { + start = m_keyframes.Length - 1; + end = -1; + } + + for (int i = start; i != end ; i += direction) + { + Keyframe k = m_keyframes[i]; + + if (k.Position.HasValue) + { + k.Position = (k.Position * direction); +// k.Velocity = (Vector3)k.Position / (k.TimeMS / 1000.0f); + k.Position += pos; + } + else + { + k.Position = pos; +// k.Velocity = Vector3.Zero; + } + + k.StartRotation = rot; + if (k.Rotation.HasValue) + { + if (direction == -1) + k.Rotation = Quaternion.Conjugate((Quaternion)k.Rotation); + k.Rotation = rot * k.Rotation; + } + else + { + k.Rotation = rot; + } + +/* ang vel not in use for now + + float angle = 0; + + float aa = k.StartRotation.X * k.StartRotation.X + k.StartRotation.Y * k.StartRotation.Y + k.StartRotation.Z * k.StartRotation.Z + k.StartRotation.W * k.StartRotation.W; + float bb = ((Quaternion)k.Rotation).X * ((Quaternion)k.Rotation).X + ((Quaternion)k.Rotation).Y * ((Quaternion)k.Rotation).Y + ((Quaternion)k.Rotation).Z * ((Quaternion)k.Rotation).Z + ((Quaternion)k.Rotation).W * ((Quaternion)k.Rotation).W; + float aa_bb = aa * bb; + + if (aa_bb == 0) + { + angle = 0; + } + else + { + float ab = k.StartRotation.X * ((Quaternion)k.Rotation).X + + k.StartRotation.Y * ((Quaternion)k.Rotation).Y + + k.StartRotation.Z * ((Quaternion)k.Rotation).Z + + k.StartRotation.W * ((Quaternion)k.Rotation).W; + float q = (ab * ab) / aa_bb; + + if (q > 1.0f) + { + angle = 0; + } + else + { + angle = (float)Math.Acos(2 * q - 1); + } + } + + k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000)); + */ + k.TimeTotal = k.TimeMS; + + m_frames.Add(k); + + pos = (Vector3)k.Position; + rot = (Quaternion)k.Rotation; + } + + m_basePosition = pos; + m_baseRotation = rot; + + m_iterations++; + } + } + + public void OnTimer(double tickDuration) + { + if (m_skipLoops > 0) + { + m_skipLoops--; + return; + } + + if (m_timerStopped) // trap events still in air even after a timer.stop + return; + + if (m_group == null) + return; + + bool update = false; + + if (m_selected) + { + if (m_group.RootPart.Velocity != Vector3.Zero) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); + + } + return; + } + + if (m_isCrossing) + { + // if crossing and timer running then cross failed + // wait some time then + // retry to set the position that evtually caused the outbound + // if still outside region this will call startCrossing below + m_isCrossing = false; + m_group.AbsolutePosition = m_nextPosition; + if (!m_isCrossing) + { + StopTimer(); + StartTimer(); + } + return; + } + + if (m_frames.Count == 0) + { + GetNextList(); + + if (m_frames.Count == 0) + { + Stop(); + Scene scene = m_group.Scene; + + IScriptModule[] scriptModules = scene.RequestModuleInterfaces(); + foreach (IScriptModule m in scriptModules) + { + if (m == null) + continue; + m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]); + } + + return; + } + + m_currentFrame = m_frames[0]; + m_currentFrame.TimeMS += (int)tickDuration; + + //force a update on a keyframe transition + update = true; + } + + m_currentFrame.TimeMS -= (int)tickDuration; + + // Do the frame processing + double steps = (double)m_currentFrame.TimeMS / tickDuration; + + if (steps <= 0.0) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.RootPart.AngularVelocity = Vector3.Zero; + + m_nextPosition = (Vector3)m_currentFrame.Position; + m_group.AbsolutePosition = m_nextPosition; + + // we are sending imediate updates, no doing force a extra terseUpdate + // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); + + m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; + m_frames.RemoveAt(0); + if (m_frames.Count > 0) + m_currentFrame = m_frames[0]; + + update = true; + } + else + { + float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; + + Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; + Vector3 motionThisFrame = v / (float)steps; + v = v * 1000 / m_currentFrame.TimeMS; + + if (Vector3.Mag(motionThisFrame) >= 0.05f) + { + // m_group.AbsolutePosition += motionThisFrame; + m_nextPosition = m_group.AbsolutePosition + motionThisFrame; + m_group.AbsolutePosition = m_nextPosition; + + //m_group.RootPart.Velocity = v; + update = true; + } + + if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) + { + Quaternion current = m_group.GroupRotation; + + Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); + step.Normalize(); +/* use simpler change detection +* float angle = 0; + + float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; + float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; + float aa_bb = aa * bb; + + if (aa_bb == 0) + { + angle = 0; + } + else + { + float ab = current.X * step.X + + current.Y * step.Y + + current.Z * step.Z + + current.W * step.W; + float q = (ab * ab) / aa_bb; + + if (q > 1.0f) + { + angle = 0; + } + else + { + angle = (float)Math.Acos(2 * q - 1); + } + } + + if (angle > 0.01f) +*/ + if(Math.Abs(step.X - current.X) > 0.001f + || Math.Abs(step.Y - current.Y) > 0.001f + || Math.Abs(step.Z - current.Z) > 0.001f) + // assuming w is a dependente var + + { +// m_group.UpdateGroupRotationR(step); + m_group.RootPart.RotationOffset = step; + + //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); + update = true; + } + } + } + + if (update) + { + m_group.SendGroupRootTerseUpdate(); + } + } + + public Byte[] Serialize() + { + StopTimer(); + MemoryStream ms = new MemoryStream(); + + BinaryFormatter fmt = new BinaryFormatter(); + SceneObjectGroup tmp = m_group; + m_group = null; + if (!m_selected && tmp != null) + m_serializedPosition = tmp.AbsolutePosition; + fmt.Serialize(ms, this); + m_group = tmp; + if (m_running && !m_waitingCrossing) + StartTimer(); + + return ms.ToArray(); + } + + public void StartCrossingCheck() + { + // timer will be restart by crossingFailure + // or never since crossing worked and this + // should be deleted + StopTimer(); + + m_isCrossing = true; + m_waitingCrossing = true; + + // to remove / retune to smoth crossings + if (m_group.RootPart.Velocity != Vector3.Zero) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); +// m_group.RootPart.ScheduleTerseUpdate(); + } + } + + public void CrossingFailure() + { + m_waitingCrossing = false; + + if (m_group != null) + { + m_group.RootPart.Velocity = Vector3.Zero; + m_group.SendGroupRootTerseUpdate(); +// m_group.RootPart.ScheduleTerseUpdate(); + + if (m_running) + { + StopTimer(); + m_skipLoops = 1200; // 60 seconds + StartTimer(); + } + } + } + } +} -- cgit v1.1 From 81ad9255b5f44d988bf37cfaf6dc59b05fd744b7 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 6 Jun 2013 03:03:05 +0100 Subject: Hook up Keyframe motion to almost everything. Failing to cross a sim border may yield unexpected results in some cases. No database persistence yet, --- .../EntityTransfer/EntityTransferModule.cs | 3 + .../InventoryAccess/InventoryAccessModule.cs | 3 + OpenSim/Region/Framework/Scenes/Scene.cs | 9 ++ OpenSim/Region/Framework/Scenes/SceneGraph.cs | 11 ++ .../Region/Framework/Scenes/SceneObjectGroup.cs | 13 ++ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 15 +++ .../Scenes/Serialization/SceneObjectSerializer.cs | 16 +++ .../Shared/Api/Implementation/LSL_Api.cs | 140 +++++++++++++++++++++ .../ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | 1 + .../Shared/Api/Runtime/LSL_Constants.cs | 13 ++ .../ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | 5 + 11 files changed, 229 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index f58a24f..85d26f3 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -2247,6 +2247,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // move out of the region creating an infinite loop of failed attempts to cross grp.UpdatePrimFlags(grp.RootPart.LocalId,false,grp.IsTemporary,grp.IsPhantom,false); + if (grp.RootPart.KeyframeMotion != null) + grp.RootPart.KeyframeMotion.CrossingFailure(); + grp.ScheduleGroupForFullUpdate(); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index e6d6cbf..880205a 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -357,6 +357,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (SceneObjectGroup objectGroup in objlist) { + if (objectGroup.RootPart.KeyframeMotion != null) + objectGroup.RootPart.KeyframeMotion.Stop(); + objectGroup.RootPart.KeyframeMotion = null; // Vector3 inventoryStoredPosition = new Vector3 // (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) // ? 250 diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 0743ce7..a9f8a85 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2364,6 +2364,12 @@ namespace OpenSim.Region.Framework.Scenes foreach (SceneObjectPart part in partList) { + if (part.KeyframeMotion != null) + { + part.KeyframeMotion.Delete(); + part.KeyframeMotion = null; + } + if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) { PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? @@ -2705,6 +2711,9 @@ namespace OpenSim.Region.Framework.Scenes // before we restart the scripts, or else some functions won't work. newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); newObject.ResumeScripts(); + + if (newObject.RootPart.KeyframeMotion != null) + newObject.RootPart.KeyframeMotion.UpdateSceneObject(newObject); } // Do this as late as possible so that listeners have full access to the incoming object diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index a84f6d3..bb7ae7f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1645,6 +1645,12 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal void LinkObjects(SceneObjectPart root, List children) { + if (root.KeyframeMotion != null) + { + root.KeyframeMotion.Stop(); + root.KeyframeMotion = null; + } + SceneObjectGroup parentGroup = root.ParentGroup; if (parentGroup == null) return; @@ -1722,6 +1728,11 @@ namespace OpenSim.Region.Framework.Scenes { if (part != null) { + if (part.KeyframeMotion != null) + { + part.KeyframeMotion.Stop(); + part.KeyframeMotion = null; + } if (part.ParentGroup.PrimCount != 1) // Skip single { if (part.LinkNum < 2) // Root diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index df23cc5..da80e4f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -455,6 +455,9 @@ namespace OpenSim.Region.Framework.Scenes || Scene.TestBorderCross(val, Cardinals.S)) && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) { + if (m_rootPart.KeyframeMotion != null) + m_rootPart.KeyframeMotion.StartCrossingCheck(); + m_scene.CrossPrimGroupIntoNewRegion(val, this, true); } } @@ -578,6 +581,8 @@ namespace OpenSim.Region.Framework.Scenes childPa.Selected = value; } } + if (RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Selected = value; } } @@ -1551,6 +1556,8 @@ namespace OpenSim.Region.Framework.Scenes newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); } + if (part.KeyframeMotion != null) + newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); } if (userExposed) @@ -1578,6 +1585,12 @@ namespace OpenSim.Region.Framework.Scenes public void ScriptSetPhysicsStatus(bool usePhysics) { + if (usePhysics) + { + if (RootPart.KeyframeMotion != null) + RootPart.KeyframeMotion.Stop(); + RootPart.KeyframeMotion = null; + } UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ea8c3c5..ff3f738 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -354,6 +354,13 @@ namespace OpenSim.Region.Framework.Scenes private UUID m_collisionSound; private float m_collisionSoundVolume; + private KeyframeMotion m_keyframeMotion = null; + + public KeyframeMotion KeyframeMotion + { + get; set; + } + #endregion Fields // ~SceneObjectPart() @@ -1799,6 +1806,8 @@ namespace OpenSim.Region.Framework.Scenes Array.Copy(Shape.ExtraParams, extraP, extraP.Length); dupe.Shape.ExtraParams = extraP; + // safeguard actual copy is done in sog.copy + dupe.KeyframeMotion = null; dupe.PayPrice = (int[])PayPrice.Clone(); dupe.DynAttrs.CopyFrom(DynAttrs); @@ -2001,6 +2010,9 @@ namespace OpenSim.Region.Framework.Scenes { if (UsePhysics) { + if (ParentGroup.RootPart.KeyframeMotion != null) + ParentGroup.RootPart.KeyframeMotion.Stop(); + ParentGroup.RootPart.KeyframeMotion = null; ParentGroup.Scene.AddPhysicalPrim(1); pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; @@ -4327,6 +4339,9 @@ namespace OpenSim.Region.Framework.Scenes if (isPhysical) { + if (ParentGroup.RootPart.KeyframeMotion != null) + ParentGroup.RootPart.KeyframeMotion.Stop(); + ParentGroup.RootPart.KeyframeMotion = null; ParentGroup.Scene.AddPhysicalPrim(1); pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 39420a6..3882b45 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -262,6 +262,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization sr.Close(); } + XmlNodeList keymotion = doc.GetElementsByTagName("KeyframeMotion"); + if (keymotion.Count > 0) + sceneObject.RootPart.KeyframeMotion = KeyframeMotion.FromData(sceneObject, Convert.FromBase64String(keymotion[0].InnerText)); + else + sceneObject.RootPart.KeyframeMotion = null; + // Script state may, or may not, exist. Not having any, is NOT // ever a problem. sceneObject.LoadScriptState(doc); @@ -1182,6 +1188,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization }); writer.WriteEndElement(); + + if (sog.RootPart.KeyframeMotion != null) + { + Byte[] data = sog.RootPart.KeyframeMotion.Serialize(); + + writer.WriteStartElement(String.Empty, "KeyframeMotion", String.Empty); + writer.WriteBase64(data, 0, data.Length); + writer.WriteEndElement(); + } + writer.WriteEndElement(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 0b4b043..cd6092d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7296,6 +7296,146 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public void llSetKeyframedMotion(LSL_List frames, LSL_List options) + { + SceneObjectGroup group = m_host.ParentGroup; + + if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical) + return; + if (group.IsAttachment) + return; + + if (frames.Data.Length > 0) // We are getting a new motion + { + if (group.RootPart.KeyframeMotion != null) + group.RootPart.KeyframeMotion.Delete(); + group.RootPart.KeyframeMotion = null; + + int idx = 0; + + KeyframeMotion.PlayMode mode = KeyframeMotion.PlayMode.Forward; + KeyframeMotion.DataFormat data = KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation; + + while (idx < options.Data.Length) + { + int option = (int)options.GetLSLIntegerItem(idx++); + int remain = options.Data.Length - idx; + + switch (option) + { + case ScriptBaseClass.KFM_MODE: + if (remain < 1) + break; + int modeval = (int)options.GetLSLIntegerItem(idx++); + switch(modeval) + { + case ScriptBaseClass.KFM_FORWARD: + mode = KeyframeMotion.PlayMode.Forward; + break; + case ScriptBaseClass.KFM_REVERSE: + mode = KeyframeMotion.PlayMode.Reverse; + break; + case ScriptBaseClass.KFM_LOOP: + mode = KeyframeMotion.PlayMode.Loop; + break; + case ScriptBaseClass.KFM_PING_PONG: + mode = KeyframeMotion.PlayMode.PingPong; + break; + } + break; + case ScriptBaseClass.KFM_DATA: + if (remain < 1) + break; + int dataval = (int)options.GetLSLIntegerItem(idx++); + data = (KeyframeMotion.DataFormat)dataval; + break; + } + } + + group.RootPart.KeyframeMotion = new KeyframeMotion(group, mode, data); + + idx = 0; + + int elemLength = 2; + if (data == (KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation)) + elemLength = 3; + + List keyframes = new List(); + while (idx < frames.Data.Length) + { + int remain = frames.Data.Length - idx; + + if (remain < elemLength) + break; + + KeyframeMotion.Keyframe frame = new KeyframeMotion.Keyframe(); + frame.Position = null; + frame.Rotation = null; + + if ((data & KeyframeMotion.DataFormat.Translation) != 0) + { + LSL_Types.Vector3 tempv = frames.GetVector3Item(idx++); + frame.Position = new Vector3((float)tempv.x, (float)tempv.y, (float)tempv.z); + } + if ((data & KeyframeMotion.DataFormat.Rotation) != 0) + { + LSL_Types.Quaternion tempq = frames.GetQuaternionItem(idx++); + Quaternion q = new Quaternion((float)tempq.x, (float)tempq.y, (float)tempq.z, (float)tempq.s); + q.Normalize(); + frame.Rotation = q; + } + + float tempf = (float)frames.GetLSLFloatItem(idx++); + frame.TimeMS = (int)(tempf * 1000.0f); + + keyframes.Add(frame); + } + + group.RootPart.KeyframeMotion.SetKeyframes(keyframes.ToArray()); + group.RootPart.KeyframeMotion.Start(); + } + else + { + if (group.RootPart.KeyframeMotion == null) + return; + + if (options.Data.Length == 0) + { + group.RootPart.KeyframeMotion.Stop(); + return; + } + + int code = (int)options.GetLSLIntegerItem(0); + + int idx = 0; + + while (idx < options.Data.Length) + { + int option = (int)options.GetLSLIntegerItem(idx++); + int remain = options.Data.Length - idx; + + switch (option) + { + case ScriptBaseClass.KFM_COMMAND: + int cmd = (int)options.GetLSLIntegerItem(idx++); + switch (cmd) + { + case ScriptBaseClass.KFM_CMD_PLAY: + group.RootPart.KeyframeMotion.Start(); + break; + case ScriptBaseClass.KFM_CMD_STOP: + group.RootPart.KeyframeMotion.Stop(); + break; + case ScriptBaseClass.KFM_CMD_PAUSE: + group.RootPart.KeyframeMotion.Pause(); + break; + } + break; + } + } + } + } + protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed) { int idx = 0; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 4ac179a..a6ea88c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -427,6 +427,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void print(string str); void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc); + void llSetKeyframedMotion(LSL_List frames, LSL_List options); LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index dc5ef13..559068d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -748,6 +748,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2; public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3; + public const int KFM_MODE = 1; + public const int KFM_LOOP = 1; + public const int KFM_REVERSE = 3; + public const int KFM_FORWARD = 0; + public const int KFM_PING_PONG = 2; + public const int KFM_DATA = 2; + public const int KFM_TRANSLATION = 2; + public const int KFM_ROTATION = 1; + public const int KFM_COMMAND = 0; + public const int KFM_CMD_PLAY = 0; + public const int KFM_CMD_STOP = 1; + public const int KFM_CMD_PAUSE = 2; + /// /// process name parameter as regex /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index c7a7cf6..398c125 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -554,6 +554,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetLinkNumberOfSides(link); } + public void llSetKeyframedMotion(LSL_List frames, LSL_List options) + { + m_LSL_Functions.llSetKeyframedMotion(frames, options); + } + public LSL_Integer llGetListEntryType(LSL_List src, int index) { return m_LSL_Functions.llGetListEntryType(src, index); -- cgit v1.1 From a3210d1cf812554b53afb407fd76dbb67ce2ac28 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 6 Jun 2013 03:17:38 +0100 Subject: Database persistence for keyframes. Contains a Migration. --- OpenSim/Data/MySQL/MySQLSimulationData.cs | 29 +++++++++++++++++++--- .../Data/MySQL/Resources/RegionStore.migrations | 7 ++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 2d20eaf..448962a 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -173,9 +173,9 @@ namespace OpenSim.Data.MySQL "ParticleSystem, ClickAction, Material, " + "CollisionSound, CollisionSoundVolume, " + "PassTouches, " + - "LinkNumber, MediaURL, DynAttrs, " + + "LinkNumber, MediaURL, KeyframeMotion, " + "PhysicsShapeType, Density, GravityModifier, " + - "Friction, Restitution " + + "Friction, Restitution, DynAttrs " + ") values (" + "?UUID, " + "?CreationDate, ?Name, ?Text, " + "?Description, ?SitName, ?TouchName, " + @@ -208,9 +208,9 @@ namespace OpenSim.Data.MySQL "?ColorB, ?ColorA, ?ParticleSystem, " + "?ClickAction, ?Material, ?CollisionSound, " + "?CollisionSoundVolume, ?PassTouches, " + - "?LinkNumber, ?MediaURL, ?DynAttrs, " + + "?LinkNumber, ?MediaURL, ?KeyframeMotion, " + "?PhysicsShapeType, ?Density, ?GravityModifier, " + - "?Friction, ?Restitution)"; + "?Friction, ?Restitution, ?DynAttrs)"; FillPrimCommand(cmd, prim, obj.UUID, regionUUID); @@ -455,7 +455,11 @@ namespace OpenSim.Data.MySQL foreach (SceneObjectPart prim in prims.Values) { if (prim.ParentUUID == UUID.Zero) + { objects[prim.UUID] = new SceneObjectGroup(prim); + if (prim.KeyframeMotion != null) + prim.KeyframeMotion.UpdateSceneObject(objects[prim.UUID]); + } } // Add all of the children objects to the SOGs @@ -1307,6 +1311,19 @@ namespace OpenSim.Data.MySQL else prim.DynAttrs = new DAMap(); + if (!(row["KeyframeMotion"] is DBNull)) + { + Byte[] data = (byte[])row["KeyframeMotion"]; + if (data.Length > 0) + prim.KeyframeMotion = KeyframeMotion.FromData(null, data); + else + prim.KeyframeMotion = null; + } + else + { + prim.KeyframeMotion = null; + } + prim.PhysicsShapeType = (byte)Convert.ToInt32(row["PhysicsShapeType"].ToString()); prim.Density = (float)(double)row["Density"]; prim.GravityModifier = (float)(double)row["GravityModifier"]; @@ -1659,6 +1676,10 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum); cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl); + if (prim.KeyframeMotion != null) + cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize()); + else + cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]); if (prim.DynAttrs.Count > 0) cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml()); diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index 513c784..70b9558 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -923,3 +923,10 @@ ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5'; COMMIT; +:VERSION 48 #---------------- Keyframes + +BEGIN; + +ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob; + +COMMIT; -- cgit v1.1 From 2ebf70d719e1db2062a9a55bd1037e43c089276e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 5 Jun 2013 20:19:59 -0700 Subject: Strengthen some assumptions. --- .../CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index e474ef6..58576d1 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -233,6 +233,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory if (sp != null) { AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + if (aCircuit == null) + return; + if (aCircuit.ServiceURLs == null) + return; + if (aCircuit.ServiceURLs.ContainsKey("InventoryServerURI")) { inventoryURL = aCircuit.ServiceURLs["InventoryServerURI"].ToString(); -- cgit v1.1 From 06012f86753b1d2d688980fae06ad27cea147ddb Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 6 Jun 2013 23:49:02 +0100 Subject: Fix keyframe motion copyright --- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 29 ++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index d773ee7..8a40278 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -1,6 +1,29 @@ -// Proprietary code of Avination Virtual Limited -// (c) 2012 Melanie Thielker -// +/* + * 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.Timers; -- cgit v1.1 From 664c6191edbbff2a88fccc2c9755c7fa0938dad3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 7 Jun 2013 08:37:18 -0700 Subject: Mantis #6620 (removed debug message) --- OpenSim/Addons/Groups/GroupsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index f805d69..5b3b9f6 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -347,7 +347,7 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); - m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog); + //m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog); // Group invitations if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)) { -- cgit v1.1 From 045c26f6265ff4e66f07280da555e10a0dc9e2fa Mon Sep 17 00:00:00 2001 From: Donnie Roberts Date: Wed, 5 Jun 2013 19:55:18 -0400 Subject: In LocalFriendshipTerminated, send the original client's agentId to the friend being removed instead of the friend's own id. --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 6 +++--- OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 4613344..41ea2a2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -685,7 +685,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // // Try local - if (LocalFriendshipTerminated(exfriendID)) + if (LocalFriendshipTerminated(client.AgentId, exfriendID)) return; PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() }); @@ -827,13 +827,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return false; } - public bool LocalFriendshipTerminated(UUID exfriendID) + public bool LocalFriendshipTerminated(UUID userID, UUID exfriendID) { IClientAPI friendClient = LocateClientObject(exfriendID); if (friendClient != null) { // the friend in this sim as root agent - friendClient.SendTerminateFriend(exfriendID); + friendClient.SendTerminateFriend(userID); // update local cache RecacheFriends(friendClient); // we're done diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs index 637beef..08196f1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs @@ -193,7 +193,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (!UUID.TryParse(request["ToID"].ToString(), out toID)) return FailureResult(); - if (m_FriendsModule.LocalFriendshipTerminated(toID)) + if (m_FriendsModule.LocalFriendshipTerminated(fromID, toID)) return SuccessResult(); return FailureResult(); -- cgit v1.1 From f2a4d9b99cfefac622cc3d499cbdc757c4bff527 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 7 Jun 2013 19:13:24 +0100 Subject: Fix regression where multiple close agents could be sent to the wrong neighbour region on root agent close. This was introduced in git master d214e2d0 (Thu May 16 17:12:02 2013) Caught out by the fact that value types used in iterators act like references and this was dispatched asynchronously. Should address http://opensimulator.org/mantis/view.php?id=6658 --- OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index 8c84c98..8238e23 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -222,7 +222,12 @@ namespace OpenSim.Region.Framework.Scenes public void SendCloseChildAgentConnections(UUID agentID, List regionslst) { foreach (ulong handle in regionslst) - Util.FireAndForget(delegate { SendCloseChildAgent(agentID, handle); }); + { + // We must take a copy here since handle is acts like a reference when used in an iterator. + // This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region. + ulong handleCopy = handle; + Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy); }); + } } public List RequestNamedRegions(string name, int maxNumber) -- cgit v1.1 From 346eda27ccffd3890509360697f7e2737ac022fb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 7 Jun 2013 19:26:09 +0100 Subject: minor: add dr0berts to contributors list --- CONTRIBUTORS.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 36b17be..7601a50 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -75,11 +75,12 @@ what it is today. * controlbreak * coyled * Daedius -* Dong Jun Lan (IBM) -* DoranZemlja * daTwitch * devalnor-#708 * dmiles (Daxtron Labs) +* Dong Jun Lan (IBM) +* DoranZemlja +* dr0b3rts * dslake (Intel) * FredoChaplin * Garmin Kawaguichi -- cgit v1.1 From 454499ff60bf45f77f6f25e9164fcbbfff967bba Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 7 Jun 2013 23:38:23 +0100 Subject: minor: Comment out debug logging (at warn level) about number of objects force selected and turn down to debug level --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index e47397d..9784d15 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4828,7 +4828,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendForceClientSelectObjects(List ObjectIDs) { - m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); +// m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); bool firstCall = true; const int MAX_OBJECTS_PER_PACKET = 251; -- cgit v1.1 From 7c0bfca7a03584dd65c5659f177b434ee94ddc9d Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 7 Jun 2013 23:43:45 +0100 Subject: Adding Avination's PollService to round out the HTTP inventory changes --- OpenSim/Framework/Console/RemoteConsole.cs | 4 +- .../Framework/Servers/HttpServer/BaseHttpServer.cs | 3 +- .../Servers/HttpServer/PollServiceEventArgs.cs | 19 +- .../HttpServer/PollServiceRequestManager.cs | 248 ++++++++++++++++----- .../Servers/HttpServer/PollServiceWorkerThread.cs | 165 -------------- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 4 +- .../Linden/Caps/WebFetchInvDescModule.cs | 4 +- .../CoreModules/Scripting/LSLHttp/UrlModule.cs | 8 +- prebuild.xml | 1 + 9 files changed, 220 insertions(+), 236 deletions(-) delete mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 27edd4b..3e3c2b3 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs @@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console string uri = "/ReadResponses/" + sessionID.ToString() + "/"; m_Server.AddPollServiceHTTPHandler( - uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID)); + uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, @@ -425,7 +425,7 @@ namespace OpenSim.Framework.Console return false; } - private Hashtable GetEvents(UUID RequestID, UUID sessionID, string request) + private Hashtable GetEvents(UUID RequestID, UUID sessionID) { ConsoleConnection c = null; diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 96a030b..eb7c578 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -1805,7 +1805,6 @@ namespace OpenSim.Framework.Servers.HttpServer // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); - m_PollServiceManager.Start(); HTTPDRunning = true; //HttpListenerContext context; @@ -1856,7 +1855,7 @@ namespace OpenSim.Framework.Servers.HttpServer HTTPDRunning = false; try { - m_PollServiceManager.Stop(); +// m_PollServiceManager.Stop(); m_httpListener2.ExceptionThrown -= httpServerException; //m_httpListener2.DisconnectHandler = null; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 3089351..c19ac32 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -34,7 +34,7 @@ namespace OpenSim.Framework.Servers.HttpServer public delegate void RequestMethod(UUID requestID, Hashtable request); public delegate bool HasEventsMethod(UUID requestID, UUID pId); - public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId, string request); + public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId); public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId); @@ -45,17 +45,30 @@ namespace OpenSim.Framework.Servers.HttpServer public NoEventsMethod NoEvents; public RequestMethod Request; public UUID Id; + public int TimeOutms; + public EventType Type; + + public enum EventType : int + { + Normal = 0, + LslHttp = 1, + Inventory = 2, + Texture = 3, + Mesh = 4 + } public PollServiceEventArgs( RequestMethod pRequest, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, - UUID pId) + UUID pId, int pTimeOutms) { Request = pRequest; HasEvents = pHasEvents; GetEvents = pGetEvents; NoEvents = pNoEvents; Id = pId; + TimeOutms = pTimeOutms; + Type = EventType.Normal; } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 3e84c55..a5380c1 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -33,53 +33,56 @@ using log4net; using HttpServer; using OpenSim.Framework; using OpenSim.Framework.Monitoring; +using Amib.Threading; +using System.IO; +using System.Text; +using System.Collections.Generic; namespace OpenSim.Framework.Servers.HttpServer { public class PollServiceRequestManager { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private readonly BaseHttpServer m_server; - private static Queue m_requests = Queue.Synchronized(new Queue()); + + private BlockingQueue m_requests = new BlockingQueue(); + private static Queue m_slowRequests = new Queue(); + private static Queue m_retryRequests = new Queue(); + private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private PollServiceWorkerThread[] m_PollServiceWorkerThreads; - private volatile bool m_running = true; - private int m_pollTimeout; + private Thread m_retrysThread; + + private bool m_running = true; + private int slowCount = 0; + + private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); + +// private int m_timeout = 1000; // increase timeout 250; now use the event one public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) { m_server = pSrv; m_WorkerThreadCount = pWorkerThreadCount; - m_pollTimeout = pTimeout; - } - - public void Start() - { - m_running = true; m_workerThreads = new Thread[m_WorkerThreadCount]; - m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; //startup worker threads for (uint i = 0; i < m_WorkerThreadCount; i++) { - m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout); - m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; - m_workerThreads[i] = Watchdog.StartThread( - m_PollServiceWorkerThreads[i].ThreadStart, + PoolWorkerJob, String.Format("PollServiceWorkerThread{0}", i), ThreadPriority.Normal, false, - true, + false, null, int.MaxValue); } - Watchdog.StartThread( - this.ThreadStart, + m_retrysThread = Watchdog.StartThread( + this.CheckRetries, "PollServiceWatcherThread", ThreadPriority.Normal, false, @@ -88,78 +91,211 @@ namespace OpenSim.Framework.Servers.HttpServer 1000 * 60 * 10); } - internal void ReQueueEvent(PollServiceHttpRequest req) + + private void ReQueueEvent(PollServiceHttpRequest req) { - // Do accounting stuff here - Enqueue(req); + if (m_running) + { + lock (m_retryRequests) + m_retryRequests.Enqueue(req); + } } public void Enqueue(PollServiceHttpRequest req) { - lock (m_requests) - m_requests.Enqueue(req); + if (m_running) + { + if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) + { + m_requests.Enqueue(req); + } + else + { + lock (m_slowRequests) + m_slowRequests.Enqueue(req); + } + } } - public void ThreadStart() + private void CheckRetries() { while (m_running) { + Thread.Sleep(100); // let the world move .. back to faster rate Watchdog.UpdateThread(); - ProcessQueuedRequests(); - Thread.Sleep(1000); + lock (m_retryRequests) + { + while (m_retryRequests.Count > 0 && m_running) + m_requests.Enqueue(m_retryRequests.Dequeue()); + } + slowCount++; + if (slowCount >= 10) + { + slowCount = 0; + + lock (m_slowRequests) + { + while (m_slowRequests.Count > 0 && m_running) + m_requests.Enqueue(m_slowRequests.Dequeue()); + } + } } } - private void ProcessQueuedRequests() + ~PollServiceRequestManager() { - lock (m_requests) + m_running = false; +// m_timeout = -10000; // cause all to expire + Thread.Sleep(1000); // let the world move + + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); + + try + { + foreach (PollServiceHttpRequest req in m_retryRequests) + { + DoHTTPGruntWork(m_server,req, + req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + } + catch + { + } + + PollServiceHttpRequest wreq; + m_retryRequests.Clear(); + + lock (m_slowRequests) { - if (m_requests.Count == 0) - return; + while (m_slowRequests.Count > 0 && m_running) + m_requests.Enqueue(m_slowRequests.Dequeue()); + } -// m_log.DebugFormat("[POLL SERVICE REQUEST MANAGER]: Processing {0} requests", m_requests.Count); + while (m_requests.Count() > 0) + { + try + { + wreq = m_requests.Dequeue(0); + DoHTTPGruntWork(m_server,wreq, + wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); + } + catch + { + } + } - int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1; + m_requests.Clear(); + } - // For Each WorkerThread - for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++) + // work threads + + private void PoolWorkerJob() + { + while (m_running) + { + PollServiceHttpRequest req = m_requests.Dequeue(5000); + + Watchdog.UpdateThread(); + if (req != null) { - //Loop over number of requests each thread handles. - for (int i = 0; i < reqperthread && m_requests.Count > 0; i++) + try { - try + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) { - m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue()); + Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); + + if (responsedata == null) + continue; + + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue + { + try + { + DoHTTPGruntWork(m_server, req, responsedata); + } + catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + } + } + else + { + m_threadPool.QueueWorkItem(x => + { + try + { + DoHTTPGruntWork(m_server, req, responsedata); + } + catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + } + + return null; + }, null); + } } - catch (InvalidOperationException) + else { - // The queue is empty, we did our calculations wrong! - return; + if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) + { + DoHTTPGruntWork(m_server, req, + req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + else + { + ReQueueEvent(req); + } } - + } + catch (Exception e) + { + m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); } } } - } - public void Stop() + // DoHTTPGruntWork changed, not sending response + // do the same work around as core + + internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) { - m_running = false; + OSHttpResponse response + = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); - foreach (object o in m_requests) - { - PollServiceHttpRequest req = (PollServiceHttpRequest) o; - PollServiceWorkerThread.DoHTTPGruntWork( - m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } + byte[] buffer = server.DoHTTPGruntWork(responsedata, response); - m_requests.Clear(); + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; - foreach (Thread t in m_workerThreads) + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) { - t.Abort(); + m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); + } + finally + { + //response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.Send(); + + //if (!response.KeepAlive && response.ReuseContext) + // response.FreeContext(); + } + catch (Exception e) + { + m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); + } } } } -} \ No newline at end of file +} + diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs deleted file mode 100644 index 5adbcd1..0000000 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs +++ /dev/null @@ -1,165 +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.Generic; -using System.IO; -using System.Text; -using HttpServer; -using OpenMetaverse; -using System.Reflection; -using log4net; -using OpenSim.Framework.Monitoring; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req); - - public class PollServiceWorkerThread - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - public event ReQueuePollServiceItem ReQueue; - - private readonly BaseHttpServer m_server; - private BlockingQueue m_request; - private bool m_running = true; - private int m_timeout = 250; - - public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout) - { - m_request = new BlockingQueue(); - m_server = pSrv; - m_timeout = pTimeout; - } - - public void ThreadStart() - { - Run(); - } - - public void Run() - { - while (m_running) - { - PollServiceHttpRequest req = m_request.Dequeue(); - - Watchdog.UpdateThread(); - - try - { - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) - { - StreamReader str; - try - { - str = new StreamReader(req.Request.Body); - } - catch (System.ArgumentException) - { - // Stream was not readable means a child agent - // was closed due to logout, leaving the - // Event Queue request orphaned. - continue; - } - - Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd()); - DoHTTPGruntWork(m_server, req, responsedata); - } - else - { - if ((Environment.TickCount - req.RequestTime) > m_timeout) - { - DoHTTPGruntWork( - m_server, - req, - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - else - { - ReQueuePollServiceItem reQueueItem = ReQueue; - if (reQueueItem != null) - reQueueItem(req); - } - } - } - catch (Exception e) - { - m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); - } - } - } - - internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest) - { - m_request.Enqueue(pPollServiceHttpRequest); - } - - /// - /// FIXME: This should be part of BaseHttpServer - /// - internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) - { - OSHttpResponse response - = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); - - byte[] buffer = server.DoHTTPGruntWork(responsedata, response); - - response.SendChunked = false; - response.ContentLength64 = buffer.Length; - response.ContentEncoding = Encoding.UTF8; - - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); - } - finally - { - //response.OutputStream.Close(); - try - { - response.OutputStream.Flush(); - response.Send(); - - //if (!response.KeepAlive && response.ReuseContext) - // response.FreeContext(); - } - catch (Exception e) - { - m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); - } - } - } - } -} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index c7d4283..e73a04a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -376,7 +376,7 @@ namespace OpenSim.Region.ClientStack.Linden // TODO: Add EventQueueGet name/description for diagnostics MainServer.Instance.AddPollServiceHTTPHandler( eventQueueGetPath, - new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID)); + new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000)); // m_log.DebugFormat( // "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", @@ -418,7 +418,7 @@ namespace OpenSim.Region.ClientStack.Linden } } - public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) + public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 7dd9770..7e6b027 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -156,12 +156,12 @@ namespace OpenSim.Region.ClientStack.Linden private Scene m_scene; public PollServiceInventoryEventArgs(Scene scene, UUID pId) : - base(null, null, null, null, pId) + base(null, null, null, null, pId, int.MaxValue) { m_scene = scene; HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); }; - GetEvents = (x, y, z) => + GetEvents = (x, y) => { lock (responses) { diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index c9cd412..976ab93 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -237,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp m_HttpServer.AddPollServiceHTTPHandler( uri, - new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode)); + new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000)); m_log.DebugFormat( "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}", @@ -282,7 +282,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp m_HttpsServer.AddPollServiceHTTPHandler( uri, - new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode)); + new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000)); m_log.DebugFormat( "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}", @@ -516,7 +516,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp } } - private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) + private Hashtable GetEvents(UUID requestID, UUID sessionID) { Hashtable response; @@ -668,4 +668,4 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp ScriptRemoved(itemID); } } -} \ No newline at end of file +} diff --git a/prebuild.xml b/prebuild.xml index 5531558..88db6ed 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -191,6 +191,7 @@ + -- cgit v1.1 From 75631e0267dbf58253dfcf6327b4d65f35bbaa6d Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 7 Jun 2013 23:55:03 +0100 Subject: Supply proper type information for the various types of requests --- OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs | 4 +--- .../Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 1 + OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs | 12 ++++++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index c19ac32..3079a7e 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -52,9 +52,7 @@ namespace OpenSim.Framework.Servers.HttpServer { Normal = 0, LslHttp = 1, - Inventory = 2, - Texture = 3, - Mesh = 4 + Inventory = 2 } public PollServiceEventArgs( diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 7e6b027..9101fc3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -288,6 +288,7 @@ namespace OpenSim.Region.ClientStack.Linden // Register this as a poll service PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); + args.Type = PollServiceEventArgs.EventType.Inventory; MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); string hostName = m_scene.RegionInfo.ExternalHostName; diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 976ab93..def8162 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -235,9 +235,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string uri = "/lslhttp/" + urlcode.ToString() + "/"; - m_HttpServer.AddPollServiceHTTPHandler( - uri, - new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000)); + PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000); + args.Type = PollServiceEventArgs.EventType.LslHttp; + m_HttpServer.AddPollServiceHTTPHandler(uri, args); m_log.DebugFormat( "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}", @@ -280,9 +280,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string uri = "/lslhttps/" + urlcode.ToString() + "/"; - m_HttpsServer.AddPollServiceHTTPHandler( - uri, - new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000)); + PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000); + args.Type = PollServiceEventArgs.EventType.LslHttp; + m_HttpsServer.AddPollServiceHTTPHandler(uri, args); m_log.DebugFormat( "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}", -- cgit v1.1 From 07cc16ff9ccecb4871ae954f2415fb2c5586ec44 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 7 Jun 2013 16:00:32 -0700 Subject: Put the configuration back in FetchInventoryDesc2 cap. --- .../Linden/Caps/WebFetchInvDescModule.cs | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 7dd9770..2586cf0 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -71,6 +71,11 @@ namespace OpenSim.Region.ClientStack.Linden private IInventoryService m_InventoryService; private ILibraryService m_LibraryService; + private bool m_Enabled; + + private string m_fetchInventoryDescendents2Url; + private string m_webFetchInventoryDescendentsUrl; + private static WebFetchInvDescHandler m_webFetchHandler; private Dictionary m_capsDict = new Dictionary(); @@ -83,15 +88,32 @@ namespace OpenSim.Region.ClientStack.Linden public void Initialise(IConfigSource source) { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config == null) + return; + + m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); + m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); + + if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) + { + m_Enabled = true; + } } public void AddRegion(Scene s) { + if (!m_Enabled) + return; + m_scene = s; } public void RemoveRegion(Scene s) { + if (!m_Enabled) + return; + m_scene.EventManager.OnRegisterCaps -= RegisterCaps; m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; m_scene = null; @@ -99,6 +121,9 @@ namespace OpenSim.Region.ClientStack.Linden public void RegionLoaded(Scene s) { + if (!m_Enabled) + return; + m_InventoryService = m_scene.InventoryService; m_LibraryService = m_scene.LibraryService; @@ -283,6 +308,9 @@ namespace OpenSim.Region.ClientStack.Linden private void RegisterCaps(UUID agentID, Caps caps) { + if (m_fetchInventoryDescendents2Url == "") + return; + string capUrl = "/CAPS/" + UUID.Random() + "/"; // Register this as a poll service @@ -300,6 +328,7 @@ namespace OpenSim.Region.ClientStack.Linden port = MainServer.Instance.SSLPort; protocol = "https"; } + caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); m_capsDict[agentID] = capUrl; -- cgit v1.1 From 138722482175ba7571f8086d9b9172c9975543a6 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Fri, 7 Jun 2013 20:09:10 -0400 Subject: Ensure selected module is the only active one --- OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index bf24030..2bb24ae 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs @@ -57,6 +57,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile public void Initialise(IConfigSource config) { + if(config.Configs["UserProfiles"] != null) + return; + m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); m_Enabled = true; } -- cgit v1.1 From 1cb1245d847fad5a088e0bb727433ee1e53d81da Mon Sep 17 00:00:00 2001 From: BlueWall Date: Fri, 7 Jun 2013 20:14:39 -0400 Subject: SQLite support for UserProfiles --- .../Data/SQLite/Resources/UserProfiles.migrations | 90 ++ OpenSim/Data/SQLite/SQLiteUserProfilesData.cs | 904 +++++++++++++++++++++ .../Avatar/UserProfiles/UserProfileModule.cs | 1 + 3 files changed, 995 insertions(+) create mode 100644 OpenSim/Data/SQLite/Resources/UserProfiles.migrations create mode 100644 OpenSim/Data/SQLite/SQLiteUserProfilesData.cs diff --git a/OpenSim/Data/SQLite/Resources/UserProfiles.migrations b/OpenSim/Data/SQLite/Resources/UserProfiles.migrations new file mode 100644 index 0000000..16581f6 --- /dev/null +++ b/OpenSim/Data/SQLite/Resources/UserProfiles.migrations @@ -0,0 +1,90 @@ +:VERSION 1 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS classifieds ( + classifieduuid char(36) NOT NULL PRIMARY KEY, + creatoruuid char(36) NOT NULL, + creationdate int(20) NOT NULL, + expirationdate int(20) NOT NULL, + category varchar(20) NOT NULL, + name varchar(255) NOT NULL, + description text NOT NULL, + parceluuid char(36) NOT NULL, + parentestate int(11) NOT NULL, + snapshotuuid char(36) NOT NULL, + simname varchar(255) NOT NULL, + posglobal varchar(255) NOT NULL, + parcelname varchar(255) NOT NULL, + classifiedflags int(8) NOT NULL, + priceforlisting int(5) NOT NULL +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS usernotes ( + useruuid varchar(36) NOT NULL, + targetuuid varchar(36) NOT NULL, + notes text NOT NULL, + UNIQUE (useruuid,targetuuid) ON CONFLICT REPLACE +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS userpicks ( + pickuuid varchar(36) NOT NULL PRIMARY KEY, + creatoruuid varchar(36) NOT NULL, + toppick int NOT NULL, + parceluuid varchar(36) NOT NULL, + name varchar(255) NOT NULL, + description text NOT NULL, + snapshotuuid varchar(36) NOT NULL, + user varchar(255) NOT NULL, + originalname varchar(255) NOT NULL, + simname varchar(255) NOT NULL, + posglobal varchar(255) NOT NULL, + sortorder int(2) NOT NULL, + enabled int NOT NULL +); + +commit; + +begin; + +CREATE TABLE IF NOT EXISTS userprofile ( + useruuid varchar(36) NOT NULL PRIMARY KEY, + profilePartner varchar(36) NOT NULL, + profileAllowPublish binary(1) NOT NULL, + profileMaturePublish binary(1) NOT NULL, + profileURL varchar(255) NOT NULL, + profileWantToMask int(3) NOT NULL, + profileWantToText text NOT NULL, + profileSkillsMask int(3) NOT NULL, + profileSkillsText text NOT NULL, + profileLanguages text NOT NULL, + profileImage varchar(36) NOT NULL, + profileAboutText text NOT NULL, + profileFirstImage varchar(36) NOT NULL, + profileFirstText text NOT NULL +); + +commit; + +:VERSION 2 # ------------------------------- + +begin; + +CREATE TABLE IF NOT EXISTS userdata ( + UserId char(36) NOT NULL, + TagId varchar(64) NOT NULL, + DataKey varchar(255), + DataVal varchar(255), + PRIMARY KEY (UserId,TagId) +); + +commit; + diff --git a/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs new file mode 100644 index 0000000..cc1dac1 --- /dev/null +++ b/OpenSim/Data/SQLite/SQLiteUserProfilesData.cs @@ -0,0 +1,904 @@ +/* + * 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.Data; +using System.Reflection; +using log4net; +#if CSharpSqlite +using Community.CsharpSqlite.Sqlite; +#else +using Mono.Data.Sqlite; +#endif +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; + +namespace OpenSim.Data.SQLite +{ + public class SQLiteUserProfilesData: IProfilesData + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private SqliteConnection m_connection; + private string m_connectionString; + + private FieldInfo[] m_Fields; + 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(); } + } + + #region IProfilesData implementation + public OSDArray GetClassifiedRecords(UUID creatorId) + { + OSDArray data = new OSDArray(); + string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = :Id"; + IDataReader reader = null; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", creatorId); + reader = cmd.ExecuteReader(); + } + + while (reader.Read()) + { + OSDMap n = new OSDMap(); + UUID Id = UUID.Zero; + string Name = null; + try + { + UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id); + Name = Convert.ToString(reader["name"]); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UserAccount exception {0}", e.Message); + } + n.Add("classifieduuid", OSD.FromUUID(Id)); + n.Add("name", OSD.FromString(Name)); + data.Add(n); + } + + reader.Close(); + + return data; + } + public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result) + { + string query = string.Empty; + + query += "INSERT OR REPLACE INTO classifieds ("; + query += "`classifieduuid`,"; + query += "`creatoruuid`,"; + query += "`creationdate`,"; + query += "`expirationdate`,"; + query += "`category`,"; + query += "`name`,"; + query += "`description`,"; + query += "`parceluuid`,"; + query += "`parentestate`,"; + query += "`snapshotuuid`,"; + query += "`simname`,"; + query += "`posglobal`,"; + query += "`parcelname`,"; + query += "`classifiedflags`,"; + query += "`priceforlisting`) "; + query += "VALUES ("; + query += ":ClassifiedId,"; + query += ":CreatorId,"; + query += ":CreatedDate,"; + query += ":ExpirationDate,"; + query += ":Category,"; + query += ":Name,"; + query += ":Description,"; + query += ":ParcelId,"; + query += ":ParentEstate,"; + query += ":SnapshotId,"; + query += ":SimName,"; + query += ":GlobalPos,"; + 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); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + else + { + duration = new TimeSpan(365,0,0,0); + expiration = now.Add(duration); + epochexp = expiration - epoch; + } + ad.CreationDate = (int)epochnow.TotalSeconds; + ad.ExpirationDate = (int)epochexp.TotalSeconds; + + try { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":ClassifiedId", ad.ClassifiedId.ToString()); + cmd.Parameters.AddWithValue(":CreatorId", ad.CreatorId.ToString()); + cmd.Parameters.AddWithValue(":CreatedDate", ad.CreationDate.ToString()); + cmd.Parameters.AddWithValue(":ExpirationDate", ad.ExpirationDate.ToString()); + cmd.Parameters.AddWithValue(":Category", ad.Category.ToString()); + cmd.Parameters.AddWithValue(":Name", ad.Name.ToString()); + cmd.Parameters.AddWithValue(":Description", ad.Description.ToString()); + cmd.Parameters.AddWithValue(":ParcelId", ad.ParcelId.ToString()); + cmd.Parameters.AddWithValue(":ParentEstate", ad.ParentEstate.ToString()); + cmd.Parameters.AddWithValue(":SnapshotId", ad.SnapshotId.ToString ()); + cmd.Parameters.AddWithValue(":SimName", ad.SimName.ToString()); + cmd.Parameters.AddWithValue(":GlobalPos", ad.GlobalPos.ToString()); + cmd.Parameters.AddWithValue(":ParcelName", ad.ParcelName.ToString()); + cmd.Parameters.AddWithValue(":Flags", ad.Flags.ToString()); + cmd.Parameters.AddWithValue(":ListingPrice", ad.Price.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": ClassifiedesUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + 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(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": DeleteClassifiedRecord exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result) + { + 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 ()) + { + ad.CreatorId = new UUID(reader["creatoruuid"].ToString()); + ad.ParcelId = new UUID(reader["parceluuid"].ToString ()); + ad.SnapshotId = new UUID(reader["snapshotuuid"].ToString ()); + ad.CreationDate = Convert.ToInt32(reader["creationdate"]); + ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]); + ad.ParentEstate = Convert.ToInt32(reader["parentestate"]); + ad.Flags = (byte) Convert.ToUInt32(reader["classifiedflags"]); + ad.Category = Convert.ToInt32(reader["category"]); + ad.Price = Convert.ToInt16(reader["priceforlisting"]); + ad.Name = reader["name"].ToString(); + ad.Description = reader["description"].ToString(); + ad.SimName = reader["simname"].ToString(); + ad.GlobalPos = reader["posglobal"].ToString(); + ad.ParcelName = reader["parcelname"].ToString(); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return true; + } + + public OSDArray GetAvatarPicks(UUID avatarId) + { + 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); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarPicks exception {0}", e.Message); + } + return data; + } + public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId) + { + 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()) + { + 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); + UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId); + pick.GlobalPos = (string)reader["posglobal"]; + bool.TryParse((string)reader["toppick"].ToString(), out pick.TopPick); + bool.TryParse((string)reader["enabled"].ToString(), out pick.Enabled); + pick.Name = (string)reader["name"]; + pick.Desc = description; + pick.User = (string)reader["user"]; + pick.OriginalName = (string)reader["originalname"]; + pick.SimName = (string)reader["simname"]; + pick.SortOrder = (int)reader["sortorder"]; + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetPickInfo exception {0}", e.Message); + } + return pick; + } + + public bool UpdatePicksRecord(UserProfilePick pick) + { + string query = string.Empty; + + query += "INSERT OR REPLACE INTO userpicks ("; + query += "pickuuid, "; + query += "creatoruuid, "; + query += "toppick, "; + query += "parceluuid, "; + query += "name, "; + query += "description, "; + query += "snapshotuuid, "; + query += "user, "; + query += "originalname, "; + query += "simname, "; + query += "posglobal, "; + query += "sortorder, "; + query += "enabled ) "; + query += "VALUES ("; + query += ":PickId,"; + query += ":CreatorId,"; + query += ":TopPick,"; + query += ":ParcelId,"; + query += ":Name,"; + query += ":Desc,"; + query += ":SnapshotId,"; + query += ":User,"; + query += ":Original,"; + query += ":SimName,"; + query += ":GlobalPos,"; + query += ":SortOrder,"; + query += ":Enabled) "; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + int top_pick; + int.TryParse(pick.TopPick.ToString(), out top_pick); + int enabled; + int.TryParse(pick.Enabled.ToString(), out enabled); + + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":PickId", pick.PickId.ToString()); + cmd.Parameters.AddWithValue(":CreatorId", pick.CreatorId.ToString()); + cmd.Parameters.AddWithValue(":TopPick", top_pick); + cmd.Parameters.AddWithValue(":ParcelId", pick.ParcelId.ToString()); + cmd.Parameters.AddWithValue(":Name", pick.Name.ToString()); + cmd.Parameters.AddWithValue(":Desc", pick.Desc.ToString()); + cmd.Parameters.AddWithValue(":SnapshotId", pick.SnapshotId.ToString()); + cmd.Parameters.AddWithValue(":User", pick.User.ToString()); + cmd.Parameters.AddWithValue(":Original", pick.OriginalName.ToString()); + cmd.Parameters.AddWithValue(":SimName",pick.SimName.ToString()); + cmd.Parameters.AddWithValue(":GlobalPos", pick.GlobalPos); + cmd.Parameters.AddWithValue(":SortOrder", pick.SortOrder.ToString ()); + cmd.Parameters.AddWithValue(":Enabled", enabled); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + 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()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":PickId", pickId.ToString()); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": DeleteUserPickRecord exception {0}", e.Message); + return false; + } + return true; + } + + 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()) + { + 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()) + { + notes.Notes = OSD.FromString((string)reader["notes"]); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return true; + } + + public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result) + { + string query = string.Empty; + bool remove; + + if(string.IsNullOrEmpty(note.Notes)) + { + remove = true; + query += "DELETE FROM usernotes WHERE "; + query += "useruuid=:UserId AND "; + query += "targetuuid=:TargetId"; + } + else + { + remove = false; + query += "INSERT OR REPLACE INTO usernotes VALUES ( "; + query += ":UserId,"; + query += ":TargetId,"; + query += ":Notes )"; + } + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + + if(!remove) + cmd.Parameters.AddWithValue(":Notes", note.Notes); + cmd.Parameters.AddWithValue(":TargetId", note.TargetId.ToString ()); + cmd.Parameters.AddWithValue(":UserId", note.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": UpdateAvatarNotes exception {0}", e.Message); + return false; + } + return true; + } + + public bool GetAvatarProperties(ref UserProfileProperties props, ref string result) + { + IDataReader reader = null; + string query = string.Empty; + + query += "SELECT * FROM userprofile WHERE "; + query += "useruuid = :Id"; + + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":Id", props.UserId.ToString()); + + + try + { + reader = cmd.ExecuteReader(); + } + catch(Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarProperties exception {0}", e.Message); + result = e.Message; + return false; + } + if(reader != null && reader.Read()) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Getting data for {0}.", props.UserId); + + props.WebUrl = (string)reader["profileURL"]; + UUID.TryParse((string)reader["profileImage"], out props.ImageId); + props.AboutText = (string)reader["profileAboutText"]; + UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId); + props.FirstLifeText = (string)reader["profileFirstText"]; + UUID.TryParse((string)reader["profilePartner"], out props.PartnerId); + props.WantToMask = (int)reader["profileWantToMask"]; + props.WantToText = (string)reader["profileWantToText"]; + props.SkillsMask = (int)reader["profileSkillsMask"]; + props.SkillsText = (string)reader["profileSkillsText"]; + props.Language = (string)reader["profileLanguages"]; + } + else + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": No data for {0}", props.UserId); + + props.WebUrl = string.Empty; + props.ImageId = UUID.Zero; + props.AboutText = string.Empty; + props.FirstLifeImageId = UUID.Zero; + props.FirstLifeText = string.Empty; + props.PartnerId = UUID.Zero; + props.WantToMask = 0; + props.WantToText = string.Empty; + props.SkillsMask = 0; + props.SkillsText = string.Empty; + props.Language = string.Empty; + props.PublishProfile = false; + props.PublishMature = false; + + query = "INSERT INTO userprofile ("; + query += "useruuid, "; + query += "profilePartner, "; + query += "profileAllowPublish, "; + query += "profileMaturePublish, "; + query += "profileURL, "; + query += "profileWantToMask, "; + query += "profileWantToText, "; + query += "profileSkillsMask, "; + query += "profileSkillsText, "; + query += "profileLanguages, "; + query += "profileImage, "; + query += "profileAboutText, "; + query += "profileFirstImage, "; + query += "profileFirstText) VALUES ("; + query += ":userId, "; + query += ":profilePartner, "; + query += ":profileAllowPublish, "; + query += ":profileMaturePublish, "; + query += ":profileURL, "; + query += ":profileWantToMask, "; + query += ":profileWantToText, "; + query += ":profileSkillsMask, "; + query += ":profileSkillsText, "; + query += ":profileLanguages, "; + query += ":profileImage, "; + query += ":profileAboutText, "; + query += ":profileFirstImage, "; + query += ":profileFirstText)"; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.CommandText = query; + put.Parameters.AddWithValue(":userId", props.UserId.ToString()); + put.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString()); + put.Parameters.AddWithValue(":profileAllowPublish", props.PublishProfile); + put.Parameters.AddWithValue(":profileMaturePublish", props.PublishMature); + put.Parameters.AddWithValue(":profileURL", props.WebUrl); + put.Parameters.AddWithValue(":profileWantToMask", props.WantToMask); + put.Parameters.AddWithValue(":profileWantToText", props.WantToText); + put.Parameters.AddWithValue(":profileSkillsMask", props.SkillsMask); + put.Parameters.AddWithValue(":profileSkillsText", props.SkillsText); + put.Parameters.AddWithValue(":profileLanguages", props.Language); + put.Parameters.AddWithValue(":profileImage", props.ImageId.ToString()); + put.Parameters.AddWithValue(":profileAboutText", props.AboutText); + put.Parameters.AddWithValue(":profileFirstImage", props.FirstLifeImageId.ToString()); + put.Parameters.AddWithValue(":profileFirstText", props.FirstLifeText); + + put.ExecuteNonQuery(); + } + } + } + return true; + } + + public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result) + { + string query = string.Empty; + + query += "UPDATE userprofile SET "; + query += "profilePartner=:profilePartner, "; + query += "profileURL=:profileURL, "; + query += "profileImage=:image, "; + query += "profileAboutText=:abouttext,"; + query += "profileFirstImage=:firstlifeimage,"; + query += "profileFirstText=:firstlifetext "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":profileURL", props.WebUrl); + cmd.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString()); + cmd.Parameters.AddWithValue(":image", props.ImageId.ToString()); + cmd.Parameters.AddWithValue(":abouttext", props.AboutText); + cmd.Parameters.AddWithValue(":firstlifeimage", props.FirstLifeImageId.ToString()); + cmd.Parameters.AddWithValue(":firstlifetext", props.FirstLifeText); + cmd.Parameters.AddWithValue(":uuid", props.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[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,"; + query += "profileSkillsMask=:SkillsMask,"; + query += "profileSkillsText=:SkillsText, "; + query += "profileLanguages=:Languages "; + query += "WHERE useruuid=:uuid"; + + try + { + using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":WantMask", up.WantToMask); + cmd.Parameters.AddWithValue(":WantText", up.WantToText); + cmd.Parameters.AddWithValue(":SkillsMask", up.SkillsMask); + cmd.Parameters.AddWithValue(":SkillsText", up.SkillsText); + cmd.Parameters.AddWithValue(":Languages", up.Language); + cmd.Parameters.AddWithValue(":uuid", up.UserId.ToString()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": AgentInterestsUpdate exception {0}", e.Message); + result = e.Message; + return false; + } + return true; + } + public bool GetUserAppData(ref UserAppData props, ref string result) + { + 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()) + { + 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()) + { + props.DataKey = (string)reader["DataKey"]; + props.DataVal = (string)reader["DataVal"]; + } + else + { + query += "INSERT INTO userdata VALUES ( "; + query += ":UserId,"; + query += ":TagId,"; + query += ":DataKey,"; + query += ":DataVal) "; + + using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand()) + { + put.Parameters.AddWithValue(":Id", props.UserId.ToString()); + put.Parameters.AddWithValue(":TagId", props.TagId.ToString()); + put.Parameters.AddWithValue(":DataKey", props.DataKey.ToString()); + put.Parameters.AddWithValue(":DataVal", props.DataVal.ToString()); + + put.ExecuteNonQuery(); + } + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": Requst application data exception {0}", e.Message); + result = e.Message; + return false; + } + 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()) + { + cmd.CommandText = query; + cmd.Parameters.AddWithValue(":UserId", props.UserId.ToString()); + cmd.Parameters.AddWithValue(":TagId", props.TagId.ToString ()); + cmd.Parameters.AddWithValue(":DataKey", props.DataKey.ToString ()); + cmd.Parameters.AddWithValue(":DataVal", props.DataKey.ToString ()); + + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": SetUserData exception {0}", e.Message); + return false; + } + return true; + } + public OSDArray GetUserImageAssets(UUID avatarId) + { + 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()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString())); + } + } + } + + 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()) + { + data.Add(new OSDString((string)reader["snapshotuuid"].ToString ())); + } + } + } + + 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()) + { + data.Add(new OSDString((string)reader["profileImage"].ToString ())); + data.Add(new OSDString((string)reader["profileFirstImage"].ToString ())); + } + } + } + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES_DATA]" + + ": GetAvatarNotes exception {0}", e.Message); + } + return data; + } + #endregion + } +} + diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index a97c9b4..72e557c 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -130,6 +130,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles if (profileConfig == null) { + m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration"); Enabled = false; return; } -- cgit v1.1 From 75e4af9d3959b666b652013d2de4d5f4625f9fa2 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sat, 8 Jun 2013 11:00:05 -0400 Subject: Catch exception triggered by incoming avatars using legacy profiles --- .../CoreModules/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 72e557c..322addd 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1317,7 +1317,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles Stream rstream = webResponse.GetResponseStream(); OSDMap response = new OSDMap(); - response = (OSDMap)OSDParser.DeserializeJson(rstream); + try + { + response = (OSDMap)OSDParser.DeserializeJson(rstream); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message); + return false; + } + if(response.ContainsKey("error")) { data = response["error"]; -- cgit v1.1 From d00770d56bf00640f23f462d8ab51f851530234c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 8 Jun 2013 11:00:22 -0700 Subject: Groups V2 -- fix mantis #6666 --- OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index 7e0b112..cff7adf 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -684,6 +684,9 @@ namespace OpenSim.Groups { serviceLocation = string.Empty; name = string.Empty; + if (groupID.Equals(UUID.Zero)) + return true; + ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty); if (group == null) { -- cgit v1.1 From e741e5ebce7759a7ee75c638d73e17c8a5f38394 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 9 Jun 2013 20:20:37 -0700 Subject: More on mantis #6666 -- Groups V2 remote connector. --- OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs index e7d38c2..79d6fc5 100644 --- a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -209,13 +209,10 @@ namespace OpenSim.Groups public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d) { GroupMembershipData activeGroup = d(); - if (activeGroup != null) - { - string cacheKey = "active-" + AgentID.ToString(); - lock (m_Cache) - if (m_Cache.Contains(cacheKey)) - m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); - } + string cacheKey = "active-" + AgentID.ToString(); + lock (m_Cache) + if (m_Cache.Contains(cacheKey)) + m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT); } public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d) -- cgit v1.1 From 7de0912a979746c1e1301c080c49152ae7cd57b5 Mon Sep 17 00:00:00 2001 From: Talun Date: Mon, 10 Jun 2013 09:32:14 +0100 Subject: Mantis 5346: llAxisAngle2Rot() should normalize before computing Corrected to agree with http://wiki.secondlife.com/wiki/Llaxisangle2rot#Deep_Notes to normalise the vector before computing the quaternion Signed-off-by: dahlia --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cd6092d..ec5aa49 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4651,6 +4651,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api s = Math.Cos(angle * 0.5); t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs + axis = LSL_Vector.Norm(axis); x = axis.x * t; y = axis.y * t; z = axis.z * t; -- cgit v1.1 From 57141e34bf415861a8acfdaa0086e0e651c679d9 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 10 Jun 2013 13:26:19 -0700 Subject: Remove Temporary from use to shortcut asset stores. The Local property differentiates between local & grid storage. The Temporary property just says that which service handles the it, the asset can be safely removed in the future. --- OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs | 1 + OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs | 2 +- .../ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs | 2 +- OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index b497fde..9f3cc19 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -189,6 +189,7 @@ namespace OpenSim.Capabilities.Handlers newTexture.Flags = AssetFlags.Collectable; newTexture.Temporary = true; + newTexture.Local = true; m_assetService.Store(newTexture); WriteTextureData(httpRequest, httpResponse, newTexture, format); return true; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index d221d68..9f58175 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs @@ -322,7 +322,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset // a copy of the local asset. m_Cache.Cache(asset); - if (asset.Temporary || asset.Local) + if (asset.Local) { if (m_Cache != null) m_Cache.Cache(asset); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 480cd69..52b1039 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -258,7 +258,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (m_Cache != null) m_Cache.Cache(asset); - if (asset.Temporary || asset.Local) + if (asset.Local) { // m_log.DebugFormat( // "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 2b2f11f..7f7f251 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -251,7 +251,7 @@ namespace OpenSim.Services.Connectors public string Store(AssetBase asset) { - if (asset.Temporary || asset.Local) + if (asset.Local) { if (m_Cache != null) m_Cache.Cache(asset); -- cgit v1.1 From 795acaa6aa8e32ad0281226208a6b1bbc2292bf5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 10 Jun 2013 14:12:45 -0700 Subject: BulletSim: add failure flag for meshing failure vs asset fetch failure so error messages make more sense. Change some BulletSim status log messages from WARN to INFO. Update TODO list. --- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 35 ++++++++++++----- .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 44 +++++++++++----------- 4 files changed, 51 insertions(+), 34 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index cca887a..a4c5e08 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -148,7 +148,7 @@ public abstract class BSPhysObject : PhysicsActor // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. public enum PrimAssetCondition { - Unknown, Waiting, Failed, Fetched + Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched } public PrimAssetCondition PrimAssetState { get; set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 423c389..dec6b6f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -249,7 +249,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters TerrainManager.CreateInitialGroundPlaneAndTerrain(); // Put some informational messages into the log file. - m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); + m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); InTaintTime = false; m_initialized = true; @@ -374,7 +374,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters } else { - m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); + m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); } return ret; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 867d2ab..202a4ce 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -167,7 +167,7 @@ public abstract class BSShape // Prevent trying to keep fetching the mesh by declaring failure. if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}", @@ -177,7 +177,8 @@ public abstract class BSShape { // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset if (prim.BaseShape.SculptEntry - && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedAssetFetch + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedMeshing && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting && prim.BaseShape.SculptTexture != OMV.UUID.Zero ) @@ -219,7 +220,7 @@ public abstract class BSShape } if (!assetFound) { - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; } physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); @@ -227,7 +228,7 @@ public abstract class BSShape } else { - xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", LogHeader, physicsScene.Name); } @@ -235,13 +236,20 @@ public abstract class BSShape } else { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}", prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); } + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) + { + physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. obj={1}, texture={2}", + LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + } } } @@ -374,7 +382,9 @@ public class BSShapeMesh : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (!newShape.isNativeShape + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { // If a mesh was what was created, remember the built shape for later sharing. // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. @@ -517,7 +527,7 @@ public class BSShapeMesh : BSShape else { // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); @@ -559,7 +569,9 @@ public class BSShapeHull : BSShape // Check to see if hull was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (!newShape.isNativeShape + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { // If a mesh was what was created, remember the built shape for later sharing. Hulls.Add(newHullKey, retHull); @@ -1079,10 +1091,13 @@ public class BSShapeGImpact : BSShape // Check to see if mesh was created (might require an asset). newShape = VerifyMeshCreated(physicsScene, newShape, prim); newShape.shapeKey = newMeshKey; - if (!newShape.isNativeShape || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) + if (!newShape.isNativeShape + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing + || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { // If a mesh was what was created, remember the built shape for later sharing. - // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. + // Also note that if meshing failed we put it in the mesh list as there is nothing + // else to do about the mesh. GImpacts.Add(newMeshKey, retGImpact); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index df1da63..1e01526 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -2,11 +2,6 @@ CURRENT PROBLEMS TO FIX AND/OR LOOK AT ================================================= Script changing rotation of child prim while vehicle moving (eg turning wheel) causes the wheel to appear to jump back. Looks like sending position from previous update. -Vehicle ride, get up, ride again. Second time vehicle does not act correctly. - Have to rez new vehicle and delete the old to fix situation. -Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd - position state where it will not settle onto ground properly, etc -Two of Nebadon vehicles in a sim max the CPU. This is new. Enable vehicle border crossings (at least as poorly as ODE) Terrain skirts Avatar created in previous region and not new region when crossing border @@ -23,24 +18,17 @@ vehicle angular banking Center-of-gravity Vehicle angular deflection Preferred orientation angular correction fix -when should angular and linear motor targets be zeroed? when selected? - Need a vehicle.clear()? Or an 'else' in prestep if not physical. Teravus llMoveToTarget script debug Mixing of hover, buoyancy/gravity, moveToTarget, into one force Setting hover height to zero disables hover even if hover flags are on (from SL wiki) limitMotorUp calibration (more down?) llRotLookAt llLookAt -Avatars walking up stairs (HALF DONE) -Avatar movement - flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) - walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) - avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) +Convert to avatar mesh capsule. Include rotation of capsule. Vehicle script tuning/debugging Avanti speed script Weapon shooter script Move material definitions (friction, ...) into simulator. -Add material densities to the material types. One sided meshes? Should terrain be built into a closed shape? When meshes get partially wedged into the terrain, they cannot push themselves out. It is possible that Bullet processes collisions whether entering or leaving a mesh. @@ -53,12 +41,8 @@ LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. Same for other velocity settings. UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: https://github.com/UbitUmarov/Ubit-opensim -Border crossing with linked vehicle causes crash - 20121129.1411: editting/moving phys object across region boundries causes crash - getPos-> btRigidBody::upcast -> getBodyType -> BOOM Vehicles (Move smoothly) Some vehicles should not be able to turn if no speed or off ground. -What to do if vehicle and prim buoyancy differ? Cannot edit/move a vehicle being ridden: it jumps back to the origional position. Neb car jiggling left and right Happens on terrain and any other mesh object. Flat cubes are much smoother. @@ -68,8 +52,6 @@ For limitMotorUp, use raycast down to find if vehicle is in the air. Verify llGetVel() is returning a smooth and good value for vehicle movement. llGetVel() should return the root's velocity if requested in a child prim. Implement function efficiency for lineaar and angular motion. -After getting off a vehicle, the root prim is phantom (can be walked through) - Need to force a position update for the root prim after compound shape destruction Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). A kludge that isn't fixing the real problem of Bullet adding extra motion. @@ -78,11 +60,10 @@ Incorporate inter-relationship of angular corrections. For instance, angularDefl creates over-correction and over-shoot and wabbling. Vehicle attributes are not restored when a vehicle is rezzed on region creation Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. +What to do if vehicle and prim buoyancy differ? GENERAL TODO LIST: ================================================= -Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. - Regular triangle meshes don't do physical collisions. Resitution of a prim works on another prim but not on terrain. The dropped prim doesn't bounce properly on the terrain. Add a sanity check for PIDTarget location. @@ -359,4 +340,25 @@ Lock axis (DONE 20130401) Terrain detail: double terrain mesh detail (DONE) Use the HACD convex hull routine in Bullet rather than the C# version. Speed up hullifying large meshes. (DONE) +Vehicle ride, get up, ride again. Second time vehicle does not act correctly. + Have to rez new vehicle and delete the old to fix situation. + (DONE 20130520: normalize rotations) +Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd + position state where it will not settle onto ground properly, etc + (DONE 20130520: normalize rotations) +Two of Nebadon vehicles in a sim max the CPU. This is new. + (DONE 20130520: two problems: if asset failed to mesh, constantly refetched + asset; vehicle was sending too many messages to all linkset members) +Add material densities to the material types. (WILL NOT BE DONE: not how it is done) +Avatars walking up stairs (DONE) +Avatar movement + flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) + walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) + avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) +After getting off a vehicle, the root prim is phantom (can be walked through) + Need to force a position update for the root prim after compound shape destruction + (DONE) +Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. + Regular triangle meshes don't do physical collisions. + (DONE: discovered GImpact is VERY CPU intensive) -- cgit v1.1 From 82e3b9a6e0f0e1731df9080e4de63bc7c7079ec4 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 10 Jun 2013 15:14:55 -0700 Subject: Fix test for adding temporary assets. Code for non-local temporary assets is there but commented out. --- .../Asset/Tests/AssetConnectorTests.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs index 1982473..7073433 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs @@ -93,7 +93,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); lasc.Initialise(config); + // If it is local, it should not be stored AssetBase a1 = AssetHelpers.CreateNotecardAsset(); + a1.Local = true; a1.Temporary = true; lasc.Store(a1); @@ -102,6 +104,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests Assert.That(lasc.GetData(a1.ID), Is.Null); Assert.That(lasc.GetMetadata(a1.ID), Is.Null); + // If it is remote, it should be stored + // AssetBase a2 = AssetHelpers.CreateNotecardAsset(); + // a2.Local = false; + // a2.Temporary = true; + + // lasc.Store(a2); + + // AssetBase retreivedA2 = lasc.Get(a2.ID); + // Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID)); + // Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID)); + // Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length)); + + // AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID); + // Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID)); + + // byte[] retrievedA2Data = lasc.GetData(a2.ID); + // Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length)); + // TODO: Add cache and check that this does receive a copy of the asset } -- cgit v1.1 From 32d1e50565787eaf8fac8b5f0bd899b6e3b3b303 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 10 Jun 2013 23:30:35 +0100 Subject: Reinstate explicit starting and stopping of PollServiceRequestManager added in 3eee991 but removed in 7c0bfca Do not rely on destructors to stop things. These fire at unpredictable times and cause problems such as http://opensimulator.org/mantis/view.php?id=6503 and most probably http://opensimulator.org/mantis/view.php?id=6668 --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 3 ++- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index eb7c578..96a030b 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -1805,6 +1805,7 @@ namespace OpenSim.Framework.Servers.HttpServer // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); + m_PollServiceManager.Start(); HTTPDRunning = true; //HttpListenerContext context; @@ -1855,7 +1856,7 @@ namespace OpenSim.Framework.Servers.HttpServer HTTPDRunning = false; try { -// m_PollServiceManager.Stop(); + m_PollServiceManager.Stop(); m_httpListener2.ExceptionThrown -= httpServerException; //m_httpListener2.DisconnectHandler = null; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index a5380c1..ef35886 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -66,7 +66,10 @@ namespace OpenSim.Framework.Servers.HttpServer m_server = pSrv; m_WorkerThreadCount = pWorkerThreadCount; m_workerThreads = new Thread[m_WorkerThreadCount]; + } + public void Start() + { //startup worker threads for (uint i = 0; i < m_WorkerThreadCount; i++) { @@ -91,7 +94,6 @@ namespace OpenSim.Framework.Servers.HttpServer 1000 * 60 * 10); } - private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) @@ -142,14 +144,14 @@ namespace OpenSim.Framework.Servers.HttpServer } } - ~PollServiceRequestManager() + public void Stop() { m_running = false; // m_timeout = -10000; // cause all to expire Thread.Sleep(1000); // let the world move foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); + Watchdog.AbortThread(t.ManagedThreadId); try { -- cgit v1.1 From 7af97f88b7f493b830b46c01acc92934852cabae Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 10 Jun 2013 23:39:17 +0100 Subject: Add port numbers to poll service thread names so that we can tell which belong to which HttpServer --- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index ef35886..aee3e3c 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_workerThreads[i] = Watchdog.StartThread( PoolWorkerJob, - String.Format("PollServiceWorkerThread{0}", i), + string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), ThreadPriority.Normal, false, false, @@ -86,7 +86,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_retrysThread = Watchdog.StartThread( this.CheckRetries, - "PollServiceWatcherThread", + string.Format("PollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, -- cgit v1.1 From a949556c4ea74c993fc15bcfdcbc672d9f971897 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 10 Jun 2013 16:42:49 -0700 Subject: add a Normalize() method for LSL_Rotation --- OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index 9ca5ca9..f6d94a3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -371,6 +371,31 @@ namespace OpenSim.Region.ScriptEngine.Shared #endregion + #region Methods + public Quaternion Normalize() + { + double length = Math.Sqrt(x * x + y * y + z * z + s * s); + if (length < float.Epsilon) + { + x = 1; + y = 0; + z = 0; + s = 0; + } + else + { + + double invLength = 1.0 / length; + x *= invLength; + y *= invLength; + z *= invLength; + s *= invLength; + } + + return this; + } + #endregion + #region Overriders public override int GetHashCode() -- cgit v1.1 From 1c7fbb86c21f79938e4ea9dafef1e8d8f4a29a8d Mon Sep 17 00:00:00 2001 From: teravus Date: Mon, 10 Jun 2013 18:47:08 -0500 Subject: Check For NaN and Infinity in llRot2Axis/Angle Fixes mantis #6669 --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 ++++-- 1 file changed, 4 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 ec5aa49..9427061 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4692,7 +4692,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api y = rot.y / s; z = rot.z / s; } - + if ((double.IsNaN(x)) || double.IsInfinity(x)) x = 0; + if ((double.IsNaN(y)) || double.IsInfinity(y)) y = 0; + if ((double.IsNaN(z)) || double.IsInfinity(z)) z = 0; return new LSL_Vector(x,y,z); } @@ -4714,7 +4716,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } double angle = 2 * Math.Acos(rot.s); - + if ((double.IsNaN(angle)) || double.IsInfinity(angle)) angle = 0; return angle; } -- cgit v1.1 From b242ead6df06f013f507a4a15495a2720ec5d089 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 10 Jun 2013 17:10:04 -0700 Subject: llRot2Axis now checks absolute value of s rotation component before normalizing. Also removed some excessive division and cleaned up a bit --- .../Shared/Api/Implementation/LSL_Api.cs | 28 +++++----------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 9427061..c48285a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4665,37 +4665,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llRot2Axis(LSL_Rotation rot) { m_host.AddScriptLPS(1); - double x,y,z; + double x, y, z; - if (rot.s > 1) // normalization needed - { - double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y + - rot.z * rot.z + rot.s * rot.s); - - rot.x /= length; - rot.y /= length; - rot.z /= length; - rot.s /= length; - - } + if (Math.Abs(rot.s) > 1) // normalization needed + rot.Normalize(); - // double angle = 2 * Math.Acos(rot.s); double s = Math.Sqrt(1 - rot.s * rot.s); if (s < 0.001) { - x = 1; - y = z = 0; + return new LSL_Vector(1, 0, 0); } else { - x = rot.x / s; // normalise axis - y = rot.y / s; - z = rot.z / s; + double invS = 1.0 / s; + return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS); } - if ((double.IsNaN(x)) || double.IsInfinity(x)) x = 0; - if ((double.IsNaN(y)) || double.IsInfinity(y)) y = 0; - if ((double.IsNaN(z)) || double.IsInfinity(z)) z = 0; - return new LSL_Vector(x,y,z); } -- cgit v1.1 From 9d9b9d4938687f97ac82fc22917471f22198ef12 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 10 Jun 2013 17:11:49 -0700 Subject: llRot2Angle now checks absolute value of s rotation component before normalizing --- .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c48285a..39bac82 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4688,19 +4688,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - if (rot.s > 1) // normalization needed - { - double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y + - rot.z * rot.z + rot.s * rot.s); - - rot.x /= length; - rot.y /= length; - rot.z /= length; - rot.s /= length; - } + if (Math.Abs(rot.s) > 1) // normalization needed + rot.Normalize(); double angle = 2 * Math.Acos(rot.s); - if ((double.IsNaN(angle)) || double.IsInfinity(angle)) angle = 0; + return angle; } -- cgit v1.1 From ba84074468e0805e0a378bf31fc580437e7ce015 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 10 Jun 2013 17:54:14 -0700 Subject: LSL_Rotation.Normalize() now returns 0,0,0,1 for x,y,z,s when normalization fails --- OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index f6d94a3..50f9377 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs @@ -377,10 +377,10 @@ namespace OpenSim.Region.ScriptEngine.Shared double length = Math.Sqrt(x * x + y * y + z * z + s * s); if (length < float.Epsilon) { - x = 1; + x = 0; y = 0; z = 0; - s = 0; + s = 1; } else { -- cgit v1.1 From ed950e6c7444510c7171c1b7829eedbf731e218a Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 11 Jun 2013 00:29:40 -0700 Subject: Adjust output of llRot2Axis and llRot2Angle to match domains SL(tm) uses. Addresses Mantis #0006671 --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 39bac82..e1630b3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4678,6 +4678,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else { double invS = 1.0 / s; + if (rot.s < 0) invS = -invS; return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS); } } @@ -4692,6 +4693,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rot.Normalize(); double angle = 2 * Math.Acos(rot.s); + if (angle > Math.PI) + angle = 2 * Math.PI - angle; return angle; } -- cgit v1.1 From d47a18fd09cfa7abc5fbd646a7a8edbec12c870c Mon Sep 17 00:00:00 2001 From: teravus Date: Tue, 11 Jun 2013 08:56:20 -0500 Subject: * Adds KeyFrameMotion storage support to SQLite, just a note, seems that there's still something wrong with keyframed motion starting when the sim starts up, you have to 'select' and 'deselect' the prim again to get it to appear to move. Not sure what this is but maybe melanie_t can comment on this. * Has a prim table migration.. that might take a while, hold on to your hats. * Fixes a null-ref when shutting down while keyframed motion is active. --- .../Data/SQLite/Resources/RegionStore.migrations | 8 ++++++++ OpenSim/Data/SQLite/SQLiteSimulationData.cs | 24 ++++++++++++++++++++++ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 5 +++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations index c6f4b48..bff039d 100644 --- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations +++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations @@ -592,3 +592,11 @@ ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6'; ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5'; COMMIT; + +:VERSION 29 #---------------- Keyframes + +BEGIN; + +ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob; + +COMMIT; diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index d4734a6..70b76c9 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -732,6 +732,8 @@ namespace OpenSim.Data.SQLite } SceneObjectGroup group = new SceneObjectGroup(prim); + if (prim.KeyframeMotion != null) + prim.KeyframeMotion.UpdateSceneObject(group); createdObjects.Add(group.UUID, group); retvals.Add(group); LoadItems(prim); @@ -1241,6 +1243,7 @@ namespace OpenSim.Data.SQLite createCol(prims, "Friction", typeof(Double)); createCol(prims, "Restitution", typeof(Double)); + createCol(prims, "KeyframeMotion", typeof(Byte[])); // Add in contraints prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] }; @@ -1736,6 +1739,20 @@ 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"]; + if (data.Length > 0) + prim.KeyframeMotion = KeyframeMotion.FromData(null, data); + else + prim.KeyframeMotion = null; + } + else + { + prim.KeyframeMotion = null; + } + return prim; } @@ -2168,6 +2185,13 @@ namespace OpenSim.Data.SQLite row["GravityModifier"] = (double)prim.GravityModifier; row["Friction"] = (double)prim.Friction; row["Restitution"] = (double)prim.Restitution; + + if (prim.KeyframeMotion != null) + row["KeyframeMotion"] = prim.KeyframeMotion.Serialize(); + else + row["KeyframeMotion"] = new Byte[0]; + + } /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ff3f738..482d958 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -779,7 +779,8 @@ namespace OpenSim.Region.Framework.Scenes } // Tell the physics engines that this prim changed. - ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); + if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null) + ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); } catch (Exception e) { @@ -892,7 +893,7 @@ namespace OpenSim.Region.Framework.Scenes //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); } - if (ParentGroup != null) + if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null) ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); //} } -- cgit v1.1 From 26b66c730e85744c365512a8c0a2a3cc64f5695c Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 11 Jun 2013 20:39:09 +0200 Subject: Put the "script saved" and "notecard saved" messages back into the bottom right corner. --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 880205a..1203192 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -260,7 +260,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return UUID.Zero; } - remoteClient.SendAgentAlertMessage("Notecard saved", false); + remoteClient.SendAlertMessage("Notecard saved"); } else if ((InventoryType)item.InvType == InventoryType.LSL) { @@ -270,7 +270,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return UUID.Zero; } - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); } AssetBase asset = -- cgit v1.1 From b33db917f59ecfcab96a2aec45e19987dbcb44a2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 11 Jun 2013 15:36:27 -0700 Subject: Really bad idea to lock m_UserCache for so long in UserManagementModule. Added a special lock object instead, if we really want to avoid concurrent executions of that code. --- .../UserManagement/UserManagementModule.cs | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 1e70b84..ac21b53 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // The cache protected Dictionary m_UserCache = new Dictionary(); + private object m_AddUserLock = new object(); #region ISharedRegionModule @@ -475,9 +476,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement UserData oldUser; //lock the whole block - prevent concurrent update - lock (m_UserCache) + lock (m_AddUserLock) { - m_UserCache.TryGetValue (id, out oldUser); + lock (m_UserCache) + m_UserCache.TryGetValue(id, out oldUser); + if (oldUser != null) { if (creatorData == null || creatorData == String.Empty) @@ -488,9 +491,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement //try update unknown users //and creator's home URL's - if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) + if ((oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith(oldUser.HomeURL))) { - m_UserCache.Remove (id); + lock (m_UserCache) + m_UserCache.Remove(id); m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); } else @@ -500,38 +504,38 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id); + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); if (account != null) { - AddUser (id, account.FirstName, account.LastName); + AddUser(id, account.FirstName, account.LastName); } else { - UserData user = new UserData (); + UserData user = new UserData(); user.Id = id; if (creatorData != null && creatorData != string.Empty) { //creatorData = ; - string[] parts = creatorData.Split (';'); + string[] parts = creatorData.Split(';'); if (parts.Length >= 1) { - user.HomeURL = parts [0]; + user.HomeURL = parts[0]; try { - Uri uri = new Uri (parts [0]); + Uri uri = new Uri(parts[0]); user.LastName = "@" + uri.Authority; } catch (UriFormatException) { - m_log.DebugFormat ("[SCENE]: Unable to parse Uri {0}", parts [0]); + m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); user.LastName = "@unknown"; } } if (parts.Length >= 2) - user.FirstName = parts [1].Replace (' ', '.'); + user.FirstName = parts[1].Replace(' ', '.'); } else { @@ -539,7 +543,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement user.LastName = "UserUMMAU"; } - AddUserInternal (user); + AddUserInternal(user); } } } -- cgit v1.1 From d8da83b4ff924587c14c888c2a992c56b9b76c80 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 11 Jun 2013 15:50:12 -0700 Subject: Removed the lock entirely --- .../UserManagement/UserManagementModule.cs | 108 ++++++++++----------- 1 file changed, 52 insertions(+), 56 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index ac21b53..864e181 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -56,7 +56,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // The cache protected Dictionary m_UserCache = new Dictionary(); - private object m_AddUserLock = new object(); #region ISharedRegionModule @@ -476,75 +475,72 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement UserData oldUser; //lock the whole block - prevent concurrent update - lock (m_AddUserLock) - { - lock (m_UserCache) - m_UserCache.TryGetValue(id, out oldUser); + lock (m_UserCache) + m_UserCache.TryGetValue(id, out oldUser); - if (oldUser != null) + if (oldUser != null) + { + if (creatorData == null || creatorData == String.Empty) { - if (creatorData == null || creatorData == String.Empty) - { - //ignore updates without creator data - return; - } - - //try update unknown users - //and creator's home URL's - if ((oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith(oldUser.HomeURL))) - { - lock (m_UserCache) - m_UserCache.Remove(id); - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); - } - else - { - //we have already a valid user within the cache - return; - } + //ignore updates without creator data + return; } - UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); - - if (account != null) + //try update unknown users + //and creator's home URL's + if ((oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith(oldUser.HomeURL))) { - AddUser(id, account.FirstName, account.LastName); + lock (m_UserCache) + m_UserCache.Remove(id); + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); } else { - UserData user = new UserData(); - user.Id = id; + //we have already a valid user within the cache + return; + } + } - if (creatorData != null && creatorData != string.Empty) - { - //creatorData = ; + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); - string[] parts = creatorData.Split(';'); - if (parts.Length >= 1) + if (account != null) + { + AddUser(id, account.FirstName, account.LastName); + } + else + { + UserData user = new UserData(); + user.Id = id; + + if (creatorData != null && creatorData != string.Empty) + { + //creatorData = ; + + string[] parts = creatorData.Split(';'); + if (parts.Length >= 1) + { + user.HomeURL = parts[0]; + try { - user.HomeURL = parts[0]; - try - { - Uri uri = new Uri(parts[0]); - user.LastName = "@" + uri.Authority; - } - catch (UriFormatException) - { - m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); - user.LastName = "@unknown"; - } + Uri uri = new Uri(parts[0]); + user.LastName = "@" + uri.Authority; + } + catch (UriFormatException) + { + m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); + user.LastName = "@unknown"; } - if (parts.Length >= 2) - user.FirstName = parts[1].Replace(' ', '.'); - } - else - { - user.FirstName = "Unknown"; - user.LastName = "UserUMMAU"; } - - AddUserInternal(user); + if (parts.Length >= 2) + user.FirstName = parts[1].Replace(' ', '.'); } + else + { + user.FirstName = "Unknown"; + user.LastName = "UserUMMAU"; + } + + AddUserInternal(user); } } -- cgit v1.1 From 135e10ba09a527d14a2fea0c6398757ce450c9fa Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 11 Jun 2013 23:55:45 +0100 Subject: Uncomment Mic's code and split to create new regression TestAddTemporaryAsset() and TestAddTemporaryLocalAsset() --- .../Asset/Tests/AssetConnectorTests.cs | 64 ++++++++++++++-------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs index 7073433..4f75191 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs @@ -42,7 +42,7 @@ using OpenSim.Tests.Common; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests { [TestFixture] - public class AssetConnectorsTests : OpenSimTestCase + public class AssetConnectorTests : OpenSimTestCase { [Test] public void TestAddAsset() @@ -77,7 +77,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests // TODO: Add cache and check that this does receive a copy of the asset } - [Test] public void TestAddTemporaryAsset() { TestHelpers.InMethod(); @@ -93,10 +92,45 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); lasc.Initialise(config); - // If it is local, it should not be stored + // If it is remote, it should be stored + AssetBase a2 = AssetHelpers.CreateNotecardAsset(); + a2.Local = false; + a2.Temporary = true; + + lasc.Store(a2); + + AssetBase retreivedA2 = lasc.Get(a2.ID); + Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID)); + Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID)); + Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length)); + + AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID); + Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID)); + + byte[] retrievedA2Data = lasc.GetData(a2.ID); + Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length)); + + // TODO: Add cache and check that this does receive a copy of the asset + } + + [Test] + public void TestAddLocalAsset() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); + config.AddConfig("AssetService"); + config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); + config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); + + LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); + lasc.Initialise(config); + AssetBase a1 = AssetHelpers.CreateNotecardAsset(); a1.Local = true; - a1.Temporary = true; lasc.Store(a1); @@ -104,29 +138,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests Assert.That(lasc.GetData(a1.ID), Is.Null); Assert.That(lasc.GetMetadata(a1.ID), Is.Null); - // If it is remote, it should be stored - // AssetBase a2 = AssetHelpers.CreateNotecardAsset(); - // a2.Local = false; - // a2.Temporary = true; - - // lasc.Store(a2); - - // AssetBase retreivedA2 = lasc.Get(a2.ID); - // Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID)); - // Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID)); - // Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length)); - - // AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID); - // Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID)); - - // byte[] retrievedA2Data = lasc.GetData(a2.ID); - // Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length)); - // TODO: Add cache and check that this does receive a copy of the asset } [Test] - public void TestAddLocalAsset() + public void TestAddTemporaryLocalAsset() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -141,8 +157,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); lasc.Initialise(config); + // If it is local, it should not be stored AssetBase a1 = AssetHelpers.CreateNotecardAsset(); a1.Local = true; + a1.Temporary = true; lasc.Store(a1); -- cgit v1.1 From 7556a0f699f8474b7ac23cbebacc695c93f374fa Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 11 Jun 2013 17:18:12 -0700 Subject: Add TriggerScenePresenceUpdated events when an animation is added or removed. Shouldn't impact anyone as only DSG seems to use OnScenePresenceUpdated event. Some minor format changes to AnimationSet's ToString(). --- OpenSim/Framework/Animation.cs | 5 ++--- OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs | 8 ++++++-- .../Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | 2 ++ OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs index 8bdf8f4..3425505 100644 --- a/OpenSim/Framework/Animation.cs +++ b/OpenSim/Framework/Animation.cs @@ -125,11 +125,10 @@ namespace OpenSim.Framework Animation other = obj as Animation; if (other != null) { - return (other.AnimID == this.AnimID + return (other.AnimID.Equals(this.AnimID) && other.SequenceNum == this.SequenceNum - && other.ObjectID == this.ObjectID); + && other.ObjectID.Equals(this.ObjectID) ); } - return base.Equals(obj); } diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index 5dee64d..b7400ea 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs @@ -312,18 +312,22 @@ namespace OpenSim.Region.Framework.Scenes.Animation buff.Append("dflt="); buff.Append(DefaultAnimation.ToString()); buff.Append(",iDflt="); - if (DefaultAnimation == ImplicitDefaultAnimation) + if (DefaultAnimation.Equals(ImplicitDefaultAnimation)) buff.Append("same"); else buff.Append(ImplicitDefaultAnimation.ToString()); if (m_animations.Count > 0) { buff.Append(",anims="); + bool firstTime = true; foreach (OpenSim.Framework.Animation anim in m_animations) { + if (!firstTime) + buff.Append(","); buff.Append("<"); buff.Append(anim.ToString()); - buff.Append(">,"); + buff.Append(">"); + firstTime = false; } } return buff.ToString(); diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index a701a79..3b5a5bd 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -94,6 +94,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) { SendAnimPack(); + m_scenePresence.TriggerScenePresenceUpdated(); } } @@ -135,6 +136,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation if (m_animations.Remove(animID, allowNoDefault)) { SendAnimPack(); + m_scenePresence.TriggerScenePresenceUpdated(); } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index bab14dd..774546c 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); // } - private void TriggerScenePresenceUpdated() + public void TriggerScenePresenceUpdated() { if (m_scene != null) m_scene.EventManager.TriggerScenePresenceUpdated(this); -- cgit v1.1 From 90097de6c3cf58989698b37c89baa8268895fc86 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Tue, 11 Jun 2013 20:35:25 -0400 Subject: Add option to set minimum fee for classified ads Upcoming phoenix-firestorm (4.4.1) adds a configurable option for setting the minimum price for publishing a classified ad. http://hg.phoenixviewer.com/phoenix-firestorm-lgpl/rev/43415d69b048 --- bin/Robust.HG.ini.example | 8 +++++++- bin/Robust.ini.example | 6 ++++++ bin/config-include/StandaloneCommon.ini.example | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index d9f1ca1..2afb978 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -1,4 +1,4 @@ -; * Run +i * Run ; * $ Robust.exe -inifile Robust.HG.ini ; * @@ -311,6 +311,9 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ;; Ask co-operative viewers to use a different currency name ;Currency = "" + ;; Minimum fee for creation of classified + ; ClassifiedFee = 0 + WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" @@ -436,6 +439,9 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ; this is the entry point for all user-related HG services ; uas = http://127.0.0.1:8002/ + ;; Minimum fee to publish classified add + ; ClassifiedFee = 0 + [GatekeeperService] LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService" ;; for the service diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 7d6492b..3440191 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -274,6 +274,9 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; Ask co-operative viewers to use a different currency name ;Currency = "" + ;; Minimum fee for creation of classified + ; ClassifiedFee = 0 + WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" @@ -393,6 +396,9 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; password help: optional: page providing password assistance for users of your grid ;password = http://127.0.0.1/password + ;; Minimum fee to publish classified add + ; ClassifiedFee = 0 + [UserProfilesService] LocalServiceModule = "OpenSim.Services.UserProfilesService.dll:UserProfilesService" Enabled = false diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 8c23c41..8ec3daf 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -222,6 +222,9 @@ ; this is the entry point for all user-related HG services ; uas = http://127.0.0.1:9000/ + ;; Minimum fee to publish classified add + ; ClassifiedFee = 0 + [MapImageService] ; Set this if you want to change the default ; TilesStoragePath = "maptiles" -- cgit v1.1 From 3cb65f0d3166f976713a7c095eb37e6de05061d0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 11 Jun 2013 17:58:08 -0700 Subject: BulletSim: when meshing or asset fetching fails, include position and region with the offending object's name in the error message. --- OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | 40 ++++++++++++++-------- .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 4 +++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index 202a4ce..006a9c1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs @@ -168,10 +168,10 @@ public abstract class BSShape if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) { prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; - physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", - LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}", - prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); } else { @@ -238,17 +238,17 @@ public abstract class BSShape { if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) { - physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", - LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}", - prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); } if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) { - physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. obj={1}, texture={2}", - LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,objNam={1},tex={2}", - prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); } } } @@ -260,6 +260,19 @@ public abstract class BSShape return fillShape.physShapeInfo; } + public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) + { + StringBuilder buff = new StringBuilder(prim.PhysObjectName); + buff.Append("/pos="); + buff.Append(prim.RawPosition.ToString()); + if (pScene != null) + { + buff.Append("/rgn="); + buff.Append(pScene.Name); + } + return buff.ToString(); + } + #endregion // Common shape routines } @@ -528,8 +541,7 @@ public class BSShapeMesh : BSShape { // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; - physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", - LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); + physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 1e01526..4357ef1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -1,5 +1,9 @@ CURRENT PROBLEMS TO FIX AND/OR LOOK AT ================================================= +Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass. + Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive? + Negative buoyancy computed correctly +Computation of mesh mass. How done? How should it be done? Script changing rotation of child prim while vehicle moving (eg turning wheel) causes the wheel to appear to jump back. Looks like sending position from previous update. Enable vehicle border crossings (at least as poorly as ODE) -- cgit v1.1 From 9fec0faade3979fc6e514b4acde92741aa0e9c16 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Tue, 11 Jun 2013 21:46:40 -0400 Subject: Revert "Add option to set minimum fee for classified ads" This reverts commit 90097de6c3cf58989698b37c89baa8268895fc86. --- bin/Robust.HG.ini.example | 8 +------- bin/Robust.ini.example | 6 ------ bin/config-include/StandaloneCommon.ini.example | 3 --- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 2afb978..d9f1ca1 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -1,4 +1,4 @@ -i * Run +; * Run ; * $ Robust.exe -inifile Robust.HG.ini ; * @@ -311,9 +311,6 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ;; Ask co-operative viewers to use a different currency name ;Currency = "" - ;; Minimum fee for creation of classified - ; ClassifiedFee = 0 - WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" @@ -439,9 +436,6 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ; this is the entry point for all user-related HG services ; uas = http://127.0.0.1:8002/ - ;; Minimum fee to publish classified add - ; ClassifiedFee = 0 - [GatekeeperService] LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService" ;; for the service diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 3440191..7d6492b 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -274,9 +274,6 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; Ask co-operative viewers to use a different currency name ;Currency = "" - ;; Minimum fee for creation of classified - ; ClassifiedFee = 0 - WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" @@ -396,9 +393,6 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; password help: optional: page providing password assistance for users of your grid ;password = http://127.0.0.1/password - ;; Minimum fee to publish classified add - ; ClassifiedFee = 0 - [UserProfilesService] LocalServiceModule = "OpenSim.Services.UserProfilesService.dll:UserProfilesService" Enabled = false diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 8ec3daf..8c23c41 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -222,9 +222,6 @@ ; this is the entry point for all user-related HG services ; uas = http://127.0.0.1:9000/ - ;; Minimum fee to publish classified add - ; ClassifiedFee = 0 - [MapImageService] ; Set this if you want to change the default ; TilesStoragePath = "maptiles" -- cgit v1.1 From 47b6e78790be5a4b7d8a0f4c860f1e2f6f87b137 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 12 Jun 2013 21:34:20 +0100 Subject: Implement logging of first 80 characters (debug level 5) or full body data (debug level 6) on outgoing requests, depending on debug level This is set via "debug http out " This matches the existing debug level behaviours for logging incoming http data --- OpenSim/Framework/Servers/MainServer.cs | 8 +++-- OpenSim/Framework/WebUtil.cs | 54 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index cfd34bb..d189580 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers + " level >= 2 then long warnings are logged when receiving bad input data.\n" + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" + " level >= 4 then the time taken to fulfill the request is logged.\n" - + " level >= 5 then a sample from the beginning of the incoming data is logged.\n" - + " level >= 6 then the entire incoming data is logged.\n" + + " level >= 5 then a sample from the beginning of the data is logged.\n" + + " level >= 6 then the entire data is logged.\n" + " no level is specified then the current level is returned.\n\n" + "If out or all and\n" + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" - + " level >= 4 then the time taken to fulfill the request is logged.\n", + + " level >= 4 then the time taken to fulfill the request is logged.\n" + + " level >= 5 then a sample from the beginning of the data is logged.\n" + + " level >= 6 then the entire data is logged.\n", HandleDebugHttpCommand); } diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 701fbb0..4599f62 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -151,6 +151,39 @@ namespace OpenSim.Framework } } + public static void LogOutgoingDetail(Stream outputStream) + { + using (StreamReader reader = new StreamReader(Util.Copy(outputStream), Encoding.UTF8)) + { + string output; + + if (DebugLevel == 5) + { + const int sampleLength = 80; + char[] sampleChars = new char[sampleLength]; + reader.Read(sampleChars, 0, sampleLength); + output = new string(sampleChars); + } + else + { + output = reader.ReadToEnd(); + } + + LogOutgoingDetail(output); + } + } + + public static void LogOutgoingDetail(string output) + { + if (DebugLevel == 5) + { + output = output.Substring(0, 80); + output = output + "..."; + } + + m_log.DebugFormat("[WEB UTIL]: {0}", output.Replace("\n", @"\n")); + } + private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) { int reqnum = RequestNumber++; @@ -178,7 +211,11 @@ namespace OpenSim.Framework // If there is some input, write it into the request if (data != null) { - strBuffer = OSDParser.SerializeJsonString(data); + strBuffer = OSDParser.SerializeJsonString(data); + + if (DebugLevel >= 5) + LogOutgoingDetail(strBuffer); + byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); if (compressed) @@ -357,6 +394,10 @@ namespace OpenSim.Framework if (data != null) { queryString = BuildQueryString(data); + + if (DebugLevel >= 5) + LogOutgoingDetail(queryString); + byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); request.ContentLength = buffer.Length; @@ -767,6 +808,9 @@ namespace OpenSim.Framework int length = (int)buffer.Length; request.ContentLength = length; + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail(buffer); + request.BeginGetRequestStream(delegate(IAsyncResult res) { Stream requestStream = request.EndGetRequestStream(res); @@ -954,6 +998,9 @@ namespace OpenSim.Framework length = (int)obj.Length; request.ContentLength = length; + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail(buffer); + Stream requestStream = null; try { @@ -1096,6 +1143,9 @@ namespace OpenSim.Framework int length = (int)buffer.Length; request.ContentLength = length; + if (WebUtil.DebugLevel >= 5) + WebUtil.LogOutgoingDetail(buffer); + Stream requestStream = null; try { @@ -1198,4 +1248,4 @@ namespace OpenSim.Framework return deserial; } } -} +} \ No newline at end of file -- cgit v1.1 From 824a4b480873721a4a10598299b185b602e1931d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 12 Jun 2013 23:47:47 +0100 Subject: After calls to GetSuitcaseXFolder() in HGSuitcaseInventoryService, consistently check for null return and log warning rather than throw exception. This was being done already in some places. If an exception is thrown it is now an error rather than debug --- .../Handlers/Inventory/XInventoryInConnector.cs | 2 +- .../HypergridService/HGSuitcaseInventoryService.cs | 24 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index 64127c2..9d28dc3 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs @@ -155,7 +155,7 @@ namespace OpenSim.Server.Handlers.Asset } catch (Exception e) { - m_log.DebugFormat("[XINVENTORY HANDLER]: Exception {0}", e.StackTrace); + m_log.ErrorFormat("[XINVENTORY HANDLER]: Exception {0}", e.StackTrace); } return FailureResult(); diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index eecf757..410916f 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -115,6 +115,12 @@ namespace OpenSim.Services.HypergridService { XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + if (suitcase == null) + { + m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for inventory skeleton", principalID); + return null; + } + List tree = GetFolderTree(principalID, suitcase.folderID); if (tree == null || (tree != null && tree.Count == 0)) return null; @@ -134,6 +140,7 @@ namespace OpenSim.Services.HypergridService public override InventoryCollection GetUserInventory(UUID userID) { m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Get Suitcase inventory for user {0}", userID); + InventoryCollection userInventory = new InventoryCollection(); userInventory.UserID = userID; userInventory.Folders = new List(); @@ -141,6 +148,12 @@ namespace OpenSim.Services.HypergridService XInventoryFolder suitcase = GetSuitcaseXFolder(userID); + if (suitcase == null) + { + m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for user inventory", userID); + return null; + } + List tree = GetFolderTree(userID, suitcase.folderID); if (tree == null || (tree != null && tree.Count == 0)) { @@ -182,7 +195,8 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetRootFolder for {0}", principalID); // Let's find out the local root folder - XInventoryFolder root = GetRootXFolder(principalID); ; + XInventoryFolder root = GetRootXFolder(principalID); + if (root == null) { m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve local root folder for user {0}", principalID); @@ -255,6 +269,13 @@ namespace OpenSim.Services.HypergridService { //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type); XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + + if (suitcase == null) + { + m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Found no suitcase folder for user {0} when looking for child type folder {1}", principalID, type); + return null; + } + XInventoryFolder[] folders = m_Database.GetFolders( new string[] { "agentID", "type", "parentFolderID" }, new string[] { principalID.ToString(), ((int)type).ToString(), suitcase.folderID.ToString() }); @@ -546,6 +567,7 @@ namespace OpenSim.Services.HypergridService private bool IsWithinSuitcaseTree(UUID principalID, UUID folderID) { XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + if (suitcase == null) { m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder", principalID); -- cgit v1.1 From 33573003620674f4a4f6c8fadd969c7aa6576a5d Mon Sep 17 00:00:00 2001 From: teravus Date: Wed, 12 Jun 2013 18:13:00 -0500 Subject: * This fixes having to select and deselect prim to get keyframemotion to start running when pulled from data storage. --- OpenSim/Data/MySQL/MySQLSimulationData.cs | 2 -- OpenSim/Data/SQLite/SQLiteSimulationData.cs | 5 +++-- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 5 +++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 448962a..de52623 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -457,8 +457,6 @@ namespace OpenSim.Data.MySQL if (prim.ParentUUID == UUID.Zero) { objects[prim.UUID] = new SceneObjectGroup(prim); - if (prim.KeyframeMotion != null) - prim.KeyframeMotion.UpdateSceneObject(objects[prim.UUID]); } } diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index 70b76c9..c35bba2 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -732,11 +732,12 @@ namespace OpenSim.Data.SQLite } SceneObjectGroup group = new SceneObjectGroup(prim); - if (prim.KeyframeMotion != null) - prim.KeyframeMotion.UpdateSceneObject(group); + createdObjects.Add(group.UUID, group); retvals.Add(group); LoadItems(prim); + + } } catch (Exception e) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index da80e4f..7b5fdcb 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -763,6 +763,11 @@ namespace OpenSim.Region.Framework.Scenes for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; + if (part.KeyframeMotion != null) + { + part.KeyframeMotion.UpdateSceneObject(this); + } + if (Object.ReferenceEquals(part, m_rootPart)) continue; -- cgit v1.1 From 7759b05dcb39298c0b47da827eda7250db5c2c83 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 13 Jun 2013 00:31:32 +0100 Subject: Make XInventoryServicesConnector properly handle a RESULT = false return for methods where this contains failure rather than throwing an exception. Result = False is generated for methods such as GetFolderForType() when the other end wants to signal a failure of the operation in methods such as GetFolderForType() --- .../Inventory/XInventoryServicesConnector.cs | 124 ++++++++++----------- 1 file changed, 56 insertions(+), 68 deletions(-) diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs index 44f5e01..36d4ae2 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs @@ -84,6 +84,30 @@ namespace OpenSim.Services.Connectors m_ServerURI = serviceURI; } + private bool CheckReturn(Dictionary ret) + { + if (ret == null) + return false; + + if (ret.Count == 0) + return false; + + if (ret.ContainsKey("RESULT")) + { + if (ret["RESULT"] is string) + { + bool result; + + if (bool.TryParse((string)ret["RESULT"], out result)) + return result; + + return false; + } + } + + return true; + } + public bool CreateUserInventory(UUID principalID) { Dictionary ret = MakeRequest("CREATEUSERINVENTORY", @@ -91,12 +115,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return false; - if (ret.Count == 0) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public List GetInventorySkeleton(UUID principalID) @@ -106,9 +125,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; Dictionary folders = (Dictionary)ret["FOLDERS"]; @@ -135,9 +152,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildFolder((Dictionary)ret["folder"]); @@ -151,9 +166,7 @@ namespace OpenSim.Services.Connectors { "TYPE", ((int)type).ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildFolder((Dictionary)ret["folder"]); @@ -174,9 +187,7 @@ namespace OpenSim.Services.Connectors { "FOLDER", folderID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; Dictionary folders = @@ -205,9 +216,7 @@ namespace OpenSim.Services.Connectors { "FOLDER", folderID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; Dictionary items = (Dictionary)ret["ITEMS"]; @@ -230,10 +239,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool UpdateFolder(InventoryFolderBase folder) @@ -248,10 +254,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool MoveFolder(InventoryFolderBase folder) @@ -263,10 +266,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", folder.Owner.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool DeleteFolders(UUID principalID, List folderIDs) @@ -282,10 +282,7 @@ namespace OpenSim.Services.Connectors { "FOLDERS", slist } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool PurgeFolder(InventoryFolderBase folder) @@ -295,10 +292,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool AddItem(InventoryItemBase item) @@ -330,10 +324,7 @@ namespace OpenSim.Services.Connectors { "CreationDate", item.CreationDate.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool UpdateItem(InventoryItemBase item) @@ -365,10 +356,7 @@ namespace OpenSim.Services.Connectors { "CreationDate", item.CreationDate.ToString() } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool MoveItems(UUID principalID, List items) @@ -389,10 +377,7 @@ namespace OpenSim.Services.Connectors { "DESTLIST", destlist } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public bool DeleteItems(UUID principalID, List itemIDs) @@ -408,10 +393,7 @@ namespace OpenSim.Services.Connectors { "ITEMS", slist } }); - if (ret == null) - return false; - - return bool.Parse(ret["RESULT"].ToString()); + return CheckReturn(ret); } public InventoryItemBase GetItem(InventoryItemBase item) @@ -423,9 +405,7 @@ namespace OpenSim.Services.Connectors { "ID", item.ID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildItem((Dictionary)ret["item"]); @@ -447,9 +427,7 @@ namespace OpenSim.Services.Connectors { "ID", folder.ID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; return BuildFolder((Dictionary)ret["folder"]); @@ -469,7 +447,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) + if (!CheckReturn(ret)) return null; List items = new List(); @@ -488,10 +466,22 @@ namespace OpenSim.Services.Connectors { "ASSET", assetID.ToString() } }); + // We cannot use CheckReturn() here because valid values for RESULT are "false" (in the case of request failure) or an int if (ret == null) return 0; - return int.Parse(ret["RESULT"].ToString()); + if (ret.ContainsKey("RESULT")) + { + if (ret["RESULT"] is string) + { + int intResult; + + if (int.TryParse ((string)ret["RESULT"], out intResult)) + return intResult; + } + } + + return 0; } public InventoryCollection GetUserInventory(UUID principalID) @@ -508,9 +498,7 @@ namespace OpenSim.Services.Connectors { "PRINCIPAL", principalID.ToString() } }); - if (ret == null) - return null; - if (ret.Count == 0) + if (!CheckReturn(ret)) return null; Dictionary folders = -- cgit v1.1 From 7c00ccb548154c73e9953be19122e4750ef781bd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 12 Jun 2013 17:48:20 -0700 Subject: DataSnapshot: changed those annoying messages to Debug instead of Info. --- OpenSim/Region/DataSnapshot/DataRequestHandler.cs | 4 ++-- OpenSim/Region/DataSnapshot/SnapshotStore.cs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs index 32e93b4..50276ae 100644 --- a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs +++ b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.DataSnapshot public Hashtable OnGetSnapshot(Hashtable keysvals) { - m_log.Info("[DATASNAPSHOT] Received collection request"); + m_log.Debug("[DATASNAPSHOT] Received collection request"); Hashtable reply = new Hashtable(); int statuscode = 200; @@ -80,7 +80,7 @@ namespace OpenSim.Region.DataSnapshot public Hashtable OnValidate(Hashtable keysvals) { - m_log.Info("[DATASNAPSHOT] Received validation request"); + m_log.Debug("[DATASNAPSHOT] Received validation request"); Hashtable reply = new Hashtable(); int statuscode = 200; diff --git a/OpenSim/Region/DataSnapshot/SnapshotStore.cs b/OpenSim/Region/DataSnapshot/SnapshotStore.cs index aa3d2ff..480aaaf 100644 --- a/OpenSim/Region/DataSnapshot/SnapshotStore.cs +++ b/OpenSim/Region/DataSnapshot/SnapshotStore.cs @@ -120,7 +120,7 @@ namespace OpenSim.Region.DataSnapshot provider.Stale = false; m_scenes[provider.GetParentScene] = true; - m_log.Info("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name); + m_log.Debug("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name); } else { @@ -134,7 +134,7 @@ namespace OpenSim.Region.DataSnapshot data = factory.ImportNode(node, true); } - m_log.Info("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name); + m_log.Debug("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name); } return data; @@ -154,7 +154,7 @@ namespace OpenSim.Region.DataSnapshot if (!m_scenes[scene]) { - m_log.Info("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache."); + m_log.Debug("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache."); //get snapshot from cache String path = DataFileNameScene(scene); @@ -168,11 +168,11 @@ namespace OpenSim.Region.DataSnapshot regionElement = factory.ImportNode(node, true); } - m_log.Info("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName); + m_log.Debug("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName); } else { - m_log.Info("[DATASNAPSHOT]: Attempting to generate snapshot."); + m_log.Debug("[DATASNAPSHOT]: Attempting to generate snapshot."); //make snapshot regionElement = MakeRegionNode(scene, factory); @@ -211,7 +211,7 @@ namespace OpenSim.Region.DataSnapshot m_scenes[scene] = false; - m_log.Info("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName); + m_log.Debug("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName); } return regionElement; -- cgit v1.1 From b2c8d5eec7cc5c6b4685d22921a6e684ce7714b1 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 13 Jun 2013 09:18:27 -0400 Subject: Add Option: ClassifiedFee Add option to set minimum fee for publishing classifieds. Many viewers have a hard coded minimum of 50, which makes publishing classifieds fail where grids have no economy. This allows the grid to set the minimum fee to a suitable value for their operation. The option is located in the [LoginService] section and defaults to 0. The value is sent as "classified_fee" in the login response. --- OpenSim/Services/LLLoginService/LLLoginResponse.cs | 18 +++++++++++++++++- OpenSim/Services/LLLoginService/LLLoginService.cs | 4 +++- bin/Robust.HG.ini.example | 3 +++ bin/Robust.ini.example | 3 +++ bin/config-include/StandaloneCommon.ini.example | 3 +++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 400f303..6ab5258 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -190,6 +190,7 @@ namespace OpenSim.Services.LLLoginService private BuddyList m_buddyList = null; private string currency; + private string classifiedFee; static LLLoginResponse() { @@ -227,7 +228,7 @@ namespace OpenSim.Services.LLLoginService GridRegion destination, List invSkel, FriendInfo[] friendsList, ILibraryService libService, string where, string startlocation, Vector3 position, Vector3 lookAt, List gestures, string message, GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency, - string DSTZone, string destinationsURL, string avatarsURL) + string DSTZone, string destinationsURL, string avatarsURL, string classifiedFee) : this() { FillOutInventoryData(invSkel, libService); @@ -251,6 +252,8 @@ namespace OpenSim.Services.LLLoginService SearchURL = searchURL; Currency = currency; + ClassifiedFee = classifiedFee; + FillOutHomeData(pinfo, home); LookAt = String.Format("[r{0},r{1},r{2}]", lookAt.X, lookAt.Y, lookAt.Z); @@ -463,6 +466,7 @@ namespace OpenSim.Services.LLLoginService searchURL = String.Empty; currency = String.Empty; + ClassifiedFee = "0"; } @@ -555,6 +559,9 @@ namespace OpenSim.Services.LLLoginService // responseData["real_currency"] = currency; responseData["currency"] = currency; } + + if (ClassifiedFee != String.Empty) + responseData["classified_fee"] = ClassifiedFee; responseData["login"] = "true"; @@ -659,6 +666,9 @@ namespace OpenSim.Services.LLLoginService if (searchURL != String.Empty) map["search"] = OSD.FromString(searchURL); + if (ClassifiedFee != String.Empty) + map["classified_fee"] = OSD.FromString(ClassifiedFee); + if (m_buddyList != null) { map["buddy-list"] = ArrayListToOSDArray(m_buddyList.ToArray()); @@ -1064,6 +1074,12 @@ namespace OpenSim.Services.LLLoginService set { currency = value; } } + public string ClassifiedFee + { + get { return classifiedFee; } + set { classifiedFee = value; } + } + public string DestinationsURL { get; set; diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index abda98f..10cf90f 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -78,6 +78,7 @@ namespace OpenSim.Services.LLLoginService protected string m_OpenIDURL; protected string m_SearchURL; protected string m_Currency; + protected string m_ClassifiedFee; protected string m_DestinationGuide; protected string m_AvatarPicker; @@ -119,6 +120,7 @@ namespace OpenSim.Services.LLLoginService m_OpenIDURL = m_LoginServerConfig.GetString("OpenIDServerURL", String.Empty); m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty); m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty); + m_ClassifiedFee = m_LoginServerConfig.GetString("ClassifiedFee", string.Empty); m_DestinationGuide = m_LoginServerConfig.GetString ("DestinationGuide", string.Empty); m_AvatarPicker = m_LoginServerConfig.GetString ("AvatarPicker", string.Empty); @@ -458,7 +460,7 @@ namespace OpenSim.Services.LLLoginService account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone, - m_DestinationGuide, m_AvatarPicker); + m_DestinationGuide, m_AvatarPicker, m_ClassifiedFee); m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index d9f1ca1..466aed2 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -311,6 +311,9 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ;; Ask co-operative viewers to use a different currency name ;Currency = "" + ;; Set minimum fee to publish classified + ; ClassifiedFee = 0 + WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 7d6492b..da1b43a 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -274,6 +274,9 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ; Ask co-operative viewers to use a different currency name ;Currency = "" + ;; Set minimum fee to publish classified + ; ClassifiedFee = 0 + WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 8c23c41..6b991a8 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -115,6 +115,9 @@ ;; Ask co-operative viewers to use a different currency name ;Currency = "" + ;; Set minimum fee to publish classified + ; ClassifiedFee = 0 + ;; Regular expressions for controlling which client versions are accepted/denied. ;; An empty string means nothing is checked. ;; -- cgit v1.1 From d412c1b0eb002b9ad5e6fc7aa1e01ea8f3725618 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 14 Jun 2013 23:53:20 +0100 Subject: Don't try to abort worker threads in WebFetchInvDescModule if module was not enabled. This also moves the abort to RemoveRegion() rather than a destructor. --- .../Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index d1afff2..2024018 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -116,6 +116,10 @@ namespace OpenSim.Region.ClientStack.Linden m_scene.EventManager.OnRegisterCaps -= RegisterCaps; m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; + + foreach (Thread t in m_workerThreads) + Watchdog.AbortThread(t.ManagedThreadId); + m_scene = null; } @@ -165,12 +169,6 @@ namespace OpenSim.Region.ClientStack.Linden #endregion - ~WebFetchInvDescModule() - { - foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); - } - private class PollServiceInventoryEventArgs : PollServiceEventArgs { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); -- cgit v1.1 From fc89bde044bf5805af9a5fe79d6e29e665e133ef Mon Sep 17 00:00:00 2001 From: Talun Date: Thu, 13 Jun 2013 22:57:09 +0100 Subject: Mantis 6108: ossetprimitiveparams temporary/phantom problem Corrected to ensure that the target prim is updated by osSetPrimitiveParams when setting PRIM_TEMP_ON_REZ and/or PRIM_PHANTOM instead of the prim that the script is in. --- OpenSim/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 e1630b3..d2e9f6c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7725,7 +7725,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return null; string ph = rules.Data[idx++].ToString(); - m_host.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1")); + part.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1")); break; @@ -7764,7 +7764,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return null; string temp = rules.Data[idx++].ToString(); - m_host.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1")); + part.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1")); break; -- cgit v1.1 From f074739e3381f85a73dfddcb522c0060edede148 Mon Sep 17 00:00:00 2001 From: Talun Date: Wed, 12 Jun 2013 00:06:08 +0100 Subject: Mantis 6280: llSetContentType(). An implementation. An implimentation of llSetContentType including all of the new constants added since the mantis was raised. --- .../Shared/Api/Implementation/LSL_Api.cs | 67 ++++++++++++++++++++++ .../ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | 1 + .../Shared/Api/Runtime/LSL_Constants.cs | 11 ++++ .../ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | 5 ++ 4 files changed, 84 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index d2e9f6c..733e868 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1480,6 +1480,73 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SetFaceColorAlpha(face, color, null); } + public void llSetContentType(LSL_Key id, LSL_Integer type) + { + m_host.AddScriptLPS(1); + + if (m_UrlModule == null) + return; + + // Make sure the content type is text/plain to start with + m_UrlModule.HttpContentType(new UUID(id), "text/plain"); + + // Is the object owner online and in the region + ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID); + if (agent == null || agent.IsChildAgent) + return; // Fail if the owner is not in the same region + + // Is it the embeded browser? + string userAgent = m_UrlModule.GetHttpHeader(new UUID(id), "user-agent"); + if (userAgent.IndexOf("SecondLife") < 0) + return; // Not the embedded browser. Is this check good enough? + + // Use the IP address of the client and check against the request + // seperate logins from the same IP will allow all of them to get non-text/plain as long + // as the owner is in the region. Same as SL! + string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString(); + string requestFromIPAddress = m_UrlModule.GetHttpHeader(new UUID(id), "remote_addr"); + //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'"); + if (requestFromIPAddress == null || requestFromIPAddress.Trim() == "") + return; + if (logonFromIPAddress == null || logonFromIPAddress.Trim() == "") + return; + + // If the request isnt from the same IP address then the request cannot be from the owner + if (!requestFromIPAddress.Trim().Equals(logonFromIPAddress.Trim())) + return; + + switch (type) + { + case ScriptBaseClass.CONTENT_TYPE_HTML: + m_UrlModule.HttpContentType(new UUID(id), "text/html"); + break; + case ScriptBaseClass.CONTENT_TYPE_XML: + m_UrlModule.HttpContentType(new UUID(id), "application/xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_XHTML: + m_UrlModule.HttpContentType(new UUID(id), "application/xhtml+xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_ATOM: + m_UrlModule.HttpContentType(new UUID(id), "application/atom+xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_JSON: + m_UrlModule.HttpContentType(new UUID(id), "application/json"); + break; + case ScriptBaseClass.CONTENT_TYPE_LLSD: + m_UrlModule.HttpContentType(new UUID(id), "application/llsd+xml"); + break; + case ScriptBaseClass.CONTENT_TYPE_FORM: + m_UrlModule.HttpContentType(new UUID(id), "application/x-www-form-urlencoded"); + break; + case ScriptBaseClass.CONTENT_TYPE_RSS: + m_UrlModule.HttpContentType(new UUID(id), "application/rss+xml"); + break; + default: + m_UrlModule.HttpContentType(new UUID(id), "text/plain"); + break; + } + } + public void SetTexGen(SceneObjectPart part, int face,int style) { Primitive.TextureEntry tex = part.Shape.Textures; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index a6ea88c..ff13ee6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -338,6 +338,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSetCameraParams(LSL_List rules); void llSetClickAction(int action); void llSetColor(LSL_Vector color, int face); + void llSetContentType(LSL_Key id, LSL_Integer type); void llSetDamage(double damage); void llSetForce(LSL_Vector force, int local); void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 559068d..1137ad8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -359,6 +359,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int HTTP_CUSTOM_HEADER = 5; public const int HTTP_PRAGMA_NO_CACHE = 6; + // llSetContentType + public const int CONTENT_TYPE_TEXT = 0; //text/plain + public const int CONTENT_TYPE_HTML = 1; //text/html + public const int CONTENT_TYPE_XML = 2; //application/xml + public const int CONTENT_TYPE_XHTML = 3; //application/xhtml+xml + public const int CONTENT_TYPE_ATOM = 4; //application/atom+xml + public const int CONTENT_TYPE_JSON = 5; //application/json + public const int CONTENT_TYPE_LLSD = 6; //application/llsd+xml + public const int CONTENT_TYPE_FORM = 7; //application/x-www-form-urlencoded + public const int CONTENT_TYPE_RSS = 8; //application/rss+xml + public const int PRIM_MATERIAL = 2; public const int PRIM_PHYSICS = 3; public const int PRIM_TEMP_ON_REZ = 4; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 398c125..87cc342 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -1528,6 +1528,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetColor(color, face); } + public void llSetContentType(LSL_Key id, LSL_Integer type) + { + m_LSL_Functions.llSetContentType(id, type); + } + public void llSetDamage(double damage) { m_LSL_Functions.llSetDamage(damage); -- cgit v1.1 From da3724a904d1edb48b83d7f87b7283fd61c7a273 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 15 Jun 2013 00:11:36 +0100 Subject: minor: remove mono compiler warnings from LSL_Api, properly format method doc for llRot2Axis() --- .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 733e868..256167c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4726,13 +4726,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_Rotation(x,y,z,s); } - - // Xantor 29/apr/2008 - // converts a Quaternion to X,Y,Z axis rotations + /// + /// Converts a Quaternion to X,Y,Z axis rotations + /// + /// + /// public LSL_Vector llRot2Axis(LSL_Rotation rot) { m_host.AddScriptLPS(1); - double x, y, z; if (Math.Abs(rot.s) > 1) // normalization needed rot.Normalize(); @@ -7454,14 +7455,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - int code = (int)options.GetLSLIntegerItem(0); - int idx = 0; while (idx < options.Data.Length) { int option = (int)options.GetLSLIntegerItem(idx++); - int remain = options.Data.Length - idx; switch (option) { -- cgit v1.1 From 720806b66183dc55589beb9161bdea071ac9c6fa Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 15 Jun 2013 00:34:45 +0100 Subject: Adjust the locking on InventoryCache. Locking for r/w of the ExpiringCache isn't needed since it's thread safe but r/w of contained dictionaries isn't thread-safe --- .../Inventory/InventoryCache.cs | 37 ++++++++++++++-------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs index 1e434b9..dcf33a1 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; - +using System.Threading; using OpenSim.Framework; using OpenMetaverse; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory { + /// + /// Cache root and system inventory folders to reduce number of potentially remote inventory calls and associated holdups. + /// public class InventoryCache { private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour @@ -16,8 +19,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory public void Cache(UUID userID, InventoryFolderBase root) { - lock (m_RootFolders) - m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS); + m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS); } public InventoryFolderBase GetRootFolder(UUID userID) @@ -31,14 +33,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory public void Cache(UUID userID, AssetType type, InventoryFolderBase folder) { - lock (m_FolderTypes) + Dictionary ff = null; + if (!m_FolderTypes.TryGetValue(userID, out ff)) + { + ff = new Dictionary(); + m_FolderTypes.Add(userID, ff, CACHE_EXPIRATION_SECONDS); + } + + // We need to lock here since two threads could potentially retrieve the same dictionary + // and try to add a folder for that type simultaneously. Dictionary<>.Add() is not described as thread-safe in the SDK + // even if the folders are identical. + lock (ff) { - Dictionary ff = null; - if (!m_FolderTypes.TryGetValue(userID, out ff)) - { - ff = new Dictionary(); - m_FolderTypes.Add(userID, ff, CACHE_EXPIRATION_SECONDS); - } if (!ff.ContainsKey(type)) ff.Add(type, folder); } @@ -50,8 +56,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory if (m_FolderTypes.TryGetValue(userID, out ff)) { InventoryFolderBase f = null; - if (ff.TryGetValue(type, out f)) - return f; + + lock (ff) + { + if (ff.TryGetValue(type, out f)) + return f; + } } return null; @@ -59,8 +69,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory public void Cache(UUID userID, InventoryCollection inv) { - lock (m_Inventories) - m_Inventories.AddOrUpdate(userID, inv, 120); + m_Inventories.AddOrUpdate(userID, inv, 120); } public InventoryCollection GetUserInventory(UUID userID) -- cgit v1.1 From ecfc6a3f4a44b70c3d7b3b03126f29f246136dfa Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 15 Jun 2013 00:36:04 +0100 Subject: Add the standard OpenSimulator copyright notice to the top of InventoryCache.cs --- .../Inventory/InventoryCache.cs | 29 +++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs index dcf33a1..2fc8ee3 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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.Threading; using OpenSim.Framework; -- cgit v1.1 From 9c530d725f13da91caffdbce2759d58a456afff5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 15 Jun 2013 00:41:02 +0100 Subject: refactor: In UserProfileModule, change classifiedCache and classifiedInterest to m_classifiedCache and m_classifiedInterest This is the coding standard name style for private fields. --- .../Avatar/UserProfiles/UserProfileModule.cs | 42 ++++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 322addd..97bb781 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -60,8 +60,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles // The pair of Dictionaries are used to handle the switching of classified ads // by maintaining a cache of classified id to creator id mappings and an interest // count. The entries are removed when the interest count reaches 0. - Dictionary classifiedCache = new Dictionary(); - Dictionary classifiedInterest = new Dictionary(); + Dictionary m_classifiedCache = new Dictionary(); + Dictionary m_classifiedInterest = new Dictionary(); public Scene Scene { @@ -331,16 +331,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles classifieds[cid] = name; - if(!classifiedCache.ContainsKey(cid)) + lock(m_classifiedCache) { - lock(classifiedCache) - classifiedCache.Add(cid,creatorId); - lock(classifiedInterest) - classifiedInterest.Add(cid, 0); + if (!m_classifiedCache.ContainsKey(cid)) + { + m_classifiedCache.Add(cid,creatorId); + + lock(m_classifiedInterest) + m_classifiedInterest.Add(cid, 0); + } } - lock(classifiedInterest) - classifiedInterest[cid] ++; + lock(m_classifiedInterest) + m_classifiedInterest[cid]++; } remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); @@ -352,19 +355,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles UserClassifiedAdd ad = new UserClassifiedAdd(); ad.ClassifiedId = queryClassifiedID; - if(classifiedCache.ContainsKey(queryClassifiedID)) + lock (classifie + if (m_classifiedCache.ContainsKey(queryClassifiedID)) { - target = classifiedCache[queryClassifiedID]; + target = m_classifiedCache[queryClassifiedID]; - lock(classifiedInterest) - classifiedInterest[queryClassifiedID] --; + lock(m_classifiedInterest) + m_classifiedInterest[queryClassifiedID] --; - if(classifiedInterest[queryClassifiedID] == 0) + if(m_classifiedInterest[queryClassifiedID] == 0) { - lock(classifiedInterest) - classifiedInterest.Remove(queryClassifiedID); - lock(classifiedCache) - classifiedCache.Remove(queryClassifiedID); + lock(m_classifiedInterest) + m_classifiedInterest.Remove(queryClassifiedID); + lock(m_classifiedCache) + m_classifiedCache.Remove(queryClassifiedID); } } @@ -1339,4 +1343,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } #endregion Web Util } -} +} \ No newline at end of file -- cgit v1.1 From 42b0c68eabcd79ea1d7d5776b399bcbb46bbbf98 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 15 Jun 2013 00:46:55 +0100 Subject: Correct build break in previous commit 9c530d7 --- .../Avatar/UserProfiles/UserProfileModule.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 97bb781..d7ffea8 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -60,8 +60,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles // The pair of Dictionaries are used to handle the switching of classified ads // by maintaining a cache of classified id to creator id mappings and an interest // count. The entries are removed when the interest count reaches 0. - Dictionary m_classifiedCache = new Dictionary(); - Dictionary m_classifiedInterest = new Dictionary(); + Dictionary m_classifiedCache = new Dictionary(); + Dictionary m_classifiedInterest = new Dictionary(); public Scene Scene { @@ -102,7 +102,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles /// /// Gets or sets a value indicating whether this - /// is enabled. + /// is enabled. /// /// /// true if enabled; otherwise, false. @@ -331,15 +331,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles classifieds[cid] = name; - lock(m_classifiedCache) + if (!m_classifiedCache.ContainsKey(cid)) { - if (!m_classifiedCache.ContainsKey(cid)) - { + lock(m_classifiedCache) m_classifiedCache.Add(cid,creatorId); - lock(m_classifiedInterest) - m_classifiedInterest.Add(cid, 0); - } + lock(m_classifiedInterest) + m_classifiedInterest.Add(cid, 0); } lock(m_classifiedInterest) @@ -355,7 +353,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles UserClassifiedAdd ad = new UserClassifiedAdd(); ad.ClassifiedId = queryClassifiedID; - lock (classifie if (m_classifiedCache.ContainsKey(queryClassifiedID)) { target = m_classifiedCache[queryClassifiedID]; -- cgit v1.1 From e6cb7b47646f8d7a23aca50d92fb57a639bbf702 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 15 Jun 2013 00:52:57 +0100 Subject: Lock m_classifiedCache and m_classifiedInterest dictionary reads in UserProfileModule since in the presence of writes these are not thread-safe operations. Simplified locking to m_classifiedCache only since r/w of both dictionaries always occurs together --- .../Avatar/UserProfiles/UserProfileModule.cs | 27 +++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index d7ffea8..161f160 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -331,17 +331,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles classifieds[cid] = name; - if (!m_classifiedCache.ContainsKey(cid)) + lock (m_classifiedCache) { - lock(m_classifiedCache) + if (!m_classifiedCache.ContainsKey(cid)) + { m_classifiedCache.Add(cid,creatorId); - - lock(m_classifiedInterest) m_classifiedInterest.Add(cid, 0); - } + } - lock(m_classifiedInterest) m_classifiedInterest[cid]++; + } } remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); @@ -353,19 +352,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles UserClassifiedAdd ad = new UserClassifiedAdd(); ad.ClassifiedId = queryClassifiedID; - if (m_classifiedCache.ContainsKey(queryClassifiedID)) - { - target = m_classifiedCache[queryClassifiedID]; + lock (m_classifiedCache) + { + if (m_classifiedCache.ContainsKey(queryClassifiedID)) + { + target = m_classifiedCache[queryClassifiedID]; - lock(m_classifiedInterest) m_classifiedInterest[queryClassifiedID] --; - if(m_classifiedInterest[queryClassifiedID] == 0) - { - lock(m_classifiedInterest) + if (m_classifiedInterest[queryClassifiedID] == 0) + { m_classifiedInterest.Remove(queryClassifiedID); - lock(m_classifiedCache) m_classifiedCache.Remove(queryClassifiedID); + } } } -- cgit v1.1 From 694c4bcbb671338263802457bb5a384c4fe44d26 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 14 Jun 2013 20:00:20 -0700 Subject: correct method doc for llRot2Axis() --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 256167c..c0b8373 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4727,7 +4727,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } /// - /// Converts a Quaternion to X,Y,Z axis rotations + /// Returns the axis of rotation for a quaternion /// /// /// -- cgit v1.1 From 0d2fd0d914581f755661455b8db2b9e399154632 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 22:39:00 +0100 Subject: Make general server stats available on the robust console as well as the simulator console This means the "show stats" command is now active on the robust console. --- .../Framework/Monitoring/ServerStatsCollector.cs | 309 +++++++++++++++++++ OpenSim/Framework/Monitoring/StatsManager.cs | 72 +++-- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 46 +-- OpenSim/Framework/Servers/ServerBase.cs | 32 ++ OpenSim/Region/Application/Application.cs | 1 + OpenSim/Region/Application/OpenSim.cs | 2 +- OpenSim/Region/Application/OpenSimBase.cs | 7 +- .../Framework/Monitoring/ServerStats.cs | 339 --------------------- OpenSim/Server/Base/ServicesServerBase.cs | 16 +- prebuild.xml | 1 + 10 files changed, 404 insertions(+), 421 deletions(-) create mode 100644 OpenSim/Framework/Monitoring/ServerStatsCollector.cs delete mode 100644 OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs new file mode 100644 index 0000000..80d0a89 --- /dev/null +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -0,0 +1,309 @@ +/* + * 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.Diagnostics; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; +using log4net; +using Nini.Config; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; + +namespace OpenSim.Framework.Monitoring +{ + public class ServerStatsCollector + { + private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private readonly string LogHeader = "[SERVER STATS]"; + + public bool Enabled = false; + private static Dictionary RegisteredStats = new Dictionary(); + + public readonly string CategoryServer = "server"; + + public readonly string ContainerProcessor = "processor"; + public readonly string ContainerMemory = "memory"; + public readonly string ContainerNetwork = "network"; + public readonly string ContainerProcess = "process"; + + public string NetworkInterfaceTypes = "Ethernet"; + + readonly int performanceCounterSampleInterval = 500; +// int lastperformanceCounterSampleTime = 0; + + private class PerfCounterControl + { + public PerformanceCounter perfCounter; + public int lastFetch; + public string name; + public PerfCounterControl(PerformanceCounter pPc) + : this(pPc, String.Empty) + { + } + public PerfCounterControl(PerformanceCounter pPc, string pName) + { + perfCounter = pPc; + lastFetch = 0; + name = pName; + } + } + + PerfCounterControl processorPercentPerfCounter = null; + + // IRegionModuleBase.Initialize + public void Initialise(IConfigSource source) + { + IConfig cfg = source.Configs["Monitoring"]; + + if (cfg != null) + Enabled = cfg.GetBoolean("ServerStatsEnabled", true); + + if (Enabled) + { + NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); + } + } + + public void Start() + { + if (RegisteredStats.Count == 0) + RegisterServerStats(); + } + + public void Close() + { + if (RegisteredStats.Count > 0) + { + foreach (Stat stat in RegisteredStats.Values) + { + StatsManager.DeregisterStat(stat); + stat.Dispose(); + } + RegisteredStats.Clear(); + } + } + + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) + { + string desc = pDesc; + if (desc == null) + desc = pName; + Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); + StatsManager.RegisterStat(stat); + RegisteredStats.Add(pName, stat); + } + + public void RegisterServerStats() + { +// lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); + PerformanceCounter tempPC; + Stat tempStat; + string tempName; + + try + { + tempName = "CPUPercent"; + tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); + processorPercentPerfCounter = new PerfCounterControl(tempPC); + // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. + tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, + StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, + StatVerbosity.Info); + StatsManager.RegisterStat(tempStat); + RegisteredStats.Add(tempName, tempStat); + + MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); + + MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); + + MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); + + MakeStat("Threads", null, "threads", ContainerProcessor, + (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); + } + + try + { + List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); + + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface nic in nics) + { + if (nic.OperationalStatus != OperationalStatus.Up) + continue; + + string nicInterfaceType = nic.NetworkInterfaceType.ToString(); + if (!okInterfaceTypes.Contains(nicInterfaceType)) + { + m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", + LogHeader, nic.Name, nicInterfaceType); + m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", + LogHeader, NetworkInterfaceTypes); + continue; + } + + if (nic.Supports(NetworkInterfaceComponent.IPv4)) + { + IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); + if (nicStats != null) + { + MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); + MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); + MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, + (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); + } + } + // TODO: add IPv6 (it may actually happen someday) + } + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); + } + + MakeStat("ProcessMemory", null, "MB", ContainerMemory, + (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); + MakeStat("ObjectMemory", null, "MB", ContainerMemory, + (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); + MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); + MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); + } + + // 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 + private delegate double PerfCounterNextValue(); + private void GetNextValue(Stat stat, PerfCounterControl perfControl) + { + GetNextValue(stat, perfControl, 1.0); + } + private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) + { + if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) + { + if (perfControl != null && perfControl.perfCounter != null) + { + try + { + // Kludge for factor to run double duty. If -1, subtract the value from one + if (factor == -1) + stat.Value = 1 - perfControl.perfCounter.NextValue(); + else + stat.Value = perfControl.perfCounter.NextValue() / factor; + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); + } + perfControl.lastFetch = Util.EnvironmentTickCount(); + } + } + } + + // Lookup the nic that goes with this stat and set the value by using a fetch action. + // Not sure about closure with delegates inside delegates. + private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); + private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) + { + // Get the one nic that has the name of this stat + IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( + (network) => network.Name == stat.Description); + try + { + foreach (NetworkInterface nic in nics) + { + IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); + if (intrStats != null) + { + double newVal = Math.Round(getter(intrStats) / factor, 3); + stat.Value = newVal; + } + break; + } + } + catch + { + // There are times interfaces go away so we just won't update the stat for this + m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); + } + } + } + + public class ServerStatsAggregator : Stat + { + public ServerStatsAggregator( + string shortName, + string name, + string description, + string unitName, + string category, + string container + ) + : base( + shortName, + name, + description, + unitName, + category, + container, + StatType.Push, + MeasuresOfInterest.None, + null, + StatVerbosity.Info) + { + } + public override string ToConsoleString() + { + StringBuilder sb = new StringBuilder(); + + return sb.ToString(); + } + + public override OSDMap ToOSDMap() + { + OSDMap ret = new OSDMap(); + + return ret; + } + } +} diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 24db6d4..3aee984 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -54,13 +54,13 @@ namespace OpenSim.Framework.Monitoring public static SortedDictionary>> RegisteredStats = new SortedDictionary>>(); - private static AssetStatsCollector assetStats; - private static UserStatsCollector userStats; - private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); +// private static AssetStatsCollector assetStats; +// private static UserStatsCollector userStats; +// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); - public static AssetStatsCollector AssetStats { get { return assetStats; } } - public static UserStatsCollector UserStats { get { return userStats; } } - public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } +// public static AssetStatsCollector AssetStats { get { return assetStats; } } +// public static UserStatsCollector UserStats { get { return userStats; } } + public static SimExtraStatsCollector SimExtraStats { get; set; } public static void RegisterConsoleCommands(ICommandConsole console) { @@ -89,10 +89,7 @@ namespace OpenSim.Framework.Monitoring if (categoryName == AllSubCommand) { - foreach (var category in RegisteredStats.Values) - { - OutputCategoryStatsToConsole(con, category); - } + OutputAllStatsToConsole(con); } else if (categoryName == ListSubCommand) { @@ -129,7 +126,18 @@ namespace OpenSim.Framework.Monitoring else { // Legacy - con.Output(SimExtraStats.Report()); + if (SimExtraStats != null) + con.Output(SimExtraStats.Report()); + else + OutputAllStatsToConsole(con); + } + } + + private static void OutputAllStatsToConsole(ICommandConsole con) + { + foreach (var category in RegisteredStats.Values) + { + OutputCategoryStatsToConsole(con, category); } } @@ -150,27 +158,27 @@ namespace OpenSim.Framework.Monitoring } } - /// - /// Start collecting statistics related to assets. - /// Should only be called once. - /// - public static AssetStatsCollector StartCollectingAssetStats() - { - assetStats = new AssetStatsCollector(); - - return assetStats; - } - - /// - /// Start collecting statistics related to users. - /// Should only be called once. - /// - public static UserStatsCollector StartCollectingUserStats() - { - userStats = new UserStatsCollector(); - - return userStats; - } +// /// +// /// Start collecting statistics related to assets. +// /// Should only be called once. +// /// +// public static AssetStatsCollector StartCollectingAssetStats() +// { +// assetStats = new AssetStatsCollector(); +// +// return assetStats; +// } +// +// /// +// /// Start collecting statistics related to users. +// /// Should only be called once. +// /// +// public static UserStatsCollector StartCollectingUserStats() +// { +// userStats = new UserStatsCollector(); +// +// return userStats; +// } /// /// Registers a statistic. diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 035b3ad..4ab6908 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -86,26 +86,23 @@ namespace OpenSim.Framework.Servers /// protected virtual void StartupSpecific() { - if (m_console == null) - return; - + StatsManager.SimExtraStats = new SimExtraStatsCollector(); RegisterCommonCommands(); - - m_console.Commands.AddCommand("General", false, "quit", - "quit", - "Quit the application", HandleQuit); + RegisterCommonComponents(Config); + } + + protected override void ShutdownSpecific() + { + m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); + + RemovePIDFile(); + + base.ShutdownSpecific(); - m_console.Commands.AddCommand("General", false, "shutdown", - "shutdown", - "Quit the application", HandleQuit); + Environment.Exit(0); } /// - /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing - /// - public virtual void ShutdownSpecific() {} - - /// /// 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. /// @@ -143,25 +140,8 @@ namespace OpenSim.Framework.Servers timeTaken.Minutes, timeTaken.Seconds); } - /// - /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing - /// - public virtual void Shutdown() + public string osSecret { - ShutdownSpecific(); - - m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); - RemovePIDFile(); - - Environment.Exit(0); - } - - private void HandleQuit(string module, string[] args) - { - Shutdown(); - } - - public string osSecret { // Secret uuid for the simulator get { return m_osSecret; } } diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 2c4a687..5358444 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -62,6 +62,8 @@ namespace OpenSim.Framework.Servers protected string m_pidFile = String.Empty; + protected ServerStatsCollector m_serverStatsCollector; + /// /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. /// @@ -259,6 +261,25 @@ namespace OpenSim.Framework.Servers "force gc", "Manually invoke runtime garbage collection. For debugging purposes", HandleForceGc); + + m_console.Commands.AddCommand( + "General", false, "quit", + "quit", + "Quit the application", (mod, args) => Shutdown()); + + m_console.Commands.AddCommand( + "General", false, "shutdown", + "shutdown", + "Quit the application", (mod, args) => Shutdown()); + + StatsManager.RegisterConsoleCommands(m_console); + } + + public void RegisterCommonComponents(IConfigSource configSource) + { + m_serverStatsCollector = new ServerStatsCollector(); + m_serverStatsCollector.Initialise(configSource); + m_serverStatsCollector.Start(); } private void HandleForceGc(string module, string[] args) @@ -698,5 +719,16 @@ namespace OpenSim.Framework.Servers if (m_console != null) m_console.OutputFormat(format, components); } + + public virtual void Shutdown() + { + m_serverStatsCollector.Close(); + ShutdownSpecific(); + } + + /// + /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing + /// + protected virtual void ShutdownSpecific() {} } } \ No newline at end of file diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index c3e7ec2..e451aa8 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -124,6 +124,7 @@ namespace OpenSim workerThreads = workerThreadsMax; m_log.InfoFormat("[OPENSIM MAIN]: Limiting 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) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 11dd052..9325b12 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -372,7 +372,7 @@ namespace OpenSim "Unload a module", HandleModules); } - public override void ShutdownSpecific() + protected override void ShutdownSpecific() { if (m_shutdownCommandsFile != String.Empty) { diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index f9e0cf1..7ca87a3 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -231,10 +231,7 @@ namespace OpenSim } if (m_console != null) - { - StatsManager.RegisterConsoleCommands(m_console); AddPluginCommands(m_console); - } } protected virtual void AddPluginCommands(ICommandConsole console) @@ -880,7 +877,7 @@ namespace OpenSim /// /// Performs any last-minute sanity checking and shuts down the region server /// - public override void ShutdownSpecific() + protected override void ShutdownSpecific() { if (proxyUrl.Length > 0) { @@ -900,6 +897,8 @@ namespace OpenSim { m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e); } + + base.ShutdownSpecific(); } /// diff --git a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs b/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs deleted file mode 100644 index 6e74ce0..0000000 --- a/OpenSim/Region/OptionalModules/Framework/Monitoring/ServerStats.cs +++ /dev/null @@ -1,339 +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.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net.NetworkInformation; -using System.Text; -using System.Threading; - -using log4net; -using Mono.Addins; -using Nini.Config; - -using OpenSim.Framework; -using OpenSim.Framework.Console; -using OpenSim.Framework.Monitoring; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -using OpenMetaverse.StructuredData; - -namespace OpenSim.Region.OptionalModules.Framework.Monitoring -{ -[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ServerStatistics")] -public class ServerStats : ISharedRegionModule -{ - private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - private readonly string LogHeader = "[SERVER STATS]"; - - public bool Enabled = false; - private static Dictionary RegisteredStats = new Dictionary(); - - public readonly string CategoryServer = "server"; - - public readonly string ContainerProcessor = "processor"; - public readonly string ContainerMemory = "memory"; - public readonly string ContainerNetwork = "network"; - public readonly string ContainerProcess = "process"; - - public string NetworkInterfaceTypes = "Ethernet"; - - readonly int performanceCounterSampleInterval = 500; - int lastperformanceCounterSampleTime = 0; - - private class PerfCounterControl - { - public PerformanceCounter perfCounter; - public int lastFetch; - public string name; - public PerfCounterControl(PerformanceCounter pPc) - : this(pPc, String.Empty) - { - } - public PerfCounterControl(PerformanceCounter pPc, string pName) - { - perfCounter = pPc; - lastFetch = 0; - name = pName; - } - } - - PerfCounterControl processorPercentPerfCounter = null; - - #region ISharedRegionModule - // IRegionModuleBase.Name - public string Name { get { return "Server Stats"; } } - // IRegionModuleBase.ReplaceableInterface - public Type ReplaceableInterface { get { return null; } } - // IRegionModuleBase.Initialize - public void Initialise(IConfigSource source) - { - IConfig cfg = source.Configs["Monitoring"]; - - if (cfg != null) - Enabled = cfg.GetBoolean("ServerStatsEnabled", true); - - if (Enabled) - { - NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); - } - } - // IRegionModuleBase.Close - public void Close() - { - if (RegisteredStats.Count > 0) - { - foreach (Stat stat in RegisteredStats.Values) - { - StatsManager.DeregisterStat(stat); - stat.Dispose(); - } - RegisteredStats.Clear(); - } - } - // IRegionModuleBase.AddRegion - public void AddRegion(Scene scene) - { - } - // IRegionModuleBase.RemoveRegion - public void RemoveRegion(Scene scene) - { - } - // IRegionModuleBase.RegionLoaded - public void RegionLoaded(Scene scene) - { - } - // ISharedRegionModule.PostInitialize - public void PostInitialise() - { - if (RegisteredStats.Count == 0) - { - RegisterServerStats(); - } - } - #endregion ISharedRegionModule - - private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) - { - string desc = pDesc; - if (desc == null) - desc = pName; - Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); - StatsManager.RegisterStat(stat); - RegisteredStats.Add(pName, stat); - } - - public void RegisterServerStats() - { - lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); - PerformanceCounter tempPC; - Stat tempStat; - string tempName; - - try - { - tempName = "CPUPercent"; - tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); - processorPercentPerfCounter = new PerfCounterControl(tempPC); - // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. - tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, - StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, - StatVerbosity.Info); - StatsManager.RegisterStat(tempStat); - RegisteredStats.Add(tempName, tempStat); - - MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); - - MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); - - MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); - - MakeStat("Threads", null, "threads", ContainerProcessor, - (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); - } - - try - { - List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); - - IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces(); - foreach (NetworkInterface nic in nics) - { - if (nic.OperationalStatus != OperationalStatus.Up) - continue; - - string nicInterfaceType = nic.NetworkInterfaceType.ToString(); - if (!okInterfaceTypes.Contains(nicInterfaceType)) - { - m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", - LogHeader, nic.Name, nicInterfaceType); - m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", - LogHeader, NetworkInterfaceTypes); - continue; - } - - if (nic.Supports(NetworkInterfaceComponent.IPv4)) - { - IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); - if (nicStats != null) - { - MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, - (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); - MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, - (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); - MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, - (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); - } - } - // TODO: add IPv6 (it may actually happen someday) - } - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); - } - - MakeStat("ProcessMemory", null, "MB", ContainerMemory, - (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); - MakeStat("ObjectMemory", null, "MB", ContainerMemory, - (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); - MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory, - (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); - MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory, - (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); - } - - // 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 - private delegate double PerfCounterNextValue(); - private void GetNextValue(Stat stat, PerfCounterControl perfControl) - { - GetNextValue(stat, perfControl, 1.0); - } - private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) - { - if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) - { - if (perfControl != null && perfControl.perfCounter != null) - { - try - { - // Kludge for factor to run double duty. If -1, subtract the value from one - if (factor == -1) - stat.Value = 1 - perfControl.perfCounter.NextValue(); - else - stat.Value = perfControl.perfCounter.NextValue() / factor; - } - catch (Exception e) - { - m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); - } - perfControl.lastFetch = Util.EnvironmentTickCount(); - } - } - } - - // Lookup the nic that goes with this stat and set the value by using a fetch action. - // Not sure about closure with delegates inside delegates. - private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); - private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) - { - // Get the one nic that has the name of this stat - IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where( - (network) => network.Name == stat.Description); - try - { - foreach (NetworkInterface nic in nics) - { - IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); - if (intrStats != null) - { - double newVal = Math.Round(getter(intrStats) / factor, 3); - stat.Value = newVal; - } - break; - } - } - catch - { - // There are times interfaces go away so we just won't update the stat for this - m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); - } - } -} - -public class ServerStatsAggregator : Stat -{ - public ServerStatsAggregator( - string shortName, - string name, - string description, - string unitName, - string category, - string container - ) - : base( - shortName, - name, - description, - unitName, - category, - container, - StatType.Push, - MeasuresOfInterest.None, - null, - StatVerbosity.Info) - { - } - public override string ToConsoleString() - { - StringBuilder sb = new StringBuilder(); - - return sb.ToString(); - } - - public override OSDMap ToOSDMap() - { - OSDMap ret = new OSDMap(); - - return ret; - } -} - -} diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index b13c87d..8243900 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -190,16 +190,7 @@ namespace OpenSim.Server.Base } RegisterCommonCommands(); - - // Register the quit command - // - MainConsole.Instance.Commands.AddCommand("General", false, "quit", - "quit", - "Quit the application", HandleQuit); - - MainConsole.Instance.Commands.AddCommand("General", false, "shutdown", - "shutdown", - "Quit the application", HandleQuit); + RegisterCommonComponents(Config); // Allow derived classes to perform initialization that // needs to be done after the console has opened @@ -231,11 +222,12 @@ namespace OpenSim.Server.Base return 0; } - protected virtual void HandleQuit(string module, string[] args) + protected override void ShutdownSpecific() { m_Running = false; m_log.Info("[CONSOLE] Quitting"); + base.ShutdownSpecific(); } protected virtual void ReadConfig() @@ -246,4 +238,4 @@ namespace OpenSim.Server.Base { } } -} +} \ No newline at end of file diff --git a/prebuild.xml b/prebuild.xml index 88db6ed..29c54c1 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -157,6 +157,7 @@ + -- cgit v1.1 From 2c9bb0f9738534732e147c090fac43f3373af1bb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 22:55:25 +0100 Subject: Add server stats for available builtin threadpool and iocp workers --- OpenSim/Framework/Monitoring/ServerStatsCollector.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index 80d0a89..fe74ef7 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -157,6 +157,22 @@ namespace OpenSim.Framework.Monitoring m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); } + MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerProcessor, + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s.Value = workerThreads; + }); + + MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerProcessor, + s => + { + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + s.Value = iocpThreads; + }); + try { List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); -- cgit v1.1 From 865d46ae1e0477f957ad674ed2a1a11ef85d885a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 22:56:39 +0100 Subject: Drop server level stats to debug instead of info. This was the original intention with these stats, as I didn't believe they would be useful to ordinary users if everything is working as it should. Please amend if this is an issue. Just for now, levels actually have no impact on what is displayed via the "show stats" command. --- OpenSim/Framework/Monitoring/ServerStatsCollector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index fe74ef7..c601c17 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -116,7 +116,7 @@ namespace OpenSim.Framework.Monitoring string desc = pDesc; if (desc == null) desc = pName; - Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info); + Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Debug); StatsManager.RegisterStat(stat); RegisteredStats.Add(pName, stat); } -- cgit v1.1 From b9dac1f8df3f58cc7b85938f7bbff1e79de371be Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 23:17:55 +0100 Subject: Fix test failure in BasicCircuitTests from previous commit 0d2fd0d9 --- OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index 556df30..b47ff54 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs @@ -33,6 +33,7 @@ using NUnit.Framework; using OpenMetaverse; using OpenMetaverse.Packets; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -69,6 +70,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests { base.SetUp(); m_scene = new SceneHelpers().SetupScene(); + StatsManager.SimExtraStats = new SimExtraStatsCollector(); } /// @@ -210,8 +212,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); Assert.That(spAfterAckTimeout, Is.Null); - -// TestHelpers.DisableLogging(); } // /// -- cgit v1.1 From 713a14a6b56188eb0ccf71e2ff78835bd258417e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 23:23:56 +0100 Subject: minor: remove mono compiler warnings in WebFetchInvDescModule --- OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 2024018..0e3cd6b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -34,6 +34,7 @@ using log4net; using Nini.Config; using Mono.Addins; using OpenMetaverse; +using OpenMetaverse.StructuredData; using OpenSim.Framework; using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; @@ -44,8 +45,6 @@ using OpenSim.Framework.Capabilities; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OpenSim.Capabilities.Handlers; -using OpenMetaverse; -using OpenMetaverse.StructuredData; namespace OpenSim.Region.ClientStack.Linden { @@ -64,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden public List folders; } - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; -- cgit v1.1 From c0a00cd7fd887190db61b1c69fb0e8f104a7e438 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 23:34:09 +0100 Subject: Fix bug where no threadpool data would be displayed in the "show threads" command if threadpool type was QueueUserWorkItem (Unsafe worked as expected) --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7f0850f..5e5eb7e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1880,7 +1880,7 @@ namespace OpenSim.Framework } } else if ( - FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem + FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) { threadPoolUsed = "BuiltInThreadPool"; -- cgit v1.1 From b7c9dee033bad425870540c08832058ac86d4ab5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 23:57:10 +0100 Subject: refactor: Move existing code to generate report information on the threadpool to the ServerBase rather than being in Util --- OpenSim/Framework/Servers/ServerBase.cs | 63 ++++++++++++++++++- OpenSim/Framework/Util.cs | 104 +++++++++++++------------------- 2 files changed, 103 insertions(+), 64 deletions(-) diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 5358444..029b848 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -667,7 +667,68 @@ namespace OpenSim.Framework.Servers sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); sb.Append("Main threadpool (excluding script engine pools)\n"); - sb.Append(Util.GetThreadPoolReport()); + sb.Append(GetThreadPoolReport()); + + return sb.ToString(); + } + + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + STPInfo stpi = Util.GetSmartThreadPoolInfo(); + + // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. + if (stpi != null) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = stpi.MaxThreads; + minThreads = stpi.MinThreads; + inUseThreads = stpi.InUseThreads; + allocatedThreads = stpi.ActiveThreads; + waitingCallbacks = stpi.WaitingCallbacks; + } + } + else if ( + Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem + || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } return sb.ToString(); } diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5e5eb7e..ba6cc75 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -89,9 +89,30 @@ namespace OpenSim.Framework } /// + /// Class for delivering SmartThreadPool statistical information + /// + /// + /// We do it this way so that we do not directly expose STP. + /// + public class STPInfo + { + public string Name { get; set; } + public STPStartInfo STPStartInfo { get; set; } + public WIGStartInfo WIGStartInfo { get; set; } + public bool IsIdle { get; set; } + public bool IsShuttingDown { get; set; } + public int MaxThreads { get; set; } + public int MinThreads { get; set; } + public int InUseThreads { get; set; } + public int ActiveThreads { get; set; } + public int WaitingCallbacks { get; set; } + public int MaxConcurrentWorkItems { get; set; } + } + + /// /// Miscellaneous utility functions /// - public class Util + public static class Util { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -1852,74 +1873,31 @@ namespace OpenSim.Framework } /// - /// Get a thread pool report. + /// Get information about the current state of the smart thread pool. /// - /// - public static string GetThreadPoolReport() + /// + /// null if this isn't the pool being used for non-scriptengine threads. + /// + public static STPInfo GetSmartThreadPoolInfo() { - string threadPoolUsed = null; - int maxThreads = 0; - int minThreads = 0; - int allocatedThreads = 0; - int inUseThreads = 0; - int waitingCallbacks = 0; - int completionPortThreads = 0; - - StringBuilder sb = new StringBuilder(); - if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - { - // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. - if (m_ThreadPool != null) - { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; - } - } - else if ( - FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem - || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) - { - threadPoolUsed = "BuiltInThreadPool"; - ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); - ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); - int availableThreads; - ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); - inUseThreads = maxThreads - availableThreads; - allocatedThreads = -1; - waitingCallbacks = -1; - } + if (m_ThreadPool == null) + return null; - if (threadPoolUsed != null) - { - sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); - sb.AppendFormat("Max threads : {0}\n", maxThreads); - sb.AppendFormat("Min threads : {0}\n", minThreads); - sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); - sb.AppendFormat("In use threads : {0}\n", inUseThreads); - sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); - } - else - { - sb.AppendFormat("Thread pool not used\n"); - } + STPInfo stpi = new STPInfo(); + stpi.Name = m_ThreadPool.Name; + stpi.STPStartInfo = m_ThreadPool.STPStartInfo; + stpi.IsIdle = m_ThreadPool.IsIdle; + stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; + stpi.MaxThreads = m_ThreadPool.MaxThreads; + stpi.MinThreads = m_ThreadPool.MinThreads; + stpi.InUseThreads = m_ThreadPool.InUseThreads; + stpi.ActiveThreads = m_ThreadPool.ActiveThreads; + stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; + stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; - return sb.ToString(); + return stpi; } -// private static object SmartThreadPoolCallback(object o) -// { -// object[] array = (object[])o; -// WaitCallback callback = (WaitCallback)array[0]; -// object obj = array[1]; -// -// callback(obj); -// return null; -// } - #endregion FireAndForget Threading Pattern /// -- cgit v1.1 From a1e32b843745581f7296359427a59e988814106b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Jun 2013 00:10:21 +0100 Subject: If SmartThreadPool is active, display statistical information about it in "show stats server" Also puts these and previous builtin threadpool stats in the "threadpool" stat container rather than "processor" --- OpenSim/Framework/Monitoring/ServerStatsCollector.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index c601c17..0ab4b93 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -49,6 +49,7 @@ namespace OpenSim.Framework.Monitoring public readonly string CategoryServer = "server"; + public readonly string ContainerThreadpool = "threadpool"; public readonly string ContainerProcessor = "processor"; public readonly string ContainerMemory = "memory"; public readonly string ContainerNetwork = "network"; @@ -157,7 +158,7 @@ namespace OpenSim.Framework.Monitoring m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); } - MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerProcessor, + MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, s => { int workerThreads, iocpThreads; @@ -165,7 +166,7 @@ namespace OpenSim.Framework.Monitoring s.Value = workerThreads; }); - MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerProcessor, + MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, s => { int workerThreads, iocpThreads; @@ -173,6 +174,16 @@ namespace OpenSim.Framework.Monitoring s.Value = iocpThreads; }); + if (Util.FireAndForgetMethod != null && Util.GetSmartThreadPoolInfo() != null) + { + MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads); + MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads); + MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems); + MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads); + MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads); + MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks); + } + try { List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); -- cgit v1.1 From 0767523834b51772cbdf61002e9c7cbae334ee72 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Jun 2013 21:21:59 +0100 Subject: Fix other places when saving scripts or notecards in prim inventories where messages should be transient without an OK button --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 6c79b13..1e4d558 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -326,7 +326,7 @@ namespace OpenSim.Region.Framework.Scenes // Update item with new asset item.AssetID = asset.FullID; if (group.UpdateInventoryItem(item)) - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); part.SendPropertiesToClient(remoteClient); @@ -342,7 +342,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); } // Tell anyone managing scripts that a script has been reloaded/changed @@ -1616,11 +1616,11 @@ namespace OpenSim.Region.Framework.Scenes remoteClient, part, transactionID, currentItem); if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) - remoteClient.SendAgentAlertMessage("Notecard saved", false); + remoteClient.SendAlertMessage("Notecard saved"); else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) - remoteClient.SendAgentAlertMessage("Script saved", false); + remoteClient.SendAlertMessage("Script saved"); else - remoteClient.SendAgentAlertMessage("Item saved", false); + remoteClient.SendAlertMessage("Item saved"); } // Base ALWAYS has move -- cgit v1.1 From 768e8e363bfb0aedc6edc2e6c1dbf35e1e66b531 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Jun 2013 22:49:49 +0100 Subject: Fix issue where stat samples were accidentally static, so that any additional stat with sampling would produce wrong results --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 2e7665f..69ac0a5 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -95,7 +95,7 @@ namespace OpenSim.Framework.Monitoring /// /// Will be null if no measures of interest require samples. /// - private static Queue m_samples; + private Queue m_samples; /// /// Maximum number of statistical samples. -- cgit v1.1 From 9501a583cbc8fd819d2b13db4f9ad76958520ce7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Jun 2013 23:07:18 +0100 Subject: Make number of inbound http requests handled available as a httpserver..IncomingHTTPRequestsProcessed stat --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 7 ++++- .../Framework/Servers/HttpServer/BaseHttpServer.cs | 30 ++++++++++++++++++---- OpenSim/Server/Base/ServicesServerBase.cs | 4 +++ prebuild.xml | 1 + 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 69ac0a5..ca71911 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -27,8 +27,9 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Text; - +using log4net; using OpenMetaverse.StructuredData; namespace OpenSim.Framework.Monitoring @@ -38,6 +39,8 @@ namespace OpenSim.Framework.Monitoring /// public class Stat : IDisposable { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// /// Category of this stat (e.g. cache, scene, etc). /// @@ -204,6 +207,8 @@ namespace OpenSim.Framework.Monitoring if (m_samples.Count >= m_maxSamples) m_samples.Dequeue(); +// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name); + m_samples.Enqueue(newValue); } } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 96a030b..6687441 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -54,7 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); - /// /// 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 @@ -81,6 +80,11 @@ namespace OpenSim.Framework.Servers.HttpServer /// public int RequestNumber { get; private set; } + /// + /// Statistic for holding number of requests processed. + /// + private Stat m_requestsProcessedStat; + private volatile int NotSocketErrors = 0; public volatile bool HTTPDRunning = false; @@ -436,9 +440,8 @@ namespace OpenSim.Framework.Servers.HttpServer } } - public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) + private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) { - OSHttpRequest req = new OSHttpRequest(context, request); WebSocketRequestDelegate dWebSocketRequestDelegate = null; lock (m_WebSocketHandlers) @@ -454,8 +457,7 @@ namespace OpenSim.Framework.Servers.HttpServer OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); resp.ReuseContext = true; - HandleRequest(req, resp); - + HandleRequest(req, resp); // !!!HACK ALERT!!! // There seems to be a bug in the underlying http code that makes subsequent requests @@ -1824,6 +1826,21 @@ namespace OpenSim.Framework.Servers.HttpServer // useful without inbound HTTP. throw e; } + + m_requestsProcessedStat + = new Stat( + "IncomingHTTPRequestsProcessed", + "Number of inbound HTTP requests processed", + "", + "requests", + "httpserver", + Port.ToString(), + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = RequestNumber, + StatVerbosity.Debug); + + StatsManager.RegisterStat(m_requestsProcessedStat); } public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) @@ -1854,6 +1871,9 @@ namespace OpenSim.Framework.Servers.HttpServer public void Stop() { HTTPDRunning = false; + + StatsManager.DeregisterStat(m_requestsProcessedStat); + try { m_PollServiceManager.Stop(); diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index 8243900..667cef8 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -34,6 +34,7 @@ using System.Text; using System.Xml; using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; using OpenSim.Framework.Servers; using log4net; using log4net.Config; @@ -205,6 +206,9 @@ namespace OpenSim.Server.Base public virtual int Run() { + Watchdog.Enabled = true; + MemoryWatchdog.Enabled = true; + while (m_Running) { try diff --git a/prebuild.xml b/prebuild.xml index 29c54c1..4cf3b83 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -745,6 +745,7 @@ + -- cgit v1.1 From dda44e31e3f649875a7fc7438c4a6880c56dbb31 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Jun 2013 23:10:50 +0100 Subject: minor: tidy up spacing if display a unit for additional stat information --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index ca71911..eb5599f 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -258,7 +258,7 @@ namespace OpenSim.Framework.Monitoring int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; - sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); + sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); } } } -- cgit v1.1 From 3fe5e9057f4f45e39c3056742855f580a51c921f Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Mon, 10 Jun 2013 19:59:08 -0400 Subject: Prevent an exception if no offline messages were retrieved. --- .../Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 7d763fa..7f3d0a2 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs @@ -182,7 +182,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); if (msglist == null) + { m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list."); + return; + } foreach (GridInstantMessage im in msglist) { -- cgit v1.1 From 1a72f62d7be483cf3a0612528c2b7d7880e0ce0c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Jun 2013 23:52:15 +0100 Subject: minor: remove mono compiler warning in OfflineIMService --- OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs index 6ba022c..6731923 100644 --- a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs +++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs @@ -46,7 +46,7 @@ namespace OpenSim.OfflineIM { public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private const int MAX_IM = 25; private XmlSerializer m_serializer; -- cgit v1.1 From 8a86e29579d654be979bac00c2620d49eb7fb457 Mon Sep 17 00:00:00 2001 From: Talun Date: Tue, 18 Jun 2013 15:09:55 +0100 Subject: Mantis 6608: Math error in parcel dimensions/borders seen with land show command This patch changes the land show console command to return numbers in the range 4 to 256 for the "to" coordinates instead of 0 to 252 Also trailing spaces removed from some lines. --- OpenSim/Region/CoreModules/World/Land/LandObject.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 8406442..e55c9ed 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -81,14 +81,14 @@ namespace OpenSim.Region.CoreModules.World.Land set { m_landData = value; } } - + public IPrimCounts PrimCounts { get; set; } public UUID RegionUUID { get { return m_scene.RegionInfo.RegionID; } } - + public Vector3 StartPoint { get @@ -101,11 +101,11 @@ namespace OpenSim.Region.CoreModules.World.Land return new Vector3(x * 4, y * 4, 0); } } - + return new Vector3(-1, -1, -1); } - } - + } + public Vector3 EndPoint { get @@ -116,15 +116,15 @@ namespace OpenSim.Region.CoreModules.World.Land { if (LandBitmap[x, y]) { - return new Vector3(x * 4, y * 4, 0); - } + return new Vector3(x * 4 + 4, y * 4 + 4, 0); + } } - } - + } + return new Vector3(-1, -1, -1); } } - + #region Constructors public LandObject(UUID owner_id, bool is_group_owned, Scene scene) -- cgit v1.1 From 84af1cab9ba991b2356f1025cab7f58433e2ec19 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 19 Jun 2013 20:48:12 +0100 Subject: Display existing statistic of how many http requests a server is making as server.network.HTTPRequestsMade in "show stats all" --- .../Framework/Monitoring/ServerStatsCollector.cs | 21 +++++++++++++++++---- OpenSim/Framework/Monitoring/Stats/Stat.cs | 5 +++++ .../Framework/Servers/HttpServer/BaseHttpServer.cs | 2 +- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index 0ab4b93..07ca14b 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -114,10 +114,15 @@ namespace OpenSim.Framework.Monitoring private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act) { + MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None); + } + + private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act, MeasuresOfInterest moi) + { string desc = pDesc; if (desc == null) desc = pName; - Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Debug); + Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug); StatsManager.RegisterStat(stat); RegisteredStats.Add(pName, stat); } @@ -141,7 +146,7 @@ namespace OpenSim.Framework.Monitoring StatsManager.RegisterStat(tempStat); RegisteredStats.Add(tempName, tempStat); - MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, + MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, @@ -158,7 +163,7 @@ namespace OpenSim.Framework.Monitoring m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); } - MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, + MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, s => { int workerThreads, iocpThreads; @@ -166,7 +171,7 @@ namespace OpenSim.Framework.Monitoring s.Value = workerThreads; }); - MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, + MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, s => { int workerThreads, iocpThreads; @@ -184,6 +189,14 @@ namespace OpenSim.Framework.Monitoring MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks); } + MakeStat( + "HTTPRequestsMade", + "Number of outbound HTTP requests made", + "requests", + ContainerNetwork, + s => s.Value = WebUtil.RequestNumber, + MeasuresOfInterest.AverageChangeOverTime); + try { List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(',')); diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index eb5599f..85d1a78 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; using log4net; @@ -247,6 +248,10 @@ namespace OpenSim.Framework.Monitoring lock (m_samples) { +// m_log.DebugFormat( +// "[STAT]: Samples for {0} are {1}", +// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); + foreach (double s in m_samples) { if (lastSample != null) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 6687441..40b8c5c 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -1829,7 +1829,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requestsProcessedStat = new Stat( - "IncomingHTTPRequestsProcessed", + "HTTPRequestsServed", "Number of inbound HTTP requests processed", "", "requests", -- cgit v1.1 From 086fd70a5fdfd9b3a0e56201596f6d6bb20f391e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:00:39 +0100 Subject: Make it possible to specify display of stats in a particular 'container' by separating category and container with a period. e.g. "show stats server.network" I failed to realize this had already been implemented without the period in the show stats command (as the command help had not been updated). However, I would prefer the . approach as it will allow specifying multiple stats, easier wildcarding, etc. This commit also prevents any stat from having a period in its short name. --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 8 ++++++++ OpenSim/Framework/Monitoring/StatsManager.cs | 12 +++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 85d1a78..c57ee0c 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -42,6 +42,8 @@ namespace OpenSim.Framework.Monitoring { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public static readonly char[] DisallowedShortNameCharacters = { '.' }; + /// /// Category of this stat (e.g. cache, scene, etc). /// @@ -166,6 +168,12 @@ namespace OpenSim.Framework.Monitoring throw new Exception( string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); + foreach (char c in DisallowedShortNameCharacters) + { + if (shortName.IndexOf(c) != -1) + throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c)); + } + ShortName = shortName; Name = name; Description = description; diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 3aee984..af9f5ba 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -68,12 +68,13 @@ namespace OpenSim.Framework.Monitoring "General", false, "show stats", - "show stats [list|all|]", + "show stats [list|all|[.]", "Show statistical information for this server", "If no final argument is specified then legacy statistics information is currently shown.\n" + "If list is specified then statistic categories are shown.\n" + "If all is specified then all registered statistics are shown.\n" + "If a category name is specified then only statistics from that category are shown.\n" + + "If a category container is also specified then only statistics from that category in that container are shown.\n" + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", HandleShowStatsCommand); } @@ -84,8 +85,11 @@ namespace OpenSim.Framework.Monitoring if (cmd.Length > 2) { - var categoryName = cmd[2]; - var containerName = cmd.Length > 3 ? cmd[3] : String.Empty; + string name = cmd[2]; + string[] components = name.Split('.'); + + string categoryName = components[0]; + string containerName = components.Length > 1 ? components[1] : null; if (categoryName == AllSubCommand) { @@ -107,7 +111,9 @@ namespace OpenSim.Framework.Monitoring else { if (String.IsNullOrEmpty(containerName)) + { OutputCategoryStatsToConsole(con, category); + } else { SortedDictionary container; -- cgit v1.1 From 3370e19205352a4ba75e384f8719836a0da0b1df Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:17:20 +0100 Subject: minor: fix mono compiler warning in FetchInventory2Handler --- .../Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs index c0ca1e1..2c91328 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs @@ -46,7 +46,7 @@ namespace OpenSim.Capabilities.Handlers { public class FetchInventory2Handler { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IInventoryService m_inventoryService; @@ -121,4 +121,4 @@ namespace OpenSim.Capabilities.Handlers return llsdItem; } } -} +} \ No newline at end of file -- cgit v1.1 From d97333255d45da686bb71d85ef492c5631c4dc31 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:20:04 +0100 Subject: Fix minor bug where the check whether to display SmartThreadPool stats was accidentally != null rather than == FireAndForgetMethod.SmartThreadPool Due to another check this had no practical effect --- OpenSim/Framework/Monitoring/ServerStatsCollector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index 07ca14b..5d1c270 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -179,7 +179,7 @@ namespace OpenSim.Framework.Monitoring s.Value = iocpThreads; }); - if (Util.FireAndForgetMethod != null && Util.GetSmartThreadPoolInfo() != null) + if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null) { MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads); MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads); -- cgit v1.1 From 5b1a9f84fdf4f9938180b403dd002b44e25c6efb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:32:12 +0100 Subject: minor: Change "memory churn" terminology in statistics to "heap allocation rate" since this is more generally meaningful --- OpenSim/Framework/Monitoring/BaseStatsCollector.cs | 12 ++++++------ OpenSim/Framework/Monitoring/MemoryWatchdog.cs | 8 ++++---- OpenSim/Framework/Monitoring/ServerStatsCollector.cs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs index be1d02b..20495f6 100644 --- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -45,16 +45,16 @@ namespace OpenSim.Framework.Monitoring sb.Append(Environment.NewLine); sb.AppendFormat( - "Allocated to OpenSim objects: {0} MB\n", + "Heap allocated to OpenSim : {0} MB\n", Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); sb.AppendFormat( - "OpenSim last object memory churn : {0} MB/s\n", - Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3)); + "Last heap allocation rate : {0} MB/s\n", + Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); sb.AppendFormat( - "OpenSim average object memory churn : {0} MB/s\n", - Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3)); + "Average heap allocation rate: {0} MB/s\n", + Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); sb.AppendFormat( "Process memory : {0} MB\n", diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs index c6010cd..c474622 100644 --- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs +++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs @@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring private static bool m_enabled; /// - /// Last memory churn in bytes per millisecond. + /// Average heap allocation rate in bytes per millisecond. /// - public static double AverageMemoryChurn + public static double AverageHeapAllocationRate { get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } } /// - /// Average memory churn in bytes per millisecond. + /// Last heap allocation in bytes /// - public static double LastMemoryChurn + public static double LastHeapAllocationRate { get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } } diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index 5d1c270..b22da1d 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -242,10 +242,10 @@ namespace OpenSim.Framework.Monitoring (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); MakeStat("ObjectMemory", null, "MB", ContainerMemory, (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); - MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory, - (s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); }); - MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory, - (s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); }); + MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); + MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory, + (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); } // Notes on performance counters: -- cgit v1.1 From 05790ba1cf7dd07f9f11ce248262041eb300ea49 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:45:56 +0100 Subject: Allow more than one stat category to be specified in "show stats" e.g. "show stats httpserver.9000 server.network" --- OpenSim/Framework/Monitoring/StatsManager.cs | 64 +++++++++++++++------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index af9f5ba..12d3a75 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace OpenSim.Framework.Monitoring @@ -68,13 +69,14 @@ namespace OpenSim.Framework.Monitoring "General", false, "show stats", - "show stats [list|all|[.]", + "show stats [list|all|([.])+", "Show statistical information for this server", "If no final argument is specified then legacy statistics information is currently shown.\n" - + "If list is specified then statistic categories are shown.\n" - + "If all is specified then all registered statistics are shown.\n" - + "If a category name is specified then only statistics from that category are shown.\n" - + "If a category container is also specified then only statistics from that category in that container are shown.\n" + + "'list' argument will show statistic categories.\n" + + "'all' will show all statistics.\n" + + "A name will show statistics from that category.\n" + + "A . name will show statistics from that category in that container.\n" + + "More than one name can be given separated by spaces.\n" + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", HandleShowStatsCommand); } @@ -85,45 +87,47 @@ namespace OpenSim.Framework.Monitoring if (cmd.Length > 2) { - string name = cmd[2]; - string[] components = name.Split('.'); + foreach (string name in cmd.Skip(2)) + { + string[] components = name.Split('.'); - string categoryName = components[0]; - string containerName = components.Length > 1 ? components[1] : null; + string categoryName = components[0]; + string containerName = components.Length > 1 ? components[1] : null; - if (categoryName == AllSubCommand) - { - OutputAllStatsToConsole(con); - } - else if (categoryName == ListSubCommand) - { - con.Output("Statistic categories available are:"); - foreach (string category in RegisteredStats.Keys) - con.OutputFormat(" {0}", category); - } - else - { - SortedDictionary> category; - if (!RegisteredStats.TryGetValue(categoryName, out category)) + if (categoryName == AllSubCommand) + { + OutputAllStatsToConsole(con); + } + else if (categoryName == ListSubCommand) { - con.OutputFormat("No such category as {0}", categoryName); + con.Output("Statistic categories available are:"); + foreach (string category in RegisteredStats.Keys) + con.OutputFormat(" {0}", category); } else { - if (String.IsNullOrEmpty(containerName)) + SortedDictionary> category; + if (!RegisteredStats.TryGetValue(categoryName, out category)) { - OutputCategoryStatsToConsole(con, category); + con.OutputFormat("No such category as {0}", categoryName); } else { - SortedDictionary container; - if (category.TryGetValue(containerName, out container)) + if (String.IsNullOrEmpty(containerName)) { - OutputContainerStatsToConsole(con, container); + OutputCategoryStatsToConsole(con, category); } else { - con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); + SortedDictionary container; + if (category.TryGetValue(containerName, out container)) + { + OutputContainerStatsToConsole(con, container); + } + else + { + con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); + } } } } -- cgit v1.1 From 085a87060a2ccb4910305b7c5f5374d1cc779d1a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:52:39 +0100 Subject: Change "ObjectMemory" stat to "HeapMemory" to align with other stat names. Also round this and ProcessMemory to three decimal places in common with other memory stats. I believe leaving out such minor info makes stats easier to read --- OpenSim/Framework/Monitoring/ServerStatsCollector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index b22da1d..ac0f0bc 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs @@ -239,9 +239,9 @@ namespace OpenSim.Framework.Monitoring } MakeStat("ProcessMemory", null, "MB", ContainerMemory, - (s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; }); - MakeStat("ObjectMemory", null, "MB", ContainerMemory, - (s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; }); + (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); }); + MakeStat("HeapMemory", null, "MB", ContainerMemory, + (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); }); MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory, (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory, -- cgit v1.1 From a33b6eed6d09661445a638efcbb354b0330f9093 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 20 Jun 2013 00:54:19 +0100 Subject: minor: remove mono compiler warnings in WebsocketServerHandler.cs --- .../Servers/HttpServer/WebsocketServerHandler.cs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs index ee96b47..de89e2e 100644 --- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs @@ -75,7 +75,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// /// This is a regular HTTP Request... This may be removed in the future. /// - public event RegularHttpRequestDelegate OnRegularHttpRequest; +// public event RegularHttpRequestDelegate OnRegularHttpRequest; /// /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired @@ -304,15 +304,14 @@ namespace OpenSim.Framework.Servers.HttpServer if (d != null) d(this, new UpgradeCompletedEventArgs()); } - catch (IOException fail) + catch (IOException) { Close(string.Empty); } - catch (ObjectDisposedException fail) + catch (ObjectDisposedException) { Close(string.Empty); - } - + } } /// @@ -414,8 +413,6 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.Header = pheader; } - - if (_socketState.FrameComplete) { ProcessFrame(_socketState); @@ -424,7 +421,6 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.ExpectedBytes = 0; } - } } else @@ -457,8 +453,7 @@ namespace OpenSim.Framework.Servers.HttpServer _socketState.ReceivedBytes.Clear(); _socketState.ExpectedBytes = 0; // do some processing - } - + } } } if (offset > 0) @@ -477,13 +472,12 @@ namespace OpenSim.Framework.Servers.HttpServer { // We can't read the stream anymore... } - } - catch (IOException fail) + catch (IOException) { Close(string.Empty); } - catch (ObjectDisposedException fail) + catch (ObjectDisposedException) { Close(string.Empty); } -- cgit v1.1 From bbeff4b8ca34a4567f2215ed5e90637a00d8c81e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 20 Jun 2013 09:55:40 -0700 Subject: BulletSim: rework velocity updating when not colliding and not flying to prevent infinite jumps. Now jumps last only AvatarJumpFrames long (default 4) which is about as high as in SL. TODO: jumping should only depend on standing (collision with feet) rather than collision anywhere on the avatar. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 44 +++++++++++++++++++--- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 ++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index ac8c30c..928b350 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -43,8 +43,14 @@ public class BSActorAvatarMove : BSActor // Set to true if we think we're going up stairs. // This state is remembered because collisions will turn on and off as we go up stairs. int m_walkingUpStairs; + // The amount the step up is applying. Used to smooth stair walking. float m_lastStepUp; + // Jumping happens over several frames. If use applies up force while colliding, start the + // jump and allow the jump to continue for this number of frames. + int m_jumpFrames = 0; + float m_jumpVelocity = 0f; + public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) : base(physicsScene, pObj, actorName) { @@ -206,17 +212,45 @@ public class BSActorAvatarMove : BSActor if (m_controllingPrim.Friction != BSParam.AvatarFriction) { - // Probably starting up walking. Set friction to moving friction. + // Probably starting to walk. Set friction to moving friction. m_controllingPrim.Friction = BSParam.AvatarFriction; m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); } - // If falling, we keep the world's downward vector no matter what the other axis specify. - // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) { - if (m_controllingPrim.RawVelocity.Z < 0) + stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + } + + + // Colliding and not flying with an upward force. The avatar must be trying to jump. + if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0) + { + // We allow the upward force to happen for this many frames. + m_jumpFrames = BSParam.AvatarJumpFrames; + m_jumpVelocity = stepVelocity.Z; + } + + // The case where the avatar is not colliding and is not flying is special. + // The avatar is either falling or jumping and the user can be applying force to the avatar + // (force in some direction or force up or down). + // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity. + // If the user is trying to apply upward force but we're not colliding, assume the avatar + // is trying to jump and don't apply the upward force if not touching the ground any more. + if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) + { + // If upward velocity is being applied, this must be a jump and only allow that to go on so long + if (m_jumpFrames > 0) + { + // Since not touching the ground, only apply upward force for so long. + m_jumpFrames--; + stepVelocity.Z = m_jumpVelocity; + } + else + { + // Since we're not affected by anything, whatever vertical motion the avatar has, continue that. stepVelocity.Z = m_controllingPrim.RawVelocity.Z; + } // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); } @@ -241,7 +275,7 @@ public class BSActorAvatarMove : BSActor m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); - // This test is done if moving forward, not flying and is colliding with something. + // Check for stairs climbing if colliding, not flying and moving forward if ( m_controllingPrim.IsColliding && !m_controllingPrim.Flying diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index aad1108..6437b04 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -134,6 +134,7 @@ public static class BSParam public static float AvatarHeightMidFudge { get; private set; } public static float AvatarHeightHighFudge { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; } + public static int AvatarJumpFrames { get; private set; } public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } public static float AvatarStepHeight { get; private set; } public static float AvatarStepApproachFactor { get; private set; } @@ -567,6 +568,8 @@ public static class BSParam 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", 1.0f ), + new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", + 4 ), new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", 0.6f ) , new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", -- cgit v1.1 From a5de4f692bd0de5faccdcf32a923a72949bb3cca Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Sat, 15 Jun 2013 17:23:43 -0400 Subject: BulletSim: Implementation of Linear Deflection, it is a partial help for the vehicle tuning diffrence between Opensim and Second life. Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 38 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 311cf4f..51207f1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -209,7 +209,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_VhoverTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: - m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); + m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f); break; case Vehicle.LINEAR_DEFLECTION_TIMESCALE: m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); @@ -1029,9 +1029,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); + //Compute Linear deflection. + Vector3 linearDeflectionFactorV = ComputeLinearDeflection(m_linearDeflectionEfficiency, currentVelV, pTimestep); + linearMotorCorrectionV += linearDeflectionFactorV; + // Friction reduces vehicle motion - Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); - linearMotorCorrectionV -= (currentVelV * frictionFactorW); + Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); + linearMotorCorrectionV -= (currentVelV * frictionFactorV); // Motor is vehicle coordinates. Rotate it to world coordinates Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; @@ -1048,9 +1052,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6},LinearDeflec={7}", ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, - linearMotorVelocityW, VehicleVelocity, frictionFactorW); + linearMotorVelocityW, VehicleVelocity, frictionFactorV, linearDeflectionFactorV); } public void ComputeLinearTerrainHeightCorrection(float pTimestep) @@ -1651,6 +1655,30 @@ namespace OpenSim.Region.Physics.BulletSPlugin } return frictionFactor; } + //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis + //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity + private Vector3 ComputeLinearDeflection(float DeflectionEfficiency,Vector3 Velocity,float pTimestep) + { + Vector3 LinearDeflection = Vector3.Zero; + LinearDeflection.Y = SortedClampInRange(0, (Velocity.Y * DeflectionEfficiency) / m_linearDeflectionTimescale, Velocity.Y); + LinearDeflection.Z = SortedClampInRange(0, (Velocity.Z * DeflectionEfficiency) / m_linearDeflectionTimescale, Velocity.Z); + LinearDeflection.X += Math.Abs(LinearDeflection.Y); + LinearDeflection.X += Math.Abs(LinearDeflection.Z); + LinearDeflection *= pTimestep; + return LinearDeflection*=new Vector3(1,-1,-1); + + } + private float SortedClampInRange(float clampa, float val, float clampb) + { + if (clampa > clampb) + { + float temp = clampa; + clampa = clampb; + clampb = temp; + } + return ClampInRange(clampa, val, clampb); + + } private float ClampInRange(float low, float val, float high) { -- cgit v1.1 From 74539659f6f9be557dbd07fdefa1adae1c59ce87 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Jun 2013 10:46:21 -0700 Subject: BulletSim: move new linear deflection code to own routine. Remove VehicleForwardVelocity changed storage since the value will be modified as movement is processed. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 64 ++++++++++++---------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 51207f1..07e87d1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -707,7 +707,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin private Vector3 m_knownRotationalVelocity; private Vector3 m_knownRotationalForce; private Vector3 m_knownRotationalImpulse; - private Vector3 m_knownForwardVelocity; // vehicle relative forward speed private const int m_knownChangedPosition = 1 << 0; private const int m_knownChangedVelocity = 1 << 1; @@ -719,7 +718,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin private const int m_knownChangedRotationalImpulse = 1 << 7; private const int m_knownChangedTerrainHeight = 1 << 8; private const int m_knownChangedWaterLevel = 1 << 9; - private const int m_knownChangedForwardVelocity = 1 <<10; public void ForgetKnownVehicleProperties() { @@ -923,12 +921,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { get { - if ((m_knownHas & m_knownChangedForwardVelocity) == 0) - { - m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); - m_knownHas |= m_knownChangedForwardVelocity; - } - return m_knownForwardVelocity; + return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); } } private float VehicleForwardSpeed @@ -981,6 +974,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin { ComputeLinearVelocity(pTimestep); + ComputeLinearDeflection(pTimestep); + ComputeLinearTerrainHeightCorrection(pTimestep); ComputeLinearHover(pTimestep); @@ -1026,14 +1021,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin { // Step the motor from the current value. Get the correction needed this step. Vector3 origVelW = VehicleVelocity; // DEBUG - Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); + Vector3 currentVelV = VehicleForwardVelocity; Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); - //Compute Linear deflection. - Vector3 linearDeflectionFactorV = ComputeLinearDeflection(m_linearDeflectionEfficiency, currentVelV, pTimestep); - linearMotorCorrectionV += linearDeflectionFactorV; - - // Friction reduces vehicle motion + // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction. Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); linearMotorCorrectionV -= (currentVelV * frictionFactorV); @@ -1050,11 +1041,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", + ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, + linearMotorVelocityW, VehicleVelocity, frictionFactorV); + } + //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis + //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity + private void ComputeLinearDeflection(float pTimestep) + { + Vector3 linearDeflectionV = Vector3.Zero; + Vector3 velocityV = VehicleForwardVelocity; - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6},LinearDeflec={7}", - ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, - linearMotorVelocityW, VehicleVelocity, frictionFactorV, linearDeflectionFactorV); + // Velocity in Y and Z dimensions is movement to the side or turning. + // Compute deflection factor from the to the side and rotational velocity + linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y); + linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z); + + // Velocity to the side and around is corrected and moved into the forward direction + linearDeflectionV.X += Math.Abs(linearDeflectionV.Y); + linearDeflectionV.X += Math.Abs(linearDeflectionV.Z); + + // Scale the deflection to the fractional simulation time + linearDeflectionV *= pTimestep; + + // Subtract the sideways and rotational velocity deflection factors while adding the correction forward + linearDeflectionV *= new Vector3(1,-1,-1); + + // Correciont is vehicle relative. Convert to world coordinates and add to the velocity + VehicleVelocity += linearDeflectionV * VehicleOrientation; + + VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}", + ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV); } public void ComputeLinearTerrainHeightCorrection(float pTimestep) @@ -1655,19 +1673,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } return frictionFactor; } - //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis - //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity - private Vector3 ComputeLinearDeflection(float DeflectionEfficiency,Vector3 Velocity,float pTimestep) - { - Vector3 LinearDeflection = Vector3.Zero; - LinearDeflection.Y = SortedClampInRange(0, (Velocity.Y * DeflectionEfficiency) / m_linearDeflectionTimescale, Velocity.Y); - LinearDeflection.Z = SortedClampInRange(0, (Velocity.Z * DeflectionEfficiency) / m_linearDeflectionTimescale, Velocity.Z); - LinearDeflection.X += Math.Abs(LinearDeflection.Y); - LinearDeflection.X += Math.Abs(LinearDeflection.Z); - LinearDeflection *= pTimestep; - return LinearDeflection*=new Vector3(1,-1,-1); - } private float SortedClampInRange(float clampa, float val, float clampb) { if (clampa > clampb) -- cgit v1.1 From 4778d67005c3364ee3f75bdd6640f03ff945d885 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 21 Jun 2013 20:52:46 -0700 Subject: Finally moved HG agent transfers to use agent fatpacks. --- .../EntityTransfer/HGEntityTransferModule.cs | 2 +- OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs | 2 +- .../Server/Handlers/Hypergrid/HomeAgentHandlers.cs | 200 +++++---------------- .../Handlers/Hypergrid/UserAgentServerConnector.cs | 2 +- .../Server/Handlers/Simulation/AgentHandlers.cs | 76 +++++--- .../Hypergrid/GatekeeperServiceConnector.cs | 68 ++----- .../Hypergrid/UserAgentServiceConnector.cs | 138 ++++---------- .../Simulation/SimulationServiceConnector.cs | 29 ++- .../Services/HypergridService/UserAgentService.cs | 12 +- OpenSim/Services/Interfaces/IHypergridServices.cs | 5 +- OpenSim/Services/LLLoginService/LLLoginService.cs | 2 +- 11 files changed, 171 insertions(+), 365 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 02ed1a0..0715324 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -273,7 +273,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); - bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); + bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, false, out reason); logout = success; // flag for later logout from this grid; this is an HG TP if (success) diff --git a/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs index cf1af15..adc2fbc 100644 --- a/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/AgentHandlers.cs @@ -61,7 +61,7 @@ namespace OpenSim.Server.Handlers.Hypergrid m_Proxy = proxy; } - protected override bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + protected override bool CreateAgent(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) { return m_GatekeeperService.LoginAgent(aCircuit, destination, out reason); } diff --git a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs index 968c1e6..df875af 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs @@ -49,191 +49,87 @@ using log4net; namespace OpenSim.Server.Handlers.Hypergrid { - public class HomeAgentHandler + public class HomeAgentHandler : AgentPostHandler { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IUserAgentService m_UserAgentService; private string m_LoginServerIP; - private bool m_Proxy = false; - public HomeAgentHandler(IUserAgentService userAgentService, string loginServerIP, bool proxy) + public HomeAgentHandler(IUserAgentService userAgentService, string loginServerIP, bool proxy) : + base("/homeagent") { m_UserAgentService = userAgentService; m_LoginServerIP = loginServerIP; m_Proxy = proxy; } - public Hashtable Handler(Hashtable request) + protected override AgentDestinationData CreateAgentDestinationData() { -// m_log.Debug("[CONNECTION DEBUGGING]: HomeAgentHandler Called"); -// -// m_log.Debug("---------------------------"); -// m_log.Debug(" >> uri=" + request["uri"]); -// m_log.Debug(" >> content-type=" + request["content-type"]); -// m_log.Debug(" >> http-method=" + request["http-method"]); -// m_log.Debug("---------------------------\n"); - - Hashtable responsedata = new Hashtable(); - responsedata["content_type"] = "text/html"; - responsedata["keepalive"] = false; - - - UUID agentID; - UUID regionID; - string action; - if (!Utils.GetParams((string)request["uri"], out agentID, out regionID, out action)) + return new ExtendedAgentDestinationData(); + } + protected override void UnpackData(OSDMap args, AgentDestinationData d, Hashtable request) + { + base.UnpackData(args, d, request); + ExtendedAgentDestinationData data = (ExtendedAgentDestinationData)d; + try { - m_log.InfoFormat("[HOME AGENT HANDLER]: Invalid parameters for agent message {0}", request["uri"]); - responsedata["int_response_code"] = 404; - responsedata["str_response_string"] = "false"; + if (args.ContainsKey("gatekeeper_host") && args["gatekeeper_host"] != null) + data.host = args["gatekeeper_host"].AsString(); + if (args.ContainsKey("gatekeeper_port") && args["gatekeeper_port"] != null) + Int32.TryParse(args["gatekeeper_port"].AsString(), out data.port); + if (args.ContainsKey("gatekeeper_serveruri") && args["gatekeeper_serveruri"] != null) + data.gatekeeperServerURI = args["gatekeeper_serveruri"]; + if (args.ContainsKey("destination_serveruri") && args["destination_serveruri"] != null) + data.destinationServerURI = args["destination_serveruri"]; - return responsedata; } - - // Next, let's parse the verb - string method = (string)request["http-method"]; - if (method.Equals("POST")) + catch (InvalidCastException e) { - DoAgentPost(request, responsedata, agentID); - return responsedata; + m_log.ErrorFormat("[HOME AGENT HANDLER]: Bad cast in UnpackData"); } - else - { - m_log.InfoFormat("[HOME AGENT HANDLER]: method {0} not supported in agent message", method); - responsedata["int_response_code"] = HttpStatusCode.MethodNotAllowed; - responsedata["str_response_string"] = "Method not allowed"; - return responsedata; - } + string callerIP = GetCallerIP(request); + // Verify if this call came from the login server + if (callerIP == m_LoginServerIP) + data.fromLogin = true; } - protected void DoAgentPost(Hashtable request, Hashtable responsedata, UUID id) + protected override GridRegion ExtractGatekeeper(AgentDestinationData d) { - OSDMap args = Utils.GetOSDMap((string)request["body"]); - if (args == null) + if (d is ExtendedAgentDestinationData) { - responsedata["int_response_code"] = HttpStatusCode.BadRequest; - responsedata["str_response_string"] = "Bad request"; - return; + ExtendedAgentDestinationData data = (ExtendedAgentDestinationData)d; + GridRegion gatekeeper = new GridRegion(); + gatekeeper.ServerURI = data.gatekeeperServerURI; + gatekeeper.ExternalHostName = data.host; + gatekeeper.HttpPort = (uint)data.port; + gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); + + return gatekeeper; } - - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - string gatekeeper_host = string.Empty; - string gatekeeper_serveruri = string.Empty; - string destination_serveruri = string.Empty; - int gatekeeper_port = 0; - IPEndPoint client_ipaddress = null; - - if (args.ContainsKey("gatekeeper_host") && args["gatekeeper_host"] != null) - gatekeeper_host = args["gatekeeper_host"].AsString(); - if (args.ContainsKey("gatekeeper_port") && args["gatekeeper_port"] != null) - Int32.TryParse(args["gatekeeper_port"].AsString(), out gatekeeper_port); - if (args.ContainsKey("gatekeeper_serveruri") && args["gatekeeper_serveruri"] !=null) - gatekeeper_serveruri = args["gatekeeper_serveruri"]; - if (args.ContainsKey("destination_serveruri") && args["destination_serveruri"] !=null) - destination_serveruri = args["destination_serveruri"]; - - GridRegion gatekeeper = new GridRegion(); - gatekeeper.ServerURI = gatekeeper_serveruri; - gatekeeper.ExternalHostName = gatekeeper_host; - gatekeeper.HttpPort = (uint)gatekeeper_port; - gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); - - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); else - m_log.WarnFormat(" -- request didn't have destination_x"); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); - else - m_log.WarnFormat(" -- request didn't have destination_y"); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - - if (args.ContainsKey("client_ip") && args["client_ip"] != null) - { - string ip_str = args["client_ip"].ToString(); - try - { - string callerIP = GetCallerIP(request); - // Verify if this caller has authority to send the client IP - if (callerIP == m_LoginServerIP) - client_ipaddress = new IPEndPoint(IPAddress.Parse(ip_str), 0); - else // leaving this for now, but this warning should be removed - m_log.WarnFormat("[HOME AGENT HANDLER]: Unauthorized machine {0} tried to set client ip to {1}", callerIP, ip_str); - } - catch - { - m_log.DebugFormat("[HOME AGENT HANDLER]: Exception parsing client ip address from {0}", ip_str); - } - } - - GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; - destination.ServerURI = destination_serveruri; - - AgentCircuitData aCircuit = new AgentCircuitData(); - try - { - aCircuit.UnpackAgentCircuitData(args); - } - catch (Exception ex) - { - m_log.InfoFormat("[HOME AGENT HANDLER]: exception on unpacking ChildCreate message {0}", ex.Message); - responsedata["int_response_code"] = HttpStatusCode.BadRequest; - responsedata["str_response_string"] = "Bad request"; - return; - } - - OSDMap resp = new OSDMap(2); - string reason = String.Empty; + m_log.WarnFormat("[HOME AGENT HANDLER]: Wrong data type"); - bool result = m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, client_ipaddress, out reason); - - resp["reason"] = OSD.FromString(reason); - resp["success"] = OSD.FromBoolean(result); - - // TODO: add reason if not String.Empty? - responsedata["int_response_code"] = HttpStatusCode.OK; - responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); + return null; } - private string GetCallerIP(Hashtable request) - { - if (!m_Proxy) - return Util.GetCallerIP(request); - - // We're behind a proxy - Hashtable headers = (Hashtable)request["headers"]; - string xff = "X-Forwarded-For"; - if (headers.ContainsKey(xff.ToLower())) - xff = xff.ToLower(); - if (!headers.ContainsKey(xff) || headers[xff] == null) - { - m_log.WarnFormat("[AGENT HANDLER]: No XFF header"); - return Util.GetCallerIP(request); - } + protected override bool CreateAgent(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) + { + return m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, fromLogin, out reason); + } - m_log.DebugFormat("[AGENT HANDLER]: XFF is {0}", headers[xff]); + } - IPEndPoint ep = Util.GetClientIPFromXFF((string)headers[xff]); - if (ep != null) - return ep.Address.ToString(); + public class ExtendedAgentDestinationData : AgentDestinationData + { + public string host; + public int port; + public string gatekeeperServerURI; + public string destinationServerURI; - // Oops - return Util.GetCallerIP(request); - } } } diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index b20f467..d9c1bd3 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -108,7 +108,7 @@ namespace OpenSim.Server.Handlers.Hypergrid server.AddXmlRPCHandler("get_uui", GetUUI, false); server.AddXmlRPCHandler("get_uuid", GetUUID, false); - server.AddHTTPHandler("/homeagent/", new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy).Handler); + server.AddStreamHandler(new HomeAgentHandler(m_HomeUsersService, loginServerIP, proxy)); } public XmlRpcResponse GetHomeRegion(XmlRpcRequest request, IPEndPoint remoteClient) diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index ae37ca7..334d313 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -328,31 +328,16 @@ namespace OpenSim.Server.Handlers.Simulation return; } - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - uint teleportFlags = 0; - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); - else - m_log.WarnFormat(" -- request didn't have destination_x"); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); - else - m_log.WarnFormat(" -- request didn't have destination_y"); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - if (args.ContainsKey("teleport_flags") && args["teleport_flags"] != null) - teleportFlags = args["teleport_flags"].AsUInteger(); + AgentDestinationData data = CreateAgentDestinationData(); + UnpackData(args, data, request); GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; + destination.RegionID = data.uuid; + destination.RegionLocX = data.x; + destination.RegionLocY = data.y; + destination.RegionName = data.name; + + GridRegion gatekeeper = ExtractGatekeeper(data); AgentCircuitData aCircuit = new AgentCircuitData(); try @@ -373,7 +358,7 @@ namespace OpenSim.Server.Handlers.Simulation // This is the meaning of POST agent //m_regionClient.AdjustUserInformation(aCircuit); //bool result = m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); - bool result = CreateAgent(destination, aCircuit, teleportFlags, out reason); + bool result = CreateAgent(gatekeeper, destination, aCircuit, data.flags, data.fromLogin, out reason); resp["reason"] = OSD.FromString(reason); resp["success"] = OSD.FromBoolean(result); @@ -385,7 +370,36 @@ namespace OpenSim.Server.Handlers.Simulation responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); } - private string GetCallerIP(Hashtable request) + protected virtual AgentDestinationData CreateAgentDestinationData() + { + return new AgentDestinationData(); + } + + protected virtual void UnpackData(OSDMap args, AgentDestinationData data, Hashtable request) + { + // retrieve the input arguments + if (args.ContainsKey("destination_x") && args["destination_x"] != null) + Int32.TryParse(args["destination_x"].AsString(), out data.x); + else + m_log.WarnFormat(" -- request didn't have destination_x"); + if (args.ContainsKey("destination_y") && args["destination_y"] != null) + Int32.TryParse(args["destination_y"].AsString(), out data.y); + else + m_log.WarnFormat(" -- request didn't have destination_y"); + if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) + UUID.TryParse(args["destination_uuid"].AsString(), out data.uuid); + if (args.ContainsKey("destination_name") && args["destination_name"] != null) + data.name = args["destination_name"].ToString(); + if (args.ContainsKey("teleport_flags") && args["teleport_flags"] != null) + data.flags = args["teleport_flags"].AsUInteger(); + } + + protected virtual GridRegion ExtractGatekeeper(AgentDestinationData data) + { + return null; + } + + protected string GetCallerIP(Hashtable request) { if (!m_Proxy) return Util.GetCallerIP(request); @@ -418,7 +432,7 @@ namespace OpenSim.Server.Handlers.Simulation } // subclasses can override this - protected virtual bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, out string reason) + protected virtual bool CreateAgent(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, uint teleportFlags, bool fromLogin, out string reason) { return m_SimulationService.CreateAgent(destination, aCircuit, teleportFlags, out reason); } @@ -593,4 +607,14 @@ namespace OpenSim.Server.Handlers.Simulation return m_SimulationService.UpdateAgent(destination, agent); } } + + public class AgentDestinationData + { + public int x; + public int y; + public string name; + public UUID uuid; + public uint flags; + public bool fromLogin; + } } diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index 5bcff48..c9c6c31 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs @@ -53,7 +53,8 @@ namespace OpenSim.Services.Connectors.Hypergrid private IAssetService m_AssetService; - public GatekeeperServiceConnector() : base() + public GatekeeperServiceConnector() + : base() { } @@ -123,11 +124,13 @@ namespace OpenSim.Services.Connectors.Hypergrid realHandle = Convert.ToUInt64((string)hash["handle"]); //m_log.Debug(">> HERE, realHandle: " + realHandle); } - if (hash["region_image"] != null) { + if (hash["region_image"] != null) + { imageURL = (string)hash["region_image"]; //m_log.Debug(">> HERE, imageURL: " + imageURL); } - if (hash["external_name"] != null) { + if (hash["external_name"] != null) + { externalName = (string)hash["external_name"]; //m_log.Debug(">> HERE, externalName: " + externalName); } @@ -178,7 +181,7 @@ namespace OpenSim.Services.Connectors.Hypergrid //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); imageData = OpenJPEG.EncodeFromImage(bitmap, true); } - + AssetBase ass = new AssetBase(UUID.Random(), "region " + name, (sbyte)AssetType.Texture, regionID.ToString()); // !!! for now @@ -257,7 +260,8 @@ namespace OpenSim.Services.Connectors.Hypergrid region.RegionName = (string)hash["region_name"]; //m_log.Debug(">> HERE, region_name: " + region.RegionName); } - if (hash["hostname"] != null) { + if (hash["hostname"] != null) + { region.ExternalHostName = (string)hash["hostname"]; //m_log.Debug(">> HERE, hostname: " + region.ExternalHostName); } @@ -275,10 +279,10 @@ namespace OpenSim.Services.Connectors.Hypergrid region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); //m_log.Debug(">> HERE, internal_port: " + region.InternalEndPoint); } - + if (hash["server_uri"] != null) { - region.ServerURI = (string) hash["server_uri"]; + region.ServerURI = (string)hash["server_uri"]; //m_log.Debug(">> HERE, server_uri: " + region.ServerURI); } @@ -295,55 +299,5 @@ namespace OpenSim.Services.Connectors.Hypergrid return null; } - - public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) - { - // m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: CreateAgent start"); - - myipaddress = String.Empty; - reason = String.Empty; - - if (destination == null) - { - m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Given destination is null"); - return false; - } - - string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; - - try - { - OSDMap args = aCircuit.PackAgentCircuitData(); - - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - args["teleport_flags"] = OSD.FromString(flags.ToString()); - - OSDMap result = WebUtil.PostToService(uri, args, 80000); - if (result["Success"].AsBoolean()) - { - OSDMap unpacked = (OSDMap)result["_Result"]; - - if (unpacked != null) - { - reason = unpacked["reason"].AsString(); - myipaddress = unpacked["your_ip"].AsString(); - return unpacked["success"].AsBoolean(); - } - } - - reason = result["Message"] != null ? result["Message"].AsString() : "error"; - return false; - } - catch (Exception e) - { - m_log.Warn("[REMOTE SIMULATION CONNECTOR]: CreateAgent failed with exception: " + e.ToString()); - reason = e.Message; - } - - return false; - } } } diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 47d0cce..d8a3184 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -44,13 +44,14 @@ using Nini.Config; namespace OpenSim.Services.Connectors.Hypergrid { - public class UserAgentServiceConnector : IUserAgentService + public class UserAgentServiceConnector : SimulationServiceConnector, IUserAgentService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - string m_ServerURL; + private string m_ServerURL; + private GridRegion m_Gatekeeper; public UserAgentServiceConnector(string url) : this(url, true) { @@ -104,9 +105,15 @@ namespace OpenSim.Services.Connectors.Hypergrid m_log.DebugFormat("[USER AGENT CONNECTOR]: UserAgentServiceConnector started for {0}", m_ServerURL); } + protected override string AgentPath() + { + return "homeagent/"; + } - // The Login service calls this interface with a non-null [client] ipaddress - public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress, out string reason) + // The Login service calls this interface with fromLogin=true + // Sims call it with fromLogin=false + // Either way, this is verified by the handler + public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, bool fromLogin, out string reason) { reason = String.Empty; @@ -117,119 +124,34 @@ namespace OpenSim.Services.Connectors.Hypergrid return false; } - string uri = m_ServerURL + "homeagent/" + aCircuit.AgentID + "/"; - - Console.WriteLine(" >>> LoginAgentToGrid <<< " + uri); - - HttpWebRequest AgentCreateRequest = (HttpWebRequest)WebRequest.Create(uri); - AgentCreateRequest.Method = "POST"; - AgentCreateRequest.ContentType = "application/json"; - AgentCreateRequest.Timeout = 10000; - //AgentCreateRequest.KeepAlive = false; - //AgentCreateRequest.Headers.Add("Authorization", authKey); - - // Fill it in - OSDMap args = PackCreateAgentArguments(aCircuit, gatekeeper, destination, ipaddress); - - string strBuffer = ""; - byte[] buffer = new byte[1]; - try - { - strBuffer = OSDParser.SerializeJsonString(args); - Encoding str = Util.UTF8; - buffer = str.GetBytes(strBuffer); - - } - catch (Exception e) - { - m_log.WarnFormat("[USER AGENT CONNECTOR]: Exception thrown on serialization of ChildCreate: {0}", e.Message); - // ignore. buffer will be empty, caller should check. - } - - Stream os = null; - try - { // send the Post - AgentCreateRequest.ContentLength = buffer.Length; //Count bytes to send - os = AgentCreateRequest.GetRequestStream(); - os.Write(buffer, 0, strBuffer.Length); //Send it - m_log.InfoFormat("[USER AGENT CONNECTOR]: Posted CreateAgent request to remote sim {0}, region {1}, x={2} y={3}", - uri, destination.RegionName, destination.RegionLocX, destination.RegionLocY); - } - //catch (WebException ex) - catch - { - //m_log.InfoFormat("[USER AGENT CONNECTOR]: Bad send on ChildAgentUpdate {0}", ex.Message); - reason = "cannot contact remote region"; - return false; - } - finally - { - if (os != null) - os.Close(); - } - - // Let's wait for the response - //m_log.Info("[USER AGENT CONNECTOR]: Waiting for a reply after DoCreateChildAgentCall"); + GridRegion home = new GridRegion(); + home.ServerURI = m_ServerURL; + home.RegionID = destination.RegionID; + home.RegionLocX = destination.RegionLocX; + home.RegionLocY = destination.RegionLocY; - try - { - using (WebResponse webResponse = AgentCreateRequest.GetResponse()) - { - if (webResponse == null) - { - m_log.Info("[USER AGENT CONNECTOR]: Null reply on DoCreateChildAgentCall post"); - } - else - { - using (Stream s = webResponse.GetResponseStream()) - { - using (StreamReader sr = new StreamReader(s)) - { - string response = sr.ReadToEnd().Trim(); - m_log.InfoFormat("[USER AGENT CONNECTOR]: DoCreateChildAgentCall reply was {0} ", response); - - if (!String.IsNullOrEmpty(response)) - { - try - { - // we assume we got an OSDMap back - OSDMap r = Util.GetOSDMap(response); - bool success = r["success"].AsBoolean(); - reason = r["reason"].AsString(); - return success; - } - catch (NullReferenceException e) - { - m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", e.Message); - - // check for old style response - if (response.ToLower().StartsWith("true")) - return true; - - return false; - } - } - } - } - } - } - } - catch (WebException ex) - { - m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", ex.Message); - reason = "Destination did not reply"; - return false; - } + m_Gatekeeper = gatekeeper; - return true; + Console.WriteLine(" >>> LoginAgentToGrid <<< " + home.ServerURI); + uint flags = fromLogin ? (uint)TeleportFlags.ViaLogin : (uint)TeleportFlags.ViaHome; + return CreateAgent(home, aCircuit, flags, out reason); } // The simulators call this interface public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, out string reason) { - return LoginAgentToGrid(aCircuit, gatekeeper, destination, null, out reason); + return LoginAgentToGrid(aCircuit, gatekeeper, destination, false, out reason); + } + + protected override void PackData(OSDMap args, AgentCircuitData aCircuit, GridRegion destination, uint flags) + { + base.PackData(args, aCircuit, destination, flags); + args["gatekeeper_serveruri"] = OSD.FromString(m_Gatekeeper.ServerURI); + args["gatekeeper_host"] = OSD.FromString(m_Gatekeeper.ExternalHostName); + args["gatekeeper_port"] = OSD.FromString(m_Gatekeeper.HttpPort.ToString()); + args["destination_serveruri"] = OSD.FromString(destination.ServerURI); } protected OSDMap PackCreateAgentArguments(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress) diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 57f2ffa..e247008 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -79,11 +79,27 @@ namespace OpenSim.Services.Connectors.Simulation return "agent/"; } + protected virtual void PackData(OSDMap args, AgentCircuitData aCircuit, GridRegion destination, uint flags) + { + args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); + args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); + args["destination_name"] = OSD.FromString(destination.RegionName); + args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); + args["teleport_flags"] = OSD.FromString(flags.ToString()); + } + public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason) { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CreateAgent start"); - + string tmp = String.Empty; + return CreateAgent(destination, aCircuit, flags, out tmp, out reason); + } + + public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) + { + m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: Creating agent at {0}", destination.ServerURI); reason = String.Empty; + myipaddress = String.Empty; + if (destination == null) { m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Given destination is null"); @@ -95,12 +111,7 @@ namespace OpenSim.Services.Connectors.Simulation try { OSDMap args = aCircuit.PackAgentCircuitData(); - - args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); - args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); - args["destination_name"] = OSD.FromString(destination.RegionName); - args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); - args["teleport_flags"] = OSD.FromString(flags.ToString()); + PackData(args, aCircuit, destination, flags); OSDMap result = WebUtil.PostToServiceCompressed(uri, args, 30000); bool success = result["success"].AsBoolean(); @@ -110,6 +121,7 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); + myipaddress = data["your_ip"].AsString(); return success; } @@ -124,6 +136,7 @@ namespace OpenSim.Services.Connectors.Simulation reason = data["reason"].AsString(); success = data["success"].AsBoolean(); + myipaddress = data["your_ip"].AsString(); m_log.WarnFormat( "[REMOTE SIMULATION CONNECTOR]: Remote simulator {0} did not accept compressed transfer, suggest updating it.", destination.RegionName); return success; diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 737e9c9..733993f 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -210,10 +210,10 @@ namespace OpenSim.Services.HypergridService return home; } - public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason) + public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason) { m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", - agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI); + agentCircuit.firstname, agentCircuit.lastname, (fromLogin ? agentCircuit.IPAddress : "stored IP"), gatekeeper.ServerURI); string gridName = gatekeeper.ServerURI; @@ -265,7 +265,7 @@ namespace OpenSim.Services.HypergridService bool success = false; string myExternalIP = string.Empty; - m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); + m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}, desired region: {2}", m_GridName, gridName, region.RegionID); if (m_GridName == gridName) success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason); @@ -296,8 +296,8 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); // else set the IP addresses associated with this client - if (clientIP != null) - m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString(); + if (fromLogin) + m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = agentCircuit.IPAddress; m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; return true; @@ -306,7 +306,7 @@ namespace OpenSim.Services.HypergridService public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason) { reason = string.Empty; - return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, null, out reason); + return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, false, out reason); } private void SetClientIP(UUID sessionID, string ip) diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs index 3dc877a..f9e7f08 100644 --- a/OpenSim/Services/Interfaces/IHypergridServices.cs +++ b/OpenSim/Services/Interfaces/IHypergridServices.cs @@ -48,10 +48,7 @@ namespace OpenSim.Services.Interfaces /// public interface IUserAgentService { - // called by login service only - bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason); - // called by simulators - bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, out string reason); + bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, bool fromLogin, out string reason); void LogoutAgent(UUID userID, UUID sessionID); GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); Dictionary GetServerURLs(UUID userID); diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 10cf90f..fe43582 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -933,7 +933,7 @@ namespace OpenSim.Services.LLLoginService private bool LaunchAgentIndirectly(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, IPEndPoint clientIP, out string reason) { m_log.Debug("[LLOGIN SERVICE] Launching agent at " + destination.RegionName); - if (m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, clientIP, out reason)) + if (m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, true, out reason)) return true; return false; } -- cgit v1.1 From ca3ce6da7349425f117ad1f1a596e7e868fdd4c1 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 22 Jun 2013 08:26:59 -0700 Subject: HG: avoid call on localhost between sim and UAS for standalone. --- .../EntityTransfer/HGEntityTransferModule.cs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 0715324..630d1c3 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -53,8 +53,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private int m_levelHGTeleport = 0; + private string m_ThisHomeURI; private GatekeeperServiceConnector m_GatekeeperConnector; + private IUserAgentService m_UAS; protected bool m_RestrictAppearanceAbroad; protected string m_AccountName; @@ -143,6 +145,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); } } + + moduleConfig = source.Configs["Hypergrid"]; + if (moduleConfig != null) + { + m_ThisHomeURI = moduleConfig.GetString("HomeURI", string.Empty); + if (m_ThisHomeURI != string.Empty && !m_ThisHomeURI.EndsWith("/")) + m_ThisHomeURI += '/'; + } } public override void AddRegion(Scene scene) @@ -194,7 +204,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer base.RegionLoaded(scene); if (m_Enabled) + { m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); + m_UAS = scene.RequestModuleInterface(); + } } public override void RemoveRegion(Scene scene) @@ -272,7 +285,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) { string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); - IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); + IUserAgentService connector; + + if (userAgentDriver.Equals(m_ThisHomeURI) && m_UAS != null) + connector = m_UAS; + else + connector = new UserAgentServiceConnector(userAgentDriver); + bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, false, out reason); logout = success; // flag for later logout from this grid; this is an HG TP -- cgit v1.1 From 6c7e33fe472014688837b993118fc48878f134ff Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 22 Jun 2013 08:29:06 -0700 Subject: Change IsLocalRegion from using region handle to using regionID. This was affecting UpdateAgent and CloseAgent in cases where the foreign region is on the same coordinates as *some* local region. --- .../Simulation/RemoteSimulationConnector.cs | 10 +++++----- OpenSim/Server/Handlers/Simulation/AgentHandlers.cs | 1 - .../Connectors/Simulation/SimulationServiceConnector.cs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index b2a1b23..d120e11 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -194,7 +194,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; // Try local first - if (m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (m_localBackend.IsLocalRegion(destination.RegionID)) return m_localBackend.UpdateAgent(destination, cAgentData); return m_remoteConnector.UpdateAgent(destination, cAgentData); @@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; // Try local first - if (m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (m_localBackend.IsLocalRegion(destination.RegionID)) return m_localBackend.UpdateAgent(destination, cAgentData); return m_remoteConnector.UpdateAgent(destination, cAgentData); @@ -224,7 +224,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return true; // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.RetrieveAgent(destination, id, out agent); return false; @@ -273,7 +273,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return true; // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.CloseAgent(destination, id); return false; @@ -296,7 +296,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionHandle)) + if (!m_localBackend.IsLocalRegion(destination.RegionID)) return m_remoteConnector.CreateObject(destination, newPosition, sog, isLocalCall); return false; diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 334d313..71a9e6f 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -576,7 +576,6 @@ namespace OpenSim.Server.Handlers.Simulation //agent.Dump(); // This is one of the meanings of PUT agent result = UpdateAgent(destination, agent); - } else if ("AgentPosition".Equals(messageType)) { diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index e247008..f51c809 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -241,7 +241,7 @@ namespace OpenSim.Services.Connectors.Simulation /// private bool UpdateAgent(GridRegion destination, IAgentData cAgentData, int timeout) { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent start"); + // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent in {0}", destination.ServerURI); // Eventually, we want to use a caps url instead of the agentID string uri = destination.ServerURI + AgentPath() + cAgentData.AgentID + "/"; -- cgit v1.1 From 4bf1afe300c61ac79fee7d794ead2b0100c5687a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 23 Jun 2013 01:14:07 +0200 Subject: Fix prim locking to behave like SL --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 7b5fdcb..f1036ae 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2699,8 +2699,8 @@ namespace OpenSim.Region.Framework.Scenes part.ClonePermissions(RootPart); }); - uint lockMask = ~(uint)PermissionMask.Move; - uint lockBit = RootPart.OwnerMask & (uint)PermissionMask.Move; + uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify); + uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify); RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask); RootPart.ScheduleFullUpdate(); } -- cgit v1.1 From 4b00203fa5d1ae645cf7bd67d061ee751d5c447b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 25 Jun 2013 00:15:55 +0100 Subject: Tidy up SOG.UpdateRootPosition() to eliminate unnecessary copying of Vector3 structs --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index f1036ae..75d0667 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -3028,8 +3028,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// Update just the root prim position in a linkset /// - /// - public void UpdateRootPosition(Vector3 pos) + /// + public void UpdateRootPosition(Vector3 newPos) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); @@ -3038,16 +3038,10 @@ namespace OpenSim.Region.Framework.Scenes // for (int i = 0; i < parts.Length; i++) // parts[i].StoreUndoState(); - Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); - Vector3 oldPos = - new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, - AbsolutePosition.Y + m_rootPart.OffsetPosition.Y, - AbsolutePosition.Z + m_rootPart.OffsetPosition.Z); + Vector3 oldPos = AbsolutePosition + RootPart.OffsetPosition; Vector3 diff = oldPos - newPos; - Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z); Quaternion partRotation = m_rootPart.RotationOffset; - axDiff *= Quaternion.Inverse(partRotation); - diff = axDiff; + diff *= Quaternion.Inverse(partRotation); SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) -- cgit v1.1 From ce9b1320d273890610a2ccd4f1ada39498135049 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 25 Jun 2013 00:41:46 +0100 Subject: Improve situation where editing just the root prim of an attachment causes other prims to be set to very far off positions on reattach. Functionally the same as the patch by tglion in http://opensimulator.org/mantis/view.php?id=5334 However, not yet perfect - after editing just root prim on reattach the position is still wrong, though other prims are not set to far off positions. --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 75d0667..4b4e4ba 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -3038,7 +3038,16 @@ namespace OpenSim.Region.Framework.Scenes // for (int i = 0; i < parts.Length; i++) // parts[i].StoreUndoState(); - Vector3 oldPos = AbsolutePosition + RootPart.OffsetPosition; + Vector3 oldPos; + + // FIXME: This improves the situation where editing just the root prim of an attached object would send + // all the other parts to oblivion after detach/reattach. However, a problem remains since the root prim + // still ends up in the wrong position on reattach. + if (IsAttachment) + oldPos = RootPart.OffsetPosition; + else + oldPos = AbsolutePosition + RootPart.OffsetPosition; + Vector3 diff = oldPos - newPos; Quaternion partRotation = m_rootPart.RotationOffset; diff *= Quaternion.Inverse(partRotation); -- cgit v1.1 From f78d2ef166a523397c770858176eff646be4021d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 25 Jun 2013 00:46:15 +0100 Subject: Update temporary "Unknown UserUMMTGUN2" name to "Unknown UserUMMTGUN3" to see if Diva's recent HG updates (post 6c7e33f) fix this issue. This string is returned if a UserManagementModule.TryGetUserNames() cannot find a server-side name binding or a user account for a given UUID. This is only called when the viewer requests a binding via the UDP UUIDNameRequest message --- .../Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 864e181..194b591 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -320,7 +320,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { names[0] = "Unknown"; - names[1] = "UserUMMTGUN2"; + names[1] = "UserUMMTGUN3"; return false; } -- cgit v1.1 From f7d09b898ad6df32b3f07cb64657623980178c2f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 27 Jun 2013 23:14:28 +0100 Subject: Make the concept of namespaces explicit in dynamic attributes This is in order to reduce the likelihood of naming clashes, make it easier to filter in/out attributes, ensure uniformity, etc. All dynattrs in the opensim distro itself or likely future ones should be in the "OpenSim" namespace. This does alter the underlying dynattrs data structure. All data in previous structures may not be available, though old structures should not cause errors. This is done without notice since this feature has been explicitly labelled as experimental, subject to change and has not been in a release. However, existing materials data is being preserved by moving it to the "Materials" store in the "OpenSim" namespace. --- OpenSim/Data/MSSQL/MSSQLSimulationData.cs | 2 +- OpenSim/Data/MySQL/MySQLSimulationData.cs | 2 +- OpenSim/Data/SQLite/SQLiteSimulationData.cs | 2 +- OpenSim/Framework/DAMap.cs | 300 ++++++++++++--------- OpenSim/Framework/DOMap.cs | 8 +- .../Framework/DynamicAttributes/DAExampleModule.cs | 17 +- .../Framework/DynamicAttributes/DOExampleModule.cs | 8 +- .../World/Serialiser/Tests/SerialiserTests.cs | 44 ++- .../Scenes/Serialization/SceneObjectSerializer.cs | 2 +- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 18 +- .../Materials/MaterialsDemoModule.cs | 26 +- 11 files changed, 257 insertions(+), 172 deletions(-) diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs index 476f57a..5135050 100644 --- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs +++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs @@ -2100,7 +2100,7 @@ VALUES parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); - if (prim.DynAttrs.Count > 0) + if (prim.DynAttrs.CountNamespaces > 0) parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml())); else parameters.Add(_Database.CreateParameter("DynAttrs", null)); diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index de52623..cf367ef 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -1679,7 +1679,7 @@ namespace OpenSim.Data.MySQL else cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]); - if (prim.DynAttrs.Count > 0) + if (prim.DynAttrs.CountNamespaces > 0) cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml()); else cmd.Parameters.AddWithValue("DynAttrs", null); diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index c35bba2..eba6612 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -2176,7 +2176,7 @@ namespace OpenSim.Data.SQLite row["MediaURL"] = prim.MediaUrl; - if (prim.DynAttrs.Count > 0) + if (prim.DynAttrs.CountNamespaces > 0) row["DynAttrs"] = prim.DynAttrs.ToXml(); else row["DynAttrs"] = null; diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index df4a6bc..a57393b 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs @@ -29,10 +29,12 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Text; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; +using log4net; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -48,13 +50,20 @@ namespace OpenSim.Framework /// within their data store. However, avoid storing large amounts of data because that /// would slow down database access. /// - public class DAMap : IDictionary, IXmlSerializable + public class DAMap : IXmlSerializable { - private static readonly int MIN_STORE_NAME_LENGTH = 4; +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - protected OSDMap m_map; - - public DAMap() { m_map = new OSDMap(); } + private static readonly int MIN_NAMESPACE_LENGTH = 4; + + private OSDMap m_map = new OSDMap(); + + // WARNING: this is temporary for experimentation only, it will be removed!!!! + public OSDMap TopLevelMap + { + get { return m_map; } + set { m_map = value; } + } public XmlSchema GetSchema() { return null; } @@ -64,39 +73,34 @@ namespace OpenSim.Framework map.ReadXml(rawXml); return map; } - + + public void ReadXml(XmlReader reader) + { + ReadXml(reader.ReadInnerXml()); + } + public void ReadXml(string rawXml) { // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml); lock (this) + { m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); + SanitiseMap(this); + } } - - // WARNING: this is temporary for experimentation only, it will be removed!!!! - public OSDMap TopLevelMap + + public void WriteXml(XmlWriter writer) { - get { return m_map; } - set { m_map = value; } + writer.WriteRaw(ToXml()); } - - public void ReadXml(XmlReader reader) - { - ReadXml(reader.ReadInnerXml()); - } - public string ToXml() { lock (this) return OSDParser.SerializeLLSDXmlString(m_map); } - public void WriteXml(XmlWriter writer) - { - writer.WriteRaw(ToXml()); - } - public void CopyFrom(DAMap other) { // Deep copy @@ -104,7 +108,7 @@ namespace OpenSim.Framework string data = null; lock (other) { - if (other.Count > 0) + if (other.CountNamespaces > 0) { data = OSDParser.SerializeLLSDXmlString(other.m_map); } @@ -120,59 +124,133 @@ namespace OpenSim.Framework } /// - /// Returns the number of data stores. + /// Sanitise the map to remove any namespaces or stores that are not OSDMap. /// - public int Count { get { lock (this) { return m_map.Count; } } } - - public bool IsReadOnly { get { return false; } } - + /// + /// + public static void SanitiseMap(DAMap daMap) + { + List keysToRemove = null; + + // Hard-coded special case that needs to be removed in the future. Normally, modules themselves should + // handle reading data from old locations + bool osMaterialsMigrationRequired = false; + + OSDMap namespacesMap = daMap.m_map; + + foreach (string key in namespacesMap.Keys) + { +// Console.WriteLine("Processing ns {0}", key); + if (!(namespacesMap[key] is OSDMap)) + { + if (keysToRemove == null) + keysToRemove = new List(); + + keysToRemove.Add(key); + } + else if (key == "OS:Materials") + { + osMaterialsMigrationRequired = true; + } + } + + if (keysToRemove != null) + { + foreach (string key in keysToRemove) + { +// Console.WriteLine ("Removing bad ns {0}", key); + namespacesMap.Remove(key); + } + } + + // Hard-coded special case that needs to be removed in the future. Normally, modules themselves should + // handle reading data from old locations + if (osMaterialsMigrationRequired) + daMap.SetStore("OpenSim", "Materials", (OSDMap)namespacesMap["OS:Materials"]); + + foreach (OSD nsOsd in namespacesMap.Values) + { + OSDMap nsOsdMap = (OSDMap)nsOsd; + keysToRemove = null; + + foreach (string key in nsOsdMap.Keys) + { + if (!(nsOsdMap[key] is OSDMap)) + { + if (keysToRemove == null) + keysToRemove = new List(); + + keysToRemove.Add(key); + } + } + + if (keysToRemove != null) + foreach (string key in keysToRemove) + nsOsdMap.Remove(key); + } + } + /// - /// Returns the names of the data stores. + /// Get the number of namespaces /// - public ICollection Keys { get { lock (this) { return m_map.Keys; } } } + public int CountNamespaces { get { lock (this) { return m_map.Count; } } } /// - /// Returns all the data stores. + /// Get the number of stores. /// - public ICollection Values + public int CountStores { - get + get { + int count = 0; + lock (this) { - List stores = new List(m_map.Count); - foreach (OSD llsd in m_map.Values) - stores.Add((OSDMap)llsd); - return stores; + foreach (OSD osdNamespace in m_map) + { + count += ((OSDMap)osdNamespace).Count; + } } + + return count; } } - - /// - /// Gets or sets one data store. - /// - /// Store name - /// - public OSDMap this[string key] - { - get - { - OSD llsd; - - lock (this) + + public OSDMap GetStore(string ns, string storeName) + { + OSD namespaceOsd; + + lock (this) + { + if (m_map.TryGetValue(ns, out namespaceOsd)) { - if (m_map.TryGetValue(key, out llsd)) - return (OSDMap)llsd; - else - return null; + OSD store; + + if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store)) + return (OSDMap)store; } - } - - set + } + + return null; + } + + public void SetStore(string ns, string storeName, OSDMap store) + { + ValidateNamespace(ns); + OSDMap nsMap; + + lock (this) { - ValidateKey(key); - lock (this) - m_map[key] = value; + if (!m_map.ContainsKey(ns)) + { + nsMap = new OSDMap(); + m_map[ns] = nsMap; + } + + nsMap = (OSDMap)m_map[ns]; + +// m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName); + nsMap[storeName] = store; } } @@ -180,54 +258,46 @@ namespace OpenSim.Framework /// Validate the key used for storing separate data stores. /// /// - public static void ValidateKey(string key) + public static void ValidateNamespace(string ns) { - if (key.Length < MIN_STORE_NAME_LENGTH) - throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH); + if (ns.Length < MIN_NAMESPACE_LENGTH) + throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH); } - public bool ContainsKey(string key) + public bool ContainsStore(string ns, string storeName) { - lock (this) - return m_map.ContainsKey(key); - } - - public void Add(string key, OSDMap store) - { - ValidateKey(key); - lock (this) - m_map.Add(key, store); - } + OSD namespaceOsd; - public void Add(KeyValuePair kvp) - { - ValidateKey(kvp.Key); lock (this) - m_map.Add(kvp.Key, kvp.Value); - } + { + if (m_map.TryGetValue(ns, out namespaceOsd)) + { + return ((OSDMap)namespaceOsd).ContainsKey(storeName); + } + } - public bool Remove(string key) - { - lock (this) - return m_map.Remove(key); - } + return false; + } - public bool TryGetValue(string key, out OSDMap store) + public bool TryGetStore(string ns, string storeName, out OSDMap store) { + OSD namespaceOsd; + lock (this) { - OSD llsd; - if (m_map.TryGetValue(key, out llsd)) - { - store = (OSDMap)llsd; - return true; - } - else + if (m_map.TryGetValue(ns, out namespaceOsd)) { - store = null; - return false; + OSD storeOsd; + + bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd); + store = (OSDMap)storeOsd; + + return result; } } + + store = null; + return false; } public void Clear() @@ -235,39 +305,25 @@ namespace OpenSim.Framework lock (this) m_map.Clear(); } - - public bool Contains(KeyValuePair kvp) - { - lock (this) - return m_map.ContainsKey(kvp.Key); - } - public void CopyTo(KeyValuePair[] array, int index) + public bool RemoveStore(string ns, string storeName) { - throw new NotImplementedException(); - } + OSD namespaceOsd; - public bool Remove(KeyValuePair kvp) - { - lock (this) - return m_map.Remove(kvp.Key); - } - - public System.Collections.IDictionaryEnumerator GetEnumerator() - { lock (this) - return m_map.GetEnumerator(); - } + { + if (m_map.TryGetValue(ns, out namespaceOsd)) + { + OSDMap namespaceOsdMap = (OSDMap)namespaceOsd; + namespaceOsdMap.Remove(storeName); - IEnumerator> IEnumerable>.GetEnumerator() - { - return null; - } + // Don't keep empty namespaces around + if (namespaceOsdMap.Count <= 0) + m_map.Remove(ns); + } + } - IEnumerator IEnumerable.GetEnumerator() - { - lock (this) - return m_map.GetEnumerator(); - } + return false; + } } } \ No newline at end of file diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs index 755e129..f5b650b 100644 --- a/OpenSim/Framework/DOMap.cs +++ b/OpenSim/Framework/DOMap.cs @@ -42,22 +42,22 @@ namespace OpenSim.Framework /// This class stores and retrieves dynamic objects. /// /// - /// Experimental - DO NOT USE. + /// Experimental - DO NOT USE. Does not yet have namespace support. /// public class DOMap { private IDictionary m_map; - public void Add(string key, object dynObj) + public void Add(string ns, string objName, object dynObj) { - DAMap.ValidateKey(key); + DAMap.ValidateNamespace(ns); lock (this) { if (m_map == null) m_map = new Dictionary(); - m_map.Add(key, dynObj); + m_map.Add(objName, dynObj); } } diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index 1f1568f..0c632b1 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs @@ -44,11 +44,12 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")] public class DAExampleModule : INonSharedRegionModule { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly bool ENABLED = false; // enable for testing + private readonly bool ENABLED = false; // enable for testing - public const string DANamespace = "DAExample Module"; + public const string Namespace = "Example"; + public const string StoreName = "DA"; protected Scene m_scene; protected IDialogModule m_dialogMod; @@ -65,6 +66,8 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule m_scene = scene; m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove; m_dialogMod = m_scene.RequestModuleInterface(); + + m_log.DebugFormat("[DA EXAMPLE MODULE]: Added region {0}", m_scene.Name); } } @@ -91,7 +94,7 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule if (sop == null) return true; - if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs)) + if (!sop.DynAttrs.TryGetStore(Namespace, StoreName, out attrs)) attrs = new OSDMap(); OSDInteger newValue; @@ -106,12 +109,14 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule attrs["moves"] = newValue; - sop.DynAttrs[DANamespace] = attrs; + sop.DynAttrs.SetStore(Namespace, StoreName, attrs); } sop.ParentGroup.HasGroupChanged = true; - m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue)); + string msg = string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue); + m_log.DebugFormat("[DA EXAMPLE MODULE]: {0}", msg); + m_dialogMod.SendGeneralAlert(msg); return true; } diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs index 650aa35..166a994 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs @@ -64,8 +64,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule private Scene m_scene; private IDialogModule m_dialogMod; - - public string Name { get { return "DOExample Module"; } } + + public string Name { get { return "DO"; } } public Type ReplaceableInterface { get { return null; } } public void Initialise(IConfigSource source) {} @@ -106,7 +106,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule // Console.WriteLine("Here for {0}", so.Name); - if (rootPart.DynAttrs.TryGetValue(DAExampleModule.DANamespace, out attrs)) + if (rootPart.DynAttrs.TryGetStore(DAExampleModule.Namespace, DAExampleModule.StoreName, out attrs)) { movesSoFar = attrs["moves"].AsInteger(); @@ -114,7 +114,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule "[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name); } - rootPart.DynObjs.Add(Name, new MyObject(movesSoFar)); + rootPart.DynObjs.Add(DAExampleModule.Namespace, Name, new MyObject(movesSoFar)); } private bool OnSceneGroupMove(UUID groupId, Vector3 delta) diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index b4348c9..66059fb 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs @@ -144,7 +144,20 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests None 00000000-0000-0000-0000-000000000000 0 - MyStorethe answer42 + + + + MyNamespace + + MyStore + + the answer + 42 + + + + + @@ -333,7 +346,20 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests 0 2147483647 None - MyStorelast wordsRosebud + + + + MyNamespace + + MyStore + + last words + Rosebud + + + + + 00000000-0000-0000-0000-000000000000 @@ -362,7 +388,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests Assert.That(rootPart.UUID, Is.EqualTo(new UUID("e6a5a05e-e8cc-4816-8701-04165e335790"))); Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("a6dacf01-4636-4bb9-8a97-30609438af9d"))); Assert.That(rootPart.Name, Is.EqualTo("PrimMyRide")); - OSDMap store = rootPart.DynAttrs["MyStore"]; + OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore"); Assert.AreEqual(42, store["the answer"].AsInteger()); // TODO: Check other properties @@ -414,13 +440,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests rp.CreatorID = rpCreatorId; rp.Shape = shape; + string daNamespace = "MyNamespace"; string daStoreName = "MyStore"; string daKey = "foo"; string daValue = "bar"; OSDMap myStore = new OSDMap(); myStore.Add(daKey, daValue); rp.DynAttrs = new DAMap(); - rp.DynAttrs[daStoreName] = myStore; + rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore); SceneObjectGroup so = new SceneObjectGroup(rp); @@ -481,7 +508,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests Assert.That(name, Is.EqualTo(rpName)); Assert.That(creatorId, Is.EqualTo(rpCreatorId)); Assert.NotNull(daMap); - Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString()); + Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString()); } [Test] @@ -496,7 +523,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests Assert.That(rootPart.UUID, Is.EqualTo(new UUID("9be68fdd-f740-4a0f-9675-dfbbb536b946"))); Assert.That(rootPart.CreatorID, Is.EqualTo(new UUID("b46ef588-411e-4a8b-a284-d7dcfe8e74ef"))); Assert.That(rootPart.Name, Is.EqualTo("PrimFun")); - OSDMap store = rootPart.DynAttrs["MyStore"]; + OSDMap store = rootPart.DynAttrs.GetStore("MyNamespace", "MyStore"); Assert.AreEqual("Rosebud", store["last words"].AsString()); // TODO: Check other properties @@ -522,13 +549,14 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests rp.CreatorID = rpCreatorId; rp.Shape = shape; + string daNamespace = "MyNamespace"; string daStoreName = "MyStore"; string daKey = "foo"; string daValue = "bar"; OSDMap myStore = new OSDMap(); myStore.Add(daKey, daValue); rp.DynAttrs = new DAMap(); - rp.DynAttrs[daStoreName] = myStore; + rp.DynAttrs.SetStore(daNamespace, daStoreName, myStore); SceneObjectGroup so = new SceneObjectGroup(rp); @@ -585,7 +613,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests Assert.That(name, Is.EqualTo(rpName)); Assert.That(creatorId, Is.EqualTo(rpCreatorId)); Assert.NotNull(daMap); - Assert.AreEqual(daValue, daMap[daStoreName][daKey].AsString()); + Assert.AreEqual(daValue, daMap.GetStore(daNamespace, daStoreName)[daKey].AsString()); } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 3882b45..945745e 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1290,7 +1290,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization if (sop.MediaUrl != null) writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); - if (sop.DynAttrs.Count > 0) + if (sop.DynAttrs.CountNamespaces > 0) { writer.WriteStartElement("DynAttrs"); sop.DynAttrs.WriteXml(writer); diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 0e83781..586b59d 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -212,7 +212,6 @@ namespace OpenSim.Region.Framework.Scenes // } // } - /// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps /// @@ -221,20 +220,23 @@ namespace OpenSim.Region.Framework.Scenes public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) { // scan thru the dynAttrs map of this part for any textures used as materials - OSDMap OSMaterials = null; + OSD osdMaterials = null; lock (part.DynAttrs) { - if (part.DynAttrs.ContainsKey("OS:Materials")) - OSMaterials = part.DynAttrs["OS:Materials"]; - if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) + { + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + materialsStore.TryGetValue("Materials", out osdMaterials); + } + + if (osdMaterials != null) { - OSD osd = OSMaterials["Materials"]; //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); - if (osd is OSDArray) + if (osdMaterials is OSDArray) { - OSDArray matsArr = osd as OSDArray; + OSDArray matsArr = osdMaterials as OSDArray; foreach (OSDMap matMap in matsArr) { try diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 4ab6609..5b15a73 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -178,7 +178,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule void GetStoredMaterialsForPart(SceneObjectPart part) { - OSDMap OSMaterials = null; + OSD OSMaterials = null; OSDArray matsArr = null; if (part.DynAttrs == null) @@ -188,23 +188,20 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule lock (part.DynAttrs) { - if (part.DynAttrs.ContainsKey("OS:Materials")) - OSMaterials = part.DynAttrs["OS:Materials"]; - if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) { - - OSD osd = OSMaterials["Materials"]; - if (osd is OSDArray) - matsArr = osd as OSDArray; + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + materialsStore.TryGetValue("Materials", out OSMaterials); } - } - if (OSMaterials == null) - return; + if (OSMaterials != null && OSMaterials is OSDArray) + matsArr = OSMaterials as OSDArray; + else + return; + } m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); - if (matsArr == null) { m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); @@ -215,7 +212,6 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { if (elemOsd != null && elemOsd is OSDMap) { - OSDMap matMap = elemOsd as OSDMap; if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) { @@ -232,7 +228,6 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } } - void StoreMaterialsForPart(SceneObjectPart part) { try @@ -277,7 +272,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule OSMaterials["Materials"] = matsArr; lock (part.DynAttrs) - part.DynAttrs["OS:Materials"] = OSMaterials; + part.DynAttrs.SetStore("OpenSim", "Materials", OSMaterials); } catch (Exception e) { @@ -285,7 +280,6 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule } } - public string RenderMaterialsPostCap(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) -- cgit v1.1 From 149487ea0f74a46a70c98b3a31259b667f4d29b2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 27 Jun 2013 23:42:35 +0100 Subject: refactor: Move code for gathering textures referenced by materials into MaterialsDemoModule from UuidGatherer This code is now triggered via EventManager.OnGatherUuids which modules can subscribe to. --- OpenSim/Region/Framework/Scenes/EventManager.cs | 31 ++++++++++ OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 69 +-------------------- .../Materials/MaterialsDemoModule.cs | 72 +++++++++++++++++++++- 3 files changed, 103 insertions(+), 69 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index a246319..720bfa9 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -1021,6 +1021,16 @@ namespace OpenSim.Region.Framework.Scenes /// public event TeleportFail OnTeleportFail; + public delegate void GatherUuids(SceneObjectPart sop, IDictionary assetUuids); + + /// + /// Triggered when UUIDs referenced by a scene object are being gathered for archiving, hg transfer, etc. + /// + /// + /// The listener should add references to the IDictionary as appropriate. + /// + public event GatherUuids OnGatherUuids; + public class MoneyTransferArgs : EventArgs { public UUID sender; @@ -3237,5 +3247,26 @@ namespace OpenSim.Region.Framework.Scenes } } } + + public void TriggerGatherUuids(SceneObjectPart sop, IDictionary assetUuids) + { + GatherUuids handler = OnGatherUuids; + + if (handler != null) + { + foreach (GatherUuids d in handler.GetInvocationList()) + { + try + { + d(sop, assetUuids); + } + catch (Exception e) + { + m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TriggerUuidGather failed - continuing {0} - {1}", + e.Message, e.StackTrace); + } + } + } + } } } diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 586b59d..3492813 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -186,8 +186,7 @@ namespace OpenSim.Region.Framework.Scenes GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); } - // get any texture UUIDs used for materials such as normal and specular maps - GatherMaterialsUuids(part, assetUuids); + part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); } catch (Exception e) { @@ -211,71 +210,7 @@ namespace OpenSim.Region.Framework.Scenes // Monitor.Pulse(this); // } // } - - /// - /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps - /// - /// - /// - public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) - { - // scan thru the dynAttrs map of this part for any textures used as materials - OSD osdMaterials = null; - - lock (part.DynAttrs) - { - if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) - { - OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); - materialsStore.TryGetValue("Materials", out osdMaterials); - } - - if (osdMaterials != null) - { - //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); - - if (osdMaterials is OSDArray) - { - OSDArray matsArr = osdMaterials as OSDArray; - foreach (OSDMap matMap in matsArr) - { - try - { - if (matMap.ContainsKey("Material")) - { - OSDMap mat = matMap["Material"] as OSDMap; - if (mat.ContainsKey("NormMap")) - { - UUID normalMapId = mat["NormMap"].AsUUID(); - if (normalMapId != UUID.Zero) - { - assetUuids[normalMapId] = AssetType.Texture; - //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); - } - } - if (mat.ContainsKey("SpecMap")) - { - UUID specularMapId = mat["SpecMap"].AsUUID(); - if (specularMapId != UUID.Zero) - { - assetUuids[specularMapId] = AssetType.Texture; - //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); - } - } - } - - } - catch (Exception e) - { - m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); - } - } - } - } - } - } - - + /// /// Get an asset synchronously, potentially using an asynchronous callback. If the /// asynchronous callback is used, we will wait for it to complete. diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 5b15a73..e7b8928 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -121,9 +121,11 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule return; m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); + m_scene = scene; - m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps); - m_scene.EventManager.OnObjectAddedToScene += new Action(EventManager_OnObjectAddedToScene); + m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; + m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; } void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) @@ -157,6 +159,10 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (!m_enabled) return; + m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; + m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; + m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; + m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); } @@ -569,5 +575,67 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule output.Flush(); } + /// + /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps + /// + /// + /// + private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) + { + // scan thru the dynAttrs map of this part for any textures used as materials + OSD osdMaterials = null; + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) + { + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + materialsStore.TryGetValue("Materials", out osdMaterials); + } + + if (osdMaterials != null) + { + //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); + + if (osdMaterials is OSDArray) + { + OSDArray matsArr = osdMaterials as OSDArray; + foreach (OSDMap matMap in matsArr) + { + try + { + if (matMap.ContainsKey("Material")) + { + OSDMap mat = matMap["Material"] as OSDMap; + if (mat.ContainsKey("NormMap")) + { + UUID normalMapId = mat["NormMap"].AsUUID(); + if (normalMapId != UUID.Zero) + { + assetUuids[normalMapId] = AssetType.Texture; + //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); + } + } + if (mat.ContainsKey("SpecMap")) + { + UUID specularMapId = mat["SpecMap"].AsUUID(); + if (specularMapId != UUID.Zero) + { + assetUuids[specularMapId] = AssetType.Texture; + //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); + } + } + } + + } + catch (Exception e) + { + m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); + } + } + } + } + } + } } } \ No newline at end of file -- cgit v1.1 From c1b8f83dd4ad3e3c811a16b4b096edab7abccf8e Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 27 Jun 2013 17:53:15 -0700 Subject: test for null return from DynAttrs.GetStore() --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index e7b8928..be2d8da 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -590,6 +590,9 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) { OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + if (materialsStore == null) + return; + materialsStore.TryGetValue("Materials", out osdMaterials); } -- cgit v1.1 From d47fc48b3230b6d5cb555014d6242960cd397810 Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 27 Jun 2013 18:01:17 -0700 Subject: and yet another check for null returned from DynAttrs.GetStore() --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index be2d8da..34dc552 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -197,6 +197,10 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) { OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + + if (materialsStore == null) + return; + materialsStore.TryGetValue("Materials", out OSMaterials); } -- cgit v1.1 From 529633d9707ee0df6b32e8dc692ab615e3563b63 Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 27 Jun 2013 18:44:27 -0700 Subject: add method docs for DAMap.GetStore() and DAMap.SetStore() --- OpenSim/Framework/DAMap.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index a57393b..fd45a11 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs @@ -216,6 +216,12 @@ namespace OpenSim.Framework } } + /// + /// Retrieve a Dynamic Attribute store + /// + /// namespace for the store - use "OpenSim" for in-core modules + /// name of the store within the namespace + /// an OSDMap representing the stored data, or null if not found public OSDMap GetStore(string ns, string storeName) { OSD namespaceOsd; @@ -234,6 +240,12 @@ namespace OpenSim.Framework return null; } + /// + /// Saves a Dynamic attribute store + /// + /// namespace for the store - use "OpenSim" for in-core modules + /// name of the store within the namespace + /// an OSDMap representing the data to store public void SetStore(string ns, string storeName, OSDMap store) { ValidateNamespace(ns); -- cgit v1.1 From f6ce87c96d037787963d203346c5cb1a1dd52747 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jun 2013 18:50:33 +0100 Subject: Reinsert code for gathering uuids reference by materials back directly into UuidGatherer for now. This cannot be triggered as an event from Scene.EventManager since some invocations of UuidGatherer (e.g. IAR saving) use scene objects which are not in scenes. There needs to be some way for modules to register for events which are not connected with a particular scene. --- OpenSim/Region/Framework/Scenes/EventManager.cs | 58 ++++----- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 71 ++++++++++- .../Materials/MaterialsDemoModule.cs | 136 +++++++++++---------- 3 files changed, 168 insertions(+), 97 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 720bfa9..61b0ebd 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -1021,15 +1021,15 @@ namespace OpenSim.Region.Framework.Scenes /// public event TeleportFail OnTeleportFail; - public delegate void GatherUuids(SceneObjectPart sop, IDictionary assetUuids); - - /// - /// Triggered when UUIDs referenced by a scene object are being gathered for archiving, hg transfer, etc. - /// - /// - /// The listener should add references to the IDictionary as appropriate. - /// - public event GatherUuids OnGatherUuids; +// public delegate void GatherUuids(SceneObjectPart sop, IDictionary assetUuids); +// +// /// +// /// Triggered when UUIDs referenced by a scene object are being gathered for archiving, hg transfer, etc. +// /// +// /// +// /// The listener should add references to the IDictionary as appropriate. +// /// +// public event GatherUuids OnGatherUuids; public class MoneyTransferArgs : EventArgs { @@ -3248,25 +3248,25 @@ namespace OpenSim.Region.Framework.Scenes } } - public void TriggerGatherUuids(SceneObjectPart sop, IDictionary assetUuids) - { - GatherUuids handler = OnGatherUuids; - - if (handler != null) - { - foreach (GatherUuids d in handler.GetInvocationList()) - { - try - { - d(sop, assetUuids); - } - catch (Exception e) - { - m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TriggerUuidGather failed - continuing {0} - {1}", - e.Message, e.StackTrace); - } - } - } - } +// public void TriggerGatherUuids(SceneObjectPart sop, IDictionary assetUuids) +// { +// GatherUuids handler = OnGatherUuids; +// +// if (handler != null) +// { +// foreach (GatherUuids d in handler.GetInvocationList()) +// { +// try +// { +// d(sop, assetUuids); +// } +// catch (Exception e) +// { +// m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TriggerUuidGather failed - continuing {0} - {1}", +// e.Message, e.StackTrace); +// } +// } +// } +// } } } diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 3492813..4e5fb8e 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -186,7 +186,13 @@ namespace OpenSim.Region.Framework.Scenes GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); } - part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); + // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed + // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and + // inventory transfer. There needs to be a way for a module to register a method without assuming a + // Scene.EventManager is present. +// part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); + + GatherMaterialsUuids(part, assetUuids); } catch (Exception e) { @@ -210,6 +216,69 @@ namespace OpenSim.Region.Framework.Scenes // Monitor.Pulse(this); // } // } + + /// + /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps + /// + /// + /// + public void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) + { + // scan thru the dynAttrs map of this part for any textures used as materials + OSD osdMaterials = null; + + lock (part.DynAttrs) + { + if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) + { + OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + materialsStore.TryGetValue("Materials", out osdMaterials); + } + + if (osdMaterials != null) + { + //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); + + if (osdMaterials is OSDArray) + { + OSDArray matsArr = osdMaterials as OSDArray; + foreach (OSDMap matMap in matsArr) + { + try + { + if (matMap.ContainsKey("Material")) + { + OSDMap mat = matMap["Material"] as OSDMap; + if (mat.ContainsKey("NormMap")) + { + UUID normalMapId = mat["NormMap"].AsUUID(); + if (normalMapId != UUID.Zero) + { + assetUuids[normalMapId] = AssetType.Texture; + //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); + } + } + if (mat.ContainsKey("SpecMap")) + { + UUID specularMapId = mat["SpecMap"].AsUUID(); + if (specularMapId != UUID.Zero) + { + assetUuids[specularMapId] = AssetType.Texture; + //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); + } + } + } + + } + catch (Exception e) + { + m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); + } + } + } + } + } + } /// /// Get an asset synchronously, potentially using an asynchronous callback. If the diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 34dc552..1cfbab0 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -125,7 +125,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_scene = scene; m_scene.EventManager.OnRegisterCaps += OnRegisterCaps; m_scene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; - m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; +// m_scene.EventManager.OnGatherUuids += GatherMaterialsUuids; } void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) @@ -161,7 +161,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps; m_scene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene; - m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; +// m_scene.EventManager.OnGatherUuids -= GatherMaterialsUuids; m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); } @@ -579,70 +579,72 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule output.Flush(); } - /// - /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps - /// - /// - /// - private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) - { - // scan thru the dynAttrs map of this part for any textures used as materials - OSD osdMaterials = null; - - lock (part.DynAttrs) - { - if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) - { - OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); - if (materialsStore == null) - return; - - materialsStore.TryGetValue("Materials", out osdMaterials); - } - - if (osdMaterials != null) - { - //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); - - if (osdMaterials is OSDArray) - { - OSDArray matsArr = osdMaterials as OSDArray; - foreach (OSDMap matMap in matsArr) - { - try - { - if (matMap.ContainsKey("Material")) - { - OSDMap mat = matMap["Material"] as OSDMap; - if (mat.ContainsKey("NormMap")) - { - UUID normalMapId = mat["NormMap"].AsUUID(); - if (normalMapId != UUID.Zero) - { - assetUuids[normalMapId] = AssetType.Texture; - //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); - } - } - if (mat.ContainsKey("SpecMap")) - { - UUID specularMapId = mat["SpecMap"].AsUUID(); - if (specularMapId != UUID.Zero) - { - assetUuids[specularMapId] = AssetType.Texture; - //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); - } - } - } - - } - catch (Exception e) - { - m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); - } - } - } - } - } - } + // FIXME: This code is currently still in UuidGatherer since we cannot use Scene.EventManager as some + // calls to the gatherer are done for objects with no scene. +// /// +// /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps +// /// +// /// +// /// +// private void GatherMaterialsUuids(SceneObjectPart part, IDictionary assetUuids) +// { +// // scan thru the dynAttrs map of this part for any textures used as materials +// OSD osdMaterials = null; +// +// lock (part.DynAttrs) +// { +// if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) +// { +// OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); +// if (materialsStore == null) +// return; +// +// materialsStore.TryGetValue("Materials", out osdMaterials); +// } +// +// if (osdMaterials != null) +// { +// //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); +// +// if (osdMaterials is OSDArray) +// { +// OSDArray matsArr = osdMaterials as OSDArray; +// foreach (OSDMap matMap in matsArr) +// { +// try +// { +// if (matMap.ContainsKey("Material")) +// { +// OSDMap mat = matMap["Material"] as OSDMap; +// if (mat.ContainsKey("NormMap")) +// { +// UUID normalMapId = mat["NormMap"].AsUUID(); +// if (normalMapId != UUID.Zero) +// { +// assetUuids[normalMapId] = AssetType.Texture; +// //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); +// } +// } +// if (mat.ContainsKey("SpecMap")) +// { +// UUID specularMapId = mat["SpecMap"].AsUUID(); +// if (specularMapId != UUID.Zero) +// { +// assetUuids[specularMapId] = AssetType.Texture; +// //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); +// } +// } +// } +// +// } +// catch (Exception e) +// { +// m_log.Warn("[MaterialsDemoModule]: exception getting materials: " + e.Message); +// } +// } +// } +// } +// } +// } } } \ No newline at end of file -- cgit v1.1 From dc0455e217b8da3fc8bd49e959b57d6021312b77 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jun 2013 19:11:44 +0100 Subject: In XAssetService, on a delete asset request also delete the asset in any chained service. This eliminates the async migration since it causes a race condition with the "delete asset" console command --- OpenSim/Data/MySQL/MySQLXAssetData.cs | 2 ++ OpenSim/Services/AssetService/XAssetService.cs | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs index 8c93825..91389ce 100644 --- a/OpenSim/Data/MySQL/MySQLXAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs @@ -199,6 +199,8 @@ namespace OpenSim.Data.MySQL /// On failure : Throw an exception and attempt to reconnect to database public void StoreAsset(AssetBase asset) { +// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID); + lock (m_dbLock) { using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs index 8a2ca7c..6047616 100644 --- a/OpenSim/Services/AssetService/XAssetService.cs +++ b/OpenSim/Services/AssetService/XAssetService.cs @@ -205,15 +205,16 @@ namespace OpenSim.Services.AssetService if (!UUID.TryParse(id, out assetID)) return false; - // Don't bother deleting from a chained asset service. This isn't a big deal since deleting happens - // very rarely. + if (HasChainedAssetService) + m_ChainedAssetService.Delete(id); return m_Database.Delete(id); } private void MigrateFromChainedService(AssetBase asset) { - Util.FireAndForget(o => { Store(asset); m_ChainedAssetService.Delete(asset.ID); }); + Store(asset); + m_ChainedAssetService.Delete(asset.ID); } } } \ No newline at end of file -- cgit v1.1 From e26e8b882965430f66c6459987a8b219d68e5da1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jun 2013 19:19:38 +0100 Subject: Remove "Asset deletion not supported by database" message from "delete asset" robust/standalone console command since it actually was implemented and performed. Improve other associated messages. --- OpenSim/Server/Handlers/Asset/AssetServerConnector.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs index ff45d94..cc4325a 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerConnector.cs @@ -119,16 +119,14 @@ namespace OpenSim.Server.Handlers.Asset if (asset == null || asset.Data.Length == 0) { - MainConsole.Instance.Output("Asset not found"); + MainConsole.Instance.OutputFormat("Could not find asset with ID {0}", args[2]); return; } - m_AssetService.Delete(args[2]); - - //MainConsole.Instance.Output("Asset deleted"); - // TODO: Implement this - - MainConsole.Instance.Output("Asset deletion not supported by database"); + if (!m_AssetService.Delete(asset.ID)) + MainConsole.Instance.OutputFormat("ERROR: Could not delete asset {0} {1}", asset.ID, asset.Name); + else + MainConsole.Instance.OutputFormat("Deleted asset {0} {1}", asset.ID, asset.Name); } void HandleDumpAsset(string module, string[] args) -- cgit v1.1 From cbb51227296df9b158430d4a8adfcc96bdd55ed5 Mon Sep 17 00:00:00 2001 From: dahlia Date: Fri, 28 Jun 2013 14:00:28 -0700 Subject: add some locking to materials storage dictionary --- .../Materials/MaterialsDemoModule.cs | 72 +++++++++++++--------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 34dc552..19d8141 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -173,11 +173,14 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule OSDMap GetMaterial(UUID id) { OSDMap map = null; - if (m_knownMaterials.ContainsKey(id)) + lock (m_knownMaterials) { - map = new OSDMap(); - map["ID"] = OSD.FromBinary(id.GetBytes()); - map["Material"] = m_knownMaterials[id]; + if (m_knownMaterials.ContainsKey(id)) + { + map = new OSDMap(); + map["ID"] = OSD.FromBinary(id.GetBytes()); + map["Material"] = m_knownMaterials[id]; + } } return map; } @@ -227,7 +230,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { try { - m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; + lock (m_knownMaterials) + m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; } catch (Exception e) { @@ -251,8 +255,11 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (te.DefaultTexture != null) { - if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) - mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; + lock (m_knownMaterials) + { + if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) + mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; + } } if (te.FaceTextures != null) @@ -261,8 +268,11 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { if (face != null) { - if (m_knownMaterials.ContainsKey(face.MaterialID)) - mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; + lock (m_knownMaterials) + { + if (m_knownMaterials.ContainsKey(face.MaterialID)) + mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; + } } } } @@ -323,18 +333,21 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule try { UUID id = new UUID(elem.AsBinary(), 0); - - if (m_knownMaterials.ContainsKey(id)) + + lock (m_knownMaterials) { - m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); - OSDMap matMap = new OSDMap(); - matMap["ID"] = OSD.FromBinary(id.GetBytes()); + if (m_knownMaterials.ContainsKey(id)) + { + m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); + OSDMap matMap = new OSDMap(); + matMap["ID"] = OSD.FromBinary(id.GetBytes()); - matMap["Material"] = m_knownMaterials[id]; - respArr.Add(matMap); + matMap["Material"] = m_knownMaterials[id]; + respArr.Add(matMap); + } + else + m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); } - else - m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); } catch (Exception e) { @@ -372,7 +385,8 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); UUID id = HashOsd(mat); - m_knownMaterials[id] = mat; + lock (m_knownMaterials) + m_knownMaterials[id] = mat; var sop = m_scene.GetSceneObjectPart(matLocalID); @@ -480,24 +494,22 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_log.Debug("[MaterialsDemoModule]: GET cap handler"); OSDMap resp = new OSDMap(); - - int matsCount = 0; - OSDArray allOsd = new OSDArray(); - foreach (KeyValuePair kvp in m_knownMaterials) + lock (m_knownMaterials) { - OSDMap matMap = new OSDMap(); - - matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); + foreach (KeyValuePair kvp in m_knownMaterials) + { + OSDMap matMap = new OSDMap(); - matMap["Material"] = kvp.Value; - allOsd.Add(matMap); - matsCount++; + matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); + matMap["Material"] = kvp.Value; + allOsd.Add(matMap); + matsCount++; + } } - resp["Zipped"] = ZCompressOSD(allOsd, false); m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); -- cgit v1.1 From 4406f07a84faf2622fb1e238757b2ce2545cc24c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jun 2013 23:34:16 +0100 Subject: Add IMG_BLOOM1.jp2 to standard asset set, which is used in stars. This makes stars appear more realistically rather than as massive chunks due to the missing IMG_BLOOM1 asset from the viewer. Thanks to YoshikoFazuku for supplying the star asset which I then uploaded via a viewer and extracted as JPEG2000. Thanks also to Ai Austin for helping this process along. See http://opensimulator.org/mantis/view.php?id=6691 for more details. --- CONTRIBUTORS.txt | 5 ++--- bin/assets/TexturesAssetSet/IMG_BLOOM1.jp2 | Bin 0 -> 11276 bytes bin/assets/TexturesAssetSet/TexturesAssetSet.xml | 12 ++++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 bin/assets/TexturesAssetSet/IMG_BLOOM1.jp2 diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 7601a50..f621cd3 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -58,7 +58,7 @@ where we are today. = Additional OpenSim Contributors = -These folks have contributed code patches to OpenSim to help make it +These folks have contributed code patches or content to OpenSimulator to help make it what it is today. * aduffy70 @@ -163,6 +163,7 @@ what it is today. * webmage (IBM) * Xantor * Y. Nitta +* YoshikoFazuku * YZh * Zackary Geers aka Kunnis Basiat * Zha Ewry @@ -215,5 +216,3 @@ In addition, we would like to thank: * The Mono Project * The NANT Developers * Microsoft (.NET, MSSQL-Adapters) -*x - diff --git a/bin/assets/TexturesAssetSet/IMG_BLOOM1.jp2 b/bin/assets/TexturesAssetSet/IMG_BLOOM1.jp2 new file mode 100644 index 0000000..8186d49 Binary files /dev/null and b/bin/assets/TexturesAssetSet/IMG_BLOOM1.jp2 differ diff --git a/bin/assets/TexturesAssetSet/TexturesAssetSet.xml b/bin/assets/TexturesAssetSet/TexturesAssetSet.xml index a4a0cba..a29ac38 100644 --- a/bin/assets/TexturesAssetSet/TexturesAssetSet.xml +++ b/bin/assets/TexturesAssetSet/TexturesAssetSet.xml @@ -746,4 +746,16 @@ + + +
+ + + + +
+ -- cgit v1.1 From 371085546d93c610770abe1182e2add1d75cb16e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 28 Jun 2013 23:57:41 +0100 Subject: Add materials store null check into UuidGatherer code. --- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 4e5fb8e..8f69ce3 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -232,6 +232,10 @@ namespace OpenSim.Region.Framework.Scenes if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) { OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); + + if (materialsStore == null) + return; + materialsStore.TryGetValue("Materials", out osdMaterials); } -- cgit v1.1 From 3a634c56e344dcaa9bf089168bed185cee4527bf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 29 Jun 2013 00:23:41 +0100 Subject: Remove hack to migrate previous experimental-level os materials data. This didn't seem to be working anyway and it's better not to have such hacks in the code for experimental stuff. --- OpenSim/Framework/DAMap.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index fd45a11..5c729e8 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs @@ -148,10 +148,6 @@ namespace OpenSim.Framework keysToRemove.Add(key); } - else if (key == "OS:Materials") - { - osMaterialsMigrationRequired = true; - } } if (keysToRemove != null) @@ -163,11 +159,6 @@ namespace OpenSim.Framework } } - // Hard-coded special case that needs to be removed in the future. Normally, modules themselves should - // handle reading data from old locations - if (osMaterialsMigrationRequired) - daMap.SetStore("OpenSim", "Materials", (OSDMap)namespacesMap["OS:Materials"]); - foreach (OSD nsOsd in namespacesMap.Values) { OSDMap nsOsdMap = (OSDMap)nsOsd; -- cgit v1.1 From 00093a305d225c98ffe00b656df7943cb50c42b0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 18:35:23 -0700 Subject: Changed HG status notifications timeout down to 15secs from the default 100. --- OpenSim/Framework/WebUtil.cs | 10 +++++++++- .../Connectors/Hypergrid/HGFriendsServicesConnector.cs | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 4599f62..6fb1e0c 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -962,11 +962,12 @@ 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) + public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs) { int reqnum = WebUtil.RequestNumber++; @@ -980,6 +981,8 @@ namespace OpenSim.Framework WebRequest request = WebRequest.Create(requestUrl); request.Method = verb; + if (timeoutsecs > 0) + request.Timeout = timeoutsecs * 1000; string respstring = String.Empty; using (MemoryStream buffer = new MemoryStream()) @@ -1073,6 +1076,11 @@ namespace OpenSim.Framework return respstring; } + + public static string MakeRequest(string verb, string requestUrl, string obj) + { + return MakeRequest(verb, requestUrl, obj, -1); + } } public class SynchronousRestObjectRequester diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs index e984a54..622d4e1 100644 --- a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs @@ -277,7 +277,7 @@ namespace OpenSim.Services.Connectors.Hypergrid { reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, - ServerUtils.BuildQueryString(sendData)); + ServerUtils.BuildQueryString(sendData), 15); } catch (Exception e) { -- cgit v1.1 From ff47cf77ab52d42195fb0f089599618511d4919b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 19:15:25 -0700 Subject: A little more debug for the Unknown User problem mantis #6625 --- .../Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs index 4dca592..1db4ad0 100644 --- a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -103,6 +103,9 @@ namespace OpenSim.Capabilities.Handlers p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower(); p.id = user.Id; p.is_display_name_default = false; + + if (user.FirstName.StartsWith("Unknown") && user.LastName.StartsWith("User")) + m_log.DebugFormat("[AVATAR PICKER SEARCH]: Sending {0} {1}", user.FirstName, user.LastName); return p; } -- cgit v1.1 From 0c9702156581cd3948fe07bdae23f3530105d2b5 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 21:05:45 -0700 Subject: More debug for mantis #6625. It looks like the home friends list is being fetched on HG TPs. --- .../CoreModules/Avatar/Friends/HGFriendsModule.cs | 41 +++++++++++----------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index b3e3aa2..ae45b99 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -183,6 +183,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp)) { IUserManagement uMan = m_Scenes[0].RequestModuleInterface(); + m_log.DebugFormat("[HGFRIENDS MODULE]: caching {0}", finfo.Friend); uMan.AddUser(id, url + ";" + first + " " + last); } } @@ -347,31 +348,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return null; } - public override FriendInfo[] GetFriendsFromService(IClientAPI client) - { -// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); - Boolean agentIsLocal = true; - if (UserManagementModule != null) - agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); +// public override FriendInfo[] GetFriendsFromService(IClientAPI client) +// { +//// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); +// Boolean agentIsLocal = true; +// if (UserManagementModule != null) +// agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); - if (agentIsLocal) - return base.GetFriendsFromService(client); +// if (agentIsLocal) +// return base.GetFriendsFromService(client); - FriendInfo[] finfos = new FriendInfo[0]; - // Foreigner - AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); - if (agentClientCircuit != null) - { - //[XXX] string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); +// FriendInfo[] finfos = new FriendInfo[0]; +// // Foreigner +// AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); +// if (agentClientCircuit != null) +// { +// //[XXX] string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); - finfos = FriendsService.GetFriends(client.AgentId.ToString()); - m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); - } +// finfos = FriendsService.GetFriends(client.AgentId.ToString()); +// m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); +// } -// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); +//// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); - return finfos; - } +// return finfos; +// } protected override bool StoreRights(UUID agentID, UUID friendID, int rights) { -- cgit v1.1 From 8fa5d12fcb73ffcc7144009e0147febcfa3ce704 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 21:26:58 -0700 Subject: One more debug mantis #6625 --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 41ea2a2..50371ce 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -292,6 +292,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends friendsData = new UserFriendData(); friendsData.PrincipalID = agentID; friendsData.Friends = GetFriendsFromService(client); + m_log.DebugFormat("[FRIENDS MODULE]: User has {1} friends", friendsData.Friends.Length); friendsData.Refcount = 1; m_Friends[agentID] = friendsData; -- cgit v1.1 From c462e0a51ce04a580eab49df6c679c20eff74c8d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 21:30:07 -0700 Subject: Fixed previous debug message --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 50371ce..d9d302c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -292,7 +292,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends friendsData = new UserFriendData(); friendsData.PrincipalID = agentID; friendsData.Friends = GetFriendsFromService(client); - m_log.DebugFormat("[FRIENDS MODULE]: User has {1} friends", friendsData.Friends.Length); + m_log.DebugFormat("[FRIENDS MODULE]: User has {0} friends", friendsData.Friends.Length); friendsData.Refcount = 1; m_Friends[agentID] = friendsData; -- cgit v1.1 From 20f2cf876982b2c7589b67ce4c8f09d8fff3e9f1 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 21:54:10 -0700 Subject: More debug mantis #6625 --- OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs index b1dd84e..1e6ff7e 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs @@ -112,6 +112,7 @@ namespace OpenSim.Services.Connectors.Friends try { + m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: Calling {0}", uri); string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); if (reply != string.Empty) { -- cgit v1.1 From 74e7fac13fcb5d15d469d27694fc89d5f784ade0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 29 Jun 2013 22:32:26 -0700 Subject: More on mantis #6625 --- .../ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 2d3ba82..70ba944 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -204,7 +204,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory Util.FireAndForget(delegate { foreach (InventoryItemBase item in items) - UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); + if (!string.IsNullOrEmpty(item.CreatorData)) + UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); }); } -- cgit v1.1 From 1fc873d09fbc0d29e35d2a8f34c134bb8ac01480 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 30 Jun 2013 07:21:22 -0700 Subject: Same fix to LocalInventoryServiceConnector.cs --- .../ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index ec5751d..99913a9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -196,7 +196,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory Util.FireAndForget(delegate { foreach (InventoryItemBase item in items) - UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); + if (!string.IsNullOrEmpty(item.CreatorData)) + UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); }); } -- cgit v1.1 From d7775d1e113560307af0170f8d2eab628a5e8acb Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 30 Jun 2013 07:22:27 -0700 Subject: Revert "A little more debug for the Unknown User problem mantis #6625" This reverts commit ff47cf77ab52d42195fb0f089599618511d4919b. --- .../Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs index 1db4ad0..4dca592 100644 --- a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -103,9 +103,6 @@ namespace OpenSim.Capabilities.Handlers p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower(); p.id = user.Id; p.is_display_name_default = false; - - if (user.FirstName.StartsWith("Unknown") && user.LastName.StartsWith("User")) - m_log.DebugFormat("[AVATAR PICKER SEARCH]: Sending {0} {1}", user.FirstName, user.LastName); return p; } -- cgit v1.1 From 1e97972f78a852f24664f730f2e502c3b8a680c8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 30 Jun 2013 07:25:13 -0700 Subject: Revert "One more debug mantis #6625" This reverts commit 8fa5d12fcb73ffcc7144009e0147febcfa3ce704. Conflicts: OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index d9d302c..41ea2a2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -292,7 +292,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends friendsData = new UserFriendData(); friendsData.PrincipalID = agentID; friendsData.Friends = GetFriendsFromService(client); - m_log.DebugFormat("[FRIENDS MODULE]: User has {0} friends", friendsData.Friends.Length); friendsData.Refcount = 1; m_Friends[agentID] = friendsData; -- cgit v1.1 From c7383688466ec61623c709800486de90240fc2d7 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 30 Jun 2013 07:25:46 -0700 Subject: Revert "More debug mantis #6625" This reverts commit 20f2cf876982b2c7589b67ce4c8f09d8fff3e9f1. --- OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs index 1e6ff7e..b1dd84e 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs @@ -112,7 +112,6 @@ namespace OpenSim.Services.Connectors.Friends try { - m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: Calling {0}", uri); string reply = SynchronousRestFormsRequester.MakeRequest("POST", uri, reqString); if (reply != string.Empty) { -- cgit v1.1 From e377abcc35c5fb4d47418524ae68364705995915 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 30 Jun 2013 08:39:35 -0700 Subject: Groups V2: charge for group creation only after the group has been successfully created --- OpenSim/Addons/Groups/GroupsModule.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 5b3b9f6..5959bac 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -766,14 +766,17 @@ namespace OpenSim.Groups remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group."); return UUID.Zero; } - money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate); } + string reason = string.Empty; UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, remoteClient.AgentId, out reason); if (groupID != UUID.Zero) { + if (money != null) + money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate); + remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly"); // Update the founder with new group information. -- cgit v1.1 From 2f4a729d408acfd311c8b7bc53d2cbff9d2ddfad Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 29 Jun 2013 06:42:38 -0700 Subject: BulletSim: add inTaintTime parameter to collision cache clear function. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 6437b04..d17c8e7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -706,7 +706,7 @@ public static class BSParam new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", 0f, (s) => { return 0f; }, - (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), + (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ), new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver", 0f, (s) => { return 0f; }, @@ -792,10 +792,10 @@ public static class BSParam // ===================================================================== // There are parameters that, when set, cause things to happen in the physics engine. // This causes the broadphase collision cache to be cleared. - private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) + private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime) { BSScene physScene = pPhysScene; - physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate() + physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate() { physScene.PE.ResetBroadphasePool(physScene.World); }); -- cgit v1.1 From 23516717e48095011c1c06d64785ef7d91754ff2 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 30 Jun 2013 13:39:58 -0700 Subject: BulletSim: a better version of llMoveToTarget that doesn't go crazy. There is still some overshoot but mostly fixes Mantis 6693. Fix bug where moveToTarget was active for non-physical objects and while selected. Fix bug where move target was not getting changed if the script changed the target during a move. --- .../Physics/BulletSPlugin/BSActorMoveToTarget.cs | 80 +++++++++++++++++++--- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 15 ++-- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 1 + OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 19 ++++- 5 files changed, 98 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs index 75ff24e..bdf4bc0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs @@ -50,7 +50,8 @@ public class BSActorMoveToTarget : BSActor // BSActor.isActive public override bool isActive { - get { return Enabled; } + // MoveToTarget only works on physical prims + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } } // Release any connections and resources used by the actor. @@ -102,16 +103,28 @@ public class BSActorMoveToTarget : BSActor // We're taking over after this. m_controllingPrim.ZeroMotion(true); - m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate", - m_controllingPrim.MoveToTargetTau, // timeScale - BSMotor.Infinite, // decay time scale - 1f // efficiency + /* Someday use the PID controller + m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString()); + m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau; + m_targetMotor.Efficiency = 1f; + */ + m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(), + m_controllingPrim.MoveToTargetTau, // timeScale + BSMotor.Infinite, // decay time scale + 1f // efficiency ); m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); - m_physicsScene.BeforeStep += Mover; + // m_physicsScene.BeforeStep += Mover; + m_physicsScene.BeforeStep += Mover2; + } + else + { + // If already allocated, make sure the target and other paramters are current + m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); + m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); } } @@ -119,12 +132,16 @@ public class BSActorMoveToTarget : BSActor { if (m_targetMotor != null) { - m_physicsScene.BeforeStep -= Mover; + // m_physicsScene.BeforeStep -= Mover; + m_physicsScene.BeforeStep -= Mover2; m_targetMotor = null; } } - // Called just before the simulation step. Update the vertical position for hoverness. + // Origional mover that set the objects position to move to the target. + // The problem was that gravity would keep trying to push the object down so + // the overall downward velocity would increase to infinity. + // Called just before the simulation step. private void Mover(float timeStep) { // Don't do hovering while the object is selected. @@ -142,6 +159,7 @@ public class BSActorMoveToTarget : BSActor m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; // Setting the position does not cause the physics engine to generate a property update. Force it. m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); } @@ -151,7 +169,51 @@ public class BSActorMoveToTarget : BSActor // Setting the position does not cause the physics engine to generate a property update. Force it. m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); } - m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", + m_controllingPrim.LocalID, origPosition, movePosition); + } + + // Version of mover that applies forces to move the physical object to the target. + // Also overcomes gravity so the object doesn't just drop to the ground. + // Called just before the simulation step. + private void Mover2(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + + OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) + OMV.Vector3 addedForce = OMV.Vector3.Zero; + + // CorrectionVector is the movement vector required this step + OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition); + + // If we are very close to our target, turn off the movement motor. + if (m_targetMotor.ErrorIsZero()) + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}", + m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass); + m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + else + { + // First force to move us there -- the motor return a timestep scaled value. + addedForce = correctionVector / timeStep; + // Remove the existing velocity (only the moveToTarget force counts) + addedForce -= m_controllingPrim.RawVelocity; + // Overcome gravity. + addedForce -= m_controllingPrim.Gravity; + + // Add enough force to overcome the mass of the object + addedForce *= m_controllingPrim.Mass; + + m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */); + } + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}", + m_controllingPrim.LocalID, origPosition, addedForce); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 48f842e..5ef6992 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -626,7 +626,7 @@ public sealed class BSCharacter : BSPhysObject OMV.Vector3 addForce = force / PhysScene.LastTimeStep; AddForce(addForce, pushforce, false); } - private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { + public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { if (force.IsFinite()) { OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index ef662b5..1214703 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -144,7 +144,6 @@ public class BSVMotor : BSMotor Vector3 correction = Vector3.Zero; Vector3 error = TargetValue - CurrentValue; - LastError = error; if (!ErrorIsZero(error)) { correction = StepError(timeStep, error); @@ -179,6 +178,7 @@ public class BSVMotor : BSMotor MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); } + LastError = error; return correction; } @@ -293,7 +293,6 @@ public class BSFMotor : BSMotor float correction = 0f; float error = TargetValue - CurrentValue; - LastError = error; if (!ErrorIsZero(error)) { correction = StepError(timeStep, error); @@ -328,6 +327,7 @@ public class BSFMotor : BSMotor MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); } + LastError = error; return CurrentValue; } @@ -363,7 +363,7 @@ public class BSFMotor : BSMotor // ============================================================================ // ============================================================================ -// Proportional, Integral, Derivitive Motor +// Proportional, Integral, Derivitive ("PID") Motor // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. public class BSPIDVMotor : BSVMotor { @@ -434,15 +434,14 @@ public class BSPIDVMotor : BSVMotor // A simple derivitive is the rate of change from the last error. Vector3 derivitive = (error - LastError) * timeStep; - LastError = error; // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) - Vector3 ret = error * timeStep * proportionFactor * FactorMix.X - + RunningIntegration * integralFactor * FactorMix.Y - + derivitive * derivFactor * FactorMix.Z + Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X + + RunningIntegration / TimeScale * integralFactor * FactorMix.Y + + derivitive / TimeScale * derivFactor * FactorMix.Z ; - MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", + MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret); return ret; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index a4c5e08..a0d5c42 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -210,6 +210,7 @@ public abstract class BSPhysObject : PhysicsActor AddAngularForce(force, pushforce, false); } public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); + public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 95bdc7b..90f74df 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -450,6 +450,9 @@ public class BSPrim : BSPhysObject Gravity = ComputeGravity(Buoyancy); PhysScene.PE.SetGravity(PhysBody, Gravity); + OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG + DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG + Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); PhysScene.PE.UpdateInertiaTensor(PhysBody); @@ -1040,6 +1043,20 @@ public class BSPrim : BSPhysObject } } + public override OMV.Vector3 PIDTarget + { + set + { + base.PIDTarget = value; + BSActor actor; + if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) + { + // if the actor exists, tell it to refresh its values. + actor.Refresh(); + } + + } + } // Used for llSetHoverHeight and maybe vehicle height // Hover Height will override MoveTo target's Z public override bool PIDHoverActive { @@ -1063,7 +1080,7 @@ public class BSPrim : BSPhysObject // Applying a force just adds this to the total force on the object. // This added force will only last the next simulation tick. - public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { + public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { // for an object, doesn't matter if force is a pushforce or not if (IsPhysicallyActive) { -- cgit v1.1 From 425d2a2a972de34c1853c6049727d4c0eea38af4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 30 Jun 2013 13:48:27 -0700 Subject: BulletSim: set linkset type to be prim specific rather than a simulator wide default. This allows individual prims to differ in the underlying linkset implementation. --- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 16 ++++------------ .../Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 2 -- OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 5 ++++- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 76c2187..ad8e10f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -33,14 +33,6 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { -// A BSPrim can get individual information about its linkedness attached -// to it through an instance of a subclass of LinksetInfo. -// Each type of linkset will define the information needed for its type. -public abstract class BSLinksetInfo -{ - public virtual void Clear() { } -} - public abstract class BSLinkset { // private static string LogHeader = "[BULLETSIM LINKSET]"; @@ -56,15 +48,15 @@ public abstract class BSLinkset { BSLinkset ret = null; - switch ((int)BSParam.LinksetImplementation) + switch (parent.LinksetType) { - case (int)LinksetImplementation.Constraint: + case LinksetImplementation.Constraint: ret = new BSLinksetConstraints(physScene, parent); break; - case (int)LinksetImplementation.Compound: + case LinksetImplementation.Compound: ret = new BSLinksetCompound(physScene, parent); break; - case (int)LinksetImplementation.Manual: + case LinksetImplementation.Manual: // ret = new BSLinksetManual(physScene, parent); break; default: diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 350a5d1..308cf13 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -238,7 +238,6 @@ public sealed class BSLinksetCompound : BSLinkset // there will already be a rebuild scheduled. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", updated.LocalID, whichUpdated); - updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. ScheduleRebuild(updated); } } @@ -294,7 +293,6 @@ public sealed class BSLinksetCompound : BSLinkset child.LocalID, child.PhysBody.AddrString); // Cause the child's body to be rebuilt and thus restored to normal operation - child.LinksetInfo = null; child.ForceBodyShapeRebuild(false); if (!HasAnyChildren) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 235da78..87eed98 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -41,12 +41,15 @@ public class BSPrimLinkable : BSPrimDisplaced // The index of this child prim. public int LinksetChildIndex { get; set; } - public BSLinksetInfo LinksetInfo { get; set; } + public BSLinkset.LinksetImplementation LinksetType { get; set; } public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) { + // Default linkset implementation for this prim + LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation; + Linkset = BSLinkset.Factory(PhysScene, this); PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() -- cgit v1.1 From 9d5ae759504f01dceac5d3f859da1e43e28797ad Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 30 Jun 2013 17:06:27 -0700 Subject: BulletSim: remove the handle to the vehicle actor and cause routines that need it to look it up. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 70 ++++++++++++++++------ .../Physics/BulletSPlugin/Tests/BasicVehicles.cs | 32 +++++----- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 90f74df..b2947c6 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -70,18 +70,17 @@ public class BSPrim : BSPhysObject private int CrossingFailures { get; set; } // Keep a handle to the vehicle actor so it is easy to set parameters on same. - public BSDynamics VehicleActor; public const string VehicleActorName = "BasicVehicle"; // Parameters for the hover actor - public const string HoverActorName = "HoverActor"; + public const string HoverActorName = "BSPrim.HoverActor"; // Parameters for the axis lock actor public const String LockedAxisActorName = "BSPrim.LockedAxis"; // Parameters for the move to target actor - public const string MoveToTargetActorName = "MoveToTargetActor"; + public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor"; // Parameters for the setForce and setTorque actors - public const string SetForceActorName = "SetForceActor"; - public const string SetTorqueActorName = "SetTorqueActor"; + public const string SetForceActorName = "BSPrim.SetForceActor"; + public const string SetTorqueActorName = "BSPrim.SetTorqueActor"; public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) @@ -100,9 +99,8 @@ public class BSPrim : BSPhysObject _isPhysical = pisPhysical; _isVolumeDetect = false; - // We keep a handle to the vehicle actor so we can set vehicle parameters later. - VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName); - PhysicalActors.Add(VehicleActorName, VehicleActor); + // Add a dynamic vehicle to our set of actors that can move this prim. + PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); _mass = CalculateMass(); @@ -505,9 +503,25 @@ public class BSPrim : BSPhysObject } } + // Find and return a handle to the current vehicle actor. + // Return 'null' if there is no vehicle actor. + public BSDynamics GetVehicleActor() + { + BSDynamics ret = null; + BSActor actor; + if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) + { + ret = actor as BSDynamics; + } + return ret; + } public override int VehicleType { get { - return (int)VehicleActor.Type; + int ret = (int)Vehicle.TYPE_NONE; + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) + ret = (int)vehicleActor.Type; + return ret; } set { Vehicle type = (Vehicle)value; @@ -518,8 +532,12 @@ public class BSPrim : BSPhysObject // change all the parameters. Like a plane changing to CAR when on the // ground. In this case, don't want to zero motion. // ZeroMotion(true /* inTaintTime */); - VehicleActor.ProcessTypeChange(type); - ActivateIfPhysical(false); + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) + { + vehicleActor.ProcessTypeChange(type); + ActivateIfPhysical(false); + } }); } } @@ -527,31 +545,47 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() { - VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) + { + vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); + ActivateIfPhysical(false); + } }); } public override void VehicleVectorParam(int param, OMV.Vector3 value) { PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() { - VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) + { + vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); + ActivateIfPhysical(false); + } }); } public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() { - VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); - ActivateIfPhysical(false); + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) + { + vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); + ActivateIfPhysical(false); + } }); } public override void VehicleFlags(int param, bool remove) { PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() { - VehicleActor.ProcessVehicleFlags(param, remove); + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) + { + vehicleActor.ProcessVehicleFlags(param, remove); + } }); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index b040e21..583c436 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs @@ -114,21 +114,25 @@ public class BasicVehicles : OpenSimTestCase // Instead the appropriate values are set and calls are made just the parts of the // controller we want to exercise. Stepping the physics engine then applies // the actions of that one feature. - TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); - TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); - TestVehicle.VehicleActor.enableAngularVerticalAttraction = true; - - TestVehicle.IsPhysical = true; - PhysicsScene.ProcessTaints(); - - // Step the simulator a bunch of times and vertical attraction should orient the vehicle up - for (int ii = 0; ii < simSteps; ii++) + BSDynamics vehicleActor = TestVehicle.GetVehicleActor(); + if (vehicleActor != null) { - TestVehicle.VehicleActor.ForgetKnownVehicleProperties(); - TestVehicle.VehicleActor.ComputeAngularVerticalAttraction(); - TestVehicle.VehicleActor.PushKnownChanged(); - - PhysicsScene.Simulate(simulationTimeStep); + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); + vehicleActor.enableAngularVerticalAttraction = true; + + TestVehicle.IsPhysical = true; + PhysicsScene.ProcessTaints(); + + // Step the simulator a bunch of times and vertical attraction should orient the vehicle up + for (int ii = 0; ii < simSteps; ii++) + { + vehicleActor.ForgetKnownVehicleProperties(); + vehicleActor.ComputeAngularVerticalAttraction(); + vehicleActor.PushKnownChanged(); + + PhysicsScene.Simulate(simulationTimeStep); + } } TestVehicle.IsPhysical = false; -- cgit v1.1 From c24c99f4bab0ef2e926ebc46235ffed25fdd9add Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 30 Jun 2013 19:08:15 -0700 Subject: BulletSim: fix an occasional crash with flushing log files. --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index dec6b6f..155d143 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -223,8 +223,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // can be left in and every call doesn't have to check for null. if (m_physicsLoggingEnabled) { - PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); - PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. + PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush); + PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages. } else { @@ -1106,8 +1106,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public void DetailLog(string msg, params Object[] args) { PhysicsLogging.Write(msg, args); - // Add the Flush() if debugging crashes. Gets all the messages written out. - if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); } // Used to fill in the LocalID when there isn't one. It's the correct number of characters. public const string DetailLogZero = "0000000000"; -- cgit v1.1 From 8eb86c9ec91ee41699ab455fc5e788a4bff53071 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 30 Jun 2013 19:22:43 -0700 Subject: BulletSim: add the reset of the last commit for flush log file problems. Fix small typo in one log message. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 07e87d1..aa247dd 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1276,7 +1276,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin VehicleAddForce(appliedGravity); - VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", + VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", ControllingPrim.LocalID, m_VehicleGravity, ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 155d143..1645c98 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -223,7 +223,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // can be left in and every call doesn't have to check for null. if (m_physicsLoggingEnabled) { - PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush); + PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush); PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages. } else -- cgit v1.1 From 635704b7ef739d553a2354bc1bde6c9588c04cad Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 1 Jul 2013 23:54:04 +0100 Subject: Update debug unknown user name UserUMMTGUN3 to UserUMMTGUN4 and UserUMMAU -> UserUMMAU2 to track any new occurences. This is to see the impact that Diva's fixes related to this issue (last one is currently commit c7383688) You will need to clear your viewer cache for this to have any effect Relates to http://opensimulator.org/mantis/view.php?id=6625 --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 194b591..5da64f7 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -320,7 +320,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { names[0] = "Unknown"; - names[1] = "UserUMMTGUN3"; + names[1] = "UserUMMTGUN4"; return false; } @@ -537,7 +537,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { user.FirstName = "Unknown"; - user.LastName = "UserUMMAU"; + user.LastName = "UserUMMAU2"; } AddUserInternal(user); -- cgit v1.1 From ccca0059695e0321ae1aa223c9e8b89cc141b58f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 13:29:44 -0700 Subject: HG: close a loophole by which if something was wrong with the ServiceURLs it resulted in never ending asset requests --- OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | 2 +- .../CoreModules/Framework/InventoryAccess/HGAssetMapper.cs | 9 +++++++++ .../Framework/InventoryAccess/HGInventoryAccessModule.cs | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs index a168bfe..4d0568d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs @@ -421,7 +421,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // foreign user is visiting, we need to try again after the first fail to the local // asset service. string assetServerURL = string.Empty; - if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL)) + if (InventoryAccessModule.IsForeignUser(AgentID, out assetServerURL) && !string.IsNullOrEmpty(assetServerURL)) { if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) assetServerURL = assetServerURL + "/"; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index 7871eda..144895c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -73,6 +73,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess private AssetMetadata FetchMetadata(string url, UUID assetID) { + if (string.IsNullOrEmpty(url)) + return null; + if (!url.EndsWith("/") && !url.EndsWith("=")) url = url + "/"; @@ -92,6 +95,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess AssetBase asset = m_scene.AssetService.Get(assetID.ToString()); if (asset == null) { + if (string.IsNullOrEmpty(url)) + return null; + if (!url.EndsWith("/") && !url.EndsWith("=")) url = url + "/"; @@ -109,6 +115,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess public bool PostAsset(string url, AssetBase asset) { + if (string.IsNullOrEmpty(url)) + return false; + if (asset != null) { if (!url.EndsWith("/") && !url.EndsWith("=")) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index b2b628d..64d5f61 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -297,7 +297,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (m_Scene.TryGetScenePresence(userID, out sp)) { AgentCircuitData aCircuit = m_Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - if (aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) + if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) { assetServerURL = aCircuit.ServiceURLs["AssetServerURI"].ToString(); assetServerURL = assetServerURL.Trim(new char[] { '/' }); -- cgit v1.1 From e984bfb4c63718d5176b17f6beea46f4512cf304 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 14:31:39 -0700 Subject: This should have a strong effect on the Unknown User issue mantis #6625 --- OpenSim/Data/IGridUserData.cs | 1 + OpenSim/Data/MSSQL/MSSQLGridUserData.cs | 7 ++++++- OpenSim/Data/MySQL/MySQLGridUserData.cs | 7 +++++-- OpenSim/Data/SQLite/SQLiteGridUserData.cs | 4 ++++ .../Framework/UserManagement/UserManagementModule.cs | 20 ++++++++++++++++++-- .../Services/UserAccountService/GridUserService.cs | 17 ++++++++++++++++- 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/OpenSim/Data/IGridUserData.cs b/OpenSim/Data/IGridUserData.cs index e15a1f8..9afa477 100644 --- a/OpenSim/Data/IGridUserData.cs +++ b/OpenSim/Data/IGridUserData.cs @@ -50,6 +50,7 @@ namespace OpenSim.Data public interface IGridUserData { GridUserData Get(string userID); + GridUserData[] GetAll(string query); bool Store(GridUserData data); } } \ No newline at end of file diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs index 9e215f9..df73e5b 100644 --- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs +++ b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs @@ -50,7 +50,7 @@ namespace OpenSim.Data.MSSQL { } - public GridUserData Get(string userID) + public new GridUserData Get(string userID) { GridUserData[] ret = Get("UserID", userID); @@ -60,5 +60,10 @@ namespace OpenSim.Data.MSSQL return ret[0]; } + public GridUserData[] GetAll(string userID) + { + return base.Get("UserID LIKE {0}%", userID); + } + } } diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs index a9ce94d..df1ecc6 100644 --- a/OpenSim/Data/MySQL/MySQLGridUserData.cs +++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs @@ -46,7 +46,7 @@ namespace OpenSim.Data.MySQL public MySQLGridUserData(string connectionString, string realm) : base(connectionString, realm, "GridUserStore") {} - public GridUserData Get(string userID) + public new GridUserData Get(string userID) { GridUserData[] ret = Get("UserID", userID); @@ -56,6 +56,9 @@ namespace OpenSim.Data.MySQL return ret[0]; } - + public GridUserData[] GetAll(string userID) + { + return base.Get("UserID LIKE {0}%", userID); + } } } \ No newline at end of file diff --git a/OpenSim/Data/SQLite/SQLiteGridUserData.cs b/OpenSim/Data/SQLite/SQLiteGridUserData.cs index 1bb5ed8..54cef1a 100644 --- a/OpenSim/Data/SQLite/SQLiteGridUserData.cs +++ b/OpenSim/Data/SQLite/SQLiteGridUserData.cs @@ -56,6 +56,10 @@ namespace OpenSim.Data.SQLite return ret[0]; } + public GridUserData[] GetAll(string userID) + { + return base.Get("UserID LIKE {0}%", userID); + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 5da64f7..a1343fb 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -319,8 +319,25 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } else { + // Let's try the GridUser service + GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); + if (uInfo != null) + { + string url, first, last, tmp; + UUID u; + if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) + { + AddUser(uuid, first, last, url); + + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; + + return true; + } + } + names[0] = "Unknown"; - names[1] = "UserUMMTGUN4"; + names[1] = "UserUMMTGUN5"; return false; } @@ -474,7 +491,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); UserData oldUser; - //lock the whole block - prevent concurrent update lock (m_UserCache) m_UserCache.TryGetValue(id, out oldUser); diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index 8388180..62b82fe 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -51,7 +51,22 @@ namespace OpenSim.Services.UserAccountService public virtual GridUserInfo GetGridUserInfo(string userID) { - GridUserData d = m_Database.Get(userID); + GridUserData d = null; + if (userID.Length > 36) // it's a UUI + d = m_Database.Get(userID); + else // it's a UUID + { + GridUserData[] ds = m_Database.GetAll(userID); + if (ds == null) + return null; + if (ds.Length > 0) + { + d = ds[0]; + foreach (GridUserData dd in ds) + if (dd.UserID.Length > d.UserID.Length) // find the longest + d = dd; + } + } if (d == null) return null; -- cgit v1.1 From 626940ceb83102a6aa0eebb81e10c86f1feb8eff Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 15:39:10 -0700 Subject: More debug messages --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 7 ++++++- OpenSim/Services/UserAccountService/GridUserService.cs | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index a1343fb..ff31b67 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -323,6 +323,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); if (uInfo != null) { + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Found grid user {0}", uInfo.UserID); string url, first, last, tmp; UUID u; if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) @@ -334,10 +335,14 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return true; } + else + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI"); } + else + m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found"); names[0] = "Unknown"; - names[1] = "UserUMMTGUN5"; + names[1] = "UserUMMTGUN6"; return false; } diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index 62b82fe..af2701d 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -46,7 +46,7 @@ namespace OpenSim.Services.UserAccountService public GridUserService(IConfigSource config) : base(config) { - m_log.Debug("[USER GRID SERVICE]: Starting user grid service"); + m_log.Debug("[GRID USER SERVICE]: Starting user grid service"); } public virtual GridUserInfo GetGridUserInfo(string userID) @@ -58,13 +58,17 @@ namespace OpenSim.Services.UserAccountService { GridUserData[] ds = m_Database.GetAll(userID); if (ds == null) + { + m_log.DebugFormat("[GRID USER SERVICE]: user not found {0}", userID); return null; + } if (ds.Length > 0) { d = ds[0]; foreach (GridUserData dd in ds) if (dd.UserID.Length > d.UserID.Length) // find the longest d = dd; + m_log.DebugFormat("[GRID USER SERVICE]: Found user {0}", d.UserID); } } -- cgit v1.1 From 2c05caec7fcf14c7e61c2f66854fc24f06d5b480 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 15:47:02 -0700 Subject: Really make it call the method with the query interface --- OpenSim/Data/MySQL/MySQLGridUserData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs index df1ecc6..f476fd2 100644 --- a/OpenSim/Data/MySQL/MySQLGridUserData.cs +++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs @@ -58,7 +58,7 @@ namespace OpenSim.Data.MySQL public GridUserData[] GetAll(string userID) { - return base.Get("UserID LIKE {0}%", userID); + return base.Get(String.Format("UserID LIKE {0}%", userID)); } } } \ No newline at end of file -- cgit v1.1 From 9725b829d5e476fc6b0894b46520ff1d7aba9936 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 15:48:30 -0700 Subject: Do the same for SQLite and MSSQL --- OpenSim/Data/MSSQL/MSSQLGridUserData.cs | 2 +- OpenSim/Data/SQLite/SQLiteGridUserData.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs index df73e5b..7d10955 100644 --- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs +++ b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs @@ -62,7 +62,7 @@ namespace OpenSim.Data.MSSQL public GridUserData[] GetAll(string userID) { - return base.Get("UserID LIKE {0}%", userID); + return base.Get(String.Format("UserID LIKE {0}%", userID)); } } diff --git a/OpenSim/Data/SQLite/SQLiteGridUserData.cs b/OpenSim/Data/SQLite/SQLiteGridUserData.cs index 54cef1a..799df91 100644 --- a/OpenSim/Data/SQLite/SQLiteGridUserData.cs +++ b/OpenSim/Data/SQLite/SQLiteGridUserData.cs @@ -58,7 +58,7 @@ namespace OpenSim.Data.SQLite public GridUserData[] GetAll(string userID) { - return base.Get("UserID LIKE {0}%", userID); + return base.Get(String.Format("UserID LIKE {0}%", userID)); } } -- cgit v1.1 From 316e8f92391f561d459bc6240ccd78b0a98c20c6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 16:10:09 -0700 Subject: Fix SQL statement --- OpenSim/Data/MSSQL/MSSQLGridUserData.cs | 2 +- OpenSim/Data/MySQL/MySQLGridUserData.cs | 2 +- OpenSim/Data/SQLite/SQLiteGridUserData.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs index 7d10955..8ec8d49 100644 --- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs +++ b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs @@ -62,7 +62,7 @@ namespace OpenSim.Data.MSSQL public GridUserData[] GetAll(string userID) { - return base.Get(String.Format("UserID LIKE {0}%", userID)); + return base.Get(String.Format("UserID LIKE '{0}%'", userID)); } } diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs index f476fd2..00560c1 100644 --- a/OpenSim/Data/MySQL/MySQLGridUserData.cs +++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs @@ -58,7 +58,7 @@ namespace OpenSim.Data.MySQL public GridUserData[] GetAll(string userID) { - return base.Get(String.Format("UserID LIKE {0}%", userID)); + return base.Get(String.Format("UserID LIKE '{0}%'", userID)); } } } \ No newline at end of file diff --git a/OpenSim/Data/SQLite/SQLiteGridUserData.cs b/OpenSim/Data/SQLite/SQLiteGridUserData.cs index 799df91..d8c52f8 100644 --- a/OpenSim/Data/SQLite/SQLiteGridUserData.cs +++ b/OpenSim/Data/SQLite/SQLiteGridUserData.cs @@ -58,7 +58,7 @@ namespace OpenSim.Data.SQLite public GridUserData[] GetAll(string userID) { - return base.Get(String.Format("UserID LIKE {0}%", userID)); + return base.Get(String.Format("UserID LIKE '{0}%'", userID)); } } -- cgit v1.1 From d01b8e163d14ee76c291565b5630d5049cde9b95 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 3 Jul 2013 00:27:22 +0100 Subject: minor: Correct typo of "Descrition" to "Description" in "show object *" console commands Thanks to Ai Austin for pointing this out. --- .../Region/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 e434b2e..0e79733 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs @@ -546,7 +546,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands { ConsoleDisplayList cdl = new ConsoleDisplayList(); cdl.AddRow("Name", so.Name); - cdl.AddRow("Descrition", so.Description); + cdl.AddRow("Description", so.Description); cdl.AddRow("Local ID", so.LocalId); cdl.AddRow("UUID", so.UUID); cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name)); -- cgit v1.1 From 4d24bf75fd695a12683987d9803018c2ec4cae60 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 16:46:35 -0700 Subject: Deleted debug messages. Fixed a null ref exception on the POST handler of GridUserServerPostHandler.cs --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 5 ++--- OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs | 6 ++++-- OpenSim/Services/UserAccountService/GridUserService.cs | 5 +---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index ff31b67..90af82e 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -323,7 +323,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); if (uInfo != null) { - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Found grid user {0}", uInfo.UserID); string url, first, last, tmp; UUID u; if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) @@ -336,10 +335,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return true; } else - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI"); + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); } else - m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found"); + m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found {0}", uuid); names[0] = "Unknown"; names[1] = "UserUMMTGUN6"; diff --git a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs index 687cf8d..7483395 100644 --- a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs +++ b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs @@ -185,10 +185,12 @@ namespace OpenSim.Server.Handlers.GridUser GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(user); Dictionary result = new Dictionary(); - result["result"] = guinfo.ToKeyValuePairs(); + if (guinfo != null) + result["result"] = guinfo.ToKeyValuePairs(); + else + result["result"] = "null"; string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[GRID USER HANDLER]: resp string: {0}", xmlString); return Util.UTF8NoBomEncoding.GetBytes(xmlString); } diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index af2701d..fa9a4a8 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -58,17 +58,14 @@ namespace OpenSim.Services.UserAccountService { GridUserData[] ds = m_Database.GetAll(userID); if (ds == null) - { - m_log.DebugFormat("[GRID USER SERVICE]: user not found {0}", userID); return null; - } + if (ds.Length > 0) { d = ds[0]; foreach (GridUserData dd in ds) if (dd.UserID.Length > d.UserID.Length) // find the longest d = dd; - m_log.DebugFormat("[GRID USER SERVICE]: Found user {0}", d.UserID); } } -- cgit v1.1 From 119f84fe11586f9abf76325e9466c8cd8f0d1a72 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 2 Jul 2013 17:03:04 -0700 Subject: Squoosh one last opportunity for Unknown Users to creep in. --- .../Framework/UserManagement/UserManagementModule.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 90af82e..e19631e 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -532,7 +532,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement UserData user = new UserData(); user.Id = id; - if (creatorData != null && creatorData != string.Empty) + if (!string.IsNullOrEmpty(creatorData)) { //creatorData = ; @@ -553,14 +553,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } if (parts.Length >= 2) user.FirstName = parts[1].Replace(' ', '.'); + + AddUserInternal(user); + } - else - { - user.FirstName = "Unknown"; - user.LastName = "UserUMMAU2"; - } + // else don't add the user to the cache, period. - AddUserInternal(user); } } -- cgit v1.1 From 25889b2d7ef08b27591aa61ab4950bdbc856d7a5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 4 Jul 2013 00:02:53 +0100 Subject: change "debug packet" command to "debug lludp packet" to conform with other "debug lludp" options also moves the implementing code into LLUDPServer.cs along with other debug commands from OpenSim.cs gets all debug lludp commands to only activate for the set scene if not root --- OpenSim/Region/Application/OpenSim.cs | 51 ------------------- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 59 ++++++++++++++++++++++ OpenSim/Region/Framework/Scenes/SceneManager.cs | 23 --------- 3 files changed, 59 insertions(+), 74 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 9325b12..6ff7f01 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -226,18 +226,6 @@ namespace OpenSim "Force the update of all objects on clients", HandleForceUpdate); - m_console.Commands.AddCommand("Debug", false, "debug packet", - "debug packet [ ]", - "Turn on packet debugging", - "If level > 255 then all incoming and outgoing packets are logged.\n" - + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" - + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" - + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" - + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" - + "If level <= 0 then no packets are logged.\n" - + "If an avatar name is given then only packets from that avatar are logged", - Debug); - m_console.Commands.AddCommand("General", false, "change region", "change region ", "Change current console region", ChangeSelectedRegion); @@ -701,45 +689,6 @@ namespace OpenSim RefreshPrompt(); } - /// - /// Turn on some debugging values for OpenSim. - /// - /// - protected void Debug(string module, string[] args) - { - if (args.Length == 1) - return; - - switch (args[1]) - { - case "packet": - string name = null; - if (args.Length == 5) - name = string.Format("{0} {1}", args[3], args[4]); - - if (args.Length > 2) - { - int newDebug; - if (int.TryParse(args[2], out newDebug)) - { - SceneManager.SetDebugPacketLevelOnCurrentScene(newDebug, name); - // We provide user information elsewhere if any clients had their debug level set. -// MainConsole.Instance.OutputFormat("Debug packet level set to {0}", newDebug); - } - else - { - MainConsole.Instance.Output("Usage: debug packet 0..255"); - } - } - - break; - - default: - MainConsole.Instance.Output("Unknown debug command"); - break; - } - } - // see BaseOpenSimServer /// /// Many commands list objects for debugging. Some of the types are listed here diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 8eb2e06..ff31ef5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -513,6 +513,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP EnablePoolStats(); MainConsole.Instance.Commands.AddCommand( + "Debug", false, "debug lludp packet", + "debug lludp packet [ ]", + "Turn on packet debugging", + "If level > 255 then all incoming and outgoing packets are logged.\n" + + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" + + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" + + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" + + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" + + "If level <= 0 then no packets are logged.\n" + + "If an avatar name is given then only packets from that avatar are logged", + HandlePacketCommand); + + MainConsole.Instance.Commands.AddCommand( "Debug", false, "debug lludp start", @@ -553,8 +566,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP HandleStatusCommand); } + private void HandlePacketCommand(string module, string[] args) + { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + + string name = null; + + if (args.Length == 6) + name = string.Format("{0} {1}", args[4], args[5]); + + if (args.Length > 3) + { + int newDebug; + if (int.TryParse(args[3], out newDebug)) + { + m_scene.ForEachScenePresence(sp => + { + if (name == null || sp.Name == name) + { + m_log.DebugFormat( + "Packet debug for {0} ({1}) set to {2} in {3}", + sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); + + sp.ControllingClient.DebugPacketLevel = newDebug; + } + }); + } + else + { + MainConsole.Instance.Output("Usage: debug lludp packet 0..255 [ ]"); + } + } + } + private void HandleStartCommand(string module, string[] args) { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + if (args.Length != 4) { MainConsole.Instance.Output("Usage: debug lludp start "); @@ -572,6 +622,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void HandleStopCommand(string module, string[] args) { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + if (args.Length != 4) { MainConsole.Instance.Output("Usage: debug lludp stop "); @@ -589,6 +642,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void HandlePoolCommand(string module, string[] args) { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + if (args.Length != 4) { MainConsole.Instance.Output("Usage: debug lludp pool "); @@ -621,6 +677,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void HandleStatusCommand(string module, string[] args) { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + MainConsole.Instance.OutputFormat( "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled"); diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index 780bd01..28f7896 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs @@ -477,29 +477,6 @@ namespace OpenSim.Region.Framework.Scenes return false; } - /// - /// Set the debug packet level on each current scene. This level governs which packets are printed out to the - /// console. - /// - /// - /// Name of avatar to debug - public void SetDebugPacketLevelOnCurrentScene(int newDebug, string name) - { - ForEachSelectedScene(scene => - scene.ForEachScenePresence(sp => - { - if (name == null || sp.Name == name) - { - m_log.DebugFormat( - "Packet debug for {0} ({1}) set to {2}", - sp.Name, sp.IsChildAgent ? "child" : "root", newDebug); - - sp.ControllingClient.DebugPacketLevel = newDebug; - } - }) - ); - } - public List GetCurrentSceneAvatars() { List avatars = new List(); -- cgit v1.1 From 27cdfb7b840423cf8cee08988dc487eeb34d71c7 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 08:47:45 -0700 Subject: HG Friends: debug an issue where the friends data stored in the DB is incomplete. --- OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | 1 + OpenSim/Services/Friends/FriendsService.cs | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index ae45b99..d8f7dc9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -546,6 +546,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1); // and also the converse FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1); + m_log.DebugFormat("[HGFRIENDS MODULE]: Stored {0} {01}", agentID, theFriendUUID); //if (!confirming) //{ diff --git a/OpenSim/Services/Friends/FriendsService.cs b/OpenSim/Services/Friends/FriendsService.cs index e2033ac..dd3f733 100644 --- a/OpenSim/Services/Friends/FriendsService.cs +++ b/OpenSim/Services/Friends/FriendsService.cs @@ -29,6 +29,7 @@ using OpenMetaverse; using OpenSim.Framework; using System; using System.Collections.Generic; +using System.Reflection; using OpenSim.Services.Interfaces; using OpenSim.Data; using Nini.Config; @@ -39,7 +40,12 @@ namespace OpenSim.Services.Friends { public class FriendsService : FriendsServiceBase, IFriendsService { - public FriendsService(IConfigSource config) : base(config) + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + public FriendsService(IConfigSource config) + : base(config) { } @@ -98,6 +104,7 @@ namespace OpenSim.Services.Friends d.Data = new Dictionary(); d.Data["Flags"] = flags.ToString(); + m_log.DebugFormat("[FRIENDS]: Storing {0} {1}", PrincipalID, Friend); return m_Database.Store(d); } -- cgit v1.1 From 5eb78aad96f2dbaf7c4c0e5fa7e678076a2edbfc Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 09:17:01 -0700 Subject: Revert "HG Friends: debug an issue where the friends data stored in the DB is incomplete." This reverts commit 27cdfb7b840423cf8cee08988dc487eeb34d71c7. --- OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | 1 - OpenSim/Services/Friends/FriendsService.cs | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index d8f7dc9..ae45b99 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -546,7 +546,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1); // and also the converse FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1); - m_log.DebugFormat("[HGFRIENDS MODULE]: Stored {0} {01}", agentID, theFriendUUID); //if (!confirming) //{ diff --git a/OpenSim/Services/Friends/FriendsService.cs b/OpenSim/Services/Friends/FriendsService.cs index dd3f733..e2033ac 100644 --- a/OpenSim/Services/Friends/FriendsService.cs +++ b/OpenSim/Services/Friends/FriendsService.cs @@ -29,7 +29,6 @@ using OpenMetaverse; using OpenSim.Framework; using System; using System.Collections.Generic; -using System.Reflection; using OpenSim.Services.Interfaces; using OpenSim.Data; using Nini.Config; @@ -40,12 +39,7 @@ namespace OpenSim.Services.Friends { public class FriendsService : FriendsServiceBase, IFriendsService { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - public FriendsService(IConfigSource config) - : base(config) + public FriendsService(IConfigSource config) : base(config) { } @@ -104,7 +98,6 @@ namespace OpenSim.Services.Friends d.Data = new Dictionary(); d.Data["Flags"] = flags.ToString(); - m_log.DebugFormat("[FRIENDS]: Storing {0} {1}", PrincipalID, Friend); return m_Database.Store(d); } -- cgit v1.1 From 16f40c1a15454fd6b093ae901c307670f12602fe Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 4 Jul 2013 17:29:53 +0100 Subject: Add --default option to "debug lludp packet" command to allow packet logging to be performed immediately from client start --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 69 ++++++++++++++++------ prebuild.xml | 1 + 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index ff31ef5..82fad11 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -34,6 +34,7 @@ using System.Net.Sockets; using System.Reflection; using System.Threading; using log4net; +using NDesk.Options; using Nini.Config; using OpenMetaverse.Packets; using OpenSim.Framework; @@ -102,10 +103,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class LLUDPServer : OpenSimUDPBase { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// Maximum transmission unit, or UDP packet size, for the LLUDP protocol public const int MTU = 1400; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Default packet debug level given to new clients + /// + public int DefaultClientPacketDebugLevel { get; set; } /// The measured resolution of Environment.TickCount public readonly float TickCountResolution; @@ -514,7 +520,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP MainConsole.Instance.Commands.AddCommand( "Debug", false, "debug lludp packet", - "debug lludp packet [ ]", + "debug lludp packet [--default] [ ]", "Turn on packet debugging", "If level > 255 then all incoming and outgoing packets are logged.\n" + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" @@ -522,7 +528,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" + "If level <= 50 then outgoing ImprovedTerseObjectUpdate packets are not logged.\n" + "If level <= 0 then no packets are logged.\n" - + "If an avatar name is given then only packets from that avatar are logged", + + "If --default is specified then the level becomes the default logging level for all subsequent agents.\n" + + "In this case, you cannot also specify an avatar name.\n" + + "If an avatar name is given then only packets from that avatar are logged.", HandlePacketCommand); MainConsole.Instance.Commands.AddCommand( @@ -571,31 +579,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) return; + bool setAsDefaultLevel = false; + OptionSet optionSet = new OptionSet().Add("default", o => setAsDefaultLevel = o != null); + List filteredArgs = optionSet.Parse(args); + string name = null; - if (args.Length == 6) - name = string.Format("{0} {1}", args[4], args[5]); + if (filteredArgs.Count == 6) + { + if (!setAsDefaultLevel) + { + name = string.Format("{0} {1}", filteredArgs[4], filteredArgs[5]); + } + else + { + MainConsole.Instance.OutputFormat("ERROR: Cannot specify a user name when setting default logging level"); + return; + } + } - if (args.Length > 3) + if (filteredArgs.Count > 3) { int newDebug; - if (int.TryParse(args[3], out newDebug)) + if (int.TryParse(filteredArgs[3], out newDebug)) { - m_scene.ForEachScenePresence(sp => + if (setAsDefaultLevel) + { + DefaultClientPacketDebugLevel = newDebug; + MainConsole.Instance.OutputFormat( + "Debug packet debug for new clients set to {0}", DefaultClientPacketDebugLevel); + } + else { - if (name == null || sp.Name == name) + m_scene.ForEachScenePresence(sp => { - m_log.DebugFormat( - "Packet debug for {0} ({1}) set to {2} in {3}", - sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); - - sp.ControllingClient.DebugPacketLevel = newDebug; - } - }); + if (name == null || sp.Name == name) + { + MainConsole.Instance.OutputFormat( + "Packet debug for {0} ({1}) set to {2} in {3}", + sp.Name, sp.IsChildAgent ? "child" : "root", newDebug, m_scene.Name); + + sp.ControllingClient.DebugPacketLevel = newDebug; + } + }); + } } else { - MainConsole.Instance.Output("Usage: debug lludp packet 0..255 [ ]"); + MainConsole.Instance.Output("Usage: debug lludp packet [--default] 0..255 [ ]"); } } } @@ -687,6 +718,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled"); MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off"); + + MainConsole.Instance.OutputFormat( + "Packet debug level for new clients is {0}", DefaultClientPacketDebugLevel); } public bool HandlesRegion(Location x) @@ -1533,6 +1567,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); client.OnLogout += LogoutHandler; + client.DebugPacketLevel = DefaultClientPacketDebugLevel; ((LLClientView)client).DisableFacelights = m_disableFacelights; diff --git a/prebuild.xml b/prebuild.xml index 4cf3b83..3337894 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1482,6 +1482,7 @@ + -- cgit v1.1 From 068a3afad9b585399e5422108f8c5074c9e6b33f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 09:51:31 -0700 Subject: HG Friends: migration #3 is failing on some installations of MySql. Setting the table to InnoDB seems to fix the problem. --- OpenSim/Data/MySQL/Resources/FriendsStore.migrations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Data/MySQL/Resources/FriendsStore.migrations b/OpenSim/Data/MySQL/Resources/FriendsStore.migrations index 55d82ec..5faf956 100644 --- a/OpenSim/Data/MySQL/Resources/FriendsStore.migrations +++ b/OpenSim/Data/MySQL/Resources/FriendsStore.migrations @@ -9,7 +9,7 @@ CREATE TABLE `Friends` ( `Offered` VARCHAR(32) NOT NULL DEFAULT 0, PRIMARY KEY(`PrincipalID`, `Friend`), KEY(`PrincipalID`) -); +) ENGINE=InnoDB; COMMIT; -- cgit v1.1 From 98a2fa8e358a6a008eea28161e48e4bfc877e11e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 10:23:20 -0700 Subject: HG Friends: this was commented some commits ago, but it shouldn't have been. --- .../CoreModules/Avatar/Friends/HGFriendsModule.cs | 49 +++++++++++----------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index ae45b99..6d1fd1f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -348,31 +348,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return null; } -// public override FriendInfo[] GetFriendsFromService(IClientAPI client) -// { -//// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); -// Boolean agentIsLocal = true; -// if (UserManagementModule != null) -// agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); - -// if (agentIsLocal) -// return base.GetFriendsFromService(client); - -// FriendInfo[] finfos = new FriendInfo[0]; -// // Foreigner -// AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); -// if (agentClientCircuit != null) -// { -// //[XXX] string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); - -// finfos = FriendsService.GetFriends(client.AgentId.ToString()); -// m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); -// } - -//// m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); - -// return finfos; -// } + public override FriendInfo[] GetFriendsFromService(IClientAPI client) + { + // m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); + Boolean agentIsLocal = true; + if (UserManagementModule != null) + agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); + + if (agentIsLocal) + return base.GetFriendsFromService(client); + + FriendInfo[] finfos = new FriendInfo[0]; + // Foreigner + AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); + if (agentClientCircuit != null) + { + // Note that this is calling a different interface than base; this one calls with a string param! + finfos = FriendsService.GetFriends(client.AgentId.ToString()); + m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); + } + + // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); + + return finfos; + } protected override bool StoreRights(UUID agentID, UUID friendID, int rights) { -- cgit v1.1 From ae42c93f9a2c7df4e7c14896df27544f283c8114 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 10:59:21 -0700 Subject: Now trying to find a cause of freeze at login related to friends status notifications. --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 41ea2a2..bc501b7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -526,8 +526,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (friendSession.RegionID != UUID.Zero) { GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); - //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); - m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); + if (region != null) + { + m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); + m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); + } } } } -- cgit v1.1 From 0cc0a2485c6502df096b9070ff0c8e5584dae2fd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 11:18:05 -0700 Subject: More debug related to the previous commit --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index bc501b7..16a2b9b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -526,9 +526,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (friendSession.RegionID != UUID.Zero) { GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); + m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", (region == null ? "null" : region.RegionName)); if (region != null) { - m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); } } -- cgit v1.1 From ec9ffbb89a8925cebae29d9950475eaa1b280de4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 11:36:10 -0700 Subject: More debug, same issue --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 6 ++++-- .../Framework/InventoryAccess/HGInventoryAccessModule.cs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 16a2b9b..ea69abb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -523,15 +523,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends foreach (PresenceInfo friendSession in friendSessions) { // let's guard against sessions-gone-bad - if (friendSession.RegionID != UUID.Zero) + if (friendSession != null && friendSession.RegionID != UUID.Zero) { + m_log.DebugFormat("[FRIENDS]: Get region {0}", friendSession.RegionID); GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); - m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", (region == null ? "null" : region.RegionName)); if (region != null) { m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); } } + else + m_log.DebugFormat("[FRIENDS]: friend session is null or the region is UUID.Zero"); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 64d5f61..1eae0ac 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -244,7 +244,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { - m_log.DebugFormat("[HGScene] RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); + m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); //if (fromTaskID.Equals(UUID.Zero)) //{ -- cgit v1.1 From bf214122cddf62b46d6074755b08a3b0acef853f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 11:53:22 -0700 Subject: More debug, same issue --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 2 ++ OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index ea69abb..6d4c65d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -498,6 +498,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected virtual void StatusNotify(List friendList, UUID userID, bool online) { + m_log.DebugFormat("[FRIENDS]: Entering StatusNotify for {0}", userID); + List friendStringIds = friendList.ConvertAll(friend => friend.Friend); List remoteFriendStringIds = new List(); foreach (string friendStringId in friendStringIds) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index 6d1fd1f..a456009 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -252,7 +252,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected override void StatusNotify(List friendList, UUID userID, bool online) { -// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); + m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); // First, let's divide the friends on a per-domain basis Dictionary> friendsPerDomain = new Dictionary>(); -- cgit v1.1 From fdafc2a16c3c661231d47f0c979438f2500ec131 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 4 Jul 2013 20:39:16 +0100 Subject: With diva's permission, temporarily reinsert Unknown UserUMMAU3 to make sure that GUN7 failure has largely disappeared. Unknown UserUMMAU3 insertion should definitely be removed down the line. However, I would like a little more time to check the GUN* reduction first, since removing UMMAU3 will make these failures appear as GUN7 instead. Also bumps GUN6 -> GUN7 and UMMAU2 -> UMMAU3 --- .../UserManagement/UserManagementModule.cs | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index e19631e..461c385 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -135,7 +135,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); } - void EventManager_OnNewClient(IClientAPI client) { client.OnConnectionClosed += new Action(HandleConnectionClosed); @@ -151,6 +150,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client) { +// m_log.DebugFormat( +// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", +// uuid, remote_client.Name); + if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) { remote_client.SendNameReply(uuid, "Mr", "OpenSim"); @@ -338,10 +341,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); } else - m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found {0}", uuid); + { + m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); + } names[0] = "Unknown"; - names[1] = "UserUMMTGUN6"; + names[1] = "UserUMMTGUN7"; return false; } @@ -553,12 +558,18 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } if (parts.Length >= 2) user.FirstName = parts[1].Replace(' ', '.'); - - AddUserInternal(user); - } - // else don't add the user to the cache, period. + else + { + // Temporarily add unknown user entries of this type into the cache so that we can distinguish + // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding + // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or + // disappeared. + user.FirstName = "Unknown"; + user.LastName = "UserUMMAU3"; + } + AddUserInternal(user); } } -- cgit v1.1 From ca380ec0397b28a3d7a3f2c60aeb6eaf1153be31 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 12:41:45 -0700 Subject: Same freeze issue, now checking if it's in estate --- OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs index 73e706c..d23e51a 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -130,6 +130,7 @@ namespace OpenSim.Region.CoreModules.World.Estate private void SendToEstate(uint EstateID, Dictionary sendData) { + m_log.DebugFormat("[XESTATE CONNECTOR]: SendToEstate"); List regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); UUID ScopeID = UUID.Zero; -- cgit v1.1 From 38a04ff993052980a2dfbfbdbe0d2853e2d8950e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 13:00:06 -0700 Subject: Revert "Same freeze issue, now checking if it's in estate" This reverts commit ca380ec0397b28a3d7a3f2c60aeb6eaf1153be31. --- OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs index d23e51a..73e706c 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs @@ -130,7 +130,6 @@ namespace OpenSim.Region.CoreModules.World.Estate private void SendToEstate(uint EstateID, Dictionary sendData) { - m_log.DebugFormat("[XESTATE CONNECTOR]: SendToEstate"); List regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); UUID ScopeID = UUID.Zero; -- cgit v1.1 From c95a23863ab51810ccc01afd3dd641c18a183305 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 13:13:52 -0700 Subject: WARNING: BRUTE FORCE DEBUG. AVOID USING THIS COMMIT. --- OpenSim/Framework/WebUtil.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 6fb1e0c..ece3129 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -1061,6 +1061,7 @@ namespace OpenSim.Framework int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > WebUtil.LongCallTime) + { m_log.InfoFormat( "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", reqnum, @@ -1069,6 +1070,9 @@ namespace OpenSim.Framework tickdiff, tickdata, obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); + Util.PrintCallStack(); + + } else if (WebUtil.DebugLevel >= 4) m_log.DebugFormat( "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", -- cgit v1.1 From 33ddb6c246e7a3b8670b759e0799884520b12e9d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 13:25:58 -0700 Subject: Revert "WARNING: BRUTE FORCE DEBUG. AVOID USING THIS COMMIT." This reverts commit c95a23863ab51810ccc01afd3dd641c18a183305. --- OpenSim/Framework/WebUtil.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index ece3129..6fb1e0c 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -1061,7 +1061,6 @@ namespace OpenSim.Framework int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > WebUtil.LongCallTime) - { m_log.InfoFormat( "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", reqnum, @@ -1070,9 +1069,6 @@ namespace OpenSim.Framework tickdiff, tickdata, obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); - Util.PrintCallStack(); - - } else if (WebUtil.DebugLevel >= 4) m_log.DebugFormat( "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", -- cgit v1.1 From da3aa441388e589ffcd7a667aadc260f8084854f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 13:27:53 -0700 Subject: Debug the RegionHandle handler (same issue) --- OpenSim/Region/Framework/Scenes/Scene.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a9f8a85..aa14529 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4889,6 +4889,7 @@ namespace OpenSim.Region.Framework.Scenes public void RegionHandleRequest(IClientAPI client, UUID regionID) { + m_log.DebugFormat("[SCENE]: RegionHandleRequest {0}", regionID); ulong handle = 0; if (regionID == RegionInfo.RegionID) handle = RegionInfo.RegionHandle; -- cgit v1.1 From d80936bbbb85280623478f3a25d59a4a4da9c3e6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 14:07:25 -0700 Subject: Guard against completely unknown user UUIDs. --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 461c385..a7cbc8f 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -332,10 +332,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement { AddUser(uuid, first, last, url); - names[0] = m_UserCache[uuid].FirstName; - names[1] = m_UserCache[uuid].LastName; + if (m_UserCache.ContainsKey(uuid)) + { + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; - return true; + return true; + } } else m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); -- cgit v1.1 From f2f33b75776539560e1dbfec12a6559f5b4be05e Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 4 Jul 2013 17:45:17 -0400 Subject: Some consistency fixes for the ini to stop parser breakage --- bin/OpenSim.ini.example | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 3015c08..1c53935 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -268,7 +268,7 @@ ; AllowedClients = ;# {BannedClients} {} {Bar (|) separated list of banned clients} {} - ;# Bar (|) separated list of viewers which may not gain access to the regions. + ;; Bar (|) separated list of viewers which may not gain access to the regions. ;; One can use a Substring of the viewer name to disable only certain ;; versions ;; Example: Agent uses the viewer "Imprudence 1.3.2.0" @@ -287,7 +287,7 @@ ;; both to set this to false and comment out the [Modules] MapImageServiceModule setting in config-include/ ; GenerateMaptiles = true - ;# {MapImageModule} [] {The map image module to use} {MapImageModule Warp3DImageModule} MapImageModule + ;# {MapImageModule} {} {The map image module to use} {MapImageModule Warp3DImageModule} MapImageModule ;; 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. @@ -474,7 +474,10 @@ ;# {XmlRpcPort} {} {Port for incoming llRemoteData xmlrpc calls} {} 20800 ;XmlRpcPort = 20800 - ;# {XmlRpcHubURI} {XmlRpcRouterModule} {URI for external service used to register xmlrpc channels created in the simulator. This depends on XmlRpcRouterModule being set to XmlRpcGridRouterModule} http://example.com + +;; {option} {depends on} {question to ask} {choices} default value + + ;# {XmlRpcHubURI} {XmlRpcRouterModule} {URI for external service used to register xmlrpc channels created in the simulator. This depends on XmlRpcRouterModule being set to XmlRpcGridRouterModule} {} http://example.com ;; If XmlRpcRouterModule is set to XmlRpcGridRouterModule, the simulator ;; will use this address to register xmlrpc channels on the external ;; service @@ -538,7 +541,7 @@ ;; Distance in meters that ordinary chat should travel. ; say_distance = 20 - ;# {shout_distance} {Distance at which a shout is heard, in meters?} {} 100 + ;# {shout_distance} {} {Distance at which a shout is heard, in meters?} {} 100 ;; Distance in meters that shouts should travel. ; shout_distance = 100 @@ -613,7 +616,8 @@ ;; the "password" parameter) ; access_password = "" - ;# List the IP addresses allowed to call RemoteAdmin + ;# {access_ip_addresses} {enabled:true} {List the IP addresses allowed to call RemoteAdmin?} {} + ;; List the IP addresses allowed to call RemoteAdmin ;; If access_ip_addresses isn't set, then all IP addresses can access RemoteAdmin. ;; access_ip_addresses = 0.0.0.0, 0.0.0.0 ... ; access_ip_addresses = @@ -798,7 +802,7 @@ ; ScriptStopStrategy = abort - ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} (true false) true + ;# {DeleteScriptsOnStartup} {} {Delete previously compiled script DLLs on startup?} {true false} true ;; Controls whether previously compiled scripts DLLs are deleted on sim restart. If you set this to false ;; then startup will be considerably faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the ;; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used -- cgit v1.1 From 8265a88c4a4b1c18f1bc0accfde250fe47b08c50 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 14:51:18 -0700 Subject: Throttle the viewer's requests for region handles. Apparently Kokua is requesting this for all landmarks in inventory. Not sure why. But this seems to be the root cause of the login freeze mentioned before. This commit adds a blocking queue / process thread pattern. --- .../GridServiceThrottleModule.cs | 161 +++++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 18 --- 2 files changed, 161 insertions(+), 18 deletions(-) create mode 100644 OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs new file mode 100644 index 0000000..5511fea --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -0,0 +1,161 @@ +/* + * 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.Reflection; +using System.Threading; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.Framework.Scenes; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Region.CoreModules.Framework +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")] + public class GridServiceThrottleModule : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private readonly List m_scenes = new List(); + + private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + + public void Initialise(IConfigSource config) + { + Watchdog.StartThread( + ProcessQueue, + "GridServiceRequestThread", + ThreadPriority.BelowNormal, + true, + true); + } + + public void AddRegion(Scene scene) + { + lock (m_scenes) + { + m_scenes.Add(scene); + scene.EventManager.OnNewClient += OnNewClient; + } + } + + public void RegionLoaded(Scene scene) + { + } + + public void RemoveRegion(Scene scene) + { + lock (m_scenes) + { + m_scenes.Remove(scene); + scene.EventManager.OnNewClient -= OnNewClient; + } + } + + void OnNewClient(IClientAPI client) + { + client.OnRegionHandleRequest += OnRegionHandleRequest; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "GridServiceThrottleModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void OnRegionHandleRequest(IClientAPI client, UUID regionID) + { + m_log.DebugFormat("[GRIDSERVICE THROTTLE]: RegionHandleRequest {0}", regionID); + ulong handle = 0; + if (IsLocalRegionHandle(regionID, out handle)) + { + client.SendRegionHandle(regionID, handle); + return; + } + + GridRegionRequest request = new GridRegionRequest(client, regionID); + m_RequestQueue.Enqueue(request); + + } + + 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 void ProcessQueue() + { + while (true) + { + GridRegionRequest request = m_RequestQueue.Dequeue(); + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + + if (r != null && r.RegionHandle != 0) + request.client.SendRegionHandle(request.regionID, r.RegionHandle); + + } + } + } + + class GridRegionRequest + { + public IClientAPI client; + public UUID regionID; + + public GridRegionRequest(IClientAPI c, UUID r) + { + client = c; + regionID = r; + } + } +} diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index aa14529..355e0ee 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3103,7 +3103,6 @@ namespace OpenSim.Region.Framework.Scenes { //client.OnNameFromUUIDRequest += HandleUUIDNameRequest; client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; - client.OnRegionHandleRequest += RegionHandleRequest; } public virtual void SubscribeToClientNetworkEvents(IClientAPI client) @@ -3227,7 +3226,6 @@ namespace OpenSim.Region.Framework.Scenes { //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest; client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest; - client.OnRegionHandleRequest -= RegionHandleRequest; } public virtual void UnSubscribeToClientNetworkEvents(IClientAPI client) @@ -4887,22 +4885,6 @@ namespace OpenSim.Region.Framework.Scenes #endregion - public void RegionHandleRequest(IClientAPI client, UUID regionID) - { - m_log.DebugFormat("[SCENE]: RegionHandleRequest {0}", regionID); - ulong handle = 0; - if (regionID == RegionInfo.RegionID) - handle = RegionInfo.RegionHandle; - else - { - GridRegion r = GridService.GetRegionByUUID(UUID.Zero, regionID); - if (r != null) - handle = r.RegionHandle; - } - - if (handle != 0) - client.SendRegionHandle(regionID, handle); - } // Commented pending deletion since this method no longer appears to do anything at all // public bool NeedSceneCacheClear(UUID agentID) -- cgit v1.1 From ca26583e6bfdc9aa62e917a736f52ed5fdac75cd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 4 Jul 2013 15:17:06 -0700 Subject: Delete some verbose debug messages --- OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 8 ++++---- OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | 2 +- .../Framework/GridServiceThrottle/GridServiceThrottleModule.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 6d4c65d..b693f2d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -498,7 +498,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected virtual void StatusNotify(List friendList, UUID userID, bool online) { - m_log.DebugFormat("[FRIENDS]: Entering StatusNotify for {0}", userID); + //m_log.DebugFormat("[FRIENDS]: Entering StatusNotify for {0}", userID); List friendStringIds = friendList.ConvertAll(friend => friend.Friend); List remoteFriendStringIds = new List(); @@ -527,15 +527,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // let's guard against sessions-gone-bad if (friendSession != null && friendSession.RegionID != UUID.Zero) { - m_log.DebugFormat("[FRIENDS]: Get region {0}", friendSession.RegionID); + //m_log.DebugFormat("[FRIENDS]: Get region {0}", friendSession.RegionID); GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); if (region != null) { m_FriendsSimConnector.StatusNotify(region, userID, friendSession.UserID, online); } } - else - m_log.DebugFormat("[FRIENDS]: friend session is null or the region is UUID.Zero"); + //else + // m_log.DebugFormat("[FRIENDS]: friend session is null or the region is UUID.Zero"); } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index a456009..d00945e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -252,7 +252,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected override void StatusNotify(List friendList, UUID userID, bool online) { - m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); + //m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); // First, let's divide the friends on a per-domain basis Dictionary> friendsPerDomain = new Dictionary>(); diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index 5511fea..a662731 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -108,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Framework public void OnRegionHandleRequest(IClientAPI client, UUID regionID) { - m_log.DebugFormat("[GRIDSERVICE THROTTLE]: RegionHandleRequest {0}", regionID); + //m_log.DebugFormat("[GRIDSERVICE THROTTLE]: RegionHandleRequest {0}", regionID); ulong handle = 0; if (IsLocalRegionHandle(regionID, out handle)) { -- cgit v1.1 From dd15f954997333e007dbdc81b8a2e0fcd4583aa2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 5 Jul 2013 20:06:27 +0100 Subject: Add very basic regression test TestChildAgentSingleRegionCapabilities() which checks for addition and removal of capabilities on add/remove of child agent --- .../Scenes/Tests/ScenePresenceCapabilityTests.cs | 88 ++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs new file mode 100644 index 0000000..5714042 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs @@ -0,0 +1,88 @@ +/* + * 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.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using Timer = System.Timers.Timer; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceCapabilityTests : OpenSimTestCase + { + [Test] + public void TestChildAgentSingleRegionCapabilities() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID spUuid = TestHelpers.ParseTail(0x1); + + // XXX: This is not great since the use of statics will mean that this has to be manually cleaned up for + // any subsequent test. + // XXX: May replace with a mock IHttpServer later. + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; + + CapabilitiesModule capsMod = new CapabilitiesModule(); + TestScene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, capsMod); + + ScenePresence sp = SceneHelpers.AddChildScenePresence(scene, spUuid); + Assert.That(capsMod.GetCapsForUser(spUuid), Is.Not.Null); + + // TODO: Need to add tests for other ICapabiltiesModule methods. + + scene.IncomingCloseAgent(sp.UUID, false); + Assert.That(capsMod.GetCapsForUser(spUuid), Is.Null); + + // TODO: Need to add tests for other ICapabiltiesModule methods. + } + } +} \ No newline at end of file -- cgit v1.1 From 5dbdd5f8b4856357340357394edc2f9e229a0582 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Jul 2013 00:12:48 +0100 Subject: refactor: Make stats and sim status simpler by extending BaseStreamHandler like other handlers instead of implementing the IStreamedRequestHandler interface directly --- OpenSim/Region/Application/OpenSimBase.cs | 74 +++++----------------- .../Region/Framework/Scenes/RegionStatsHandler.cs | 26 ++------ 2 files changed, 23 insertions(+), 77 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 7ca87a3..841069c 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -759,73 +759,49 @@ namespace OpenSim /// /// Handler to supply the current status of this sim /// + /// /// Currently this is always OK if the simulator is still listening for connections on its HTTP service - public class SimStatusHandler : IStreamedRequestHandler + /// + public class SimStatusHandler : BaseStreamHandler { - public byte[] Handle(string path, Stream request, + public SimStatusHandler() : base("GET", "/simstatus", "SimStatus", "Simulator Status") {} + + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes("OK"); } - public string Name { get { return "SimStatus"; } } - public string Description { get { return "Simulator Status"; } } - - public string ContentType + public override string ContentType { get { return "text/plain"; } } - - public string HttpMethod - { - get { return "GET"; } - } - - public string Path - { - get { return "/simstatus"; } - } } /// /// Handler to supply the current extended status of this sim /// Sends the statistical data in a json serialization /// - public class XSimStatusHandler : IStreamedRequestHandler + public class XSimStatusHandler : BaseStreamHandler { OpenSimBase m_opensim; - string osXStatsURI = String.Empty; - - public string Name { get { return "XSimStatus"; } } - public string Description { get { return "Simulator XStatus"; } } - public XSimStatusHandler(OpenSimBase sim) + public XSimStatusHandler(OpenSimBase sim) + : base("GET", "/" + Util.SHA1Hash(sim.osSecret), "XSimStatus", "Simulator XStatus") { m_opensim = sim; - osXStatsURI = Util.SHA1Hash(sim.osSecret); } - public byte[] Handle(string path, Stream request, + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest)); } - public string ContentType + public override string ContentType { get { return "text/plain"; } } - - public string HttpMethod - { - get { return "GET"; } - } - - public string Path - { - // This is for the OpenSimulator instance and is the osSecret hashed - get { return "/" + osXStatsURI; } - } } /// @@ -834,42 +810,26 @@ namespace OpenSim /// If the request contains a key, "callback" the response will be wrappend in the /// associated value for jsonp used with ajax/javascript /// - public class UXSimStatusHandler : IStreamedRequestHandler + public class UXSimStatusHandler : BaseStreamHandler { OpenSimBase m_opensim; - string osUXStatsURI = String.Empty; - - public string Name { get { return "UXSimStatus"; } } - public string Description { get { return "Simulator UXStatus"; } } public UXSimStatusHandler(OpenSimBase sim) + : base("GET", "/" + sim.userStatsURI, "UXSimStatus", "Simulator UXStatus") { - m_opensim = sim; - osUXStatsURI = sim.userStatsURI; - + m_opensim = sim; } - public byte[] Handle(string path, Stream request, + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest)); } - public string ContentType + public override string ContentType { get { return "text/plain"; } } - - public string HttpMethod - { - get { return "GET"; } - } - - public string Path - { - // This is for the OpenSimulator instance and is the user provided URI - get { return "/" + osUXStatsURI; } - } } #endregion diff --git a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs index c11174d..726becf 100644 --- a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs +++ b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs @@ -46,47 +46,33 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.Framework.Scenes { - public class RegionStatsHandler : IStreamedRequestHandler + public class RegionStatsHandler : BaseStreamHandler { //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private string osRXStatsURI = String.Empty; private string osXStatsURI = String.Empty; //private string osSecret = String.Empty; private OpenSim.Framework.RegionInfo regionInfo; public string localZone = TimeZone.CurrentTimeZone.StandardName; public TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now); - public string Name { get { return "RegionStats"; } } - public string Description { get { return "Region Statistics"; } } - - public RegionStatsHandler(RegionInfo region_info) + public RegionStatsHandler(RegionInfo region_info) + : base("GET", "/" + Util.SHA1Hash(region_info.regionSecret), "RegionStats", "Region Statistics") { regionInfo = region_info; - osRXStatsURI = Util.SHA1Hash(regionInfo.regionSecret); osXStatsURI = Util.SHA1Hash(regionInfo.osSecret); } - public byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + public override byte[] Handle( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes(Report()); } - public string ContentType + public override string ContentType { get { return "text/plain"; } } - - public string HttpMethod - { - get { return "GET"; } - } - - public string Path - { - // This is for the region and is the regionSecret hashed - get { return "/" + osRXStatsURI; } - } private string Report() { -- cgit v1.1 From 67407024a2e0b6e27f526cc2312e93fd867a855b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Jul 2013 00:29:19 +0100 Subject: Update thread watchdog on GridServiceRequestThread periodically and turn off alarming Unfortunately, alarm can spuriously go off if the thread blocks for a long time on an empty queue. --- .../Framework/GridServiceThrottle/GridServiceThrottleModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index a662731..f1eb1ad 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.CoreModules.Framework "GridServiceRequestThread", ThreadPriority.BelowNormal, true, - true); + false); } public void AddRegion(Scene scene) @@ -137,6 +137,8 @@ namespace OpenSim.Region.CoreModules.Framework { while (true) { + Watchdog.UpdateThread(); + GridRegionRequest request = m_RequestQueue.Dequeue(); GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); -- cgit v1.1 From a44ad0149213887b284b3fe65b9bddb0b63abff6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Jul 2013 00:32:11 +0100 Subject: Fix build break from recent commit dd15f95 on windows --- prebuild.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/prebuild.xml b/prebuild.xml index 3337894..74cfcb0 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2965,6 +2965,7 @@ + -- cgit v1.1 From 55ac8c83c78d3b8d5fd027174328171849f8d1e2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Jul 2013 00:34:22 +0100 Subject: Get InventoryWorkerThreads to update watchdog on processing requests --- OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 0e3cd6b..b90df17 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -347,6 +347,8 @@ namespace OpenSim.Region.ClientStack.Linden { while (true) { + Watchdog.UpdateThread(); + aPollRequest poolreq = m_queue.Dequeue(); poolreq.thepoll.Process(poolreq); -- cgit v1.1 From ccceb6d6d2d2359797b78b78f8057b57a6cd8bb4 Mon Sep 17 00:00:00 2001 From: justincc Date: Sat, 6 Jul 2013 00:52:54 +0100 Subject: Fix windows build break fromrecent dd1f95 for real this time - put new dll reference in the wrong place --- prebuild.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prebuild.xml b/prebuild.xml index 74cfcb0..d9e32ea 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2965,7 +2965,6 @@ - @@ -3197,6 +3196,7 @@ + -- cgit v1.1 From 98de67d57316a20fc813db853d6175fb8d8783ef Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 6 Jul 2013 00:55:14 +0100 Subject: Fix mono warning in LLImageManagerTests --- OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index a0e0078..83144e3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs @@ -73,7 +73,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests } [SetUp] - public void SetUp() + public override void SetUp() { base.SetUp(); -- cgit v1.1 From c358d5d168f349cbfbb10c1c4f1e992830b11fa4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 5 Jul 2013 20:17:10 -0700 Subject: Changed a few bits in Inventory/Archiver/InventoryArchiveReadRequest.cs to be less dependent on a Scene. --- .../Archiver/InventoryArchiveReadRequest.cs | 32 ++++++++++++---------- .../Inventory/Archiver/InventoryArchiverModule.cs | 4 +-- .../Tests/InventoryArchiveLoadPathTests.cs | 12 ++++---- .../Archiver/Tests/InventoryArchiveSaveTests.cs | 2 +- .../CoreModules/Framework/Library/LibraryModule.cs | 4 +-- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 98285e9..31c42d8 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs @@ -67,10 +67,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver ///
protected bool m_merge; - /// - /// We only use this to request modules - /// - protected Scene m_scene; + protected IInventoryService m_InventoryService; + protected IAssetService m_AssetService; + protected IUserAccountService m_UserAccountService; /// /// The stream from which the inventory archive will be loaded. @@ -118,9 +117,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver protected Dictionary m_creatorIdForAssetId = new Dictionary(); public InventoryArchiveReadRequest( - Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge) + IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, string loadPath, bool merge) : this( - scene, + inv, + assets, + uacc, userInfo, invPath, new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress), @@ -129,9 +130,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } public InventoryArchiveReadRequest( - Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge) + IInventoryService inv, IAssetService assets, IUserAccountService uacc, UserAccount userInfo, string invPath, Stream loadStream, bool merge) { - m_scene = scene; + m_InventoryService = inv; + m_AssetService = assets; + m_UserAccountService = uacc; m_merge = merge; m_userInfo = userInfo; m_invPath = invPath; @@ -162,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver List folderCandidates = InventoryArchiveUtils.FindFoldersByPath( - m_scene.InventoryService, m_userInfo.PrincipalID, m_invPath); + m_InventoryService, m_userInfo.PrincipalID, m_invPath); if (folderCandidates.Count == 0) { @@ -297,7 +300,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); List folderCandidates = InventoryArchiveUtils.FindFoldersByPath( - m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); + m_InventoryService, m_userInfo.PrincipalID, plainPath); if (folderCandidates.Count != 0) { @@ -380,7 +383,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver = new InventoryFolderBase( newFolderId, newFolderName, m_userInfo.PrincipalID, (short)AssetType.Unknown, destFolder.ID, 1); - m_scene.InventoryService.AddFolder(destFolder); + m_InventoryService.AddFolder(destFolder); // Record that we have now created this folder iarPathExisting += rawDirsToCreate[i] + "/"; @@ -406,7 +409,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // Don't use the item ID that's in the file item.ID = UUID.Random(); - UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_scene.UserAccountService); + UUID ospResolvedId = OspResolver.ResolveOspa(item.CreatorId, m_UserAccountService); if (UUID.Zero != ospResolvedId) // The user exists in this grid { // m_log.DebugFormat("[INVENTORY ARCHIVER]: Found creator {0} via OSPA resolution", ospResolvedId); @@ -436,7 +439,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // relying on native tar tools. m_creatorIdForAssetId[item.AssetID] = item.CreatorIdAsUuid; - m_scene.AddInventoryItem(item); + if (!m_InventoryService.AddItem(item)) + m_log.WarnFormat("[INVENTORY ARCHIVER]: Unable to save item {0} in folder {1}", item.Name, item.Folder); return item; } @@ -533,7 +537,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); asset.Data = data; - m_scene.AssetService.Store(asset); + m_AssetService.Store(asset); return true; } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index 849449b..797097f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs @@ -294,7 +294,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver try { - request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge); + request = new InventoryArchiveReadRequest(m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge); } catch (EntryPointNotFoundException e) { @@ -342,7 +342,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver try { - request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge); + request = new InventoryArchiveReadRequest(m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge); } catch (EntryPointNotFoundException e) { diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs index 95f562e..08f199a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveLoadPathTests.cs @@ -229,7 +229,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { // Test replication of path1 - new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) + new InventoryArchiveReadRequest(scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) .ReplicateArchivePathToUserInventory( iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), foldersCreated, nodesLoaded); @@ -246,7 +246,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { // Test replication of path2 - new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) + new InventoryArchiveReadRequest(scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) .ReplicateArchivePathToUserInventory( iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), foldersCreated, nodesLoaded); @@ -291,8 +291,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); - - new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) + + new InventoryArchiveReadRequest(scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, null, (Stream)null, false) .ReplicateArchivePathToUserInventory( itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), new Dictionary(), new HashSet()); @@ -342,8 +342,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); - - new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true) + + new InventoryArchiveReadRequest(scene.InventoryService, scene.AssetService, scene.UserAccountService, ua1, folder1ExistingName, (Stream)null, true) .ReplicateArchivePathToUserInventory( itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), new Dictionary(), new HashSet()); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs index 5e7e24c..b85739e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveSaveTests.cs @@ -86,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); InventoryArchiveReadRequest iarr - = new InventoryArchiveReadRequest(null, null, null, (Stream)null, false); + = new InventoryArchiveReadRequest(null, null, null, null, null, (Stream)null, false); iarr.LoadControlFile(filePath, data); Assert.That(iarr.ControlFileLoaded, Is.True); diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index d07cff4..69d7e16 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs @@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); simpleName = GetInventoryPathFromName(simpleName); - InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false); + InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, simpleName, iarFileName, false); try { HashSet nodes = archread.Execute(); @@ -185,7 +185,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library // didn't find the subfolder with the given name; place it on the top m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); archread.Close(); - archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); + archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, "/", iarFileName, false); archread.Execute(); } -- cgit v1.1 From 5f97c6f8f06f0b90ab815a1d44358dc256ec5a50 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 4 Jul 2013 12:16:33 -0700 Subject: BulletSim: non-functional updates. Comments and formatting. Update TODO list. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 14 +++- OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 15 +++-- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 6 +- .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 75 +++++++++++++--------- 4 files changed, 67 insertions(+), 43 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index aa247dd..c27d3f0 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -774,7 +774,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Since the computation of terrain height can be a little involved, this routine // is used to fetch the height only once for each vehicle simulation step. - Vector3 lastRememberedHeightPos; + Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1); private float GetTerrainHeight(Vector3 pos) { if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) @@ -788,14 +788,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Since the computation of water level can be a little involved, this routine // is used ot fetch the level only once for each vehicle simulation step. + Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1); private float GetWaterLevel(Vector3 pos) { - if ((m_knownHas & m_knownChangedWaterLevel) == 0) + if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos) { + lastRememberedWaterHeightPos = pos; m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); m_knownHas |= m_knownChangedWaterLevel; } - return (float)m_knownWaterLevel; + return m_knownWaterLevel; } private Vector3 VehiclePosition @@ -991,11 +993,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin { Vector3 vel = VehicleVelocity; if ((m_flags & (VehicleFlag.NO_X)) != 0) + { vel.X = 0; + } if ((m_flags & (VehicleFlag.NO_Y)) != 0) + { vel.Y = 0; + } if ((m_flags & (VehicleFlag.NO_Z)) != 0) + { vel.Z = 0; + } VehicleVelocity = vel; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 1214703..7693195 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -188,6 +188,8 @@ public class BSVMotor : BSMotor CurrentValue = current; return Step(timeStep); } + // Given and error, computer a correction for this step. + // Simple scaling of the error by the timestep. public virtual Vector3 StepError(float timeStep, Vector3 error) { if (!Enabled) return Vector3.Zero; @@ -221,7 +223,7 @@ public class BSVMotor : BSMotor CurrentValue, TargetValue); LastError = BSMotor.InfiniteVector; - while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) + while (maxOutput-- > 0 && !ErrorIsZero()) { Vector3 lastStep = Step(timeStep); MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", @@ -375,7 +377,6 @@ public class BSPIDVMotor : BSVMotor // The factors are vectors for the three dimensions. This is the proportional of each // that is applied. This could be multiplied through the actual factors but it // is sometimes easier to manipulate the factors and their mix separately. - // to public Vector3 FactorMix; // Arbritrary factor range. @@ -413,14 +414,14 @@ public class BSPIDVMotor : BSVMotor // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. // If efficiency is low (0f), use a factor value that overcorrects. // TODO: might want to vary contribution of different factor depending on efficiency. - float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; - // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; + // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; + float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; proportionFactor = new Vector3(factor, factor, factor); integralFactor = new Vector3(factor, factor, factor); derivFactor = new Vector3(factor, factor, factor); - MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); + MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); } } @@ -441,8 +442,8 @@ public class BSPIDVMotor : BSVMotor + derivitive / TimeScale * derivFactor * FactorMix.Z ; - MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", - BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret); + MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}", + BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret); return ret; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index b2947c6..f0858ca 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -1125,7 +1125,9 @@ public class BSPrim : BSPhysObject OMV.Vector3 addForce = force; PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() { - // Bullet adds this central force to the total force for this tick + // Bullet adds this central force to the total force for this tick. + // Deep down in Bullet: + // linearVelocity += totalForce / mass * timeStep; DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); if (PhysBody.HasPhysicalBody) { @@ -1493,6 +1495,8 @@ public class BSPrim : BSPhysObject returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); + DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}", + LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size); return returnMass; }// end CalculateMass diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 4357ef1..0453376 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -3,25 +3,21 @@ CURRENT PROBLEMS TO FIX AND/OR LOOK AT Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass. Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive? Negative buoyancy computed correctly +Center-of-gravity Computation of mesh mass. How done? How should it be done? -Script changing rotation of child prim while vehicle moving (eg turning wheel) causes - the wheel to appear to jump back. Looks like sending position from previous update. Enable vehicle border crossings (at least as poorly as ODE) Terrain skirts Avatar created in previous region and not new region when crossing border Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) +User settable terrain mesh + Allow specifying as convex or concave and use different getHeight functions depending +Boats, when turning nose down into the water + Acts like rotation around Z is also effecting rotation around X and Y Deleting a linkset while standing on the root will leave the physical shape of the root behind. Not sure if it is because standing on it. Done with large prim linksets. Linkset child rotations. Nebadon spiral tube has middle sections which are rotated wrong. Select linked spiral tube. Delink and note where the middle section ends up. -Refarb compound linkset creation to create a pseudo-root for center-of-mass - Let children change their shape to physical indendently and just add shapes to compound -Vehicle angular vertical attraction -vehicle angular banking -Center-of-gravity -Vehicle angular deflection - Preferred orientation angular correction fix Teravus llMoveToTarget script debug Mixing of hover, buoyancy/gravity, moveToTarget, into one force Setting hover height to zero disables hover even if hover flags are on (from SL wiki) @@ -33,10 +29,16 @@ Vehicle script tuning/debugging Avanti speed script Weapon shooter script Move material definitions (friction, ...) into simulator. +osGetPhysicsEngineVerion() and create a version code for the C++ DLL One sided meshes? Should terrain be built into a closed shape? When meshes get partially wedged into the terrain, they cannot push themselves out. It is possible that Bullet processes collisions whether entering or leaving a mesh. Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869 +Small physical objects do not interact correctly + Create chain of .5x.5x.1 torui and make all but top physical so to hang. + The chain will fall apart and pairs will dance around on ground + Chains of 1x1x.2 will stay connected but will dance. + Chains above 2x2x.4 are more stable and get stablier as torui get larger. VEHICLES TODO LIST: ================================================= @@ -45,14 +47,12 @@ LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. Same for other velocity settings. UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: https://github.com/UbitUmarov/Ubit-opensim -Vehicles (Move smoothly) Some vehicles should not be able to turn if no speed or off ground. Cannot edit/move a vehicle being ridden: it jumps back to the origional position. Neb car jiggling left and right Happens on terrain and any other mesh object. Flat cubes are much smoother. This has been reduced but not eliminated. Implement referenceFrame for all the motion routines. -For limitMotorUp, use raycast down to find if vehicle is in the air. Verify llGetVel() is returning a smooth and good value for vehicle movement. llGetVel() should return the root's velocity if requested in a child prim. Implement function efficiency for lineaar and angular motion. @@ -93,29 +93,15 @@ Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. Duplicating a physical prim causes old prim to jump away Dup a phys prim and the original become unselected and thus interacts w/ selected prim. Scenes with hundred of thousands of static objects take a lot of physics CPU time. -BSPrim.Force should set a continious force on the prim. The force should be - applied each tick. Some limits? Gun sending shooter flying. Collision margin (gap between physical objects lying on each other) Boundry checking (crashes related to crossing boundry) Add check for border edge position for avatars and objects. Verify the events are created for border crossings. -Avatar rotation (check out changes to ScenePresence for physical rotation) -Avatar running (what does phys engine need to do?) -Small physical objects do not interact correctly - Create chain of .5x.5x.1 torui and make all but top physical so to hang. - The chain will fall apart and pairs will dance around on ground - Chains of 1x1x.2 will stay connected but will dance. - Chains above 2x2x.4 are more stable and get stablier as torui get larger. -Add PID motor for avatar movement (slow to stop, ...) -setForce should set a constant force. Different than AddImpulse. -Implement raycast. Implement ShapeCollection.Dispose() -Implement water as a plain so raycasting and collisions can happen with same. +Implement water as a plain or mesh so raycasting and collisions can happen with same. Add collision penetration return Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance() -Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE - Also osGetPhysicsEngineVerion() maybe. Linkset.Position and Linkset.Orientation requre rewrite to properly return child position. LinksetConstraint acts like it's at taint time!! Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) @@ -127,9 +113,6 @@ Selecting and deselecting physical objects causes CPU processing time to jump Re-implement buoyancy as a separate force on the object rather than diddling gravity. Register a pre-step event to add the force. More efficient memory usage when passing hull information from BSPrim to BulletSim -Avatar movement motor check for zero or small movement. Somehow suppress small movements - when avatar has stopped and is just standing. Simple test for near zero has - the problem of preventing starting up (increase from zero) especially when falling. Physical and phantom will drop through the terrain @@ -172,7 +155,6 @@ Do we need to do convex hulls all the time? Can complex meshes be left meshes? There is some problem with meshes and collisions Hulls are not as detailed as meshes. Hulled vehicles insides are different shape. Debounce avatar contact so legs don't keep folding up when standing. -Implement LSL physics controls. Like STATUS_ROTATE_X. Add border extensions to terrain to help region crossings and objects leaving region. Use a different capsule shape for avatar when sitting LL uses a pyrimidal shape scaled by the avatar's bounding box @@ -205,8 +187,6 @@ Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale INTERNAL IMPROVEMENT/CLEANUP ================================================= -Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to - BSScene.TaintedObject() could immediately execute the callback if already in taint time. Create the physical wrapper classes (BulletBody, BulletShape) by methods on BSAPITemplate and make their actual implementation Bullet engine specific. For the short term, just call the existing functions in ShapeCollection. @@ -365,4 +345,35 @@ After getting off a vehicle, the root prim is phantom (can be walked through) Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. Regular triangle meshes don't do physical collisions. (DONE: discovered GImpact is VERY CPU intensive) +Script changing rotation of child prim while vehicle moving (eg turning wheel) causes + the wheel to appear to jump back. Looks like sending position from previous update. + (DONE: redo of compound linksets fixed problem) +Refarb compound linkset creation to create a pseudo-root for center-of-mass + Let children change their shape to physical indendently and just add shapes to compound + (DONE: redo of compound linkset fixed problem) +Vehicle angular vertical attraction (DONE: vegaslon code) +vehicle angular banking (DONE: vegaslon code) +Vehicle angular deflection (DONE: vegaslon code) + Preferred orientation angular correction fix +Vehicles (Move smoothly) +For limitMotorUp, use raycast down to find if vehicle is in the air. + (WILL NOT BE DONE: gravity does the job well enough) +BSPrim.Force should set a continious force on the prim. The force should be + applied each tick. Some limits? + (DONE: added physical actors. Implemented SetForce, SetTorque, ...) +Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE) +Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE +Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE) +Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force) +setForce should set a constant force. Different than AddImpulse. (DONE) +Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok) +Avatar movement motor check for zero or small movement. Somehow suppress small movements + when avatar has stopped and is just standing. Simple test for near zero has + the problem of preventing starting up (increase from zero) especially when falling. + (DONE: avatar movement actor knows if standing on stationary object and zeros motion) +Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to + BSScene.TaintedObject() could immediately execute the callback if already in taint time. + (DONE) + + -- cgit v1.1 From 03268d85c41c94e7b35802b9dea1ce08299e5426 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 2 Jun 2013 10:04:15 -0700 Subject: BulletSim: comments and non-functional changes working toward the center-of-gravity implementation. --- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 11 +++++---- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 +++ .../Physics/BulletSPlugin/BSPrimDisplaced.cs | 26 +++++++++++++--------- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 19 ++++++++++++---- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 308cf13..30f6c8c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -315,7 +315,6 @@ public sealed class BSLinksetCompound : BSLinkset // Note that this works for rebuilding just the root after a linkset is taken apart. // Called at taint time!! private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape - private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting private void RecomputeLinksetCompound() { try @@ -331,9 +330,7 @@ public sealed class BSLinksetCompound : BSLinkset // There is no reason to build all this physical stuff for a non-physical linkset. if (!LinksetRoot.IsPhysicallyActive) { - // Clean up any old linkset shape and make sure the root shape is set to the root object. DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); - return; // Note the 'finally' clause at the botton which will get executed. } @@ -347,9 +344,9 @@ public sealed class BSLinksetCompound : BSLinkset OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); - // 'centerDisplacement' is the value to subtract from children to give physical offset position + // 'centerDisplacementV' is the value to subtract from children to give physical offset position OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; - if (UseBulletSimRootOffsetHack || disableCOM) + if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) { centerDisplacementV = OMV.Vector3.Zero; LinksetRoot.ClearDisplacement(); @@ -357,6 +354,8 @@ public sealed class BSLinksetCompound : BSLinkset else { LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); + // The actual center-of-mass could have been set by the user. + centerDisplacementV = LinksetRoot.PositionDisplacement; } DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV); @@ -409,7 +408,7 @@ public sealed class BSLinksetCompound : BSLinkset { // Enable the physical position updator to return the position and rotation of the root shape. // This enables a feature in the C++ code to return the world coordinates of the first shape in the - // compound shape. This eleviates the need to offset the returned physical position by the + // compound shape. This aleviates the need to offset the returned physical position by the // center-of-mass offset. m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index d17c8e7..0f84bf7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -176,6 +176,7 @@ public static class BSParam // Linkset implementation parameters public static float LinksetImplementation { get; private set; } + public static bool LinksetOffsetCenterOfMass { get; private set; } public static bool LinkConstraintUseFrameOffset { get; private set; } public static bool LinkConstraintEnableTransMotor { get; private set; } public static float LinkConstraintTransMotorMaxVel { get; private set; } @@ -684,6 +685,8 @@ public static class BSParam new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", (float)BSLinkset.LinksetImplementation.Compound ), + new ParameterDefn("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", + false ), new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", false ), new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index f5ee671..9a05349 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs @@ -44,12 +44,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public class BSPrimDisplaced : BSPrim { - // The purpose of this module is to do any mapping between what the simulator thinks + // The purpose of this subclass is to do any mapping between what the simulator thinks // the prim position and orientation is and what the physical position/orientation. // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> - // of the prim/linkset. The simulator tracks the location of the prim/linkset by - // the location of the root prim. So, if center-of-mass is anywhere but the origin - // of the root prim, the physical origin is displaced from the simulator origin. + // of the prim/linkset. The simulator, on the other hand, tracks the location of + // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere + // but the origin of the root prim, the physical origin is displaced from the simulator origin. // // This routine works by capturing the Force* setting of position/orientation/... and // adjusting the simulator values (being set) into the physical values. @@ -61,6 +61,7 @@ public class BSPrimDisplaced : BSPrim public virtual OMV.Vector3 PositionDisplacement { get; set; } public virtual OMV.Quaternion OrientationDisplacement { get; set; } + public virtual OMV.Quaternion OrientationDisplacementOrigInv { get; set; } public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) @@ -99,7 +100,8 @@ public class BSPrimDisplaced : BSPrim // Remember the displacement from root as well as the origional rotation of the // new center-of-mass. PositionDisplacement = comDisp; - OrientationDisplacement = OMV.Quaternion.Identity; + OrientationDisplacement = Quaternion.Normalize(RawOrientation); + OrientationDisplacementOrigInv = Quaternion.Inverse(OrientationDisplacement); } } @@ -110,7 +112,7 @@ public class BSPrimDisplaced : BSPrim { if (PositionDisplacement != OMV.Vector3.Zero) { - OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation); + OMV.Vector3 displacedPos = value - (PositionDisplacement * (OrientationDisplacementOrigInv * RawOrientation)); DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos); base.ForcePosition = displacedPos; } @@ -126,7 +128,8 @@ public class BSPrimDisplaced : BSPrim get { return base.ForceOrientation; } set { - // TODO: + // Changing orientation also changes the position of the center-of-mass since + // the orientation passed is for a rotation around the root prim's center. base.ForceOrientation = value; } } @@ -150,10 +153,13 @@ public class BSPrimDisplaced : BSPrim // Undo any center-of-mass displacement that might have been done. if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity) { - // Correct for any rotation around the center-of-mass - // TODO!!! + // The origional shape was offset from 'zero' by PositionDisplacement and rotated by OrientationDisplacement. + // These physical locations and rotation must be back converted to be centered around the displaced + // root shape. + + // The root position is the reported position displaced by the rotated displacement. + OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * (entprop.Rotation * OrientationDisplacementOrigInv)); - OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos); entprop.Position = displacedPos; // entprop.Rotation = something; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 87eed98..6d7de35 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -37,6 +37,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin { public class BSPrimLinkable : BSPrimDisplaced { + // The purpose of this subclass is to add linkset functionality to the prim. This overrides + // operations necessary for keeping the linkset created and, additionally, this + // calls the linkset implementation for its creation and management. + + // This adds the overrides for link() and delink() so the prim is linkable. + public BSLinkset Linkset { get; set; } // The index of this child prim. public int LinksetChildIndex { get; set; } @@ -69,8 +75,8 @@ public class BSPrimLinkable : BSPrimDisplaced BSPrimLinkable parent = obj as BSPrimLinkable; if (parent != null) { - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; + BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG + int childrenBefore = Linkset.NumberOfChildren; // DEBUG Linkset = parent.Linkset.AddMeToLinkset(this); @@ -85,8 +91,8 @@ public class BSPrimLinkable : BSPrimDisplaced // TODO: decide if this parent checking needs to happen at taint time // Race condition here: if link() and delink() in same simulation tick, the delink will not happen - BSPhysObject parentBefore = Linkset.LinksetRoot; - int childrenBefore = Linkset.NumberOfChildren; + BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG + int childrenBefore = Linkset.NumberOfChildren; // DEBUG Linkset = Linkset.RemoveMeFromLinkset(this); @@ -128,6 +134,7 @@ public class BSPrimLinkable : BSPrimDisplaced get { return Linkset.LinksetMass; } } + // Refresh the linkset structure and parameters when the prim's physical parameters are changed. public override void UpdatePhysicalParameters() { base.UpdatePhysicalParameters(); @@ -139,6 +146,7 @@ public class BSPrimLinkable : BSPrimDisplaced Linkset.Refresh(this); } + // When the prim is made dynamic or static, the linkset needs to change. protected override void MakeDynamic(bool makeStatic) { base.MakeDynamic(makeStatic); @@ -155,6 +163,8 @@ public class BSPrimLinkable : BSPrimDisplaced base.RemoveDependencies(); } + // Called after a simulation step for the changes in physical object properties. + // Do any filtering/modification needed for linksets. public override void UpdateProperties(EntityProperties entprop) { if (Linkset.IsRoot(this)) @@ -176,6 +186,7 @@ public class BSPrimLinkable : BSPrimDisplaced Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); } + // Called after a simulation step to post a collision with this object. public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { -- cgit v1.1 From 97698ae3119e01ecd2c98f7a17ad37204b9bfd9c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 10 Jun 2013 06:40:07 -0700 Subject: BulletSim: More tweaking on center-of-mass. Almost there. Changes have no effect if LinksetOffsetCenterOfMass=false (the default). --- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 78 +++++----------------- .../Physics/BulletSPlugin/BSPrimDisplaced.cs | 63 +++++++---------- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 10 +++ OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 1 - 4 files changed, 51 insertions(+), 101 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 30f6c8c..96626ca 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -35,62 +35,6 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { - /* -// When a child is linked, the relationship position of the child to the parent -// is remembered so the child's world position can be recomputed when it is -// removed from the linkset. -sealed class BSLinksetCompoundInfo : BSLinksetInfo -{ - public int Index; - public OMV.Vector3 OffsetFromRoot; - public OMV.Vector3 OffsetFromCenterOfMass; - public OMV.Quaternion OffsetRot; - public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r) - { - Index = indx; - OffsetFromRoot = p; - OffsetFromCenterOfMass = p; - OffsetRot = r; - } - // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) - public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) - { - // Each child position and rotation is given relative to the center-of-mass. - OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); - OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation; - OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement; - OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation; - - // Save relative position for recomputing child's world position after moving linkset. - Index = indx; - OffsetFromRoot = displacementFromRoot; - OffsetFromCenterOfMass = displacementFromCOM; - OffsetRot = displacementRot; - } - public override void Clear() - { - Index = 0; - OffsetFromRoot = OMV.Vector3.Zero; - OffsetFromCenterOfMass = OMV.Vector3.Zero; - OffsetRot = OMV.Quaternion.Identity; - } - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -}; - */ - public sealed class BSLinksetCompound : BSLinkset { private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; @@ -151,7 +95,9 @@ public sealed class BSLinksetCompound : BSLinkset public override bool MakeStatic(BSPrimLinkable child) { bool ret = false; + DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); if (IsRoot(child)) { // Schedule a rebuild to verify that the root shape is set to the real shape. @@ -364,16 +310,28 @@ public sealed class BSLinksetCompound : BSLinkset int memberIndex = 1; ForEachMember(delegate(BSPrimLinkable cPrim) { - // Root shape is always index zero. - cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex; + if (IsRoot(cPrim)) + { + // Root shape is always index zero. + cPrim.LinksetChildIndex = 0; + } + else + { + cPrim.LinksetChildIndex = memberIndex; + memberIndex++; + } // Get a reference to the shape of the child and add that shape to the linkset compound shape BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); + + // Offset the child shape from the center-of-mass and rotate it to vehicle relative OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV; OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; + + // Add the child shape to the compound shape being built m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", - LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot); + LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); // Since we are borrowing the shape of the child, disable the origional child body if (!IsRoot(cPrim)) @@ -385,8 +343,6 @@ public sealed class BSLinksetCompound : BSLinkset cPrim.PhysBody.collisionType = CollisionType.LinksetChild; } - memberIndex++; - return false; // 'false' says to move onto the next child in the list }); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index 9a05349..a11bca0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs @@ -51,7 +51,7 @@ public class BSPrimDisplaced : BSPrim // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere // but the origin of the root prim, the physical origin is displaced from the simulator origin. // - // This routine works by capturing the Force* setting of position/orientation/... and + // This routine works by capturing ForcePosition and // adjusting the simulator values (being set) into the physical values. // The conversion is also done in the opposite direction (physical origin -> simulator origin). // @@ -60,8 +60,6 @@ public class BSPrimDisplaced : BSPrim // class. public virtual OMV.Vector3 PositionDisplacement { get; set; } - public virtual OMV.Quaternion OrientationDisplacement { get; set; } - public virtual OMV.Quaternion OrientationDisplacementOrigInv { get; set; } public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) @@ -70,15 +68,17 @@ public class BSPrimDisplaced : BSPrim ClearDisplacement(); } + // Clears any center-of-mass displacement introduced by linksets, etc. + // Does not clear the displacement set by the user. public void ClearDisplacement() { - PositionDisplacement = OMV.Vector3.Zero; - OrientationDisplacement = OMV.Quaternion.Identity; + SetEffectiveCenterOfMassDisplacement(OMV.Vector3.Zero); } // Set this sets and computes the displacement from the passed prim to the center-of-mass. // A user set value for center-of-mass overrides whatever might be passed in here. // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). + // Called at taint time. public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) { Vector3 comDisp; @@ -87,21 +87,17 @@ public class BSPrimDisplaced : BSPrim else comDisp = centerOfMassDisplacement; + if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) ) + comDisp = Vector3.Zero; + DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); - if (comDisp == Vector3.Zero) + if ( comDisp != PositionDisplacement ) { - // If there is no diplacement. Things get reset. - PositionDisplacement = OMV.Vector3.Zero; - OrientationDisplacement = OMV.Quaternion.Identity; - } - else - { - // Remember the displacement from root as well as the origional rotation of the - // new center-of-mass. + // Displacement setting is changing. + // The relationship between the physical object and simulated object must be aligned. PositionDisplacement = comDisp; - OrientationDisplacement = Quaternion.Normalize(RawOrientation); - OrientationDisplacementOrigInv = Quaternion.Inverse(OrientationDisplacement); + this.ForcePosition = RawPosition; } } @@ -112,7 +108,11 @@ public class BSPrimDisplaced : BSPrim { if (PositionDisplacement != OMV.Vector3.Zero) { - OMV.Vector3 displacedPos = value - (PositionDisplacement * (OrientationDisplacementOrigInv * RawOrientation)); + // The displacement is always relative to the vehicle so, when setting position, + // the caller means to set the position of the root prim. + // This offsets the setting value to the center-of-mass and sends that to the + // physics engine. + OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation); DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos); base.ForcePosition = displacedPos; } @@ -123,26 +123,12 @@ public class BSPrimDisplaced : BSPrim } } - public override Quaternion ForceOrientation - { - get { return base.ForceOrientation; } - set - { - // Changing orientation also changes the position of the center-of-mass since - // the orientation passed is for a rotation around the root prim's center. - base.ForceOrientation = value; - } - } - - // TODO: decide if this is the right place for these variables. - // Somehow incorporate the optional settability by the user. - // Is this used? + // These are also overridden by BSPrimLinkable if the prim can be part of a linkset public override OMV.Vector3 CenterOfMass { get { return RawPosition; } } - // Is this used? public override OMV.Vector3 GeometricCenter { get { return RawPosition; } @@ -151,18 +137,17 @@ public class BSPrimDisplaced : BSPrim public override void UpdateProperties(EntityProperties entprop) { // Undo any center-of-mass displacement that might have been done. - if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity) + if (PositionDisplacement != OMV.Vector3.Zero) { - // The origional shape was offset from 'zero' by PositionDisplacement and rotated by OrientationDisplacement. - // These physical locations and rotation must be back converted to be centered around the displaced + // The origional shape was offset from 'zero' by PositionDisplacement. + // These physical location must be back converted to be centered around the displaced // root shape. // The root position is the reported position displaced by the rotated displacement. - OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * (entprop.Rotation * OrientationDisplacementOrigInv)); - - DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos); + OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); + DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},newPos={3}", + LocalID, entprop.Position, PositionDisplacement, displacedPos); entprop.Position = displacedPos; - // entprop.Rotation = something; } base.UpdateProperties(entprop); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 6d7de35..7058646 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -134,6 +134,16 @@ public class BSPrimLinkable : BSPrimDisplaced get { return Linkset.LinksetMass; } } + public override OMV.Vector3 CenterOfMass + { + get { return Linkset.CenterOfMass; } + } + + public override OMV.Vector3 GeometricCenter + { + get { return Linkset.GeometricCenter; } + } + // Refresh the linkset structure and parameters when the prim's physical parameters are changed. public override void UpdatePhysicalParameters() { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 1645c98..e56a6f6 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -785,7 +785,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters { // The simulation of the time interval took less than realtime. // Do a sleep for the rest of realtime. - DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); } else -- cgit v1.1 From a65cec3986431f5a2f4f9eb2424157def0d035c8 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 6 Jul 2013 08:22:59 -0700 Subject: BulletSim: implementation of linkset center-of-mass. Default off, for the moment, until more testing. Add separate thread and center-of-mass flags to OpenSimDefaults.ini. Clean up comments in OpenSimDefaults.ini. --- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 20 +++++--- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 3 ++ OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 5 +- .../Physics/BulletSPlugin/BSPrimDisplaced.cs | 60 ++++++++++++++++------ .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 11 ++-- bin/OpenSimDefaults.ini | 56 +++++++++++++------- 6 files changed, 107 insertions(+), 48 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 96626ca..1d94142 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -271,6 +271,8 @@ public sealed class BSLinksetCompound : BSLinkset // to what they should be as if the root was not in a linkset. // Not that bad since we only get into this routine if there are children in the linkset and // something has been updated/changed. + // Have to do the rebuild before checking for physical because this might be a linkset + // being destructed and going non-physical. LinksetRoot.ForceBodyShapeRebuild(true); // There is no reason to build all this physical stuff for a non-physical linkset. @@ -283,28 +285,29 @@ public sealed class BSLinksetCompound : BSLinkset // Get a new compound shape to build the linkset shape in. BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); - // The center of mass for the linkset is the geometric center of the group. // Compute a displacement for each component so it is relative to the center-of-mass. // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); + OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; - // 'centerDisplacementV' is the value to subtract from children to give physical offset position + // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) { + // Zero everything if center-of-mass displacement is not being done. centerDisplacementV = OMV.Vector3.Zero; LinksetRoot.ClearDisplacement(); } else { - LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); // The actual center-of-mass could have been set by the user. - centerDisplacementV = LinksetRoot.PositionDisplacement; + centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); } + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", - LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV); + LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); // Add the shapes of all the components of the linkset int memberIndex = 1; @@ -321,11 +324,11 @@ public sealed class BSLinksetCompound : BSLinkset memberIndex++; } - // Get a reference to the shape of the child and add that shape to the linkset compound shape + // Get a reference to the shape of the child for adding of that shape to the linkset compound shape BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); - // Offset the child shape from the center-of-mass and rotate it to vehicle relative - OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV; + // Offset the child shape from the center-of-mass and rotate it to vehicle relative. + OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; // Add the child shape to the compound shape being built @@ -366,6 +369,7 @@ public sealed class BSLinksetCompound : BSLinkset // This enables a feature in the C++ code to return the world coordinates of the first shape in the // compound shape. This aleviates the need to offset the returned physical position by the // center-of-mass offset. + // TODO: either debug this feature or remove it. m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index a0d5c42..738e2d0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -90,6 +90,8 @@ public abstract class BSPhysObject : PhysicsActor PhysBody = new BulletBody(localID); PhysShape = new BSShapeNull(); + UserSetCenterOfMassDisplacement = null; + PrimAssetState = PrimAssetCondition.Unknown; // Default material type. Also sets Friction, Restitution and Density. @@ -180,6 +182,7 @@ public abstract class BSPhysObject : PhysicsActor Material = (MaterialAttributes.Material)material; // Setting the material sets the material attributes also. + // TODO: decide if this is necessary -- the simulator does this. MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); Friction = matAttrib.friction; Restitution = matAttrib.restitution; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index f0858ca..ce4c3da 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -802,6 +802,7 @@ public class BSPrim : BSPhysObject // isSolid: other objects bounce off of this object // isVolumeDetect: other objects pass through but can generate collisions // collisionEvents: whether this object returns collision events + // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters. public virtual void UpdatePhysicalParameters() { if (!PhysBody.HasPhysicalBody) @@ -1532,6 +1533,8 @@ public class BSPrim : BSPhysObject // The physics engine says that properties have updated. Update same and inform // the world that things have changed. + // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. + // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. public override void UpdateProperties(EntityProperties entprop) { // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. @@ -1567,8 +1570,6 @@ public class BSPrim : BSPhysObject LastEntityProperties = CurrentEntityProperties; CurrentEntityProperties = entprop; - // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. - PhysScene.PostUpdate(this); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index a11bca0..35d5a08 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs @@ -59,6 +59,7 @@ public class BSPrimDisplaced : BSPrim // are converted into simulator origin values before being passed to the base // class. + // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass. public virtual OMV.Vector3 PositionDisplacement { get; set; } public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, @@ -72,49 +73,77 @@ public class BSPrimDisplaced : BSPrim // Does not clear the displacement set by the user. public void ClearDisplacement() { - SetEffectiveCenterOfMassDisplacement(OMV.Vector3.Zero); + if (UserSetCenterOfMassDisplacement.HasValue) + PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement; + else + PositionDisplacement = OMV.Vector3.Zero; } // Set this sets and computes the displacement from the passed prim to the center-of-mass. // A user set value for center-of-mass overrides whatever might be passed in here. // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). + // Returns the relative offset from the root position to the center-of-mass. // Called at taint time. - public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) + public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) { + PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement"); Vector3 comDisp; if (UserSetCenterOfMassDisplacement.HasValue) comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; else comDisp = centerOfMassDisplacement; + // Eliminate any jitter caused be very slight differences in masses and positions if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) ) comDisp = Vector3.Zero; DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); - if ( comDisp != PositionDisplacement ) + if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) ) { // Displacement setting is changing. // The relationship between the physical object and simulated object must be aligned. PositionDisplacement = comDisp; this.ForcePosition = RawPosition; } + + return PositionDisplacement; } + // 'ForcePosition' is the one way to set the physical position of the body in the physics engine. + // Displace the simulator idea of position (center of root prim) to the physical position. public override Vector3 ForcePosition { - get { return base.ForcePosition; } + get { + OMV.Vector3 physPosition = base.ForcePosition; + if (PositionDisplacement != OMV.Vector3.Zero) + { + // If there is some displacement, return the physical position (center-of-mass) + // location minus the displacement to give the center of the root prim. + OMV.Vector3 displacement = PositionDisplacement * ForceOrientation; + DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}", + LocalID, physPosition, displacement, physPosition - displacement); + physPosition -= displacement; + } + return physPosition; + } set { if (PositionDisplacement != OMV.Vector3.Zero) { - // The displacement is always relative to the vehicle so, when setting position, - // the caller means to set the position of the root prim. - // This offsets the setting value to the center-of-mass and sends that to the - // physics engine. - OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation); - DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos); - base.ForcePosition = displacedPos; + // This value is the simulator's idea of where the prim is: the center of the root prim + RawPosition = value; + + // Move the passed root prim postion to the center-of-mass position and set in the physics engine. + OMV.Vector3 displacement = PositionDisplacement * RawOrientation; + OMV.Vector3 displacedPos = RawPosition + displacement; + DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}", + LocalID, RawPosition, displacement, displacedPos); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation); + ActivateIfPhysical(false); + } } else { @@ -143,10 +172,11 @@ public class BSPrimDisplaced : BSPrim // These physical location must be back converted to be centered around the displaced // root shape. - // The root position is the reported position displaced by the rotated displacement. - OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); - DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},newPos={3}", - LocalID, entprop.Position, PositionDisplacement, displacedPos); + // Move the returned center-of-mass location to the root prim location. + OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation; + OMV.Vector3 displacedPos = entprop.Position - displacement; + DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}", + LocalID, entprop.Position, displacement, displacedPos); entprop.Position = displacedPos; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 7058646..1fbcfcc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -160,10 +160,13 @@ public class BSPrimLinkable : BSPrimDisplaced protected override void MakeDynamic(bool makeStatic) { base.MakeDynamic(makeStatic); - if (makeStatic) - Linkset.MakeStatic(this); - else - Linkset.MakeDynamic(this); + if (Linkset != null) // null can happen during initialization + { + if (makeStatic) + Linkset.MakeStatic(this); + else + Linkset.MakeDynamic(this); + } } // Body is being taken apart. Remove physical dependencies and schedule a rebuild. diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 4a89fe2..4a3104e 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -919,54 +919,72 @@ ; ## 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 + ; 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 ; ## - ; physical collision mesh proxies are normally created for complex prim shapes, and collisions for simple boxes and - ; spheres are computed algorithmically. 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. + ; Physical collision mesh proxies are normally created for complex prim shapes, + ; and collisions for simple boxes and spheres are computed algorithmically. + ; 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 [BulletSim] - ; All the BulletSim parameters can be displayed with the console command "physics get all" - ; and all are defined in the source file OpenSim/Regions/Physics/BulletSPlugin/BSParam.cs. + ; All the BulletSim parameters can be displayed with the console command + ; "physics get all" and all are defined in the source file + ; OpenSim/Regions/Physics/BulletSPlugin/BSParam.cs. - ; There are two bullet physics libraries, bulletunmanaged is the default and is a native c++ dll - ; bulletxna is a managed C# dll. They have comparible functionality but the c++ one is much faster. + ; There are two bullet physics libraries, bulletunmanaged is the default and is a + ; native c++ dll bulletxna is a managed C# dll. They have comparible functionality + ; but the c++ one is much faster. BulletEngine = "bulletunmanaged" ; BulletEngine = "bulletxna" - ; Terrain Implementation - TerrainImplementation = 1 ; 0=Heightfield, 1=mesh - ; For mesh terrain, the detail of the created mesh. '1' gives 256x256 (heightfield resolution). '2' - ; gives 512x512. Etc. Cannot be larger than '4'. Higher magnification uses lots of memory. + ; BulletSim can run on its own thread independent of the simulator's heartbeat + ; thread. Enabling this will nto let the physics engine slow down avatar movement, etc. + UseSeparatePhysicsThread = false + + ; Terrain implementation can use either Bullet's heightField or BulletSim can build + ; a mesh. 0=heightField, 1=mesh + TerrainImplementation = 1 + ; For mesh terrain, the detail of the created mesh. '1' gives 256x256 (heightfield + ; resolution). '2' gives 512x512. Etc. Cannot be larger than '4'. Higher + ; magnification uses lots of memory. TerrainMeshMagnification = 2 - ; Avatar physics height adjustments. http://opensimulator.org/wiki/BulletSim#Adjusting_Avatar_Height + ; Avatar physics height adjustments. + ; http://opensimulator.org/wiki/BulletSim#Adjusting_Avatar_Height AvatarHeightLowFudge = -0.2 ; Adjustment at low end of height range AvatarHeightMidFudge = 0.1 ; Adjustment at mid point of avatar height range AvatarHeightHighFudge = 0.1 ; Adjustment at high end of height range ; Default linkset implmentation - ; 'Constraint' uses physics constraints to hold linkset together. 'Compound' builds a compound - ; shape from the children shapes to create a single physical shape. 'Compound' uses a lot less CPU time. + ; 'Constraint' uses physics constraints to hold linkset together. 'Compound' + ; builds a compound shape from the children shapes to create a single physical + ; shape. 'Compound' uses a lot less CPU time. LinkImplementation = 1 ; 0=constraint, 1=compound + ; If 'true', offset a linkset's origin based on mass of linkset parts. + LinksetOffsetCenterOfMass = false + ; If 'true', turn scuplties into meshes MeshSculptedPrim = true ; If 'true', force simple prims (box and sphere) to be meshed - ; If 'false', the Bullet native special case shape is used for square rectangles and even dimensioned spheres + ; If 'false', the Bullet native special case shape is used for square rectangles + ; and even dimensioned spheres. ForceSimplePrimMeshing = false ; If 'true', when creating meshes, remove all triangles that have two equal vertexes. - ; Happens often in sculpties. If turned off, there will be some doorways that cannot be walked through. + ; Happens often in sculpties. If turned off, there will be some doorways + ; that cannot be walked through. ShouldRemoveZeroWidthTriangles = true ; If 'true', use convex hull definition in mesh asset if present. -- cgit v1.1 From d838f15d97d5ae400af86aa52c9ea68f0ba299bb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 6 Jul 2013 09:53:30 -0700 Subject: Add implementations for llSetVelocity and llSetAngularVelocity. --- .../Shared/Api/Implementation/LSL_Api.cs | 26 ++++++++++++++++++++++ .../ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | 2 ++ .../ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | 10 +++++++++ 3 files changed, 38 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c0b8373..34e2b4d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2382,6 +2382,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return force; } + public void llSetVelocity(LSL_Vector velocity, int local) + { + m_host.AddScriptLPS(1); + + if (!m_host.ParentGroup.IsDeleted) + { + if (local != 0) + velocity *= llGetRot(); + + m_host.ParentGroup.RootPart.Velocity = velocity; + } + } + + public void llSetAngularVelocity(LSL_Vector angularVelocity, int local) + { + m_host.AddScriptLPS(1); + + if (!m_host.ParentGroup.IsDeleted) + { + if (local != 0) + angularVelocity *= llGetRot(); + + m_host.ParentGroup.RootPart.AngularVelocity = angularVelocity; + } + } + public LSL_Integer llTarget(LSL_Vector position, double range) { 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 ff13ee6..340edb3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -342,6 +342,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSetDamage(double damage); void llSetForce(LSL_Vector force, int local); void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local); + void llSetVelocity(LSL_Vector velocity, int local); + void llSetAngularVelocity(LSL_Vector angularVelocity, int local); void llSetHoverHeight(double height, int water, double tau); void llSetInventoryPermMask(string item, int mask, int value); void llSetLinkAlpha(int linknumber, double alpha, int face); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 87cc342..7cd17e7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -1548,6 +1548,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetForceAndTorque(force, torque, local); } + public void llSetVelocity(LSL_Vector force, int local) + { + m_LSL_Functions.llSetVelocity(force, local); + } + + public void llSetAngularVelocity(LSL_Vector force, int local) + { + m_LSL_Functions.llSetAngularVelocity(force, local); + } + public void llSetHoverHeight(double height, int water, double tau) { m_LSL_Functions.llSetHoverHeight(height, water, tau); -- cgit v1.1 From b29a09ab8e4040cc09f8021f638d7604f2372bad Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 15:17:55 -0700 Subject: Simina activity detector was too eager. Disabled it in case simian is not being used. --- .../Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 7bb06fb..0a39088 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -65,7 +65,7 @@ namespace OpenSim.Services.Connectors.SimianGrid public void PostInitialise() { } public void Close() { } - public SimianPresenceServiceConnector() { m_activityDetector = new SimianActivityDetector(this); } + public SimianPresenceServiceConnector() { } public string Name { get { return "SimianPresenceServiceConnector"; } } public void AddRegion(Scene scene) { @@ -121,6 +121,7 @@ namespace OpenSim.Services.Connectors.SimianGrid if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) serviceUrl = serviceUrl + '/'; m_serverUrl = serviceUrl; + m_activityDetector = new SimianActivityDetector(this); m_Enabled = true; } } -- cgit v1.1 From 9b75d757241e87408c50b1f92996bf667960c348 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 16:51:14 -0700 Subject: WARNING: BRUTE FORCE DEBUG AGAIN. AVOID USING THIS COMMIT --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index a7cbc8f..11227ef 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -521,6 +521,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement lock (m_UserCache) m_UserCache.Remove(id); m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); + Util.PrintCallStack(); + } else { @@ -555,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } catch (UriFormatException) { - m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); + m_log.DebugFormat("[SCENE]: Unable to parse Uri {0} from {1}", parts[0], creatorData); user.LastName = "@unknown"; } } -- cgit v1.1 From 1dd3a0bc576b04e8989e8ac16e96aff024c0d6cd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 17:29:19 -0700 Subject: MORE DEBUG. DON"T USE THIS. --- .../Inventory/RemoteXInventoryServiceConnector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 70ba944..8f41355 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -201,12 +201,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory List items = new List(invCol.Items); if (items != null && items.Count > 0) - Util.FireAndForget(delegate - { + //Util.FireAndForget(delegate + //{ foreach (InventoryItemBase item in items) if (!string.IsNullOrEmpty(item.CreatorData)) UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); - }); + //}); } return invCol; -- cgit v1.1 From 391633c072792fc36a188d6fa88e994fa150807d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 18:02:17 -0700 Subject: Some more fixes on strange behaviors of Unknown User, esp. related to large messy inventories and esp. related to kokua --- .../UserManagement/UserManagementModule.cs | 5 ++-- .../Inventory/RemoteXInventoryServiceConnector.cs | 27 +++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 11227ef..74608b3 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -514,9 +514,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return; } - //try update unknown users - //and creator's home URL's - if ((oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith(oldUser.HomeURL))) + //try update unknown users, but don't update anyone else + if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) { lock (m_UserCache) m_UserCache.Remove(id); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 8f41355..7f78076 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -195,19 +195,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory { InventoryCollection invCol = m_RemoteConnector.GetFolderContent(userID, folderID); - if (invCol != null && UserManager != null) - { - // Protect ourselves against the caller subsequently modifying the items list - List items = new List(invCol.Items); - - if (items != null && items.Count > 0) - //Util.FireAndForget(delegate - //{ - foreach (InventoryItemBase item in items) - if (!string.IsNullOrEmpty(item.CreatorData)) - UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); - //}); - } + // Commenting this for now, because it's causing more grief than good + //if (invCol != null && UserManager != null) + //{ + // // Protect ourselves against the caller subsequently modifying the items list + // List items = new List(invCol.Items); + + // if (items != null && items.Count > 0) + // //Util.FireAndForget(delegate + // //{ + // foreach (InventoryItemBase item in items) + // if (!string.IsNullOrEmpty(item.CreatorData)) + // UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); + // //}); + //} return invCol; } -- cgit v1.1 From 71e26555bd67b8636cf71f71951cfc2aad68a2ee Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 18:16:27 -0700 Subject: Revert "WARNING: BRUTE FORCE DEBUG AGAIN. AVOID USING THIS COMMIT" This reverts commit 9b75d757241e87408c50b1f92996bf667960c348. --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 74608b3..524d159 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -520,8 +520,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement lock (m_UserCache) m_UserCache.Remove(id); m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); - Util.PrintCallStack(); - } else { @@ -556,7 +554,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } catch (UriFormatException) { - m_log.DebugFormat("[SCENE]: Unable to parse Uri {0} from {1}", parts[0], creatorData); + m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); user.LastName = "@unknown"; } } -- cgit v1.1 From 803e5498b09c241a8bab8e8deeeff3a259766c2d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 18:27:03 -0700 Subject: A little more debug --- OpenSim/Services/UserAccountService/GridUserService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index fa9a4a8..b1cdd45 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -156,7 +156,7 @@ namespace OpenSim.Services.UserAccountService public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) { - //m_log.DebugFormat("[Grid User Service]: SetLastPosition for {0}", userID); + m_log.DebugFormat("[GRID USER SERVICE]: SetLastPosition for {0}", userID); GridUserData d = m_Database.Get(userID); if (d == null) { -- cgit v1.1 From 128667735291234c4655216af0fdfc6f07355e20 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Jul 2013 18:37:54 -0700 Subject: Try to normalize the creatorData of scene object parts with the trailing '/'. What a nightmare this '/' is! --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 482d958..f287a34 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -505,7 +505,11 @@ namespace OpenSim.Region.Framework.Scenes CreatorID = uuid; } if (parts.Length >= 2) + { CreatorData = parts[1]; + if (!CreatorData.EndsWith("/")) + CreatorData += "/"; + } if (parts.Length >= 3) name = parts[2]; -- cgit v1.1 From 70d24a654b8eb0257ca927327d51bd0e47f85259 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 7 Jul 2013 05:46:24 -0700 Subject: BulletSim: rename position and orientation variables to remove the inconsistant use of Raw* and _* conventions. --- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 78 +++++++++----------- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 84 ++++++++++------------ 3 files changed, 71 insertions(+), 95 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 5ef6992..c9e3ca0 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -43,12 +43,10 @@ public sealed class BSCharacter : BSPhysObject private OMV.Vector3 _size; private bool _grabbed; private bool _selected; - private OMV.Vector3 _position; private float _mass; private float _avatarVolume; private float _collisionScore; private OMV.Vector3 _acceleration; - private OMV.Quaternion _orientation; private int _physicsActorType; private bool _isPhysical; private bool _flying; @@ -70,10 +68,10 @@ public sealed class BSCharacter : BSPhysObject : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; - _position = pos; + RawPosition = pos; _flying = isFlying; - _orientation = OMV.Quaternion.Identity; + RawOrientation = OMV.Quaternion.Identity; RawVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); Friction = BSParam.AvatarStandingFriction; @@ -133,7 +131,7 @@ public sealed class BSCharacter : BSPhysObject PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); ZeroMotion(true); - ForcePosition = _position; + ForcePosition = RawPosition; // Set the velocity if (m_moveActor != null) @@ -272,38 +270,33 @@ public sealed class BSCharacter : BSPhysObject public override void LockAngularMotion(OMV.Vector3 axis) { return; } - public override OMV.Vector3 RawPosition - { - get { return _position; } - set { _position = value; } - } public override OMV.Vector3 Position { get { // Don't refetch the position because this function is called a zillion times - // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); - return _position; + // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); + return RawPosition; } set { - _position = value; + RawPosition = value; PhysScene.TaintedObject("BSCharacter.setPosition", delegate() { - DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); + DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); PositionSanityCheck(); - ForcePosition = _position; + ForcePosition = RawPosition; }); } } public override OMV.Vector3 ForcePosition { get { - _position = PhysScene.PE.GetPosition(PhysBody); - return _position; + RawPosition = PhysScene.PE.GetPosition(PhysBody); + return RawPosition; } set { - _position = value; + RawPosition = value; if (PhysBody.HasPhysicalBody) { - PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); } } } @@ -331,16 +324,16 @@ public sealed class BSCharacter : BSPhysObject float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); if (Position.Z < terrainHeight) { - DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); - _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; + DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); ret = true; } if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) { - float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); if (Position.Z < waterHeight) { - _position.Z = waterHeight; + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); ret = true; } } @@ -360,8 +353,8 @@ public sealed class BSCharacter : BSPhysObject // just assign to "Position" because of potential call loops. PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() { - DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); - ForcePosition = _position; + DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + ForcePosition = RawPosition; }); ret = true; } @@ -466,19 +459,14 @@ public sealed class BSCharacter : BSPhysObject get { return _acceleration; } set { _acceleration = value; } } - public override OMV.Quaternion RawOrientation - { - get { return _orientation; } - set { _orientation = value; } - } public override OMV.Quaternion Orientation { - get { return _orientation; } + get { return RawOrientation; } set { // Orientation is set zillions of times when an avatar is walking. It's like // the viewer doesn't trust us. - if (_orientation != value) + if (RawOrientation != value) { - _orientation = value; + RawOrientation = value; PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() { // Bullet assumes we know what we are doing when forcing orientation @@ -486,10 +474,10 @@ public sealed class BSCharacter : BSPhysObject // This forces rotation to be only around the Z axis and doesn't change any of the other axis. // This keeps us from flipping the capsule over which the veiwer does not understand. float oRoll, oPitch, oYaw; - _orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); + RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", - // LocalID, _orientation, OMV.Vector3.UnitX * _orientation, + // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation, // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); ForceOrientation = trimmedOrientation; }); @@ -501,16 +489,16 @@ public sealed class BSCharacter : BSPhysObject { get { - _orientation = PhysScene.PE.GetOrientation(PhysBody); - return _orientation; + RawOrientation = PhysScene.PE.GetOrientation(PhysBody); + return RawOrientation; } set { - _orientation = value; + RawOrientation = value; if (PhysBody.HasPhysicalBody) { - // _position = PhysicsScene.PE.GetPosition(BSBody); - PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); + // RawPosition = PhysicsScene.PE.GetPosition(BSBody); + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); } } } @@ -723,9 +711,9 @@ public sealed class BSCharacter : BSPhysObject { // Don't change position if standing on a stationary object. if (!IsStationary) - _position = entprop.Position; + RawPosition = entprop.Position; - _orientation = entprop.Rotation; + RawOrientation = entprop.Rotation; // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar // and will send agent updates to the clients if velocity changes by more than @@ -740,8 +728,8 @@ public sealed class BSCharacter : BSPhysObject // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. if (PositionSanityCheck(true)) { - DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); - entprop.Position = _position; + DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); + entprop.Position = RawPosition; } // remember the current and last set values @@ -755,7 +743,7 @@ public sealed class BSCharacter : BSPhysObject // base.RequestPhysicsterseUpdate(); DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); + LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 738e2d0..a41eaf8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -197,10 +197,10 @@ 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); - public abstract OMV.Vector3 RawPosition { get; set; } + public virtual OMV.Vector3 RawPosition { get; set; } public abstract OMV.Vector3 ForcePosition { get; set; } - public abstract OMV.Quaternion RawOrientation { get; set; } + public virtual OMV.Quaternion RawOrientation { get; set; } public abstract OMV.Quaternion ForceOrientation { get; set; } public OMV.Vector3 RawVelocity { get; set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index ce4c3da..d43448e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -51,12 +51,8 @@ public class BSPrim : BSPhysObject private bool _isSelected; private bool _isVolumeDetect; - // _position is what the simulator thinks the positions of the prim is. - private OMV.Vector3 _position; - private float _mass; // the mass of this object private OMV.Vector3 _acceleration; - private OMV.Quaternion _orientation; private int _physicsActorType; private bool _isPhysical; private bool _flying; @@ -88,10 +84,10 @@ public class BSPrim : BSPhysObject { // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); _physicsActorType = (int)ActorTypes.Prim; - _position = pos; + RawPosition = pos; _size = size; Scale = size; // prims are the size the user wants them to be (different for BSCharactes). - _orientation = rotation; + RawOrientation = rotation; _buoyancy = 0f; RawVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero; @@ -270,46 +266,42 @@ public class BSPrim : BSPhysObject return; } - public override OMV.Vector3 RawPosition - { - get { return _position; } - set { _position = value; } - } public override OMV.Vector3 Position { get { // don't do the GetObjectPosition for root elements because this function is called a zillion times. - // _position = ForcePosition; - return _position; + // RawPosition = ForcePosition; + return RawPosition; } set { // If the position must be forced into the physics engine, use ForcePosition. // All positions are given in world positions. - if (_position == value) + if (RawPosition == value) { - DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); + DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); return; } - _position = value; + RawPosition = value; PositionSanityCheck(false); PhysScene.TaintedObject("BSPrim.setPosition", delegate() { - DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); - ForcePosition = _position; + DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + ForcePosition = RawPosition; }); } } + // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. public override OMV.Vector3 ForcePosition { get { - _position = PhysScene.PE.GetPosition(PhysBody); - return _position; + RawPosition = PhysScene.PE.GetPosition(PhysBody); + return RawPosition; } set { - _position = value; + RawPosition = value; if (PhysBody.HasPhysicalBody) { - PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); ActivateIfPhysical(false); } } @@ -343,10 +335,10 @@ public class BSPrim : BSPhysObject float targetHeight = terrainHeight + (Size.Z / 2f); // If the object is below ground it just has to be moved up because pushing will // not get it through the terrain - _position.Z = targetHeight; + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); if (inTaintTime) { - ForcePosition = _position; + ForcePosition = RawPosition; } // If we are throwing the object around, zero its other forces ZeroMotion(inTaintTime); @@ -355,7 +347,7 @@ public class BSPrim : BSPhysObject if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) { - float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); // TODO: a floating motor so object will bob in the water if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) { @@ -364,7 +356,7 @@ public class BSPrim : BSPhysObject // Apply upforce and overcome gravity. OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; - DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); + DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce); AddForce(correctionForce, false, inTaintTime); ret = true; } @@ -383,11 +375,11 @@ public class BSPrim : BSPhysObject uint wayOutThere = Constants.RegionSize * Constants.RegionSize; // There have been instances of objects getting thrown way out of bounds and crashing // the border crossing code. - if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere - || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere - || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere) + if ( RawPosition.X < -Constants.RegionSize || RawPosition.X > wayOutThere + || RawPosition.Y < -Constants.RegionSize || RawPosition.Y > wayOutThere + || RawPosition.Z < -Constants.RegionSize || RawPosition.Z > wayOutThere) { - _position = new OMV.Vector3(10, 10, 50); + RawPosition = new OMV.Vector3(10, 10, 50); ZeroMotion(inTaintTime); ret = true; } @@ -713,23 +705,19 @@ public class BSPrim : BSPhysObject get { return _acceleration; } set { _acceleration = value; } } - public override OMV.Quaternion RawOrientation - { - get { return _orientation; } - set { _orientation = value; } - } + public override OMV.Quaternion Orientation { get { - return _orientation; + return RawOrientation; } set { - if (_orientation == value) + if (RawOrientation == value) return; - _orientation = value; + RawOrientation = value; PhysScene.TaintedObject("BSPrim.setOrientation", delegate() { - ForceOrientation = _orientation; + ForceOrientation = RawOrientation; }); } } @@ -738,14 +726,14 @@ public class BSPrim : BSPhysObject { get { - _orientation = PhysScene.PE.GetOrientation(PhysBody); - return _orientation; + RawOrientation = PhysScene.PE.GetOrientation(PhysBody); + return RawOrientation; } set { - _orientation = value; + RawOrientation = value; if (PhysBody.HasPhysicalBody) - PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); } } public override int PhysicsActorType { @@ -889,7 +877,7 @@ public class BSPrim : BSPhysObject // PhysicsScene.PE.ClearAllForces(BSBody); // For good measure, make sure the transform is set through to the motion state - ForcePosition = _position; + ForcePosition = RawPosition; ForceVelocity = RawVelocity; ForceRotationalVelocity = _rotationalVelocity; @@ -1543,8 +1531,8 @@ public class BSPrim : BSPhysObject // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG // Assign directly to the local variables so the normal set actions do not happen - _position = entprop.Position; - _orientation = entprop.Rotation; + RawPosition = entprop.Position; + RawOrientation = entprop.Rotation; // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be // very sensitive to velocity changes. if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) @@ -1557,13 +1545,13 @@ public class BSPrim : BSPhysObject // The sanity check can change the velocity and/or position. if (PositionSanityCheck(true /* inTaintTime */ )) { - entprop.Position = _position; + entprop.Position = RawPosition; entprop.Velocity = RawVelocity; entprop.RotationalVelocity = _rotationalVelocity; entprop.Acceleration = _acceleration; } - OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG + OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); // remember the current and last set values -- cgit v1.1 From 6026759406f20cb89cbc62fcfc3af324c61c5ab0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 7 Jul 2013 05:47:41 -0700 Subject: BulletSim: fix jumping up and down of linksets when center-of-mass was enabled. Didn't effect the physical position but the viewer saw the linkset jumping between its simulator center and its physical center. --- OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index 35d5a08..2eb1440 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs @@ -23,11 +23,6 @@ * 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. - * - * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial - * are Copyright (c) 2009 Linden Research, Inc and are used under their license - * of Creative Commons Attribution-Share Alike 3.0 - * (http://creativecommons.org/licenses/by-sa/3.0/). */ using System; @@ -115,7 +110,7 @@ public class BSPrimDisplaced : BSPrim public override Vector3 ForcePosition { get { - OMV.Vector3 physPosition = base.ForcePosition; + OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody); if (PositionDisplacement != OMV.Vector3.Zero) { // If there is some displacement, return the physical position (center-of-mass) @@ -125,6 +120,7 @@ public class BSPrimDisplaced : BSPrim LocalID, physPosition, displacement, physPosition - displacement); physPosition -= displacement; } + RawPosition = physPosition; return physPosition; } set -- cgit v1.1 From bbc40fab620dd61e500d8f74fa1b0d64ecc7c3b6 Mon Sep 17 00:00:00 2001 From: Vegaslon Date: Sat, 6 Jul 2013 12:53:20 -0400 Subject: BulletSim: Different Implementation of Angular Deflection for vehicles, Activates it again and fixes problem with fighting with vertical attractor removing wobble of forward axis. Comments on testing welcome, May require adjustments of this force or other forces after this commit, exact tweaking to come after testing on other hardware. Signed-off-by: Robert Adams --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index c27d3f0..82fe267 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -144,7 +144,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin public void SetupVehicleDebugging() { enableAngularVerticalAttraction = true; - enableAngularDeflection = false; + enableAngularDeflection = true; enableAngularBanking = true; if (BSParam.VehicleDebuggingEnable) { @@ -173,7 +173,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin switch (pParam) { case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: - m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); + m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f); break; case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); @@ -1512,11 +1512,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // in that direction. // TODO: implement reference frame. public void ComputeAngularDeflection() - { - // Since angularMotorUp and angularDeflection are computed independently, they will calculate - // approximately the same X or Y correction. When added together (when contributions are combined) - // this creates an over-correction and then wabbling as the target is overshot. - // TODO: rethink how the different correction computations inter-relate. + { if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) { @@ -1531,10 +1527,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin // The direction the vehicle is pointing Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; - pointingDirection.Normalize(); + //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep + // from overshooting and allow this correction to merge with the Vertical Attraction peacefully. + Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); + predictedPointingDirection.Normalize(); // The difference between what is and what should be. - Vector3 deflectionError = movingDirection - pointingDirection; + // Vector3 deflectionError = movingDirection - predictedPointingDirection; + Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection); // Don't try to correct very large errors (not our job) // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); @@ -1547,15 +1547,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); // Scale the correction by recovery timescale and efficiency - deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency; - deflectContributionV /= m_angularDeflectionTimescale; - - VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; + // Not modeling a spring so clamp the scale to no more then the arc + deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f); + //deflectContributionV /= m_angularDeflectionTimescale; + // VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; + VehicleRotationalVelocity += deflectContributionV; VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); - VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", - ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); + VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}", + ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection); } } -- cgit v1.1 From bbb9af363de5cabf44dec2b5aba6fb386a1e7fad Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 7 Jul 2013 20:43:42 -0700 Subject: Print out caller IP when unusual requests are received. --- OpenSim/Server/Handlers/Simulation/AgentHandlers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 71a9e6f..b01de7a 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -107,7 +107,7 @@ namespace OpenSim.Server.Handlers.Simulation } else { - m_log.InfoFormat("[AGENT HANDLER]: method {0} not supported in agent message", method); + m_log.InfoFormat("[AGENT HANDLER]: method {0} not supported in agent message (caller is {1})", method, Util.GetCallerIP(request)); responsedata["int_response_code"] = HttpStatusCode.MethodNotAllowed; responsedata["str_response_string"] = "Method not allowed"; -- cgit v1.1 From c66a9a08e4fed5cc675aac8a7a2999549049d79c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 8 Jul 2013 08:41:18 -0700 Subject: Placed a throttle on UserManagementModule for name lookups. Singularity apparently is flooding the sims with name requests. --- .../UserManagement/HGUserManagementModule.cs | 2 +- .../UserManagement/UserManagementModule.cs | 66 ++++++++++++++++++---- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index ad3cf15..245c808 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (umanmod == Name) { m_Enabled = true; - RegisterConsoleCmds(); + Init(); m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); } } diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 524d159..a528093 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -28,9 +28,11 @@ using System; using System.Collections.Generic; using System.IO; using System.Reflection; +using System.Threading; using OpenSim.Framework; using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; using OpenSim.Region.ClientStack.LindenUDP; using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; @@ -57,6 +59,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // The cache protected Dictionary m_UserCache = new Dictionary(); + // Throttle the name requests + private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + + #region ISharedRegionModule public void Initialise(IConfigSource config) @@ -65,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (umanmod == Name) { m_Enabled = true; - RegisterConsoleCmds(); + Init(); m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); } } @@ -160,16 +166,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } else { - string[] names; - bool foundRealName = TryGetUserNames(uuid, out names); + NameRequest request = new NameRequest(remote_client, uuid); + m_RequestQueue.Enqueue(request); - if (names.Length == 2) - { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, remote_client.Name); - - remote_client.SendNameReply(uuid, names[0], names[1]); - } } } @@ -596,6 +595,18 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #endregion IUserManagement + protected void Init() + { + RegisterConsoleCmds(); + Watchdog.StartThread( + ProcessQueue, + "NameRequestThread", + ThreadPriority.BelowNormal, + true, + false); + + } + protected void RegisterConsoleCmds() { MainConsole.Instance.Commands.AddCommand("Users", true, @@ -662,5 +673,40 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement MainConsole.Instance.Output(cdt.ToString()); } + + private void ProcessQueue() + { + while (true) + { + Watchdog.UpdateThread(); + + NameRequest request = m_RequestQueue.Dequeue(); + string[] names; + bool foundRealName = TryGetUserNames(request.uuid, out names); + + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + + request.client.SendNameReply(request.uuid, names[0], names[1]); + } + + } + } + + } + + class NameRequest + { + public IClientAPI client; + public UUID uuid; + + public NameRequest(IClientAPI c, UUID n) + { + client = c; + uuid = n; + } } + } \ No newline at end of file -- cgit v1.1 From a38c2abae4a5262ec0332426c9721b8718d4e85f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 18:07:04 +0100 Subject: Make dictionary read/write locking consistent in CapabilitiesModule, rename two dictionary fields to standard m_ format --- .../Framework/Caps/CapabilitiesModule.cs | 130 +++++++++++++-------- 1 file changed, 82 insertions(+), 48 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 6ae9448..c8b341b 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -57,8 +57,8 @@ namespace OpenSim.Region.CoreModules.Framework ///
protected Dictionary m_capsObjects = new Dictionary(); - protected Dictionary capsPaths = new Dictionary(); - protected Dictionary> childrenSeeds + protected Dictionary m_capsPaths = new Dictionary(); + protected Dictionary> m_childrenSeeds = new Dictionary>(); public void Initialise(IConfigSource source) @@ -105,35 +105,42 @@ namespace OpenSim.Region.CoreModules.Framework if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) return; + Caps caps; String capsObjectPath = GetCapsPath(agentId); - if (m_capsObjects.ContainsKey(agentId)) + lock (m_capsObjects) { - Caps oldCaps = m_capsObjects[agentId]; - - m_log.DebugFormat( - "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", - agentId, oldCaps.CapsObjectPath, capsObjectPath); - // This should not happen. The caller code is confused. We need to fix that. - // CAPs can never be reregistered, or the client will be confused. - // Hence this return here. - //return; - } + if (m_capsObjects.ContainsKey(agentId)) + { + Caps oldCaps = m_capsObjects[agentId]; + + m_log.DebugFormat( + "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", + agentId, oldCaps.CapsObjectPath, capsObjectPath); + // This should not happen. The caller code is confused. We need to fix that. + // CAPs can never be reregistered, or the client will be confused. + // Hence this return here. + //return; + } - Caps caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, - (MainServer.Instance == null) ? 0: MainServer.Instance.Port, - capsObjectPath, agentId, m_scene.RegionInfo.RegionName); + caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, + (MainServer.Instance == null) ? 0: MainServer.Instance.Port, + capsObjectPath, agentId, m_scene.RegionInfo.RegionName); - m_capsObjects[agentId] = caps; + m_capsObjects[agentId] = caps; + } m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); } public void RemoveCaps(UUID agentId) { - if (childrenSeeds.ContainsKey(agentId)) + lock (m_childrenSeeds) { - childrenSeeds.Remove(agentId); + if (m_childrenSeeds.ContainsKey(agentId)) + { + m_childrenSeeds.Remove(agentId); + } } lock (m_capsObjects) @@ -168,16 +175,22 @@ namespace OpenSim.Region.CoreModules.Framework public void SetAgentCapsSeeds(AgentCircuitData agent) { - capsPaths[agent.AgentID] = agent.CapsPath; - childrenSeeds[agent.AgentID] - = ((agent.ChildrenCapSeeds == null) ? new Dictionary() : agent.ChildrenCapSeeds); + lock (m_capsPaths) + m_capsPaths[agent.AgentID] = agent.CapsPath; + + lock (m_childrenSeeds) + m_childrenSeeds[agent.AgentID] + = ((agent.ChildrenCapSeeds == null) ? new Dictionary() : agent.ChildrenCapSeeds); } public string GetCapsPath(UUID agentId) { - if (capsPaths.ContainsKey(agentId)) + lock (m_capsPaths) { - return capsPaths[agentId]; + if (m_capsPaths.ContainsKey(agentId)) + { + return m_capsPaths[agentId]; + } } return null; @@ -186,17 +199,24 @@ namespace OpenSim.Region.CoreModules.Framework public Dictionary GetChildrenSeeds(UUID agentID) { Dictionary seeds = null; - if (childrenSeeds.TryGetValue(agentID, out seeds)) - return seeds; + + lock (m_childrenSeeds) + if (m_childrenSeeds.TryGetValue(agentID, out seeds)) + return seeds; + return new Dictionary(); } public void DropChildSeed(UUID agentID, ulong handle) { Dictionary seeds; - if (childrenSeeds.TryGetValue(agentID, out seeds)) + + lock (m_childrenSeeds) { - seeds.Remove(handle); + if (m_childrenSeeds.TryGetValue(agentID, out seeds)) + { + seeds.Remove(handle); + } } } @@ -204,30 +224,41 @@ namespace OpenSim.Region.CoreModules.Framework { Dictionary seeds; string returnval; - if (childrenSeeds.TryGetValue(agentID, out seeds)) + + lock (m_childrenSeeds) { - if (seeds.TryGetValue(handle, out returnval)) - return returnval; + if (m_childrenSeeds.TryGetValue(agentID, out seeds)) + { + if (seeds.TryGetValue(handle, out returnval)) + return returnval; + } } + return null; } public void SetChildrenSeed(UUID agentID, Dictionary seeds) { //m_log.DebugFormat(" !!! Setting child seeds in {0} to {1}", m_scene.RegionInfo.RegionName, seeds.Count); - childrenSeeds[agentID] = seeds; + + lock (m_childrenSeeds) + m_childrenSeeds[agentID] = seeds; } public void DumpChildrenSeeds(UUID agentID) { m_log.Info("================ ChildrenSeed "+m_scene.RegionInfo.RegionName+" ================"); - foreach (KeyValuePair kvp in childrenSeeds[agentID]) + + lock (m_childrenSeeds) { - uint x, y; - Utils.LongToUInts(kvp.Key, out x, out y); - x = x / Constants.RegionSize; - y = y / Constants.RegionSize; - m_log.Info(" >> "+x+", "+y+": "+kvp.Value); + foreach (KeyValuePair kvp in m_childrenSeeds[agentID]) + { + uint x, y; + Utils.LongToUInts(kvp.Key, out x, out y); + x = x / Constants.RegionSize; + y = y / Constants.RegionSize; + m_log.Info(" >> "+x+", "+y+": "+kvp.Value); + } } } @@ -236,21 +267,24 @@ namespace OpenSim.Region.CoreModules.Framework StringBuilder caps = new StringBuilder(); caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); - foreach (KeyValuePair kvp in m_capsObjects) + lock (m_capsObjects) { - caps.AppendFormat("** User {0}:\n", kvp.Key); - - for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) + foreach (KeyValuePair kvp in m_capsObjects) { - Uri uri = new Uri(kvp2.Value.ToString()); - caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); - } + caps.AppendFormat("** User {0}:\n", kvp.Key); + + for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) + { + Uri uri = new Uri(kvp2.Value.ToString()); + caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); + } - foreach (KeyValuePair kvp3 in kvp.Value.ExternalCapsHandlers) - caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); + foreach (KeyValuePair kvp3 in kvp.Value.ExternalCapsHandlers) + caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); + } } MainConsole.Instance.Output(caps.ToString()); } } -} +} \ No newline at end of file -- cgit v1.1 From e19defde36ddbd5ff90d8304c6fe3b57110f8078 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 22:03:07 +0100 Subject: Add "show caps stats by user" and "show caps stats by cap" console commands to print various counts of capability invocation by user and by cap This currently prints caps requests received and handled, so that overload of received compared to handled or deadlock can be detected. This involves making BaseStreamHandler and BaseOutputStream record the ints, which means inheritors should subclass ProcessRequest() instead of Handle() However, existing inheriting classes overriding Handle() will still work, albeit without stats recording. "show caps" becomes "show caps list" to disambiguate between show caps commands --- .../Hypergrid/HGGroupsServiceRobustConnector.cs | 2 +- .../Groups/Remote/GroupsServiceRobustConnector.cs | 2 +- .../Remote/OfflineIMServiceRobustConnector.cs | 2 +- OpenSim/Capabilities/CapsHandlers.cs | 16 +- .../AvatarPickerSearchHandler.cs | 2 +- .../Handlers/GetTexture/GetTextureHandler.cs | 2 +- OpenSim/Capabilities/LLSDStreamHandler.cs | 2 +- .../Servers/HttpServer/BaseRequestHandler.cs | 4 + .../Servers/HttpServer/BaseStreamHandler.cs | 27 ++- .../Servers/HttpServer/BinaryStreamHandler.cs | 2 +- .../HttpServer/Interfaces/IStreamHandler.cs | 15 +- .../Servers/HttpServer/RestDeserialiseHandler.cs | 4 +- .../Servers/HttpServer/RestSessionService.cs | 13 +- .../Servers/HttpServer/RestStreamHandler.cs | 2 +- OpenSim/Region/Application/OpenSimBase.cs | 8 +- .../ClientStack/Linden/Caps/RegionConsoleModule.cs | 2 +- .../Avatar/Friends/FriendsRequestHandler.cs | 2 +- .../Framework/Caps/CapabilitiesModule.cs | 234 ++++++++++++++++++++- .../World/Estate/XEstateRequestHandler.cs | 2 +- .../Region/Framework/Scenes/RegionStatsHandler.cs | 2 +- .../ViewerSupport/DynamicMenuModule.cs | 2 +- .../World/WorldView/WorldViewRequestHandler.cs | 2 +- .../Handlers/Asset/AssetServerDeleteHandler.cs | 2 +- .../Server/Handlers/Asset/AssetServerGetHandler.cs | 2 +- .../Handlers/Asset/AssetServerPostHandler.cs | 2 +- .../AuthenticationServerPostHandler.cs | 2 +- .../Handlers/Authentication/OpenIdServerHandler.cs | 30 +-- .../AuthorizationServerPostHandler.cs | 2 +- .../Handlers/Avatar/AvatarServerPostHandler.cs | 2 +- .../Handlers/Friends/FriendsServerPostHandler.cs | 2 +- .../Server/Handlers/Grid/GridServerPostHandler.cs | 2 +- .../Handlers/GridUser/GridUserServerPostHandler.cs | 2 +- .../Hypergrid/HGFriendsServerPostHandler.cs | 2 +- .../Handlers/Hypergrid/HeloServerConnector.cs | 2 +- .../Server/Handlers/Hypergrid/HomeAgentHandlers.cs | 1 + .../Inventory/InventoryServerMoveItemsHandler.cs | 2 +- .../Handlers/Inventory/XInventoryInConnector.cs | 2 +- .../Server/Handlers/Map/MapAddServerConnector.cs | 2 +- .../Server/Handlers/Map/MapGetServerConnector.cs | 2 +- .../Server/Handlers/Neighbour/NeighbourHandlers.cs | 8 +- .../Handlers/Presence/PresenceServerPostHandler.cs | 2 +- .../Server/Handlers/Simulation/AgentHandlers.cs | 4 +- .../UserAccounts/UserAccountServerPostHandler.cs | 2 +- 43 files changed, 346 insertions(+), 80 deletions(-) diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs index 3584f78..67750f5 100644 --- a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs @@ -113,7 +113,7 @@ namespace OpenSim.Groups m_GroupsService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index 28f7acc..515b818 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -75,7 +75,7 @@ namespace OpenSim.Groups m_GroupsService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs index 2b3a01d..32c24db 100644 --- a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs +++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs @@ -75,7 +75,7 @@ namespace OpenSim.OfflineIM m_OfflineIMService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs index 458272d..890df90 100644 --- a/OpenSim/Capabilities/CapsHandlers.cs +++ b/OpenSim/Capabilities/CapsHandlers.cs @@ -39,7 +39,7 @@ namespace OpenSim.Framework.Capabilities ///
public class CapsHandlers { - private Dictionary m_capsHandlers = new Dictionary(); + private Dictionary m_capsHandlers = new Dictionary(); private IHttpServer m_httpListener; private string m_httpListenerHostName; private uint m_httpListenerPort; @@ -184,5 +184,17 @@ namespace OpenSim.Framework.Capabilities return caps; } + + /// + /// Returns a copy of the dictionary of all the HTTP cap handlers + /// + /// + /// The dictionary copy. The key is the capability name, the value is the HTTP handler. + /// + public Dictionary GetCapsHandlers() + { + lock (m_capsHandlers) + return new Dictionary(m_capsHandlers); + } } -} +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs index 4dca592..426174d 100644 --- a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs +++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs @@ -56,7 +56,7 @@ namespace OpenSim.Capabilities.Handlers m_PeopleService = peopleService; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + 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); diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index 9f3cc19..789bf2b 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -64,7 +64,7 @@ namespace OpenSim.Capabilities.Handlers m_assetService = assService; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + 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); diff --git a/OpenSim/Capabilities/LLSDStreamHandler.cs b/OpenSim/Capabilities/LLSDStreamHandler.cs index 5df24b2..4fa1153 100644 --- a/OpenSim/Capabilities/LLSDStreamHandler.cs +++ b/OpenSim/Capabilities/LLSDStreamHandler.cs @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Capabilities m_method = method; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //Encoding encoding = Util.UTF8; diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index ae7aaf2..bbac699 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs @@ -31,6 +31,10 @@ namespace OpenSim.Framework.Servers.HttpServer { public abstract class BaseRequestHandler { + public int RequestsReceived { get; protected set; } + + public int RequestsHandled { get; protected set; } + public virtual string ContentType { get { return "application/xml"; } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index 6342983..252cc2a 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs @@ -29,14 +29,35 @@ using System.IO; namespace OpenSim.Framework.Servers.HttpServer { + /// + /// Base streamed request handler. + /// + /// + /// Inheriting classes should override ProcessRequest() rather than Handle() + /// public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler { - public abstract byte[] Handle(string path, Stream request, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse); - protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} protected BaseStreamHandler(string httpMethod, string path, string name, string description) : base(httpMethod, path, name, description) {} + + public virtual byte[] Handle( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + RequestsReceived++; + + byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); + + RequestsHandled++; + + return result; + } + + protected virtual byte[] ProcessRequest( + string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + return null; + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs index b94bfb4..1b03f54 100644 --- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs @@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = binaryMethod; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] data = ReadFully(request); string param = GetParam(path); diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs index cb5cce5..b8541cb 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs @@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer { public interface IRequestHandler { - /// /// Name for this handler. /// @@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer // Return path string Path { get; } + + /// + /// Number of requests received by this handler + /// + int RequestsReceived { get; } + + /// + /// Number of requests handled. + /// + /// + /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock. + /// + int RequestsHandled { get; } } public interface IStreamedRequestHandler : IRequestHandler @@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer public interface IStreamHandler : IRequestHandler { - // Handle request stream, return byte array void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); } diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs index 07082a8..bd55657 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs @@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer { public delegate TResponse RestDeserialiseMethod(TRequest request); - public class RestDeserialiseHandler : BaseRequestHandler, IStreamHandler + public class RestDeserialiseHandler : BaseOutputStreamHandler, IStreamHandler where TRequest : new() { private RestDeserialiseMethod m_method; @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = method; } - public void Handle(string path, Stream request, Stream responseStream, + protected override void ProcessRequest(string path, Stream request, Stream responseStream, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { TRequest deserial; diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs index edcd134..83c9848 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs @@ -183,7 +183,7 @@ namespace OpenSim.Framework.Servers.HttpServer public delegate bool CheckIdentityMethod(string sid, string aid); - public class RestDeserialiseSecureHandler : BaseRequestHandler, IStreamHandler + public class RestDeserialiseSecureHandler : BaseOutputStreamHandler, IStreamHandler where TRequest : new() { private static readonly ILog m_log @@ -201,7 +201,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = method; } - public void Handle(string path, Stream request, Stream responseStream, + protected override void ProcessRequest(string path, Stream request, Stream responseStream, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { RestSessionObject deserial = default(RestSessionObject); @@ -237,7 +237,7 @@ namespace OpenSim.Framework.Servers.HttpServer public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); - public class RestDeserialiseTrustedHandler : BaseRequestHandler, IStreamHandler + public class RestDeserialiseTrustedHandler : BaseOutputStreamHandler, IStreamHandler where TRequest : new() { private static readonly ILog m_log @@ -260,7 +260,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_method = method; } - public void Handle(string path, Stream request, Stream responseStream, + protected override void ProcessRequest(string path, Stream request, Stream responseStream, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { TRequest deserial = default(TRequest); @@ -292,6 +292,5 @@ namespace OpenSim.Framework.Servers.HttpServer serializer.Serialize(xmlWriter, response); } } - } - -} + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs index 1f17fee..0305dee 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_restMethod = restMethod; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { Encoding encoding = Encoding.UTF8; StreamReader streamReader = new StreamReader(request, encoding); diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 841069c..f0c088a 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -766,7 +766,7 @@ namespace OpenSim { public SimStatusHandler() : base("GET", "/simstatus", "SimStatus", "Simulator Status") {} - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes("OK"); @@ -792,7 +792,7 @@ namespace OpenSim m_opensim = sim; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest)); @@ -810,7 +810,7 @@ namespace OpenSim /// If the request contains a key, "callback" the response will be wrappend in the /// associated value for jsonp used with ajax/javascript ///
- public class UXSimStatusHandler : BaseStreamHandler + protected class UXSimStatusHandler : BaseStreamHandler { OpenSimBase m_opensim; @@ -820,7 +820,7 @@ namespace OpenSim m_opensim = sim; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest)); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs index 69dd76f..a133a69 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/RegionConsoleModule.cs @@ -176,7 +176,7 @@ namespace OpenSim.Region.ClientStack.Linden m_isGod = m_scene.Permissions.IsGod(agentID); } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader reader = new StreamReader(request); string message = reader.ReadToEnd(); diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs index 08196f1..2116605 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs @@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_FriendsModule = fmodule; } - public override byte[] Handle( + protected override byte[] ProcessRequest( string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index c8b341b..bd60611 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; using log4net; @@ -37,6 +38,7 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using Caps=OpenSim.Framework.Capabilities.Caps; @@ -58,6 +60,7 @@ namespace OpenSim.Region.CoreModules.Framework protected Dictionary m_capsObjects = new Dictionary(); protected Dictionary m_capsPaths = new Dictionary(); + protected Dictionary> m_childrenSeeds = new Dictionary>(); @@ -70,9 +73,24 @@ namespace OpenSim.Region.CoreModules.Framework m_scene = scene; m_scene.RegisterModuleInterface(this); - MainConsole.Instance.Commands.AddCommand("Comms", false, "show caps", - "show caps", - "Shows all registered capabilities for users", HandleShowCapsCommand); + MainConsole.Instance.Commands.AddCommand( + "Comms", false, "show caps list", + "show caps list", + "Shows list of registered capabilities for users.", HandleShowCapsListCommand); + + MainConsole.Instance.Commands.AddCommand( + "Comms", false, "show caps stats by user", + "show caps stats [ ]", + "Shows statistics on capabilities use by user.", + "If a user name is given, then prints a detailed breakdown of caps use ordered by number of requests received.", + HandleShowCapsStatsByUserCommand); + + MainConsole.Instance.Commands.AddCommand( + "Comms", false, "show caps stats by cap", + "show caps stats by cap []", + "Shows statistics on capabilities use by capability.", + "If a capability name is given, then prints a detailed breakdown of use by each user.", + HandleShowCapsStatsByCapCommand); } public void RegionLoaded(Scene scene) @@ -262,8 +280,11 @@ namespace OpenSim.Region.CoreModules.Framework } } - private void HandleShowCapsCommand(string module, string[] cmdparams) + private void HandleShowCapsListCommand(string module, string[] cmdParams) { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + StringBuilder caps = new StringBuilder(); caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); @@ -286,5 +307,210 @@ namespace OpenSim.Region.CoreModules.Framework MainConsole.Instance.Output(caps.ToString()); } + + private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams) + { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + + if (cmdParams.Length != 5 && cmdParams.Length != 6) + { + MainConsole.Instance.Output("Usage: show caps stats by cap []"); + return; + } + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Region {0}:\n", m_scene.Name); + + if (cmdParams.Length == 5) + { + BuildSummaryStatsByCapReport(sb); + } + else if (cmdParams.Length == 6) + { + BuildDetailedStatsByCapReport(sb, cmdParams[5]); + } + + MainConsole.Instance.Output(sb.ToString()); + } + + private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName) + { + sb.AppendFormat("Capability name {0}\n", capName); + + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("User Name", 34); + cdt.AddColumn("Req Received", 12); + cdt.AddColumn("Req Handled", 12); + cdt.Indent = 2; + + Dictionary receivedStats = new Dictionary(); + Dictionary handledStats = new Dictionary(); + + m_scene.ForEachScenePresence( + sp => + { + Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); + + if (caps == null) + return; + + Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + + IRequestHandler reqHandler; + if (capsHandlers.TryGetValue(capName, out reqHandler)) + { + receivedStats[sp.Name] = reqHandler.RequestsReceived; + handledStats[sp.Name] = reqHandler.RequestsHandled; + } + } + ); + + foreach (KeyValuePair kvp in receivedStats.OrderByDescending(kp => kp.Value)) + { + cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]); + } + + sb.Append(cdt.ToString()); + } + + private void BuildSummaryStatsByCapReport(StringBuilder sb) + { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Name", 34); + cdt.AddColumn("Req Received", 12); + cdt.AddColumn("Req Handled", 12); + cdt.Indent = 2; + + Dictionary receivedStats = new Dictionary(); + Dictionary handledStats = new Dictionary(); + + m_scene.ForEachScenePresence( + sp => + { + Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); + + if (caps == null) + return; + + Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + + foreach (IRequestHandler reqHandler in capsHandlers.Values) + { + string reqName = reqHandler.Name ?? ""; + + if (!receivedStats.ContainsKey(reqName)) + { + receivedStats[reqName] = reqHandler.RequestsReceived; + handledStats[reqName] = reqHandler.RequestsHandled; + } + else + { + receivedStats[reqName] += reqHandler.RequestsReceived; + handledStats[reqName] += reqHandler.RequestsHandled; + } + } + } + ); + + foreach (KeyValuePair kvp in receivedStats.OrderByDescending(kp => kp.Value)) + cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]); + + sb.Append(cdt.ToString()); + } + + private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams) + { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + + if (cmdParams.Length != 5 && cmdParams.Length != 7) + { + MainConsole.Instance.Output("Usage: show caps stats by user [ ]"); + return; + } + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Region {0}:\n", m_scene.Name); + + if (cmdParams.Length == 5) + { + BuildSummaryStatsByUserReport(sb); + } + else if (cmdParams.Length == 7) + { + string firstName = cmdParams[5]; + string lastName = cmdParams[6]; + + ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); + + if (sp == null) + return; + + BuildDetailedStatsByUserReport(sb, sp); + } + + MainConsole.Instance.Output(sb.ToString()); + } + + private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp) + { + sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root"); + + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Cap Name", 34); + cdt.AddColumn("Req Received", 12); + cdt.AddColumn("Req Handled", 12); + cdt.Indent = 2; + + Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); + + if (caps == null) + return; + + Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + + foreach (IRequestHandler reqHandler in capsHandlers.Values.OrderByDescending(rh => rh.RequestsReceived)) + { + cdt.AddRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled); + } + + sb.Append(cdt.ToString()); + } + + private void BuildSummaryStatsByUserReport(StringBuilder sb) + { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Name", 32); + cdt.AddColumn("Type", 5); + cdt.AddColumn("Req Received", 12); + cdt.AddColumn("Req Handled", 12); + cdt.Indent = 2; + + m_scene.ForEachScenePresence( + sp => + { + Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); + + if (caps == null) + return; + + Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + + int totalRequestsReceived = 0; + int totalRequestsHandled = 0; + + foreach (IRequestHandler reqHandler in capsHandlers.Values) + { + totalRequestsReceived += reqHandler.RequestsReceived; + totalRequestsHandled += reqHandler.RequestsHandled; + } + + cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled); + } + ); + + sb.Append(cdt.ToString()); + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs index eb74cda..2366767 100644 --- a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.World.Estate m_EstateModule = fmodule; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs index 726becf..f208afb 100644 --- a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs +++ b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.Framework.Scenes osXStatsURI = Util.SHA1Hash(regionInfo.osSecret); } - public override byte[] Handle( + protected override byte[] ProcessRequest( string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return Util.UTF8.GetBytes(Report()); diff --git a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs index 1ea1c20..6e0a80a 100644 --- a/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs +++ b/OpenSim/Region/OptionalModules/ViewerSupport/DynamicMenuModule.cs @@ -281,7 +281,7 @@ namespace OpenSim.Region.OptionalModules.ViewerSupport m_module = module; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader reader = new StreamReader(request); string requestBody = reader.ReadToEnd(); diff --git a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs index 550b5d4..8720cc7 100644 --- a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs +++ b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewRequestHandler.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.OptionalModules.World.WorldView m_WorldViewModule = fmodule; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { httpResponse.ContentType = "image/jpeg"; diff --git a/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs index 986394b..941b97d 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs @@ -70,7 +70,7 @@ namespace OpenSim.Server.Handlers.Asset m_allowedTypes = allowedTypes; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { bool result = false; diff --git a/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs index 8f7412b..8b23a83 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs @@ -54,7 +54,7 @@ namespace OpenSim.Server.Handlers.Asset m_AssetService = service; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] result = new byte[0]; diff --git a/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs b/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs index a006fa8..8eebc61 100644 --- a/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs @@ -54,7 +54,7 @@ namespace OpenSim.Server.Handlers.Asset m_AssetService = service; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { AssetBase asset; diff --git a/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs b/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs index 6b93cd9..16e011a 100644 --- a/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs @@ -70,7 +70,7 @@ namespace OpenSim.Server.Handlers.Authentication } } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { string[] p = SplitParams(path); diff --git a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs index 18cef15..66a26fc 100644 --- a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs +++ b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs @@ -147,7 +147,7 @@ namespace OpenSim.Server.Handlers.Authentication #endregion } - public class OpenIdStreamHandler : IStreamHandler + public class OpenIdStreamHandler : BaseOutputStreamHandler { #region HTML @@ -191,42 +191,34 @@ For more information, see http://openid.net/. #endregion HTML - public string Name { get { return "OpenId"; } } - public string Description { get { return null; } } - public string ContentType { get { return m_contentType; } } - public string HttpMethod { get { return m_httpMethod; } } - public string Path { get { return m_path; } } - - string m_contentType; - string m_httpMethod; - string m_path; IAuthenticationService m_authenticationService; IUserAccountService m_userAccountService; ProviderMemoryStore m_openidStore = new ProviderMemoryStore(); + public override string ContentType { get { return "text/html"; } } + /// /// Constructor /// - public OpenIdStreamHandler(string httpMethod, string path, IUserAccountService userService, IAuthenticationService authService) + public OpenIdStreamHandler( + string httpMethod, string path, IUserAccountService userService, IAuthenticationService authService) + : base(httpMethod, path, "OpenId", "OpenID stream handler") { m_authenticationService = authService; m_userAccountService = userService; - m_httpMethod = httpMethod; - m_path = path; - - m_contentType = "text/html"; } /// /// Handles all GET and POST requests for OpenID identifier pages and endpoint /// server communication /// - public void Handle(string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override void ProcessRequest( + string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { Uri providerEndpoint = new Uri(String.Format("{0}://{1}{2}", httpRequest.Url.Scheme, httpRequest.Url.Authority, httpRequest.Url.AbsolutePath)); // Defult to returning HTML content - m_contentType = "text/html"; + httpResponse.ContentType = ContentType; try { @@ -276,7 +268,7 @@ For more information, see http://openid.net/. string[] contentTypeValues = provider.Request.Response.Headers.GetValues("Content-Type"); if (contentTypeValues != null && contentTypeValues.Length == 1) - m_contentType = contentTypeValues[0]; + httpResponse.ContentType = contentTypeValues[0]; // Set the response code and document body based on the OpenID result httpResponse.StatusCode = (int)provider.Request.Response.Code; @@ -344,4 +336,4 @@ For more information, see http://openid.net/. return false; } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs b/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs index bcf9d47..c9b4e9b 100644 --- a/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Authorization/AuthorizationServerPostHandler.cs @@ -54,7 +54,7 @@ namespace OpenSim.Server.Handlers.Authorization m_AuthorizationService = service; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { XmlSerializer xs = new XmlSerializer(typeof (AuthorizationRequest)); diff --git a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs index 8cd747e..d6bbb8f 100644 --- a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs @@ -56,7 +56,7 @@ namespace OpenSim.Server.Handlers.Avatar m_AvatarService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs index 47a8558..ca0a24c 100644 --- a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs @@ -57,7 +57,7 @@ namespace OpenSim.Server.Handlers.Friends m_FriendsService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs index ef5f33e..89cba8a 100644 --- a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs @@ -57,7 +57,7 @@ namespace OpenSim.Server.Handlers.Grid m_GridService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs index 7483395..0b98e9a 100644 --- a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs +++ b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs @@ -56,7 +56,7 @@ namespace OpenSim.Server.Handlers.GridUser m_GridUserService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs index 0aa2729..a2bdadb 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs @@ -68,7 +68,7 @@ namespace OpenSim.Server.Handlers.Hypergrid m_log.ErrorFormat("[HGFRIENDS HANDLER]: TheService is null!"); } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs index f306b1c..06eaf2e 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HeloServerConnector.cs @@ -91,7 +91,7 @@ namespace OpenSim.Server.Handlers.Hypergrid m_HandlersType = handlersType; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { return OKResponse(httpResponse); diff --git a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs index df875af..f37f2f1 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs @@ -68,6 +68,7 @@ namespace OpenSim.Server.Handlers.Hypergrid { return new ExtendedAgentDestinationData(); } + protected override void UnpackData(OSDMap args, AgentDestinationData d, Hashtable request) { base.UnpackData(args, d, request); diff --git a/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs b/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs index 231e32f..e2c50fe 100644 --- a/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs +++ b/OpenSim/Server/Handlers/Inventory/InventoryServerMoveItemsHandler.cs @@ -56,7 +56,7 @@ namespace OpenSim.Server.Handlers.Inventory m_InventoryService = service; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { XmlSerializer xs = new XmlSerializer(typeof (List)); diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index 9d28dc3..0d7c136 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs @@ -87,7 +87,7 @@ namespace OpenSim.Server.Handlers.Asset m_InventoryService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs index 4a61969..d438fc7 100644 --- a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs @@ -99,7 +99,7 @@ namespace OpenSim.Server.Handlers.MapImage m_Proxy = proxy; } - public override byte[] Handle(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[MAP SERVICE IMAGE HANDLER]: Received {0}", path); StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs index fb85d1c..7bb2f39 100644 --- a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs @@ -80,7 +80,7 @@ namespace OpenSim.Server.Handlers.MapImage m_MapService = service; } - public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] result = new byte[0]; diff --git a/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs b/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs index 8a1f824..3525a01 100644 --- a/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs +++ b/OpenSim/Server/Handlers/Neighbour/NeighbourHandlers.cs @@ -58,7 +58,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AuthenticationService = authentication; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Not implemented yet @@ -83,7 +83,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AllowForeignGuests = foreignGuests; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] result = new byte[0]; @@ -176,7 +176,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AuthenticationService = authentication; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Not implemented yet @@ -197,7 +197,7 @@ namespace OpenSim.Server.Handlers.Neighbour // TODO: unused: m_AuthenticationService = authentication; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // Not implemented yet diff --git a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs index 2d67c6d..abb4b19 100644 --- a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs @@ -56,7 +56,7 @@ namespace OpenSim.Server.Handlers.Presence m_PresenceService = service; } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 71a9e6f..a9fd4ed 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -251,7 +251,7 @@ namespace OpenSim.Server.Handlers.Simulation m_SimulationService = null; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[SIMULATION]: Stream handler called"); @@ -457,7 +457,7 @@ namespace OpenSim.Server.Handlers.Simulation m_SimulationService = null; } - public override byte[] Handle(string path, Stream request, + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // m_log.DebugFormat("[SIMULATION]: Stream handler called"); diff --git a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs index 72551ef..24c9de6 100644 --- a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs +++ b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs @@ -68,7 +68,7 @@ namespace OpenSim.Server.Handlers.UserAccounts } } - public override byte[] Handle(string path, Stream requestData, + protected override byte[] ProcessRequest(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { StreamReader sr = new StreamReader(requestData); -- cgit v1.1 From b2d4b8b1da10e88d0f2471fb9cd502a8ed7dd095 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 8 Jul 2013 14:12:11 -0700 Subject: BaseHttpServer: if the handler sets the content length, don't override it. This happens in HEAD handlers. --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 40b8c5c..6863e0e 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -688,7 +688,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (buffer != null) { - if (!response.SendChunked) + if (!response.SendChunked && response.ContentLength64 <= 0) response.ContentLength64 = buffer.LongLength; response.OutputStream.Write(buffer, 0, buffer.Length); -- cgit v1.1 From 013710168b3878fc0a93a92a1c026efb49da9935 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 22:39:07 +0100 Subject: For stat purposes, add names to capability request handlers where these were not set --- OpenSim/Capabilities/Caps.cs | 1 - .../Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 10 ++++++++-- .../ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | 3 ++- OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | 6 +++--- .../Region/OptionalModules/Materials/MaterialsDemoModule.cs | 11 +++++++---- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index bc6f6f9..1bed1a5 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -144,7 +144,6 @@ namespace OpenSim.Framework.Capabilities public void RegisterHandler(string capName, IRequestHandler handler) { m_capsHandlers[capName] = handler; - //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); } /// diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index a46c24a..5c6bc1c 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -207,9 +207,15 @@ namespace OpenSim.Region.ClientStack.Linden m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); - IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); + + IRequestHandler getObjectPhysicsDataHandler + = new RestStreamHandler( + "POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData, "GetObjectPhysicsData", null); m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); - IRequestHandler UpdateAgentInformationHandler = new RestStreamHandler("POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation); + + IRequestHandler UpdateAgentInformationHandler + = new RestStreamHandler( + "POST", capsBase + m_UpdateAgentInformationPath, UpdateAgentInformation, "UpdateAgentInformation", null); m_HostCapsObj.RegisterHandler("UpdateAgentInformation", UpdateAgentInformationHandler); m_HostCapsObj.RegisterHandler( diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index e73a04a..50bfda1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -366,7 +366,8 @@ namespace OpenSim.Region.ClientStack.Linden // EventQueueGet when it receive capability information, but then we replace the rest handler immediately // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but // really it should be possible to directly register the poll handler as a capability. - caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null)); + caps.RegisterHandler( + "EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null, "EventQueueGet", null)); // delegate(Hashtable m_dhttpMethod) // { // return ProcessQueue(m_dhttpMethod, agentID, caps); diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index a542d62..0cd495c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs @@ -122,9 +122,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods { string uri = "/CAPS/" + UUID.Random(); - caps.RegisterHandler("UntrustedSimulatorMessage", - new RestStreamHandler("POST", uri, - HandleUntrustedSimulatorMessage)); + caps.RegisterHandler( + "UntrustedSimulatorMessage", + new RestStreamHandler("POST", uri, HandleUntrustedSimulatorMessage, "UntrustedSimulatorMessage", null)); } private string HandleUntrustedSimulatorMessage(string request, diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 3a39971..00504d0 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -139,18 +139,21 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { string capsBase = "/CAPS/" + caps.CapsObjectPath; - IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); - caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); + IRequestHandler renderMaterialsPostHandler + = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterialsPost", null); + caps.RegisterHandler("RenderMaterialsPost", renderMaterialsPostHandler); // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET // and POST handlers, (at least at the time this was originally written), so we first set up a POST // handler normally and then add a GET handler via MainServer - IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); + IRequestHandler renderMaterialsGetHandler + = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterialsGet", null); MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well - IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap); + IRequestHandler renderMaterialsPutHandler + = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterialsPut", null); MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); } -- cgit v1.1 From 8be59829d1fcf4c4f42a1a859aef6aa5f4f29073 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 22:41:24 +0100 Subject: minor: Add back commented out logging message in Caps.RegisterHandler() that I accidentally removed. --- OpenSim/Capabilities/Caps.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 1bed1a5..6c95d8b 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -143,6 +143,7 @@ namespace OpenSim.Framework.Capabilities /// public void RegisterHandler(string capName, IRequestHandler handler) { + //m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path); m_capsHandlers[capName] = handler; } -- cgit v1.1 From eccec4f8f654633ee97942a2decf8a7ba3a2b153 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 23:32:19 +0100 Subject: minor: remove now unused migration-hack bool from DAMap --- OpenSim/Framework/DAMap.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index 5c729e8..4995a92 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs @@ -132,10 +132,6 @@ namespace OpenSim.Framework { List keysToRemove = null; - // Hard-coded special case that needs to be removed in the future. Normally, modules themselves should - // handle reading data from old locations - bool osMaterialsMigrationRequired = false; - OSDMap namespacesMap = daMap.m_map; foreach (string key in namespacesMap.Keys) -- cgit v1.1 From 047ef9c2a5cb573c0a506fecd0f2a7e8dc85c023 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 23:36:57 +0100 Subject: minor: remove some mono compiler warnings in OdePlugin --- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 1 - OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 0d66496..13c69d6 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -108,7 +108,6 @@ namespace OpenSim.Region.Physics.OdePlugin private Vector3 m_taintAngularLock = Vector3.One; private IntPtr Amotor = IntPtr.Zero; - private object m_assetsLock = new object(); private bool m_assetFailed = false; private Vector3 m_PIDTarget; diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 07663b3..7e652fc 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -46,7 +46,7 @@ namespace OpenSim.Region.Physics.OdePlugin /// public class OdePlugin : IPhysicsPlugin { - private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private OdeScene m_scene; -- cgit v1.1 From 2025dd25f6041e276e9ecde6829d0c51a565fae5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 23:50:40 +0100 Subject: Add missing file BaseOutputStreamHandler.cs from recent commit e19defd --- .../Servers/HttpServer/BaseOutputStreamHandler.cs | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs diff --git a/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs new file mode 100644 index 0000000..72b3065 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs @@ -0,0 +1,60 @@ +/* + * 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.IO; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// Base handler for writing to an output stream + /// + /// + /// Inheriting classes should override ProcessRequest() rather than Handle() + /// + public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler + { + protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} + + protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description) + : base(httpMethod, path, name, description) {} + + public virtual void Handle( + string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + RequestsReceived++; + + ProcessRequest(path, request, response, httpRequest, httpResponse); + + RequestsHandled++; + } + + protected virtual void ProcessRequest( + string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + } + } +} \ No newline at end of file -- cgit v1.1 From af9b17c54570a1634d078df0feb8f1b53ffb0726 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 23:52:40 +0100 Subject: minor: remove mono compiler warnings related to keyframe code --- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 9 +++------ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 2 -- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 8a40278..29652aa 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -55,7 +55,6 @@ namespace OpenSim.Region.Framework.Scenes private object m_lockObject = new object(); private object m_timerLock = new object(); private const double m_tickDuration = 50.0; - private Scene m_scene; public double TickDuration { @@ -69,8 +68,6 @@ namespace OpenSim.Region.Framework.Scenes m_timer.AutoReset = true; m_timer.Elapsed += OnTimer; - m_scene = scene; - m_timer.Start(); } @@ -94,13 +91,13 @@ namespace OpenSim.Region.Framework.Scenes { m.OnTimer(TickDuration); } - catch (Exception inner) + catch (Exception) { // Don't stop processing } } } - catch (Exception e) + catch (Exception) { // Keep running no matter what } @@ -157,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes [Serializable] public class KeyframeMotion { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public enum PlayMode : int { diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index f287a34..f361acb 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -354,8 +354,6 @@ namespace OpenSim.Region.Framework.Scenes private UUID m_collisionSound; private float m_collisionSoundVolume; - private KeyframeMotion m_keyframeMotion = null; - public KeyframeMotion KeyframeMotion { get; set; -- cgit v1.1 From 83da14008f9a8a4ad0cf0dd5487327e4a319fd5d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 8 Jul 2013 23:57:05 +0100 Subject: minor: remove some mono compiler warnings in new groups code --- OpenSim/Addons/Groups/GroupsModule.cs | 2 +- OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 1 - OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs | 2 -- OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs | 4 ---- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 5959bac..82e2d6f 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -485,7 +485,7 @@ namespace OpenSim.Groups return; //// 16 bytes are the UUID. Maybe. - UUID folderID = new UUID(im.binaryBucket, 0); +// UUID folderID = new UUID(im.binaryBucket, 0); UUID noticeID = new UUID(im.imSessionID); GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID); diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index cff7adf..c3c759e 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -543,7 +543,6 @@ namespace OpenSim.Groups List urls = new List(); foreach (GroupMembersData m in members) { - UUID userID = UUID.Zero; if (!m_UserManagement.IsLocalGridUser(m.AgentID)) { string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI"); diff --git a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs index 67750f5..d2bcba5 100644 --- a/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Hypergrid/HGGroupsServiceRobustConnector.cs @@ -47,7 +47,6 @@ namespace OpenSim.Groups private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HGGroupsService m_GroupsService; - private string m_HomeURI = string.Empty; private string m_ConfigName = "Groups"; // Called by Robust shell @@ -209,7 +208,6 @@ namespace OpenSim.Groups UUID groupID = new UUID(request["GroupID"].ToString()); string agentID = request["AgentID"].ToString(); string token = request["AccessToken"].ToString(); - string reason = string.Empty; m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token); } diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index 515b818..106c6c4 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -269,7 +269,6 @@ namespace OpenSim.Groups UUID groupID = new UUID(request["GroupID"].ToString()); string agentID = request["AgentID"].ToString(); string requestingAgentID = request["RequestingAgentID"].ToString(); - string reason = string.Empty; m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID); } @@ -500,7 +499,6 @@ namespace OpenSim.Groups else { string op = request["OP"].ToString(); - string reason = string.Empty; bool success = false; if (op == "ADD") @@ -568,7 +566,6 @@ namespace OpenSim.Groups else { string op = request["OP"].ToString(); - string reason = string.Empty; if (op == "GROUP") { @@ -631,7 +628,6 @@ namespace OpenSim.Groups else { string op = request["OP"].ToString(); - string reason = string.Empty; if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID")) { -- cgit v1.1 From 5f58b9b5526c401e039d27b8c92603ff02421fb8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Jul 2013 00:04:46 +0100 Subject: minor: remove some mono compiler warnings in UserProfileModule --- .../Avatar/UserProfiles/UserProfileModule.cs | 29 ++++++++++------------ 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 161f160..44edd7f 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -304,7 +304,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(targetID, out serverURI); +// bool foreign = GetUserProfileServerURI(targetID, out serverURI); UUID creatorId = UUID.Zero; OSDMap parameters= new OSDMap(); @@ -369,7 +369,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(target, out serverURI); +// bool foreign = GetUserProfileServerURI(target, out serverURI); object Ad = (object)ad; if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) @@ -438,10 +438,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); ScenePresence p = FindPresence(remoteClient.AgentId); - Vector3 avaPos = p.AbsolutePosition; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if (land == null) { @@ -488,7 +487,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) { string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); UUID classifiedId; OSDMap parameters= new OSDMap(); @@ -538,7 +537,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(targetId, out serverURI); +// bool foreign = GetUserProfileServerURI(targetId, out serverURI); OSDMap parameters= new OSDMap(); parameters.Add("creatorId", OSD.FromUUID(targetId)); @@ -589,7 +588,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles UUID targetID; UUID.TryParse(args[0], out targetID); string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(targetID, out serverURI); +// bool foreign = GetUserProfileServerURI(targetID, out serverURI); IClientAPI remoteClient = (IClientAPI)sender; UserProfilePick pick = new UserProfilePick(); @@ -657,7 +656,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); ScenePresence p = FindPresence(remoteClient.AgentId); Vector3 avaPos = p.AbsolutePosition; @@ -717,7 +716,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void PickDelete(IClientAPI remoteClient, UUID queryPickID) { string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); OSDMap parameters= new OSDMap(); parameters.Add("pickId", OSD.FromUUID(queryPickID)); @@ -752,7 +751,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles IClientAPI remoteClient = (IClientAPI)sender; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); note.TargetId = remoteClient.AgentId; UUID.TryParse(args[0], out note.UserId); @@ -788,7 +787,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles note.Notes = queryNotes; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Note = note; if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) @@ -833,7 +832,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles prop.Language = languages; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Param = prop; if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) @@ -955,7 +954,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles prop.FirstLifeText = newProfile.FirstLifeAboutText; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); +// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Prop = prop; @@ -994,7 +993,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); +// bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); // This is checking a friend on the home grid // Not HG friend @@ -1247,7 +1246,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles return false; } - byte[] buf = new byte[8192]; Stream rstream = webResponse.GetResponseStream(); OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); @@ -1313,7 +1311,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles return false; } - byte[] buf = new byte[8192]; Stream rstream = webResponse.GetResponseStream(); OSDMap response = new OSDMap(); -- cgit v1.1 From 76b2b20f7e89d521114cea60746212fade90c14c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Jul 2013 00:06:22 +0100 Subject: minor: remove mono compiler warnings from HGSuitcaseInventoryService --- OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index 410916f..2567c8f 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -54,7 +54,7 @@ namespace OpenSim.Services.HypergridService LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private string m_HomeURL; +// private string m_HomeURL; private IUserAccountService m_UserAccountService; private IAvatarService m_AvatarService; @@ -96,8 +96,8 @@ namespace OpenSim.Services.HypergridService if (m_AvatarService == null) throw new Exception(String.Format("Unable to create m_AvatarService from {0}", avatarDll)); - m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", - new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty); +// m_HomeURL = Util.GetConfigVarFromSections(config, "HomeURI", +// new string[] { "Startup", "Hypergrid", m_ConfigName }, String.Empty); // m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); } -- cgit v1.1 From fad4241e4ea898b0dca0176cc9b428d03ba44d1c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 8 Jul 2013 16:21:10 -0700 Subject: BulletSim: make all the different angularVerticalAttraction algorithms selectable from configuration paramters. Changed default algorithm to "1" from previous default as it seems to handle Y axis correction a little better. Add config file independent enablement of vehicle angular forces to make debugging easier (independent testing of forces). --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 261 ++++++++++----------- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 15 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 4 +- .../Physics/BulletSPlugin/Tests/BasicVehicles.cs | 4 +- 4 files changed, 146 insertions(+), 138 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 82fe267..a5f2e98 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -125,33 +125,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin static readonly float PIOverFour = ((float)Math.PI) / 4f; static readonly float PIOverTwo = ((float)Math.PI) / 2f; - // For debugging, flags to turn on and off individual corrections. - public bool enableAngularVerticalAttraction; - public bool enableAngularDeflection; - public bool enableAngularBanking; - public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) : base(myScene, myPrim, actorName) { ControllingPrim = myPrim; Type = Vehicle.TYPE_NONE; m_haveRegisteredForSceneEvents = false; - SetupVehicleDebugging(); - } - - // Stopgap debugging enablement. Allows source level debugging but still checking - // in changes by making enablement of debugging flags from INI file. - public void SetupVehicleDebugging() - { - enableAngularVerticalAttraction = true; - enableAngularDeflection = true; - enableAngularBanking = true; - if (BSParam.VehicleDebuggingEnable) - { - enableAngularVerticalAttraction = true; - enableAngularDeflection = false; - enableAngularBanking = false; - } } // Return 'true' if this vehicle is doing vehicle things @@ -556,10 +535,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin } m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); - m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); - m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) /* Not implemented m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, @@ -1393,116 +1372,134 @@ namespace OpenSim.Region.Physics.BulletSPlugin { // If vertical attaction timescale is reasonable - if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) + if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) { - //Another formula to try got from : - //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html - - Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation; - - // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 - // since only computing half the distance between the angles. - float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; - - // Make a prediction of where the up axis will be when this is applied rather then where it is now as - // this makes for a smoother adjustment and less fighting between the various forces. - Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); - - // This is only half the distance to the target so it will take 2 seconds to complete the turn. - Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); - - // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared - Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; - - VehicleRotationalVelocity += vertContributionV; - - VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", - ControllingPrim.LocalID, - VehicleUpAxis, - predictedUp, - torqueVector, - vertContributionV); - //===================================================================== - /* - // Possible solution derived from a discussion at: - // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no - - // Create a rotation that is only the vehicle's rotation around Z - Vector3 currentEuler = Vector3.Zero; - VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); - Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); - - // Create the axis that is perpendicular to the up vector and the rotated up vector. - Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); - // Compute the angle between those to vectors. - double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); - // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical - - // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. - // TODO: add 'efficiency'. - differenceAngle /= m_verticalAttractionTimescale; - - // Create the quaterian representing the correction angle - Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); - - // Turn that quaternion into Euler values to make it into velocities to apply. - Vector3 vertContributionV = Vector3.Zero; - correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); - vertContributionV *= -1f; - - VehicleRotationalVelocity += vertContributionV; - - VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", - ControllingPrim.LocalID, - differenceAxis, - differenceAngle, - correctionRotation, - vertContributionV); - */ - - // =================================================================== - /* - Vector3 vertContributionV = Vector3.Zero; - Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG - - // Take a vector pointing up and convert it from world to vehicle relative coords. - Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation); - - // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) - // is now: - // leaning to one side: rotated around the X axis with the Y value going - // from zero (nearly straight up) to one (completely to the side)) or - // leaning front-to-back: rotated around the Y axis with the value of X being between - // zero and one. - // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. - - // Y error means needed rotation around X axis and visa versa. - // Since the error goes from zero to one, the asin is the corresponding angle. - vertContributionV.X = (float)Math.Asin(verticalError.Y); - // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) - vertContributionV.Y = -(float)Math.Asin(verticalError.X); - - // If verticalError.Z is negative, the vehicle is upside down. Add additional push. - if (verticalError.Z < 0f) + Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleOrientation; + switch (BSParam.VehicleAngularVerticalAttractionAlgorithm) { - vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; - // vertContribution.Y -= PIOverFour; + case 0: + { + //Another formula to try got from : + //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html + + // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 + // since only computing half the distance between the angles. + float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; + + // Make a prediction of where the up axis will be when this is applied rather then where it is now as + // this makes for a smoother adjustment and less fighting between the various forces. + Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); + + // This is only half the distance to the target so it will take 2 seconds to complete the turn. + Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); + + // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared + Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; + + VehicleRotationalVelocity += vertContributionV; + + VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", + ControllingPrim.LocalID, + vehicleUpAxis, + predictedUp, + torqueVector, + vertContributionV); + break; + } + case 1: + { + // Possible solution derived from a discussion at: + // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no + + // Create a rotation that is only the vehicle's rotation around Z + Vector3 currentEuler = Vector3.Zero; + VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); + Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); + + // Create the axis that is perpendicular to the up vector and the rotated up vector. + Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); + // Compute the angle between those to vectors. + double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); + // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical + + // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. + // TODO: add 'efficiency'. + differenceAngle /= m_verticalAttractionTimescale; + + // Create the quaterian representing the correction angle + Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); + + // Turn that quaternion into Euler values to make it into velocities to apply. + Vector3 vertContributionV = Vector3.Zero; + correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); + vertContributionV *= -1f; + + VehicleRotationalVelocity += vertContributionV; + + VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}", + ControllingPrim.LocalID, + vehicleUpAxis, + differenceAxis, + differenceAngle, + correctionRotation, + vertContributionV); + break; + } + case 2: + { + Vector3 vertContributionV = Vector3.Zero; + Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG + + // Take a vector pointing up and convert it from world to vehicle relative coords. + Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation); + + // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) + // is now: + // leaning to one side: rotated around the X axis with the Y value going + // from zero (nearly straight up) to one (completely to the side)) or + // leaning front-to-back: rotated around the Y axis with the value of X being between + // zero and one. + // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. + + // Y error means needed rotation around X axis and visa versa. + // Since the error goes from zero to one, the asin is the corresponding angle. + vertContributionV.X = (float)Math.Asin(verticalError.Y); + // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) + vertContributionV.Y = -(float)Math.Asin(verticalError.X); + + // If verticalError.Z is negative, the vehicle is upside down. Add additional push. + if (verticalError.Z < 0f) + { + vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; + // vertContribution.Y -= PIOverFour; + } + + // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. + // Correction happens over a number of seconds. + Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG + + // The correction happens over the user's time period + vertContributionV /= m_verticalAttractionTimescale; + + // Rotate the vehicle rotation to the world coordinates. + VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); + + VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}", + ControllingPrim.LocalID, + vehicleUpAxis, + origRotVelW, + verticalError, + unscaledContribVerticalErrorV, + m_verticalAttractionEfficiency, + m_verticalAttractionTimescale, + vertContributionV); + break; + } + default: + { + break; + } } - - // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. - // Correction happens over a number of seconds. - Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG - - // The correction happens over the user's time period - vertContributionV /= m_verticalAttractionTimescale; - - // Rotate the vehicle rotation to the world coordinates. - VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); - - VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", - Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, - m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); - */ } } @@ -1514,7 +1511,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin public void ComputeAngularDeflection() { - if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) + if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) { Vector3 deflectContributionV = Vector3.Zero; @@ -1593,7 +1590,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // make a sluggish vehicle by giving it a timescale of several seconds. public void ComputeAngularBanking() { - if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) + if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) { Vector3 bankingContributionV = Vector3.Zero; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 0f84bf7..75c3399 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -155,7 +155,10 @@ public static class BSParam public static Vector3 VehicleInertiaFactor { get; private set; } public static float VehicleGroundGravityFudge { get; private set; } public static float VehicleAngularBankingTimescaleFudge { get; private set; } - public static bool VehicleDebuggingEnable { get; private set; } + public static bool VehicleEnableAngularVerticalAttraction { get; private set; } + public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } + public static bool VehicleEnableAngularDeflection { get; private set; } + public static bool VehicleEnableAngularBanking { get; private set; } // Convex Hulls public static int CSHullMaxDepthSplit { get; private set; } @@ -606,8 +609,14 @@ public static class BSParam 0.2f ), new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 60.0f ), - new ParameterDefn("VehicleDebuggingEnable", "Turn on/off vehicle debugging", - false ), + new ParameterDefn("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", + true ), + new ParameterDefn("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", + 1 ), + new ParameterDefn("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", + true ), + new ParameterDefn("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", + true ), new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 0f, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index e56a6f6..214271b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -648,7 +648,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters simTime = Util.EnvironmentTickCountSubtract(beforeTime); if (PhysicsLogging.Enabled) { - DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", + DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 583c436..48d3742 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs @@ -57,6 +57,8 @@ public class BasicVehicles : OpenSimTestCase public void Init() { Dictionary engineParams = new Dictionary(); + engineParams.Add("VehicleEnableAngularVerticalAttraction", "true"); + engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1"); PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); @@ -119,7 +121,7 @@ public class BasicVehicles : OpenSimTestCase { vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); - vehicleActor.enableAngularVerticalAttraction = true; + // vehicleActor.enableAngularVerticalAttraction = true; TestVehicle.IsPhysical = true; PhysicsScene.ProcessTaints(); -- cgit v1.1 From 33eea62606908ca39ac90eb9c99b0eee3c5f39de Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 8 Jul 2013 17:12:39 -0700 Subject: remove an invalid null UUID check which caused a warning --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 00504d0..b997d4d 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -416,14 +416,7 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule if (te.DefaultTexture == null) m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); else - { - if (te.DefaultTexture.MaterialID == null) - m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); - else - { - te.DefaultTexture.MaterialID = id; - } - } + te.DefaultTexture.MaterialID = id; } else { -- cgit v1.1 From 065f8f56a248724c34d115f77a4d5b1a422f26f4 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 8 Jul 2013 19:18:01 -0700 Subject: remove some cruft and trigger a rebuild --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index b997d4d..0a0d65c 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -397,7 +397,6 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); else { - //var te = sop.Shape.Textures; var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); if (te == null) -- cgit v1.1 From 2c761cef192670a6f54fe10bb5b5894b5371ea7c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Jul 2013 09:33:46 -0700 Subject: BulletSim: add parameter to optionally disable vehicle linear deflection. Add parameter to not apply vehicle linear deflection Z forces if vehicle is not colliding. This defaults to 'true' so vehicles will fall even if there is some linear deflection to apply. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 42 ++++++++++++++-------- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 8 ++++- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index a5f2e98..0204967 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -905,6 +905,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); } } + private float VehicleForwardSpeed { get @@ -1040,26 +1041,37 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 linearDeflectionV = Vector3.Zero; Vector3 velocityV = VehicleForwardVelocity; - // Velocity in Y and Z dimensions is movement to the side or turning. - // Compute deflection factor from the to the side and rotational velocity - linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y); - linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z); + if (BSParam.VehicleEnableLinearDeflection) + { + // Velocity in Y and Z dimensions is movement to the side or turning. + // Compute deflection factor from the to the side and rotational velocity + linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y); + linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z); - // Velocity to the side and around is corrected and moved into the forward direction - linearDeflectionV.X += Math.Abs(linearDeflectionV.Y); - linearDeflectionV.X += Math.Abs(linearDeflectionV.Z); + // Velocity to the side and around is corrected and moved into the forward direction + linearDeflectionV.X += Math.Abs(linearDeflectionV.Y); + linearDeflectionV.X += Math.Abs(linearDeflectionV.Z); - // Scale the deflection to the fractional simulation time - linearDeflectionV *= pTimestep; + // Scale the deflection to the fractional simulation time + linearDeflectionV *= pTimestep; - // Subtract the sideways and rotational velocity deflection factors while adding the correction forward - linearDeflectionV *= new Vector3(1,-1,-1); + // Subtract the sideways and rotational velocity deflection factors while adding the correction forward + linearDeflectionV *= new Vector3(1, -1, -1); - // Correciont is vehicle relative. Convert to world coordinates and add to the velocity - VehicleVelocity += linearDeflectionV * VehicleOrientation; + // Correction is vehicle relative. Convert to world coordinates. + Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation; - VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}", - ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV); + // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. + if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.IsColliding) + { + linearDeflectionW.Z = 0f; + } + + VehicleVelocity += linearDeflectionW; + + VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}", + ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV); + } } public void ComputeLinearTerrainHeightCorrection(float pTimestep) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 75c3399..dcf1e83 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -155,6 +155,8 @@ public static class BSParam public static Vector3 VehicleInertiaFactor { get; private set; } public static float VehicleGroundGravityFudge { get; private set; } public static float VehicleAngularBankingTimescaleFudge { get; private set; } + public static bool VehicleEnableLinearDeflection { get; private set; } + public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; } public static bool VehicleEnableAngularVerticalAttraction { get; private set; } public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } public static bool VehicleEnableAngularDeflection { get; private set; } @@ -609,10 +611,14 @@ public static class BSParam 0.2f ), new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 60.0f ), + new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", + true ), + new ParameterDefn("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles", + true ), new ParameterDefn("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", true ), new ParameterDefn("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", - 1 ), + 0 ), new ParameterDefn("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", true ), new ParameterDefn("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", -- cgit v1.1 From 67e500383eb024fe4dd2681d0c5d902f289b65d8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 9 Jul 2013 14:12:52 -0700 Subject: Put guards on a bunch of exception-inducing code, as seen in logs from load test. --- .../CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs | 6 +++--- .../Framework/InventoryAccess/HGInventoryAccessModule.cs | 2 +- .../CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs | 5 +++++ OpenSim/Region/Framework/Scenes/Scene.cs | 4 +++- OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs | 6 ++++++ OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | 3 ++- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 630d1c3..759155a 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -171,11 +171,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!so.IsAttachment) return; - if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) + if (so.AttachedAvatar == UUID.Zero || Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar)) return; // foreign user - AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); + AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar); if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) { if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) @@ -183,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); Dictionary ids = new Dictionary(); - HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url); + HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url); uuidGatherer.GatherAssetUuids(so, ids); foreach (KeyValuePair kvp in ids) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 1eae0ac..e0c8ea6 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -135,7 +135,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (sp is ScenePresence) { AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId); - if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) + if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) { if (m_RestrictInventoryAccessAbroad) { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs index 221f815..e05d186 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs @@ -81,6 +81,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser public void OnConnectionClose(IClientAPI client) { + if (client == null) + return; + if (client.SceneAgent == null) + return; + if (client.SceneAgent.IsChildAgent) return; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 355e0ee..54956ee 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3687,7 +3687,9 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", sp.Name, sp.UUID, RegionInfo.RegionName); - sp.ControllingClient.Close(true); + if (sp.ControllingClient != null) + sp.ControllingClient.Close(true); + sp = null; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index dcb62f8..527ca35 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -67,6 +67,12 @@ namespace OpenSim.Region.Framework.Scenes { int scriptsStarted = 0; + if (m_scene == null) + { + m_log.DebugFormat("[PRIM INVENTORY]: m_scene is null. Unable to create script instances"); + return 0; + } + // Don't start scripts if they're turned off in the region! if (!m_scene.RegionInfo.RegionSettings.DisableScripts) { diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 7dba7c8..3f223a3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -553,7 +553,8 @@ namespace OpenSim.Region.Framework.Scenes /// public void StopScriptInstance(TaskInventoryItem item) { - m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID); + if (m_part.ParentGroup.Scene != null) + m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID); // At the moment, even stopped scripts are counted as active, which is probably wrong. // m_part.ParentGroup.AddActiveScriptCount(-1); -- cgit v1.1 From 095066b1cefa7e25ba5983ead1818727c2d64ccc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Jul 2013 23:39:29 +0100 Subject: Handle UUIDNameRequest UDP packet processing async instead of within the main inbound UDP processing loop, to avoid any chance that this is delaying the main udp in loop. The potential impact of this should be lower now that these requests are being placed on a queue. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 9784d15..bd61c3f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5390,7 +5390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest); AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); - AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); + AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest); AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); -- cgit v1.1 From cec8e6d0f7d073d69166a7bc3594772ae51820e2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 9 Jul 2013 23:52:47 +0100 Subject: If a sensor is in an attachment, avoid throwing an exception if the attachee is removed from the scene before we try to retrieve them. --- .../Shared/Api/Implementation/Plugins/SensorRepeat.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 88ab515..6e74227 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -353,6 +353,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Position of a sensor in a child prim attached to an avatar // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); + + // Don't proceed if the avatar for this attachment has since been removed from the scene. + if (avatar == null) + return sensedEntities; + q = avatar.GetWorldRotation() * q; } @@ -480,6 +485,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins // Position of a sensor in a child prim attached to an avatar // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); + + // Don't proceed if the avatar for this attachment has since been removed from the scene. + if (avatar == null) + return sensedEntities; + q = avatar.GetWorldRotation() * q; } -- cgit v1.1 From bb6fb65392dfa2249eeade137ea3316b3b3364c9 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Jul 2013 18:24:39 -0700 Subject: Revert "minor: remove some mono compiler warnings in UserProfileModule" Revert until we understand why all the calls to GetUserProfileServerURI were also commented out. This reverts commit 5f58b9b5526c401e039d27b8c92603ff02421fb8. --- .../Avatar/UserProfiles/UserProfileModule.cs | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 44edd7f..161f160 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -304,7 +304,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(targetID, out serverURI); + bool foreign = GetUserProfileServerURI(targetID, out serverURI); UUID creatorId = UUID.Zero; OSDMap parameters= new OSDMap(); @@ -369,7 +369,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(target, out serverURI); + bool foreign = GetUserProfileServerURI(target, out serverURI); object Ad = (object)ad; if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) @@ -438,9 +438,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); ScenePresence p = FindPresence(remoteClient.AgentId); + Vector3 avaPos = p.AbsolutePosition; string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if (land == null) { @@ -487,7 +488,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) { string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); UUID classifiedId; OSDMap parameters= new OSDMap(); @@ -537,7 +538,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(targetId, out serverURI); + bool foreign = GetUserProfileServerURI(targetId, out serverURI); OSDMap parameters= new OSDMap(); parameters.Add("creatorId", OSD.FromUUID(targetId)); @@ -588,7 +589,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles UUID targetID; UUID.TryParse(args[0], out targetID); string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(targetID, out serverURI); + bool foreign = GetUserProfileServerURI(targetID, out serverURI); IClientAPI remoteClient = (IClientAPI)sender; UserProfilePick pick = new UserProfilePick(); @@ -656,7 +657,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); ScenePresence p = FindPresence(remoteClient.AgentId); Vector3 avaPos = p.AbsolutePosition; @@ -716,7 +717,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void PickDelete(IClientAPI remoteClient, UUID queryPickID) { string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); OSDMap parameters= new OSDMap(); parameters.Add("pickId", OSD.FromUUID(queryPickID)); @@ -751,7 +752,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles IClientAPI remoteClient = (IClientAPI)sender; string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); note.TargetId = remoteClient.AgentId; UUID.TryParse(args[0], out note.UserId); @@ -787,7 +788,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles note.Notes = queryNotes; string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Note = note; if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) @@ -832,7 +833,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles prop.Language = languages; string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Param = prop; if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) @@ -954,7 +955,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles prop.FirstLifeText = newProfile.FirstLifeAboutText; string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Prop = prop; @@ -993,7 +994,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; -// bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); + bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); // This is checking a friend on the home grid // Not HG friend @@ -1246,6 +1247,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles return false; } + byte[] buf = new byte[8192]; Stream rstream = webResponse.GetResponseStream(); OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); @@ -1311,6 +1313,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles return false; } + byte[] buf = new byte[8192]; Stream rstream = webResponse.GetResponseStream(); OSDMap response = new OSDMap(); -- cgit v1.1 From 38e6da5522a53c7f65eac64ae7b0af929afb1ae6 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Jul 2013 18:34:24 -0700 Subject: Comment out old inbound UDP throttling hack. This would cause the UDP reception thread to sleep for 30ms if the number of available user worker threads got low. It doesn't look like any of the UDP packet types are marked async so this check is 1) unnecessary and 2) really crazy since it stops up the reception thread under heavy load without any indication. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 82fad11..2aab4f9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1615,6 +1615,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { IncomingPacket incomingPacket = null; + /* // HACK: This is a test to try and rate limit packet handling on Mono. // If it works, a more elegant solution can be devised if (Util.FireAndForgetCount() < 2) @@ -1622,6 +1623,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); Thread.Sleep(30); } + */ if (packetInbox.Dequeue(100, ref incomingPacket)) { -- cgit v1.1 From 59d19f038a3fdac0c347844c7884e813f5c5c136 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 10 Jul 2013 08:55:54 -0700 Subject: Remove a null reference exception in SimianPresenceServiceConnector that occurs when GetGridUserInfo cannot find the requested user info. --- .../Connectors/SimianGrid/SimianPresenceServiceConnector.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 0a39088..01163aa 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -315,11 +315,15 @@ namespace OpenSim.Services.Connectors.SimianGrid UUID userID = new UUID(user); OSDMap userResponse = GetUserData(userID); - if (userResponse != null) - return ResponseToGridUserInfo(userResponse); - m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID,userResponse["Message"].AsString()); - return null; + if (userResponse == null) + { + m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}", userID); + } + + // Note that ResponseToGridUserInfo properly checks for and returns a null if passed a null. + return ResponseToGridUserInfo(userResponse); + } #endregion -- cgit v1.1 From 1b265b213b65076ee346d85f62d2d61a72ea3ca6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 10 Jul 2013 16:09:45 -0700 Subject: Added show client-stats [first last] command to expose what viewers are requesting. --- OpenSim/Framework/ClientInfo.cs | 11 ++- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 18 +++- .../Region/ClientStack/Linden/UDP/LLUDPClient.cs | 27 +++-- .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 109 ++++++++++++++++++++- 4 files changed, 145 insertions(+), 20 deletions(-) diff --git a/OpenSim/Framework/ClientInfo.cs b/OpenSim/Framework/ClientInfo.cs index 62acb70..9021315 100644 --- a/OpenSim/Framework/ClientInfo.cs +++ b/OpenSim/Framework/ClientInfo.cs @@ -33,12 +33,13 @@ namespace OpenSim.Framework { public class ClientInfo { - public AgentCircuitData agentcircuit; + public readonly DateTime StartedTime = DateTime.Now; + public AgentCircuitData agentcircuit = null; public Dictionary needAck; - public List out_packets; - public Dictionary pendingAcks; + public List out_packets = new List(); + public Dictionary pendingAcks = new Dictionary(); public EndPoint proxyEP; public uint sequence; @@ -53,5 +54,9 @@ namespace OpenSim.Framework public int assetThrottle; public int textureThrottle; public int totalThrottle; + + public Dictionary SyncRequests = new Dictionary(); + public Dictionary AsyncRequests = new Dictionary(); + public Dictionary GenericRequests = new Dictionary(); } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index bd61c3f..3d92705 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -678,12 +678,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP //there is a local handler for this packet type if (pprocessor.Async) { + ClientInfo cinfo = UDPClient.GetClientInfo(); + if (!cinfo.AsyncRequests.ContainsKey(packet.Type.ToString())) + cinfo.AsyncRequests[packet.Type.ToString()] = 0; + cinfo.AsyncRequests[packet.Type.ToString()]++; + object obj = new AsyncPacketProcess(this, pprocessor.method, packet); Util.FireAndForget(ProcessSpecificPacketAsync, obj); result = true; } else { + ClientInfo cinfo = UDPClient.GetClientInfo(); + if (!cinfo.SyncRequests.ContainsKey(packet.Type.ToString())) + cinfo.SyncRequests[packet.Type.ToString()] = 0; + cinfo.SyncRequests[packet.Type.ToString()]++; + result = pprocessor.method(this, packet); } } @@ -698,6 +708,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP } if (found) { + ClientInfo cinfo = UDPClient.GetClientInfo(); + if (!cinfo.GenericRequests.ContainsKey(packet.Type.ToString())) + cinfo.GenericRequests[packet.Type.ToString()] = 0; + cinfo.GenericRequests[packet.Type.ToString()]++; + result = method(this, packet); } } @@ -12030,7 +12045,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP ClientInfo info = m_udpClient.GetClientInfo(); info.proxyEP = null; - info.agentcircuit = RequestClientInfo(); + if (info.agentcircuit == null) + info.agentcircuit = RequestClientInfo(); return info; } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 621e0fd..7749446 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -159,6 +159,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC private int m_maxRTO = 60000; + private ClientInfo m_info = new ClientInfo(); + /// /// Default constructor /// @@ -240,20 +242,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists // of pending and needed ACKs for every client every time some method wants information about // this connection is a recipe for poor performance - ClientInfo info = new ClientInfo(); - info.pendingAcks = new Dictionary(); - info.needAck = new Dictionary(); - - info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; - info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; - info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; - info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; - info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; - info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; - info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; - info.totalThrottle = (int)m_throttleCategory.DripRate; - - return info; + + m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; + m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; + m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; + m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; + m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; + m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; + m_info.totalThrottle = (int)m_throttleCategory.DripRate; + + return m_info; } /// diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index 992f38e..b1aec81 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; using log4net; @@ -51,7 +52,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LindenUDPInfoModule")] public class LindenUDPInfoModule : ISharedRegionModule { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected Dictionary m_scenes = new Dictionary(); @@ -130,6 +131,15 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden "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]", + "Show client request stats", + "Without the 'first_name last_name' option, all clients are shown." + + " With the 'first_name last_name' option only a specific client is shown.", + (mod, cmd) => MainConsole.Instance.Output(HandleClientStatsReport(cmd))); + } public void RemoveRegion(Scene scene) @@ -587,6 +597,101 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden (throttleRates.Asset * 8) / 1000); return report.ToString(); - } + } + + /// + /// Show client stats data + /// + /// + /// + protected string HandleClientStatsReport(string[] showParams) + { + // NOTE: This writes to m_log on purpose. We want to store this information + // in case we need to analyze it later. + // + if (showParams.Length <= 3) + { + m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,6} {3,11} {4, 10}", "Region", "Name", "Root", "Time", "Reqs/min"); + foreach (Scene scene in m_scenes.Values) + { + scene.ForEachClient( + delegate(IClientAPI client) + { + if (client is LLClientView) + { + LLClientView llClient = client as LLClientView; + ClientInfo cinfo = llClient.UDPClient.GetClientInfo(); + int avg_reqs = cinfo.AsyncRequests.Count + cinfo.GenericRequests.Count + cinfo.SyncRequests.Count; + avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); + + m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,4} {3,9}min {4,10}", + scene.RegionInfo.RegionName, llClient.Name, + (llClient.SceneAgent.IsChildAgent ? "N" : "Y"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs); + } + }); + } + return string.Empty; + } + + string fname = "", lname = ""; + + if (showParams.Length > 2) + fname = showParams[2]; + if (showParams.Length > 3) + lname = showParams[3]; + + foreach (Scene scene in m_scenes.Values) + { + scene.ForEachClient( + delegate(IClientAPI client) + { + if (client is LLClientView) + { + LLClientView llClient = client as LLClientView; + + if (llClient.Name == fname + " " + lname) + { + + ClientInfo cinfo = llClient.GetClientInfo(); + AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(llClient.CircuitCode); + if (aCircuit == null) // create a dummy one + aCircuit = new AgentCircuitData(); + + if (!llClient.SceneAgent.IsChildAgent) + m_log.InfoFormat("[INFO]: {0} # {1} # {2}", llClient.Name, aCircuit.Viewer, aCircuit.Id0); + + int avg_reqs = cinfo.AsyncRequests.Count + cinfo.GenericRequests.Count + cinfo.SyncRequests.Count; + avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); + + m_log.InfoFormat("[INFO]:"); + m_log.InfoFormat("[INFO]: {0} # {1} # Time: {2}min # Avg Reqs/min: {3}", scene.RegionInfo.RegionName, + (llClient.SceneAgent.IsChildAgent ? "Child" : "Root"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs); + + Dictionary sortedDict = (from entry in cinfo.AsyncRequests orderby entry.Value descending select entry) + .ToDictionary(pair => pair.Key, pair => pair.Value); + + m_log.InfoFormat("[INFO]: {0,25}", "TOP ASYNC"); + foreach (KeyValuePair kvp in sortedDict.Take(12)) + m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); + + m_log.InfoFormat("[INFO]:"); + sortedDict = (from entry in cinfo.SyncRequests orderby entry.Value descending select entry) + .ToDictionary(pair => pair.Key, pair => pair.Value); + m_log.InfoFormat("[INFO]: {0,25}", "TOP SYNC"); + foreach (KeyValuePair kvp in sortedDict.Take(12)) + m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); + + m_log.InfoFormat("[INFO]:"); + sortedDict = (from entry in cinfo.GenericRequests orderby entry.Value descending select entry) + .ToDictionary(pair => pair.Key, pair => pair.Value); + m_log.InfoFormat("[INFO]: {0,25}", "TOP GENERIC"); + foreach (KeyValuePair kvp in sortedDict.Take(12)) + m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); + } + } + }); + } + return string.Empty; + } } } \ No newline at end of file -- cgit v1.1 From bdaeb02863cb56e0d543b1e97eb3356571911f90 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 10 Jul 2013 17:14:20 -0700 Subject: show client stats: Fixed the requests/min. Also changed the spelling of the command, not without the dash. --- .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index b1aec81..79509ab 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -133,8 +133,8 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden HandleEmergencyMonitoring); scene.AddCommand( - "Comms", this, "show client-stats", - "show client-stats [first_name last_name]", + "Comms", this, "show client stats", + "show client stats [first_name last_name]", "Show client request stats", "Without the 'first_name last_name' option, all clients are shown." + " With the 'first_name last_name' option only a specific client is shown.", @@ -609,7 +609,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden // NOTE: This writes to m_log on purpose. We want to store this information // in case we need to analyze it later. // - if (showParams.Length <= 3) + if (showParams.Length <= 4) { m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,6} {3,11} {4, 10}", "Region", "Name", "Root", "Time", "Reqs/min"); foreach (Scene scene in m_scenes.Values) @@ -621,7 +621,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden { LLClientView llClient = client as LLClientView; ClientInfo cinfo = llClient.UDPClient.GetClientInfo(); - int avg_reqs = cinfo.AsyncRequests.Count + cinfo.GenericRequests.Count + cinfo.SyncRequests.Count; + int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,4} {3,9}min {4,10}", @@ -635,10 +635,10 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden string fname = "", lname = ""; - if (showParams.Length > 2) - fname = showParams[2]; if (showParams.Length > 3) - lname = showParams[3]; + fname = showParams[3]; + if (showParams.Length > 4) + lname = showParams[4]; foreach (Scene scene in m_scenes.Values) { @@ -660,7 +660,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden if (!llClient.SceneAgent.IsChildAgent) m_log.InfoFormat("[INFO]: {0} # {1} # {2}", llClient.Name, aCircuit.Viewer, aCircuit.Id0); - int avg_reqs = cinfo.AsyncRequests.Count + cinfo.GenericRequests.Count + cinfo.SyncRequests.Count; + int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); m_log.InfoFormat("[INFO]:"); @@ -669,29 +669,30 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden Dictionary sortedDict = (from entry in cinfo.AsyncRequests orderby entry.Value descending select entry) .ToDictionary(pair => pair.Key, pair => pair.Value); + PrintRequests("TOP ASYNC", sortedDict, cinfo.AsyncRequests.Values.Sum()); - m_log.InfoFormat("[INFO]: {0,25}", "TOP ASYNC"); - foreach (KeyValuePair kvp in sortedDict.Take(12)) - m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); - - m_log.InfoFormat("[INFO]:"); sortedDict = (from entry in cinfo.SyncRequests orderby entry.Value descending select entry) .ToDictionary(pair => pair.Key, pair => pair.Value); - m_log.InfoFormat("[INFO]: {0,25}", "TOP SYNC"); - foreach (KeyValuePair kvp in sortedDict.Take(12)) - m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); + PrintRequests("TOP SYNC", sortedDict, cinfo.SyncRequests.Values.Sum()); - m_log.InfoFormat("[INFO]:"); sortedDict = (from entry in cinfo.GenericRequests orderby entry.Value descending select entry) .ToDictionary(pair => pair.Key, pair => pair.Value); - m_log.InfoFormat("[INFO]: {0,25}", "TOP GENERIC"); - foreach (KeyValuePair kvp in sortedDict.Take(12)) - m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); + PrintRequests("TOP GENERIC", sortedDict, cinfo.GenericRequests.Values.Sum()); } } }); } return string.Empty; - } + } + + private void PrintRequests(string type, Dictionary sortedDict, int sum) + { + m_log.InfoFormat("[INFO]:"); + m_log.InfoFormat("[INFO]: {0,25}", type); + foreach (KeyValuePair kvp in sortedDict.Take(12)) + m_log.InfoFormat("[INFO]: {0,25} {1,-6}", kvp.Key, kvp.Value); + m_log.InfoFormat("[INFO]: {0,25}", "..."); + m_log.InfoFormat("[INFO]: {0,25} {1,-6}", "Total", sum); + } } } \ No newline at end of file -- cgit v1.1 From fe5da43d15506d029be260b2e60a69787686d062 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 10 Jul 2013 19:29:14 -0700 Subject: EXPERIMENTAL: make RequestImage (UDP packet handler) sync instead of async. This _shouldn't_ screw things up, given that all this does is to dump the request in a queue. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 3d92705..16e7207 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5373,7 +5373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); - AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); + AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); -- cgit v1.1 From 9173130fde7dd93d6d9ad5dea317e5f1f0e66b40 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 10 Jul 2013 20:48:13 -0700 Subject: Switched RegionHandshakeReply to Sync, because it's not doing anything blocking. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 16e7207..c5b6ac6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5312,7 +5312,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.RezObject, HandlerRezObject); AddLocalPacketHandler(PacketType.DeRezObject, HandlerDeRezObject); AddLocalPacketHandler(PacketType.ModifyLand, HandlerModifyLand); - AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply); + AddLocalPacketHandler(PacketType.RegionHandshakeReply, HandlerRegionHandshakeReply, false); AddLocalPacketHandler(PacketType.AgentWearablesRequest, HandlerAgentWearablesRequest); AddLocalPacketHandler(PacketType.AgentSetAppearance, HandlerAgentSetAppearance); AddLocalPacketHandler(PacketType.AgentIsNowWearing, HandlerAgentIsNowWearing); -- cgit v1.1 From 0120e858b7985b0f9571461d036a9099a25af9ad Mon Sep 17 00:00:00 2001 From: dahlia Date: Wed, 10 Jul 2013 22:30:41 -0700 Subject: remove names from Capability handlers (added by justincc in commit 013710168b3878fc0a93a92a1c026efb49da9935) as they seem to disable the use of multiple access methods for a single Capability in MaterialsDemoModule --- .../Region/OptionalModules/Materials/MaterialsDemoModule.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 0a0d65c..088eb0f 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -139,21 +139,18 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { string capsBase = "/CAPS/" + caps.CapsObjectPath; - IRequestHandler renderMaterialsPostHandler - = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterialsPost", null); - caps.RegisterHandler("RenderMaterialsPost", renderMaterialsPostHandler); + IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); + caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET // and POST handlers, (at least at the time this was originally written), so we first set up a POST // handler normally and then add a GET handler via MainServer - IRequestHandler renderMaterialsGetHandler - = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterialsGet", null); + IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well - IRequestHandler renderMaterialsPutHandler - = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterialsPut", null); + IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap); MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); } -- cgit v1.1 From 3b48b6a7927796c3d830a83afe8c8ad558ddf1f8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 09:44:48 -0700 Subject: Switched TransferRequest (UDP packet handler) to sync. The permissions checks may block, so they get a FireAndForget. Everything else is non-blocking. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 214 +++++++++++---------- 1 file changed, 115 insertions(+), 99 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index c5b6ac6..ef4f190 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5374,7 +5374,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); - AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest); + AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); AddLocalPacketHandler(PacketType.SendXferPacket, HandleSendXferPacket); @@ -7751,129 +7751,145 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); TransferRequestPacket transfer = (TransferRequestPacket)Pack; - //m_log.Debug("Transfer Request: " + transfer.ToString()); - // Validate inventory transfers - // Has to be done here, because AssetCache can't do it - // UUID taskID = UUID.Zero; if (transfer.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) { - taskID = new UUID(transfer.TransferInfo.Params, 48); - UUID itemID = new UUID(transfer.TransferInfo.Params, 64); - UUID requestID = new UUID(transfer.TransferInfo.Params, 80); - -// m_log.DebugFormat( -// "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", -// requestID, itemID, taskID, Name); - if (!(((Scene)m_scene).Permissions.BypassPermissions())) { - if (taskID != UUID.Zero) // Prim + // We're spawning a thread because the permissions check can block this thread + Util.FireAndForget(delegate { - SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); + // This requests the asset if needed + HandleSimInventoryTransferRequestWithPermsCheck(sender, transfer); + }); + return true; + } + } + else if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) + { + //TransferRequestPacket does not include covenant uuid? + //get scene covenant uuid + taskID = m_scene.RegionInfo.RegionSettings.Covenant; + } - if (part == null) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", - Name, requestID, itemID, taskID); - return true; - } + // This is non-blocking + MakeAssetRequest(transfer, taskID); - TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); - if (tii == null) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", - Name, requestID, itemID, taskID); - return true; - } + return true; + } - if (tii.Type == (int)AssetType.LSLText) - { - if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) - return true; - } - else if (tii.Type == (int)AssetType.Notecard) - { - if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) - return true; - } - else - { - // TODO: Change this code to allow items other than notecards and scripts to be successfully - // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule - if (part.OwnerID != AgentId) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", - Name, requestID, itemID, taskID, part.OwnerID); - return true; - } + private void HandleSimInventoryTransferRequestWithPermsCheck(IClientAPI sender, TransferRequestPacket transfer) + { + UUID taskID = new UUID(transfer.TransferInfo.Params, 48); + UUID itemID = new UUID(transfer.TransferInfo.Params, 64); + UUID requestID = new UUID(transfer.TransferInfo.Params, 80); - if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", - Name, requestID, itemID, taskID); - return true; - } + //m_log.DebugFormat( + // "[CLIENT]: Got request for asset {0} from item {1} in prim {2} by {3}", + // requestID, itemID, taskID, Name); - if (tii.OwnerID != AgentId) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", - Name, requestID, itemID, taskID, tii.OwnerID); - return true; - } + //m_log.Debug("Transfer Request: " + transfer.ToString()); + // Validate inventory transfers + // Has to be done here, because AssetCache can't do it + // + if (taskID != UUID.Zero) // Prim + { + SceneObjectPart part = ((Scene)m_scene).GetSceneObjectPart(taskID); - if (( - tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) - != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", - Name, requestID, itemID, taskID); - return true; - } + if (part == null) + { + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but prim does not exist", + Name, requestID, itemID, taskID); + return; + } - if (tii.AssetID != requestID) - { - m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", - Name, requestID, itemID, taskID, tii.AssetID); - return true; - } - } + TaskInventoryItem tii = part.Inventory.GetInventoryItem(itemID); + if (tii == null) + { + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item does not exist", + Name, requestID, itemID, taskID); + return; + } + + if (tii.Type == (int)AssetType.LSLText) + { + if (!((Scene)m_scene).Permissions.CanEditScript(itemID, taskID, AgentId)) + return; + } + else if (tii.Type == (int)AssetType.Notecard) + { + if (!((Scene)m_scene).Permissions.CanEditNotecard(itemID, taskID, AgentId)) + return; + } + else + { + // TODO: Change this code to allow items other than notecards and scripts to be successfully + // shared with group. In fact, this whole block of permissions checking should move to an IPermissionsModule + if (part.OwnerID != AgentId) + { + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the prim is owned by {4}", + Name, requestID, itemID, taskID, part.OwnerID); + return; } - else // Agent + + if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0) { - IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); - if (invAccess != null) - { - if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) - return false; - } - else - { - return false; - } + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but modify permissions are not set", + Name, requestID, itemID, taskID); + return; + } + + if (tii.OwnerID != AgentId) + { + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but the item is owned by {4}", + Name, requestID, itemID, taskID, tii.OwnerID); + return; + } + + if (( + tii.CurrentPermissions & ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) + != ((uint)PermissionMask.Modify | (uint)PermissionMask.Copy | (uint)PermissionMask.Transfer)) + { + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but item permissions are not modify/copy/transfer", + Name, requestID, itemID, taskID); + return; + } + + if (tii.AssetID != requestID) + { + m_log.WarnFormat( + "[CLIENT]: {0} requested asset {1} from item {2} in prim {3} but this does not match item's asset {4}", + Name, requestID, itemID, taskID, tii.AssetID); + return; } } } - else - if (transfer.TransferInfo.SourceType == (int)SourceType.SimEstate) + else // Agent + { + IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); + if (invAccess != null) + { + if (!invAccess.CanGetAgentInventoryItem(this, itemID, requestID)) + return; + } + else { - //TransferRequestPacket does not include covenant uuid? - //get scene covenant uuid - taskID = m_scene.RegionInfo.RegionSettings.Covenant; + return; } + } + // Permissions out of the way, let's request the asset MakeAssetRequest(transfer, taskID); - return true; } + private bool HandleAssetUploadRequest(IClientAPI sender, Packet Pack) { AssetUploadRequestPacket request = (AssetUploadRequestPacket)Pack; -- cgit v1.1 From 604967b31e0ce4500587d0b88b81e6eecc4efdae Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 09:47:46 -0700 Subject: Switched UUIDNameRequest and RegionHandleRequest to Sync, because now they are also non-blocking handlers. --- 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 ef4f190..79c80a7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5405,8 +5405,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.TeleportLandmarkRequest, HandleTeleportLandmarkRequest); AddLocalPacketHandler(PacketType.TeleportCancel, HandleTeleportCancel); AddLocalPacketHandler(PacketType.TeleportLocationRequest, HandleTeleportLocationRequest); - AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest); - AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest); + AddLocalPacketHandler(PacketType.UUIDNameRequest, HandleUUIDNameRequest, false); + AddLocalPacketHandler(PacketType.RegionHandleRequest, HandleRegionHandleRequest, false); AddLocalPacketHandler(PacketType.ParcelInfoRequest, HandleParcelInfoRequest); AddLocalPacketHandler(PacketType.ParcelAccessListRequest, HandleParcelAccessListRequest, false); AddLocalPacketHandler(PacketType.ParcelAccessListUpdate, HandleParcelAccessListUpdate, false); -- cgit v1.1 From c4f1ec1fd643ab3748235dfb89bc1e66165558f9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 10:21:20 -0700 Subject: Changed the UserProfileModule so that it's less greedy in terms of thread usage. --- .../CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 161f160..c04098c 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -173,7 +173,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles if(obj.PresenceType == PresenceType.Npc) return; - GetImageAssets(((IScenePresence)obj).UUID); + Util.FireAndForget(delegate + { + GetImageAssets(((IScenePresence)obj).UUID); + }); } /// @@ -1044,12 +1047,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles { OSDString assetId = (OSDString)asset; - Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString()), this, - delegate (string assetID, Object s, AssetBase a) - { - // m_log.DebugFormat("[PROFILES]: Getting Image Assets {0}", assetID); - return; - }); + Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString())); } return true; } -- cgit v1.1 From 51d106cff88334e1b9eb3628f7bdb8d6a18af4f6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 14:21:57 -0700 Subject: Added a test for the asset service --- OpenSim/Tests/Clients/Assets/AssetsClient.cs | 99 ++++++++++++++++++++++++++++ prebuild.xml | 27 ++++++++ 2 files changed, 126 insertions(+) create mode 100644 OpenSim/Tests/Clients/Assets/AssetsClient.cs diff --git a/OpenSim/Tests/Clients/Assets/AssetsClient.cs b/OpenSim/Tests/Clients/Assets/AssetsClient.cs new file mode 100644 index 0000000..dd168a1 --- /dev/null +++ b/OpenSim/Tests/Clients/Assets/AssetsClient.cs @@ -0,0 +1,99 @@ +/* + * 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.Net; +using System.Text; +using System.Reflection; +using System.Threading; + +using OpenMetaverse; +using log4net; +using log4net.Appender; +using log4net.Layout; + +using OpenSim.Framework; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors; + +namespace OpenSim.Tests.Clients.AssetsClient +{ + public class AssetsClient + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private static int m_MaxThreadID = 0; + private static readonly int NREQS = 150; + private static int m_NReceived = 0; + + public static void Main(string[] args) + { + ConsoleAppender consoleAppender = new ConsoleAppender(); + consoleAppender.Layout = + new PatternLayout("[%thread] - %message%newline"); + log4net.Config.BasicConfigurator.Configure(consoleAppender); + + string serverURI = "http://127.0.0.1:8003"; + if (args.Length > 1) + serverURI = args[1]; + int max1, max2; + ThreadPool.GetMaxThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} max threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.GetMinThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} min threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.SetMinThreads(1, 1); + ThreadPool.SetMaxThreads(10, 3); + ServicePointManager.DefaultConnectionLimit = 12; + + AssetServicesConnector m_Connector = new AssetServicesConnector(serverURI); + m_Connector.MaxAssetRequestConcurrency = 30; + + for (int i = 0; i < NREQS; i++) + { + UUID uuid = UUID.Random(); + m_Connector.Get(uuid.ToString(), null, ResponseReceived); + m_log.InfoFormat("[ASSET CLIENT]: [{0}] requested asset {1}", i, uuid); + } + + Thread.Sleep(20 * 1000); + m_log.InfoFormat("[ASSET CLIENT]: Received responses {0}", m_NReceived); + } + + private static void ResponseReceived(string id, Object sender, AssetBase asset) + { + if (Thread.CurrentThread.ManagedThreadId > m_MaxThreadID) + m_MaxThreadID = Thread.CurrentThread.ManagedThreadId; + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3})", id, m_MaxThreadID, max1, max2); + m_NReceived++; + } + } +} diff --git a/prebuild.xml b/prebuild.xml index d9e32ea..c7463e4 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2631,6 +2631,33 @@ + + + + ../../../../bin/ + + + + + ../../../../bin/ + + + + ../../../../bin/ + + + + + + + + + + + + + + -- cgit v1.1 From ee51a9f9c902e1587023b900438331c086680b30 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 14:23:37 -0700 Subject: Added property to make for more flexible testing. --- OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 7f7f251..8b04d7f 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -55,6 +55,11 @@ namespace OpenSim.Services.Connectors // Maps: Asset ID -> Handlers which will be called when the asset has been loaded private Dictionary m_AssetHandlers = new Dictionary(); + public int MaxAssetRequestConcurrency + { + get { return m_maxAssetRequestConcurrency; } + set { m_maxAssetRequestConcurrency = value; } + } public AssetServicesConnector() { -- cgit v1.1 From 44e9849ed1190dbc29ffa97fa5df286dc9794edb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 11 Jul 2013 23:02:30 +0100 Subject: Fix regression where llHTTPRequests which did not get an OK response returned 499 and the exception message in the http_response event rather than the actual response code and body. This was a regression since commit 831e4c3 (Thu Apr 4 00:36:15 2013) This commit also adds a regression test for this case, though this currently only works with Mono This aims to address http://opensimulator.org/mantis/view.php?id=6704 --- OpenSim/Framework/Util.cs | 7 +- .../Scripting/HttpRequest/ScriptsHttpRequests.cs | 77 ++++---- .../HttpRequest/Tests/ScriptsHttpRequestsTests.cs | 201 +++++++++++++++++++++ prebuild.xml | 1 + 4 files changed, 245 insertions(+), 41 deletions(-) create mode 100644 OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ba6cc75..cafe103 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -141,6 +141,11 @@ namespace OpenSim.Framework public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; + public static bool IsPlatformMono + { + get { return Type.GetType("Mono.Runtime") != null; } + } + /// /// Gets the name of the directory where the current running executable /// is located @@ -1326,7 +1331,7 @@ namespace OpenSim.Framework ru = "OSX/Mono"; else { - if (Type.GetType("Mono.Runtime") != null) + if (IsPlatformMono) ru = "Win/Mono"; else ru = "Win/.NET"; diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 6793fc8..1a62405 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs @@ -419,7 +419,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest get { return _reqID; } set { _reqID = value; } } - public HttpWebRequest Request; + public WebRequest Request; public string ResponseBody; public List ResponseMetadata; public Dictionary ResponseHeaders; @@ -431,18 +431,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest SendRequest(); } - /* - * TODO: More work on the response codes. Right now - * returning 200 for success or 499 for exception - */ - public void SendRequest() { - HttpWebResponse response = null; - try { - Request = (HttpWebRequest) WebRequest.Create(Url); + Request = WebRequest.Create(Url); Request.Method = HttpMethod; Request.ContentType = HttpMIMEType; @@ -480,14 +473,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest } } - foreach (KeyValuePair entry in ResponseHeaders) - if (entry.Key.ToLower().Equals("user-agent")) - Request.UserAgent = entry.Value; - else - Request.Headers[entry.Key] = entry.Value; + if (ResponseHeaders != null) + { + foreach (KeyValuePair entry in ResponseHeaders) + if (entry.Key.ToLower().Equals("user-agent") && Request is HttpWebRequest) + ((HttpWebRequest)Request).UserAgent = entry.Value; + else + Request.Headers[entry.Key] = entry.Value; + } // Encode outbound data - if (OutboundBody.Length > 0) + if (OutboundBody != null && OutboundBody.Length > 0) { byte[] data = Util.UTF8.GetBytes(OutboundBody); @@ -510,12 +506,19 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest { throw; } - response = (HttpWebResponse)e.Response; + + HttpWebResponse response = (HttpWebResponse)e.Response; + + Status = (int)response.StatusCode; + ResponseBody = response.StatusDescription; _finished = true; } } catch (Exception e) { +// m_log.Debug( +// string.Format("[SCRIPTS HTTP REQUESTS]: Exception on request to {0} for {1} ", Url, ItemID), e); + Status = (int)OSHttpStatusCode.ClientErrorJoker; ResponseBody = e.Message; _finished = true; @@ -528,33 +531,27 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest try { - response = (HttpWebResponse)Request.EndGetResponse(ar); - Status = (int)response.StatusCode; - - Stream resStream = response.GetResponseStream(); - StringBuilder sb = new StringBuilder(); - byte[] buf = new byte[8192]; - string tempString = null; - int count = 0; - - do + try { - // fill the buffer with data - count = resStream.Read(buf, 0, buf.Length); - - // make sure we read some data - if (count != 0) + response = (HttpWebResponse)Request.EndGetResponse(ar); + } + catch (WebException e) + { + if (e.Status != WebExceptionStatus.ProtocolError) { - // translate from bytes to ASCII text - tempString = Util.UTF8.GetString(buf, 0, count); - - // continue building the string - sb.Append(tempString); + throw; } - } - while (count > 0); // any more data to read? - ResponseBody = sb.ToString(); + response = (HttpWebResponse)e.Response; + } + + Status = (int)response.StatusCode; + + using (Stream stream = response.GetResponseStream()) + { + StreamReader reader = new StreamReader(stream, Encoding.UTF8); + ResponseBody = reader.ReadToEnd(); + } } catch (Exception e) { @@ -587,4 +584,4 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest Request.Abort(); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs new file mode 100644 index 0000000..f638f91 --- /dev/null +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs @@ -0,0 +1,201 @@ +/* + * 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.Net; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading; +using log4net.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Scripting.HttpRequest; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests +{ + class TestWebRequestCreate : IWebRequestCreate + { + public TestWebRequest NextRequest { get; set; } + + public WebRequest Create(Uri uri) + { +// NextRequest.RequestUri = uri; + + return NextRequest; + +// return new TestWebRequest(new SerializationInfo(typeof(TestWebRequest), new FormatterConverter()), new StreamingContext()); + } + } + + class TestWebRequest : WebRequest + { + public override string ContentType { get; set; } + public override string Method { get; set; } + + public Func OnEndGetResponse { get; set; } + + public TestWebRequest() : base() + { +// Console.WriteLine("created"); + } + +// public TestWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) +// : base(serializationInfo, streamingContext) +// { +// Console.WriteLine("created"); +// } + + public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) + { +// Console.WriteLine("bish"); + TestAsyncResult tasr = new TestAsyncResult(); + callback(tasr); + + return tasr; + } + + public override WebResponse EndGetResponse(IAsyncResult asyncResult) + { +// Console.WriteLine("bosh"); + return OnEndGetResponse(asyncResult); + } + } + + class TestHttpWebResponse : HttpWebResponse + { + public string Response { get; set; } + + public TestHttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext) + : base(serializationInfo, streamingContext) {} + + public override Stream GetResponseStream() + { + return new MemoryStream(Encoding.UTF8.GetBytes(Response)); + } + } + + class TestAsyncResult : IAsyncResult + { + WaitHandle m_wh = new ManualResetEvent(true); + + object IAsyncResult.AsyncState + { + get { + throw new System.NotImplementedException (); + } + } + + WaitHandle IAsyncResult.AsyncWaitHandle + { + get { return m_wh; } + } + + bool IAsyncResult.CompletedSynchronously + { + get { return false; } + } + + bool IAsyncResult.IsCompleted + { + get { return true; } + } + } + + /// + /// Test script http request code. + /// + /// + /// This class uses some very hacky workarounds in order to mock HttpWebResponse which are Mono dependent (though + /// alternative code can be written to make this work for Windows). However, the value of being able to + /// regression test this kind of code is very high. + /// + [TestFixture] + public class ScriptsHttpRequestsTests : OpenSimTestCase + { + /// + /// Test what happens when we get a 404 response from a call. + /// + [Test] + public void Test404Response() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + if (!Util.IsPlatformMono) + Assert.Ignore("Ignoring test since can only currently run on Mono"); + + string rawResponse = "boom"; + + TestWebRequestCreate twrc = new TestWebRequestCreate(); + + TestWebRequest twr = new TestWebRequest(); + //twr.OnEndGetResponse += ar => new TestHttpWebResponse(null, new StreamingContext()); + twr.OnEndGetResponse += ar => + { + SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new FormatterConverter()); + StreamingContext sc = new StreamingContext(); +// WebHeaderCollection headers = new WebHeaderCollection(); +// si.AddValue("m_HttpResponseHeaders", headers); + si.AddValue("uri", new Uri("test://arrg")); +// si.AddValue("m_Certificate", null); + si.AddValue("version", HttpVersion.Version11); + si.AddValue("statusCode", HttpStatusCode.NotFound); + si.AddValue("contentLength", 0); + si.AddValue("method", "GET"); + si.AddValue("statusDescription", "Not Found"); + si.AddValue("contentType", null); + si.AddValue("cookieCollection", new CookieCollection()); + + TestHttpWebResponse thwr = new TestHttpWebResponse(si, sc); + thwr.Response = rawResponse; + + throw new WebException("no message", null, WebExceptionStatus.ProtocolError, thwr); + }; + + twrc.NextRequest = twr; + + WebRequest.RegisterPrefix("test", twrc); + HttpRequestClass hr = new HttpRequestClass(); + hr.Url = "test://something"; + hr.SendRequest(); + + while (!hr.Finished) + Thread.Sleep(100); + + Assert.That(hr.Status, Is.EqualTo((int)HttpStatusCode.NotFound)); + Assert.That(hr.ResponseBody, Is.EqualTo(rawResponse)); + } + } +} \ No newline at end of file diff --git a/prebuild.xml b/prebuild.xml index d9e32ea..d32287a 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3102,6 +3102,7 @@ + -- cgit v1.1 From e15a15688bbee6b7a76bb29f7879e0c59491449a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 11 Jul 2013 23:11:35 +0100 Subject: minor: Take out unnecessary clumsy sleep at the end of regression Test404Response(). This wasn't actually necessary in the end but was accidentally left in. --- .../Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs index f638f91..180a046 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs @@ -191,9 +191,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests hr.Url = "test://something"; hr.SendRequest(); - while (!hr.Finished) - Thread.Sleep(100); - Assert.That(hr.Status, Is.EqualTo((int)HttpStatusCode.NotFound)); Assert.That(hr.ResponseBody, Is.EqualTo(rawResponse)); } -- cgit v1.1 From 7c2e4786ce9b85459b8c8973f658aa9a221925dc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 11 Jul 2013 23:19:55 +0100 Subject: minor: remove some regression test logging switches accidentally left uncommented. --- .../CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs | 2 +- OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs index 180a046..e812d81 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs @@ -151,7 +151,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests public void Test404Response() { TestHelpers.InMethod(); - TestHelpers.EnableLogging(); +// TestHelpers.EnableLogging(); if (!Util.IsPlatformMono) Assert.Ignore("Ignoring test since can only currently run on Mono"); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs index 5714042..b6fb730 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCapabilityTests.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestChildAgentSingleRegionCapabilities() { TestHelpers.InMethod(); - TestHelpers.EnableLogging(); +// TestHelpers.EnableLogging(); UUID spUuid = TestHelpers.ParseTail(0x1); -- cgit v1.1 From ba8f9c9d0a7d07b7587663baef9c52293a3ac404 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 11 Jul 2013 23:51:10 +0100 Subject: Try naming the materials handlers again, this time registering the POST as RenderMaterials This was probably the mistake. The other handlers are named RenderMaterials as well but this actully has no affect apart from on stats, due to a (counterintuitive) disconnect between the registration name and the name of the request handler. Will be tested very soon and reverted if this still does not work. --- OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs index 088eb0f..d8f5563 100644 --- a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs @@ -139,18 +139,21 @@ namespace OpenSim.Region.OptionalModules.MaterialsDemoModule { string capsBase = "/CAPS/" + caps.CapsObjectPath; - IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); + IRequestHandler renderMaterialsPostHandler + = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET // and POST handlers, (at least at the time this was originally written), so we first set up a POST // handler normally and then add a GET handler via MainServer - IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); + IRequestHandler renderMaterialsGetHandler + = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap, "RenderMaterials", null); MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well - IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap); + IRequestHandler renderMaterialsPutHandler + = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap, "RenderMaterials", null); MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); } -- cgit v1.1 From 83d1680057419229b0708bde59b12159006195cd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 11 Jul 2013 16:43:43 -0700 Subject: Added a few more thingies to the asset client test to poke the threadpool. --- OpenSim/Tests/Clients/Assets/AssetsClient.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tests/Clients/Assets/AssetsClient.cs b/OpenSim/Tests/Clients/Assets/AssetsClient.cs index dd168a1..26d740b 100644 --- a/OpenSim/Tests/Clients/Assets/AssetsClient.cs +++ b/OpenSim/Tests/Clients/Assets/AssetsClient.cs @@ -82,7 +82,16 @@ namespace OpenSim.Tests.Clients.AssetsClient m_log.InfoFormat("[ASSET CLIENT]: [{0}] requested asset {1}", i, uuid); } - Thread.Sleep(20 * 1000); + for (int i = 0; i < 500; i++) + { + var x = i; + ThreadPool.QueueUserWorkItem(delegate + { + Dummy(x); + }); + } + + Thread.Sleep(30 * 1000); m_log.InfoFormat("[ASSET CLIENT]: Received responses {0}", m_NReceived); } @@ -92,8 +101,16 @@ namespace OpenSim.Tests.Clients.AssetsClient m_MaxThreadID = Thread.CurrentThread.ManagedThreadId; int max1, max2; ThreadPool.GetAvailableThreads(out max1, out max2); - m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3})", id, m_MaxThreadID, max1, max2); + m_log.InfoFormat("[ASSET CLIENT]: Received asset {0} ({1}) ({2}-{3}) {4}", id, m_MaxThreadID, max1, max2, DateTime.Now.ToString("hh:mm:ss")); m_NReceived++; } + + private static void Dummy(int i) + { + int max1, max2; + ThreadPool.GetAvailableThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: ({0}) Hello! {1} - {2} {3}", i, max1, max2, DateTime.Now.ToString("hh:mm:ss")); + Thread.Sleep(2000); + } } } -- cgit v1.1 From 1909ee70f8f3df6558ce2abfc8b1d03fc5565a63 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 11 Jul 2013 16:57:07 -0700 Subject: Centralize duplicated code in SceneObjectPart for subscribing to collision events. Improve logic for knowing when to add processing routine to physics actor. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 97 ++++++++++------------ 1 file changed, 43 insertions(+), 54 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index f361acb..830fe31 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4213,31 +4213,12 @@ namespace OpenSim.Region.Framework.Scenes AddToPhysics(UsePhysics, SetPhantom, false); pa = PhysActor; - if (pa != null) { pa.SetMaterial(Material); DoPhysicsPropertyUpdate(UsePhysics, true); - - if ( - ((AggregateScriptEvents & scriptEvents.collision) != 0) || - ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || - (CollisionSound != UUID.Zero) - ) - { - pa.OnCollisionUpdate += PhysicsCollision; - pa.SubscribeEvents(1000); - } + + SubscribeForCollisionEvents(); } } else // it already has a physical representation @@ -4291,6 +4272,46 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags); } + // Subscribe for physics collision events if needed for scripts and sounds + public void SubscribeForCollisionEvents() + { + if (PhysActor != null) + { + if ( + ((AggregateScriptEvents & scriptEvents.collision) != 0) || + ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || + ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || + ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || + ((AggregateScriptEvents & scriptEvents.land_collision) != 0) || + ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || + ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) || + ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) || + ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) || + ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || + ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) || + ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || + (CollisionSound != UUID.Zero) + ) + { + if (!PhysActor.SubscribedEvents()) + { + // If not already subscribed for event, set up for a collision event. + PhysActor.OnCollisionUpdate += PhysicsCollision; + PhysActor.SubscribeEvents(1000); + } + } + else + { + // There is no need to be subscribed to collisions so, if subscribed, remove subscription + if (PhysActor.SubscribedEvents()) + { + PhysActor.OnCollisionUpdate -= PhysicsCollision; + PhysActor.UnSubscribeEvents(); + } + } + } + } + /// /// Adds this part to the physics scene. /// @@ -4680,39 +4701,7 @@ namespace OpenSim.Region.Framework.Scenes objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop; } - PhysicsActor pa = PhysActor; - - if ( - ((AggregateScriptEvents & scriptEvents.collision) != 0) || - ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision) != 0) || - ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) || - ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) || - (CollisionSound != UUID.Zero) - ) - { - // subscribe to physics updates. - if (pa != null) - { - pa.OnCollisionUpdate += PhysicsCollision; - pa.SubscribeEvents(1000); - } - } - else - { - if (pa != null) - { - pa.UnSubscribeEvents(); - pa.OnCollisionUpdate -= PhysicsCollision; - } - } + SubscribeForCollisionEvents(); //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) //{ -- cgit v1.1 From 65239b059fc8a92eee1d27655a6f85826c99306b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 11 Jul 2013 20:55:32 -0700 Subject: Enhance NullEstateData to remember stored estate values and return them next time asked. This keeps any estate settings from being reset when the estate dialog is opened in a region with null estate storage. --- OpenSim/Data/Null/NullEstateData.cs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenSim/Data/Null/NullEstateData.cs b/OpenSim/Data/Null/NullEstateData.cs index d64136d..1df397d 100755 --- a/OpenSim/Data/Null/NullEstateData.cs +++ b/OpenSim/Data/Null/NullEstateData.cs @@ -42,6 +42,22 @@ namespace OpenSim.Data.Null // private string m_connectionString; + private Dictionary m_knownEstates = new Dictionary(); + private EstateSettings m_estate = null; + + private EstateSettings GetEstate() + { + if (m_estate == null) + { + // This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase). + // The estate info is pretty empty so don't try banning anyone. + m_estate = new EstateSettings(); + m_estate.EstateID = 1; + m_estate.OnSave += StoreEstateSettings; + } + return m_estate; + } + protected virtual Assembly Assembly { get { return GetType().Assembly; } @@ -68,21 +84,18 @@ namespace OpenSim.Data.Null public EstateSettings LoadEstateSettings(UUID regionID, bool create) { - // This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase). - // The estate info is pretty empty so don't try banning anyone. - EstateSettings oneEstate = new EstateSettings(); - oneEstate.EstateID = 1; - return oneEstate; + return GetEstate(); } public void StoreEstateSettings(EstateSettings es) { + m_estate = es; return; } public EstateSettings LoadEstateSettings(int estateID) { - return new EstateSettings(); + return GetEstate(); } public EstateSettings CreateNewEstate() @@ -93,13 +106,14 @@ namespace OpenSim.Data.Null public List LoadEstateSettingsAll() { List allEstateSettings = new List(); - allEstateSettings.Add(new EstateSettings()); + allEstateSettings.Add(GetEstate()); return allEstateSettings; } public List GetEstatesAll() { List result = new List(); + result.Add((int)GetEstate().EstateID); return result; } -- cgit v1.1 From 29f6ae199efd705052422b2fe9dd0e815447b0a8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 12 Jul 2013 12:53:58 -0700 Subject: Changed UploadBakedTextureModule so that it uses the same pattern as the others, in preparation for experiments to direct baked texture uploads to a robust instance. No functional or configuration changes -- should work exactly as before. --- .../Linden/Caps/UploadBakedTextureModule.cs | 35 +++++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 3b0ccd7..79a935d 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs @@ -63,9 +63,16 @@ namespace OpenSim.Region.ClientStack.Linden private Scene m_scene; private bool m_persistBakedTextures; + private string m_URL; public void Initialise(IConfigSource source) { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + if (config == null) + return; + + m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty); + IConfig appearanceConfig = source.Configs["Appearance"]; if (appearanceConfig != null) m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures); @@ -100,15 +107,27 @@ namespace OpenSim.Region.ClientStack.Linden public void RegisterCaps(UUID agentID, Caps caps) { - caps.RegisterHandler( - "UploadBakedTexture", - new RestStreamHandler( - "POST", - "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, - new UploadBakedTextureHandler( - caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture, + UUID capID = UUID.Random(); + + //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); + if (m_URL == "localhost") + { + caps.RegisterHandler( "UploadBakedTexture", - agentID.ToString())); + new RestStreamHandler( + "POST", + "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, + new UploadBakedTextureHandler( + caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture, + "UploadBakedTexture", + agentID.ToString())); + + } + else + { + caps.RegisterHandler("UploadBakedTexture", m_URL); + } + } } } \ No newline at end of file -- cgit v1.1 From fa02f28dbfef9b9dc3621f5bbd6b026c827459a5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 12 Jul 2013 14:04:14 -0700 Subject: Add ToOSDMap() overrides to the Stat subclass CounterStat. Add a GetStatsAsOSDMap method to StatsManager which allows the filtered fetching of stats for eventual returning over the internets. --- OpenSim/Framework/Monitoring/Stats/CounterStat.cs | 21 ++++++++ OpenSim/Framework/Monitoring/Stats/Stat.cs | 1 + OpenSim/Framework/Monitoring/StatsManager.cs | 66 +++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs index caea30d..04442c3 100755 --- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs @@ -224,5 +224,26 @@ public class CounterStat : Stat } } } + + // CounterStat is a basic stat plus histograms + public override OSDMap ToOSDMap() + { + // Get the foundational instance + OSDMap map = base.ToOSDMap(); + + map["StatType"] = "CounterStat"; + + // If there are any histograms, add a new field that is an array of histograms as OSDMaps + if (m_histograms.Count > 0) + { + OSDArray histos = new OSDArray(); + foreach (EventHistogram histo in m_histograms.Values) + { + histos.Add(histo.GetHistogramAsOSDMap()); + } + map.Add("Histograms", histos); + } + return map; + } } } diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index c57ee0c..9629b6e 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -242,6 +242,7 @@ namespace OpenSim.Framework.Monitoring ret.Add("Description", OSD.FromString(Description)); ret.Add("UnitName", OSD.FromString(UnitName)); ret.Add("Value", OSD.FromReal(Value)); + ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat return ret; } diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 12d3a75..a5b54c9 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -30,6 +30,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { /// @@ -168,6 +170,70 @@ namespace OpenSim.Framework.Monitoring } } + // Creates an OSDMap of the format: + // { categoryName: { + // containerName: { + // statName: { + // "Name": name, + // "ShortName": shortName, + // ... + // }, + // statName: { + // "Name": name, + // "ShortName": shortName, + // ... + // }, + // ... + // }, + // containerName: { + // ... + // }, + // ... + // }, + // categoryName: { + // ... + // }, + // ... + // } + // The passed in parameters will filter the categories, containers and stats returned. If any of the + // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned. + // Case matters. + public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName) + { + OSDMap map = new OSDMap(); + + foreach (string catName in RegisteredStats.Keys) + { + // Do this category if null spec, "all" subcommand or category name matches passed parameter. + // Skip category if none of the above. + if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName)) + continue; + + OSDMap contMap = new OSDMap(); + foreach (string contName in RegisteredStats[catName].Keys) + { + if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName)) + continue; + + OSDMap statMap = new OSDMap(); + + SortedDictionary theStats = RegisteredStats[catName][contName]; + foreach (string statName in theStats.Keys) + { + if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName)) + continue; + + statMap.Add(statName, theStats[statName].ToOSDMap()); + } + + contMap.Add(contName, statMap); + } + map.Add(catName, contMap); + } + + return map; + } + // /// // /// Start collecting statistics related to assets. // /// Should only be called once. -- cgit v1.1 From 3d118fb580ea0a5e9d9b23f5f876fca80cd17d0e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 12 Jul 2013 18:53:27 +0100 Subject: In co-op termination, extend EventWaitHandle to give this an indefinite lifetime in order to avoid a later RemotingException if scripts are being loaded into their own domains. This is necessary because XEngineScriptBase now retains a reference to an EventWaitHandle when co-op termination is active. Aims to address http://opensimulator.org/mantis/view.php?id=6634 --- .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 887a317..229180f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -241,7 +241,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (Engine.Config.GetString("ScriptStopStrategy", "abort") == "co-op") { m_coopTermination = true; - m_coopSleepHandle = new AutoResetEvent(false); + m_coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset); } } @@ -1201,4 +1201,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance Suspended = false; } } -} + + /// + /// Xengine event wait handle. + /// + /// + /// This class exists becase XEngineScriptBase gets a reference to this wait handle. We need to make sure that + /// when scripts are running in different AppDomains the lease does not expire. + /// FIXME: Like LSL_Api, etc., this effectively leaks memory since the GC will never collect it. To avoid this, + /// proper remoting sponsorship needs to be implemented across the board. + /// + public class XEngineEventWaitHandle : EventWaitHandle + { + public XEngineEventWaitHandle(bool initialState, EventResetMode mode) : base(initialState, mode) {} + + public override Object InitializeLifetimeService() + { + return null; + } + } +} \ No newline at end of file -- cgit v1.1 From d06c85ea77f76f4d915081ed6b314d66d6d38fbf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 13 Jul 2013 00:29:07 +0100 Subject: Reinsert PhysicsActor variable back into SOP.SubscribeForCollisionEvents() in order to avoid a race condition. A separate PhysicsActor variable is used in case some other thread removes the PhysicsActor whilst this code is executing. If this is now impossible please revert - just adding this now whilst I remember. Also makes method comment into proper method doc. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 830fe31..eb3af42 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4272,10 +4272,14 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags); } - // Subscribe for physics collision events if needed for scripts and sounds + /// + /// Subscribe for physics collision events if needed for scripts and sounds + /// public void SubscribeForCollisionEvents() { - if (PhysActor != null) + PhysicsActor pa = PhysActor; + + if (pa != null) { if ( ((AggregateScriptEvents & scriptEvents.collision) != 0) || @@ -4293,20 +4297,20 @@ namespace OpenSim.Region.Framework.Scenes (CollisionSound != UUID.Zero) ) { - if (!PhysActor.SubscribedEvents()) + if (!pa.SubscribedEvents()) { // If not already subscribed for event, set up for a collision event. - PhysActor.OnCollisionUpdate += PhysicsCollision; - PhysActor.SubscribeEvents(1000); + pa.OnCollisionUpdate += PhysicsCollision; + pa.SubscribeEvents(1000); } } else { // There is no need to be subscribed to collisions so, if subscribed, remove subscription - if (PhysActor.SubscribedEvents()) + if (pa.SubscribedEvents()) { - PhysActor.OnCollisionUpdate -= PhysicsCollision; - PhysActor.UnSubscribeEvents(); + pa.OnCollisionUpdate -= PhysicsCollision; + pa.UnSubscribeEvents(); } } } -- cgit v1.1 From cd64a70c793e746416a7f91e423d52dda4b05722 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 08:31:03 -0700 Subject: Added UploadBakedTexture/UploadBakedTextureServerConnector, so that this can eventually be served by a robust instance. NOT FINISHED YET. --- .../UploadBakedTextureServerConnector.cs | 76 ++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs diff --git a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs new file mode 100644 index 0000000..10ea8ee --- /dev/null +++ b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs @@ -0,0 +1,76 @@ +/* + * 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 Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; + +namespace OpenSim.Capabilities.Handlers +{ + public class UploadBakedTextureServerConnector : ServiceConnector + { + private IAssetService m_AssetService; + private string m_ConfigName = "CapsService"; + + public UploadBakedTextureServerConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string assetService = serverConfig.GetString("AssetService", String.Empty); + + if (assetService == String.Empty) + throw new Exception("No AssetService in config file"); + + Object[] args = new Object[] { config }; + m_AssetService = + ServerUtils.LoadPlugin(assetService, args); + + if (m_AssetService == null) + throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); + + // NEED TO FIX THIS + OpenSim.Framework.Capabilities.Caps caps = new OpenSim.Framework.Capabilities.Caps(server, "", server.Port, "", UUID.Zero, ""); + server.AddStreamHandler(new RestStreamHandler( + "POST", + "/CAPS/UploadBakedTexture/", + new UploadBakedTextureHandler(caps, m_AssetService, true).UploadBakedTexture, + "UploadBakedTexture", + "Upload Baked Texture Capability")); + + } + } +} \ No newline at end of file -- cgit v1.1 From a412b1d6823141129bef3ab906c6590eb6a81c72 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 09:46:58 -0700 Subject: Moved SendInitialDataToMe to earlier in CompleteMovement. Moved TriggerOnMakeRootAgent to the end of CompleteMovement. Justin, if you read this, there's a long story here. Some time ago you placed SendInitialDataToMe at the very beginning of client creation (in LLUDPServer). That is problematic, as we discovered relatively recently: on TPs, as soon as the client starts getting data from child agents, it starts requesting resources back *from the simulator where its root agent is*. We found this to be the problem behind meshes missing on HG TPs (because the viewer was requesting the meshes of the receiving sim from the departing grid). But this affects much more than meshes and HG TPs. It may also explain cloud avatars after a local TP: baked textures are only stored in the simulator, so if a child agent receives a UUID of a baked texture in the destination sim and requests that texture from the departing sim where the root agent is, it will fail to get that texture. Bottom line: we need to delay sending the new simulator data to the viewer until we are absolutely sure that the viewer knows that its main agent is in a new sim. Hence, moving it to CompleteMovement. Now I am trying to tune the initial rez delay that we all experience in the CC. I think that when I fixed the issue described above, I may have moved SendInitialDataToMe to much later than it should be, so now I'm moving to earlier in CompleteMovement. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 2aab4f9..85270a6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1469,7 +1469,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); bool tp = (aCircuit.teleportFlags > 0); - // Let's delay this for TP agents, otherwise the viewer doesn't know where to get meshes from + // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from if (!tp) client.SceneAgent.SendInitialDataToMe(); } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 774546c..bd4f68e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1010,7 +1010,9 @@ namespace OpenSim.Region.Framework.Scenes // recorded, which stops the input from being processed. MovementFlag = 0; - m_scene.EventManager.TriggerOnMakeRootAgent(this); + // DIVA NOTE: I moved TriggerOnMakeRootAgent out of here and into the end of + // CompleteMovement. We don't want modules doing heavy computation before CompleteMovement + // is over. } public int GetStateSource() @@ -1327,10 +1329,15 @@ namespace OpenSim.Region.Framework.Scenes bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); MakeRootAgent(AbsolutePosition, flying); ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + // Remember in HandleUseCircuitCode, we delayed this to here + // This will also send the initial data to clients when TP to a neighboring region. + // Not ideal, but until we know we're TP-ing from a neighboring region, there's not much we can do + if (m_teleportFlags > 0) + SendInitialDataToMe(); // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); - if ((m_callbackURI != null) && !m_callbackURI.Equals("")) + if (!string.IsNullOrEmpty(m_callbackURI)) { // We cannot sleep here since this would hold up the inbound packet processing thread, as // CompleteMovement() is executed synchronously. However, it might be better to delay the release @@ -1358,9 +1365,6 @@ namespace OpenSim.Region.Framework.Scenes // Create child agents in neighbouring regions if (openChildAgents && !IsChildAgent) { - // Remember in HandleUseCircuitCode, we delayed this to here - SendInitialDataToMe(); - IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); if (m_agentTransfer != null) Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); @@ -1382,6 +1386,11 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); + + // DIVA NOTE: moved this here from MakeRoot. We don't want modules making heavy + // computations before CompleteMovement is over + m_scene.EventManager.TriggerOnMakeRootAgent(this); + } /// -- cgit v1.1 From ff4ad60207431427e26a365df1ff28aa380faf12 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 10:05:11 -0700 Subject: Same issue as previous commit. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index bd4f68e..fcb841a 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2694,15 +2694,16 @@ namespace OpenSim.Region.Framework.Scenes // we created a new ScenePresence (a new child agent) in a fresh region. // Request info about all the (root) agents in this region // Note: This won't send data *to* other clients in that region (children don't send) - SendOtherAgentsAvatarDataToMe(); - SendOtherAgentsAppearanceToMe(); - EntityBase[] entities = Scene.Entities.GetEntities(); foreach(EntityBase e in entities) { if (e != null && e is SceneObjectGroup) ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); } + + SendOtherAgentsAvatarDataToMe(); + SendOtherAgentsAppearanceToMe(); + }); } -- cgit v1.1 From 3a26e366d2829c2f66a8aa22158bd0905f0894de Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 10:35:41 -0700 Subject: This commit effectively reverses the previous one, but it's just to log that we found the root of the rez delay: the priority scheme BestAvatarResponsiveness, which is currently the default, was the culprit. Changing it to FrontBack made the region rez be a lot more natural. BestAvatarResponsiveness introduces the region rez delay in cases where the region is full of avatars with lots of attachments, which is the case in CC load tests. In that case, the inworld prims are sent only after all avatar attachments are sent. Not recommended for regions with heavy avatar traffic! --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index fcb841a..9f8ada3 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2694,16 +2694,16 @@ namespace OpenSim.Region.Framework.Scenes // we created a new ScenePresence (a new child agent) in a fresh region. // Request info about all the (root) agents in this region // Note: This won't send data *to* other clients in that region (children don't send) + SendOtherAgentsAvatarDataToMe(); + SendOtherAgentsAppearanceToMe(); + EntityBase[] entities = Scene.Entities.GetEntities(); - foreach(EntityBase e in entities) + foreach (EntityBase e in entities) { if (e != null && e is SceneObjectGroup) ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); } - SendOtherAgentsAvatarDataToMe(); - SendOtherAgentsAppearanceToMe(); - }); } -- cgit v1.1 From 682537738008746f0aca22954902f3a4dfbdc95f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 11:11:18 -0700 Subject: Trying to reduce CPU usage on logins and TPs: trying radical elimination of all FireAndForgets throughout CompleteMovement. There were 4. --- .../Avatar/UserProfiles/UserProfileModule.cs | 5 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 60 ++++++++++------------ 2 files changed, 27 insertions(+), 38 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index c04098c..e7216ed 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -173,10 +173,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles if(obj.PresenceType == PresenceType.Npc) return; - Util.FireAndForget(delegate - { - GetImageAssets(((IScenePresence)obj).UUID); - }); + GetImageAssets(((IScenePresence)obj).UUID); } /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9f8ada3..4d796fe 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -958,14 +958,7 @@ namespace OpenSim.Region.Framework.Scenes // Viewers which have a current outfit folder will actually rez their own attachments. However, // viewers without (e.g. v1 viewers) will not, so we still need to make this call. if (Scene.AttachmentsModule != null) - Util.FireAndForget( - o => - { -// if (PresenceType != PresenceType.Npc && Util.FireAndForgetMethod != FireAndForgetMethod.None) -// System.Threading.Thread.Sleep(7000); - - Scene.AttachmentsModule.RezAttachments(this); - }); + Scene.AttachmentsModule.RezAttachments(this); } else { @@ -1362,18 +1355,6 @@ namespace OpenSim.Region.Framework.Scenes ValidateAndSendAppearanceAndAgentData(); - // Create child agents in neighbouring regions - if (openChildAgents && !IsChildAgent) - { - IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); - if (m_agentTransfer != null) - Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); - - IFriendsModule friendsModule = m_scene.RequestModuleInterface(); - if (friendsModule != null) - friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); - } - // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. // This may be due to viewer code or it may be something we're not doing properly simulator side. @@ -1383,6 +1364,19 @@ namespace OpenSim.Region.Framework.Scenes sog.ScheduleGroupForFullUpdate(); } + // Create child agents in neighbouring regions + if (openChildAgents && !IsChildAgent) + { + IFriendsModule friendsModule = m_scene.RequestModuleInterface(); + if (friendsModule != null) + friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + m_agentTransfer.EnableChildAgents(this); // this can take a while... several seconds + + } + // m_log.DebugFormat( // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); @@ -2689,22 +2683,20 @@ namespace OpenSim.Region.Framework.Scenes public void SendInitialDataToMe() { // Send all scene object to the new client - Util.FireAndForget(delegate + + // we created a new ScenePresence (a new child agent) in a fresh region. + // Request info about all the (root) agents in this region + // Note: This won't send data *to* other clients in that region (children don't send) + SendOtherAgentsAvatarDataToMe(); + SendOtherAgentsAppearanceToMe(); + + EntityBase[] entities = Scene.Entities.GetEntities(); + foreach (EntityBase e in entities) { - // we created a new ScenePresence (a new child agent) in a fresh region. - // Request info about all the (root) agents in this region - // Note: This won't send data *to* other clients in that region (children don't send) - SendOtherAgentsAvatarDataToMe(); - SendOtherAgentsAppearanceToMe(); - - EntityBase[] entities = Scene.Entities.GetEntities(); - foreach (EntityBase e in entities) - { - if (e != null && e is SceneObjectGroup) - ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); - } + if (e != null && e is SceneObjectGroup) + ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); + } - }); } /// -- cgit v1.1 From bc405a6a349f4d2be3f79afe7e8a88738339ef1f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 11:30:37 -0700 Subject: That didn't fix the problem. Revert "Trying to reduce CPU usage on logins and TPs: trying radical elimination of all FireAndForgets throughout CompleteMovement. There were 4." This reverts commit 682537738008746f0aca22954902f3a4dfbdc95f. --- .../Avatar/UserProfiles/UserProfileModule.cs | 5 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 60 ++++++++++++---------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index e7216ed..c04098c 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -173,7 +173,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles if(obj.PresenceType == PresenceType.Npc) return; - GetImageAssets(((IScenePresence)obj).UUID); + Util.FireAndForget(delegate + { + GetImageAssets(((IScenePresence)obj).UUID); + }); } /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4d796fe..9f8ada3 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -958,7 +958,14 @@ namespace OpenSim.Region.Framework.Scenes // Viewers which have a current outfit folder will actually rez their own attachments. However, // viewers without (e.g. v1 viewers) will not, so we still need to make this call. if (Scene.AttachmentsModule != null) - Scene.AttachmentsModule.RezAttachments(this); + Util.FireAndForget( + o => + { +// if (PresenceType != PresenceType.Npc && Util.FireAndForgetMethod != FireAndForgetMethod.None) +// System.Threading.Thread.Sleep(7000); + + Scene.AttachmentsModule.RezAttachments(this); + }); } else { @@ -1355,26 +1362,25 @@ namespace OpenSim.Region.Framework.Scenes ValidateAndSendAppearanceAndAgentData(); - // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region - // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. - // This may be due to viewer code or it may be something we're not doing properly simulator side. - lock (m_attachments) - { - foreach (SceneObjectGroup sog in m_attachments) - sog.ScheduleGroupForFullUpdate(); - } - // Create child agents in neighbouring regions if (openChildAgents && !IsChildAgent) { + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); + IFriendsModule friendsModule = m_scene.RequestModuleInterface(); if (friendsModule != null) friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + } - IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); - if (m_agentTransfer != null) - m_agentTransfer.EnableChildAgents(this); // this can take a while... several seconds - + // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region + // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. + // This may be due to viewer code or it may be something we're not doing properly simulator side. + lock (m_attachments) + { + foreach (SceneObjectGroup sog in m_attachments) + sog.ScheduleGroupForFullUpdate(); } // m_log.DebugFormat( @@ -2683,20 +2689,22 @@ namespace OpenSim.Region.Framework.Scenes public void SendInitialDataToMe() { // Send all scene object to the new client - - // we created a new ScenePresence (a new child agent) in a fresh region. - // Request info about all the (root) agents in this region - // Note: This won't send data *to* other clients in that region (children don't send) - SendOtherAgentsAvatarDataToMe(); - SendOtherAgentsAppearanceToMe(); - - EntityBase[] entities = Scene.Entities.GetEntities(); - foreach (EntityBase e in entities) + Util.FireAndForget(delegate { - if (e != null && e is SceneObjectGroup) - ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); - } + // we created a new ScenePresence (a new child agent) in a fresh region. + // Request info about all the (root) agents in this region + // Note: This won't send data *to* other clients in that region (children don't send) + SendOtherAgentsAvatarDataToMe(); + SendOtherAgentsAppearanceToMe(); + + EntityBase[] entities = Scene.Entities.GetEntities(); + foreach (EntityBase e in entities) + { + if (e != null && e is SceneObjectGroup) + ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); + } + }); } /// -- cgit v1.1 From 5a1d6727e15623af4700058d516cabf03fb910ac Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 11:39:17 -0700 Subject: Some more debug to see how many threads are available. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9f8ada3..11b15a7 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1383,6 +1383,8 @@ namespace OpenSim.Region.Framework.Scenes sog.ScheduleGroupForFullUpdate(); } + m_log.DebugFormat("[SCENE PRESENCE]: ({0}) Available threads: {1}", Name, Util.FireAndForgetCount()); + // m_log.DebugFormat( // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); -- cgit v1.1 From 4d93870fe589ec4d184ee1e4165b7a1bbf18abc6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 17:52:05 -0700 Subject: Gatekeeper: stop bogus agents earlier, here at the Gatekeeper. No need to bother the sim. --- OpenSim/Services/HypergridService/GatekeeperService.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 0cf1c14..0a3e70b 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -419,6 +419,12 @@ namespace OpenSim.Services.HypergridService if (!CheckAddress(aCircuit.ServiceSessionID)) return false; + if (string.IsNullOrEmpty(aCircuit.IPAddress)) + { + m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide a client IP address."); + return false; + } + string userURL = string.Empty; if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) userURL = aCircuit.ServiceURLs["HomeURI"].ToString(); -- cgit v1.1 From 931eb892d92bcd61194655ec02def6264d8b182e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 17:56:42 -0700 Subject: Deleted GET agent all around. Not used. --- .../Simulation/LocalSimulationConnector.cs | 20 ------- .../Simulation/RemoteSimulationConnector.cs | 18 ------- .../Server/Handlers/Simulation/AgentHandlers.cs | 61 +--------------------- .../Simulation/SimulationServiceConnector.cs | 35 ------------- OpenSim/Services/Interfaces/ISimulationService.cs | 2 - 5 files changed, 2 insertions(+), 134 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 9427961..2dc3d2a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -250,26 +250,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return true; } - public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) - { - agent = null; - - if (destination == null) - return false; - - if (m_scenes.ContainsKey(destination.RegionID)) - { -// m_log.DebugFormat( -// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", -// s.RegionInfo.RegionName, destination.RegionHandle); - - return m_scenes[destination.RegionID].IncomingRetrieveRootAgent(id, out agent); - } - - //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate"); - return false; - } - public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) { reason = "Communications failure"; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index d120e11..4aa2d2a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -212,24 +212,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return m_remoteConnector.UpdateAgent(destination, cAgentData); } - public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) - { - agent = null; - - if (destination == null) - return false; - - // Try local first - if (m_localBackend.RetrieveAgent(destination, id, out agent)) - return true; - - // else do the remote thing - if (!m_localBackend.IsLocalRegion(destination.RegionID)) - return m_remoteConnector.RetrieveAgent(destination, id, out agent); - - return false; - } - public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) { reason = "Communications failure"; diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 40a34c6..17a8ef4 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -90,12 +90,7 @@ namespace OpenSim.Server.Handlers.Simulation // Next, let's parse the verb string method = (string)request["http-method"]; - if (method.Equals("GET")) - { - DoAgentGet(request, responsedata, agentID, regionID); - return responsedata; - } - else if (method.Equals("DELETE")) + if (method.Equals("DELETE")) { DoAgentDelete(request, responsedata, agentID, action, regionID); return responsedata; @@ -107,7 +102,7 @@ namespace OpenSim.Server.Handlers.Simulation } else { - m_log.InfoFormat("[AGENT HANDLER]: method {0} not supported in agent message (caller is {1})", method, Util.GetCallerIP(request)); + m_log.ErrorFormat("[AGENT HANDLER]: method {0} not supported in agent message {1} (caller is {2})", method, (string)request["uri"], Util.GetCallerIP(request)); responsedata["int_response_code"] = HttpStatusCode.MethodNotAllowed; responsedata["str_response_string"] = "Method not allowed"; @@ -156,58 +151,6 @@ namespace OpenSim.Server.Handlers.Simulation // Console.WriteLine("str_response_string [{0}]", responsedata["str_response_string"]); } - protected virtual void DoAgentGet(Hashtable request, Hashtable responsedata, UUID id, UUID regionID) - { - if (m_SimulationService == null) - { - m_log.Debug("[AGENT HANDLER]: Agent GET called. Harmless but useless."); - responsedata["content_type"] = "application/json"; - responsedata["int_response_code"] = HttpStatusCode.NotImplemented; - responsedata["str_response_string"] = string.Empty; - - return; - } - - GridRegion destination = new GridRegion(); - destination.RegionID = regionID; - - IAgentData agent = null; - bool result = m_SimulationService.RetrieveAgent(destination, id, out agent); - OSDMap map = null; - if (result) - { - if (agent != null) // just to make sure - { - map = agent.Pack(); - string strBuffer = ""; - try - { - strBuffer = OSDParser.SerializeJsonString(map); - } - catch (Exception e) - { - m_log.WarnFormat("[AGENT HANDLER]: Exception thrown on serialization of DoAgentGet: {0}", e.Message); - responsedata["int_response_code"] = HttpStatusCode.InternalServerError; - // ignore. buffer will be empty, caller should check. - } - - responsedata["content_type"] = "application/json"; - responsedata["int_response_code"] = HttpStatusCode.OK; - responsedata["str_response_string"] = strBuffer; - } - else - { - responsedata["int_response_code"] = HttpStatusCode.InternalServerError; - responsedata["str_response_string"] = "Internal error"; - } - } - else - { - responsedata["int_response_code"] = HttpStatusCode.NotFound; - responsedata["str_response_string"] = "Not Found"; - } - } - protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID) { m_log.Debug(" >>> DoDelete action:" + action + "; RegionID:" + regionID); diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index f51c809..7eb8c24 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -271,41 +271,6 @@ namespace OpenSim.Services.Connectors.Simulation return false; } - /// - /// Not sure what sequence causes this function to be invoked. The only calling - /// path is through the GET method - /// - public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) - { - // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: RetrieveAgent start"); - - agent = null; - - // Eventually, we want to use a caps url instead of the agentID - string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; - - try - { - OSDMap result = WebUtil.GetFromService(uri, 10000); - if (result["Success"].AsBoolean()) - { - // OSDMap args = Util.GetOSDMap(result["_RawResult"].AsString()); - OSDMap args = (OSDMap)result["_Result"]; - if (args != null) - { - agent = new CompleteAgentData(); - agent.Unpack(args, null); - return true; - } - } - } - catch (Exception e) - { - m_log.Warn("[REMOTE SIMULATION CONNECTOR]: UpdateAgent failed with exception: " + e.ToString()); - } - - return false; - } /// /// diff --git a/OpenSim/Services/Interfaces/ISimulationService.cs b/OpenSim/Services/Interfaces/ISimulationService.cs index b10a85c..c9cbd1a 100644 --- a/OpenSim/Services/Interfaces/ISimulationService.cs +++ b/OpenSim/Services/Interfaces/ISimulationService.cs @@ -75,8 +75,6 @@ namespace OpenSim.Services.Interfaces /// bool UpdateAgent(GridRegion destination, AgentPosition data); - bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent); - bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason); /// -- cgit v1.1 From b4f1b9acf65f9e782d56602e60c58be6145c5cca Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 21:28:46 -0700 Subject: Guard against unauthorized agent deletes. --- .../EntityTransfer/EntityTransferModule.cs | 14 ++++++------ .../Simulation/LocalSimulationConnector.cs | 4 ++-- .../Simulation/RemoteSimulationConnector.cs | 6 ++--- OpenSim/Region/Framework/Scenes/Scene.cs | 26 +++++++++++++++++----- .../Framework/Scenes/SceneCommunicationService.cs | 8 +++---- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 6 ++++- .../Server/Handlers/Simulation/AgentHandlers.cs | 16 ++++++++----- .../Simulation/SimulationServiceConnector.cs | 7 +++--- OpenSim/Services/Interfaces/ISimulationService.cs | 2 +- 9 files changed, 57 insertions(+), 32 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 85d26f3..ef2ed4f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -817,7 +817,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established."); + Fail(sp, finalDestination, logout, Util.Md5Hash(currentAgentCircuit.Id0), "Connection between viewer and destination region could not be established."); return; } @@ -829,7 +829,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); - CleanupFailedInterRegionTeleport(sp, finalDestination); + CleanupFailedInterRegionTeleport(sp, Util.Md5Hash(currentAgentCircuit.Id0), finalDestination); return; } @@ -873,7 +873,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion."); + Fail(sp, finalDestination, logout, Util.Md5Hash(currentAgentCircuit.Id0), "Destination region did not signal teleport completion."); return; } @@ -927,7 +927,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) + protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination) { m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); @@ -938,7 +938,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Finally, kill the agent we just created at the destination. // XXX: Possibly this should be done asynchronously. - Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); + Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token); } /// @@ -948,9 +948,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// Human readable reason for teleport failure. Will be sent to client. - protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason) + protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string auth_code, string reason) { - CleanupFailedInterRegionTeleport(sp, finalDestination); + CleanupFailedInterRegionTeleport(sp, auth_code, finalDestination); m_interRegionTeleportFailures.Value++; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 2dc3d2a..6d5039b 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -286,7 +286,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - public bool CloseAgent(GridRegion destination, UUID id) + public bool CloseAgent(GridRegion destination, UUID id, string auth_token) { if (destination == null) return false; @@ -297,7 +297,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // s.RegionInfo.RegionName, destination.RegionHandle); - m_scenes[destination.RegionID].IncomingCloseAgent(id, false); + m_scenes[destination.RegionID].IncomingCloseAgent(id, false, auth_token); return true; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index 4aa2d2a..8722b80 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -245,18 +245,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } - public bool CloseAgent(GridRegion destination, UUID id) + public bool CloseAgent(GridRegion destination, UUID id, string auth_token) { if (destination == null) return false; // Try local first - if (m_localBackend.CloseAgent(destination, id)) + if (m_localBackend.CloseAgent(destination, id, auth_token)) return true; // else do the remote thing if (!m_localBackend.IsLocalRegion(destination.RegionID)) - return m_remoteConnector.CloseAgent(destination, id); + return m_remoteConnector.CloseAgent(destination, id, auth_token); return false; } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 54956ee..becea1f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3452,7 +3452,7 @@ namespace OpenSim.Region.Framework.Scenes regions.Remove(RegionInfo.RegionHandle); // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. - m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); + m_sceneGridService.SendCloseChildAgentConnections(agentID, Util.Md5Hash(acd.Id0), regions); } m_eventManager.TriggerClientClosed(agentID, this); @@ -4277,6 +4277,25 @@ namespace OpenSim.Region.Framework.Scenes return false; } + /// + /// Authenticated close (via network) + /// + /// + /// + /// + /// + public bool IncomingCloseAgent(UUID agentID, bool force, string auth_token) + { + //m_log.DebugFormat("[SCENE]: Processing incoming close agent {0} in region {1} with auth_token {2}", agentID, RegionInfo.RegionName, auth_token); + + // Check that the auth_token is valid + AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID); + if (acd != null && Util.Md5Hash(acd.Id0) == auth_token) + return IncomingCloseAgent(agentID, force); + else + m_log.ErrorFormat("[SCENE]: Request to close agent {0} with invalid authorization token {1}", agentID, auth_token); + return false; + } /// /// Tell a single agent to disconnect from the region. @@ -4292,12 +4311,9 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); if (presence != null) - { presence.ControllingClient.Close(force); - return true; - } - // Agent not here + // Agent not here return false; } diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index 8238e23..77889fa 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -197,7 +197,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Closes a child agent on a given region /// - protected void SendCloseChildAgent(UUID agentID, ulong regionHandle) + protected void SendCloseChildAgent(UUID agentID, ulong regionHandle, string auth_token) { // let's do our best, but there's not much we can do if the neighbour doesn't accept. @@ -210,7 +210,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[SCENE COMMUNICATION SERVICE]: Sending close agent ID {0} to {1}", agentID, destination.RegionName); - m_scene.SimulationService.CloseAgent(destination, agentID); + m_scene.SimulationService.CloseAgent(destination, agentID, auth_token); } /// @@ -219,14 +219,14 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public void SendCloseChildAgentConnections(UUID agentID, List regionslst) + public void SendCloseChildAgentConnections(UUID agentID, string auth_code, List regionslst) { foreach (ulong handle in regionslst) { // We must take a copy here since handle is acts like a reference when used in an iterator. // This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region. ulong handleCopy = handle; - Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy); }); + Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); }); } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 11b15a7..5991a34 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3167,7 +3167,11 @@ namespace OpenSim.Region.Framework.Scenes { m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); - m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); + AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID); + string auth = string.Empty; + if (acd != null) + auth = Util.Md5Hash(acd.Id0); + m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); } foreach (ulong handle in byebyeRegions) diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 17a8ef4..cd172e4 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -27,11 +27,13 @@ using System; using System.Collections; +using System.Collections.Specialized; using System.IO; using System.IO.Compression; using System.Reflection; using System.Net; using System.Text; +using System.Web; using OpenSim.Server.Base; using OpenSim.Server.Handlers.Base; @@ -92,7 +94,11 @@ namespace OpenSim.Server.Handlers.Simulation string method = (string)request["http-method"]; if (method.Equals("DELETE")) { - DoAgentDelete(request, responsedata, agentID, action, regionID); + string auth_token = string.Empty; + if (request.ContainsKey("auth")) + auth_token = request["auth"].ToString(); + + DoAgentDelete(request, responsedata, agentID, action, regionID, auth_token); return responsedata; } else if (method.Equals("QUERYACCESS")) @@ -151,9 +157,9 @@ namespace OpenSim.Server.Handlers.Simulation // Console.WriteLine("str_response_string [{0}]", responsedata["str_response_string"]); } - protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID) + protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID, string auth_token) { - m_log.Debug(" >>> DoDelete action:" + action + "; RegionID:" + regionID); + m_log.DebugFormat("[AGENT HANDLER]: >>> DELETE action: {0}; RegionID: {1}; from: {2}; auth_code: {3}", action, regionID, Util.GetCallerIP(request), auth_token); GridRegion destination = new GridRegion(); destination.RegionID = regionID; @@ -161,12 +167,12 @@ namespace OpenSim.Server.Handlers.Simulation if (action.Equals("release")) ReleaseAgent(regionID, id); else - Util.FireAndForget(delegate { m_SimulationService.CloseAgent(destination, id); }); + Util.FireAndForget(delegate { m_SimulationService.CloseAgent(destination, id, auth_token); }); responsedata["int_response_code"] = HttpStatusCode.OK; responsedata["str_response_string"] = "OpenSim agent " + id.ToString(); - m_log.DebugFormat("[AGENT HANDLER]: Agent {0} Released/Deleted from region {1}", id, regionID); + //m_log.DebugFormat("[AGENT HANDLER]: Agent {0} Released/Deleted from region {1}", id, regionID); } protected virtual void ReleaseAgent(UUID regionID, UUID id) diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 7eb8c24..aca414b 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -367,11 +367,10 @@ namespace OpenSim.Services.Connectors.Simulation /// /// - public bool CloseAgent(GridRegion destination, UUID id) + public bool CloseAgent(GridRegion destination, UUID id, string auth_code) { -// m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent start"); - - string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; + string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/?auth=" + auth_code; + m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent {0}", uri); try { diff --git a/OpenSim/Services/Interfaces/ISimulationService.cs b/OpenSim/Services/Interfaces/ISimulationService.cs index c9cbd1a..1c82b3e 100644 --- a/OpenSim/Services/Interfaces/ISimulationService.cs +++ b/OpenSim/Services/Interfaces/ISimulationService.cs @@ -93,7 +93,7 @@ namespace OpenSim.Services.Interfaces /// /// /// - bool CloseAgent(GridRegion destination, UUID id); + bool CloseAgent(GridRegion destination, UUID id, string auth_token); #endregion Agents -- cgit v1.1 From a2ee887c6d4cc0756b808353ad0183b1e7e29b74 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 22:32:52 -0700 Subject: Deleted a line too many --- OpenSim/Region/Framework/Scenes/Scene.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index becea1f..264aaa8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4311,7 +4311,10 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); if (presence != null) + { presence.ControllingClient.Close(force); + return true; + } // Agent not here return false; -- cgit v1.1 From e4f741f0062dfe948e071a88f643f96931140f67 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 22:52:51 -0700 Subject: This should fix the failing test. --- OpenSim/Region/Framework/Scenes/Scene.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 264aaa8..155054a 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3452,7 +3452,7 @@ namespace OpenSim.Region.Framework.Scenes regions.Remove(RegionInfo.RegionHandle); // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. - m_sceneGridService.SendCloseChildAgentConnections(agentID, Util.Md5Hash(acd.Id0), regions); + m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.Id0 != null ? Util.Md5Hash(acd.Id0) : string.Empty, regions); } m_eventManager.TriggerClientClosed(agentID, this); @@ -4308,7 +4308,6 @@ namespace OpenSim.Region.Framework.Scenes public bool IncomingCloseAgent(UUID agentID, bool force) { //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); - ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); if (presence != null) { -- cgit v1.1 From fcb0349d565154926be87144d374c7b6d6476eab Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 13 Jul 2013 23:01:41 -0700 Subject: And this fixes the other failing tests. Justin, the thread pool is not being initialized in the tests! --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 5991a34..b7ce173 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1383,8 +1383,6 @@ namespace OpenSim.Region.Framework.Scenes sog.ScheduleGroupForFullUpdate(); } - m_log.DebugFormat("[SCENE PRESENCE]: ({0}) Available threads: {1}", Name, Util.FireAndForgetCount()); - // m_log.DebugFormat( // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); -- cgit v1.1 From f3b3e21dea98b4ea974ae7649a63d00b69e6dfed Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 07:28:40 -0700 Subject: Change the auth token to be the user's sessionid. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 6 +++--- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++-- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- OpenSim/Server/Handlers/Simulation/AgentHandlers.cs | 5 ++++- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ef2ed4f..344c8d7 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -817,7 +817,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - Fail(sp, finalDestination, logout, Util.Md5Hash(currentAgentCircuit.Id0), "Connection between viewer and destination region could not be established."); + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); return; } @@ -829,7 +829,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); - CleanupFailedInterRegionTeleport(sp, Util.Md5Hash(currentAgentCircuit.Id0), finalDestination); + CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); return; } @@ -873,7 +873,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - Fail(sp, finalDestination, logout, Util.Md5Hash(currentAgentCircuit.Id0), "Destination region did not signal teleport completion."); + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); return; } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 155054a..ea7081c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3452,7 +3452,7 @@ namespace OpenSim.Region.Framework.Scenes regions.Remove(RegionInfo.RegionHandle); // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. - m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.Id0 != null ? Util.Md5Hash(acd.Id0) : string.Empty, regions); + m_sceneGridService.SendCloseChildAgentConnections(agentID, acd.SessionID.ToString(), regions); } m_eventManager.TriggerClientClosed(agentID, this); @@ -4290,7 +4290,7 @@ namespace OpenSim.Region.Framework.Scenes // Check that the auth_token is valid AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID); - if (acd != null && Util.Md5Hash(acd.Id0) == auth_token) + if (acd != null && acd.SessionID.ToString() == auth_token) return IncomingCloseAgent(agentID, force); else m_log.ErrorFormat("[SCENE]: Request to close agent {0} with invalid authorization token {1}", agentID, auth_token); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index b7ce173..c5cca22 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3168,7 +3168,7 @@ namespace OpenSim.Region.Framework.Scenes AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID); string auth = string.Empty; if (acd != null) - auth = Util.Md5Hash(acd.Id0); + auth = acd.SessionID.ToString(); m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); } diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index cd172e4..4ac477f 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -159,7 +159,10 @@ namespace OpenSim.Server.Handlers.Simulation protected void DoAgentDelete(Hashtable request, Hashtable responsedata, UUID id, string action, UUID regionID, string auth_token) { - m_log.DebugFormat("[AGENT HANDLER]: >>> DELETE action: {0}; RegionID: {1}; from: {2}; auth_code: {3}", action, regionID, Util.GetCallerIP(request), auth_token); + if (string.IsNullOrEmpty(action)) + m_log.DebugFormat("[AGENT HANDLER]: >>> DELETE <<< RegionID: {0}; from: {1}; auth_code: {2}", regionID, Util.GetCallerIP(request), auth_token); + else + m_log.DebugFormat("[AGENT HANDLER]: Release {0} to RegionID: {1}", id, regionID); GridRegion destination = new GridRegion(); destination.RegionID = regionID; -- cgit v1.1 From c61ff917ef99a00d4062f264ed10c2a662585e8a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 09:21:28 -0700 Subject: Authenticate ChildAgentUpdate too. --- OpenSim/Framework/ChildAgentDataUpdate.cs | 3 +- OpenSim/Framework/Tests/MundaneFrameworkTests.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 42 +++++++++++++++--------- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 +- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index dfe60aa..9fc048b 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -171,9 +171,10 @@ namespace OpenSim.Framework /// Soon to be decommissioned /// /// - public void CopyFrom(ChildAgentDataUpdate cAgent) + public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid) { AgentID = new UUID(cAgent.AgentID); + SessionID = sid; // next: ??? Size = new Vector3(); diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs index 1dc8053..3f0a031 100644 --- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs +++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs @@ -100,7 +100,7 @@ namespace OpenSim.Framework.Tests cadu.AVHeight = Size1.Z; AgentPosition position2 = new AgentPosition(); - position2.CopyFrom(cadu); + position2.CopyFrom(cadu, position1.SessionID); Assert.IsTrue( position2.AgentID == position1.AgentID diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index ea7081c..b07faa2 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4202,10 +4202,18 @@ namespace OpenSim.Region.Framework.Scenes if (childAgentUpdate != null) { - childAgentUpdate.ChildAgentDataUpdate(cAgentData); - return true; + if (cAgentData.SessionID == childAgentUpdate.ControllingClient.SessionId) + { + childAgentUpdate.ChildAgentDataUpdate(cAgentData); + return true; + } + else + { + m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID); + Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}", + childAgentUpdate.UUID, childAgentUpdate.ControllingClient.SessionId, cAgentData.SessionID)); + } } - return false; } @@ -4221,20 +4229,24 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); if (childAgentUpdate != null) { - // I can't imagine *yet* why we would get an update if the agent is a root agent.. - // however to avoid a race condition crossing borders.. - if (childAgentUpdate.IsChildAgent) + if (childAgentUpdate.ControllingClient.SessionId == cAgentData.SessionID) { - uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); - uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); - uint tRegionX = RegionInfo.RegionLocX; - uint tRegionY = RegionInfo.RegionLocY; - //Send Data to ScenePresence - childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); - // Not Implemented: - //TODO: Do we need to pass the message on to one of our neighbors? + // I can't imagine *yet* why we would get an update if the agent is a root agent.. + // however to avoid a race condition crossing borders.. + if (childAgentUpdate.IsChildAgent) + { + uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); + uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); + uint tRegionX = RegionInfo.RegionLocX; + uint tRegionY = RegionInfo.RegionLocY; + //Send Data to ScenePresence + childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); + // Not Implemented: + //TODO: Do we need to pass the message on to one of our neighbors? + } } - + else + m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID); return true; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index c5cca22..990ef6e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2927,7 +2927,7 @@ namespace OpenSim.Region.Framework.Scenes cadu.Velocity = Velocity; AgentPosition agentpos = new AgentPosition(); - agentpos.CopyFrom(cadu); + agentpos.CopyFrom(cadu, ControllingClient.SessionId); // Let's get this out of the update loop Util.FireAndForget(delegate { m_scene.SendOutChildAgentUpdates(agentpos, this); }); @@ -3266,6 +3266,7 @@ namespace OpenSim.Region.Framework.Scenes cAgent.AgentID = UUID; cAgent.RegionID = Scene.RegionInfo.RegionID; + cAgent.SessionID = ControllingClient.SessionId; cAgent.Position = AbsolutePosition; cAgent.Velocity = m_velocity; -- cgit v1.1 From 98f59ffed59d33c3737787bff85a72fde545fc94 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 09:22:55 -0700 Subject: Fix broken tests -- the test setup was wrong... sigh. --- OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs | 1 + OpenSim/Tests/Common/Mock/TestClient.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 5a72239..5df9aba 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -112,6 +112,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; + moveArgs.SessionID = acd.SessionID; originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index c660501..2fc3f0b 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -584,7 +584,7 @@ namespace OpenSim.Tests.Common.Mock { AgentCircuitData agentData = new AgentCircuitData(); agentData.AgentID = AgentId; - agentData.SessionID = UUID.Zero; + agentData.SessionID = SessionId; agentData.SecureSessionID = UUID.Zero; agentData.circuitcode = m_circuitCode; agentData.child = false; -- cgit v1.1 From c8dcb8474d0b0698168863328e61a6929bb0770f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 10:26:05 -0700 Subject: Let's go easy on authenticating ChildAgentUpdates, otherwise this will be chaotic while ppl are using different versions of opensim. Warning only, but no enforcement. --- OpenSim/Region/Framework/Scenes/Scene.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index b07faa2..9cfe869 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4202,17 +4202,15 @@ namespace OpenSim.Region.Framework.Scenes if (childAgentUpdate != null) { - if (cAgentData.SessionID == childAgentUpdate.ControllingClient.SessionId) + if (cAgentData.SessionID != childAgentUpdate.ControllingClient.SessionId) { - childAgentUpdate.ChildAgentDataUpdate(cAgentData); - return true; - } - else - { - m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID); + m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", childAgentUpdate.UUID, cAgentData.SessionID); Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}", childAgentUpdate.UUID, childAgentUpdate.ControllingClient.SessionId, cAgentData.SessionID)); } + + childAgentUpdate.ChildAgentDataUpdate(cAgentData); + return true; } return false; } -- cgit v1.1 From 593952903639e51df6faf6c8649a0410c9649184 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 14:29:10 -0700 Subject: Minor typo in log message --- OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs index 94bda82..1a62d2f 100644 --- a/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs +++ b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs @@ -214,7 +214,7 @@ namespace OpenSim.Services.Connectors } else - m_log.DebugFormat("[GRID USER CONNECTOR]: Loggedin received empty reply"); + m_log.DebugFormat("[GRID USER CONNECTOR]: Get received empty reply"); } catch (Exception e) { -- cgit v1.1 From e33ac50388b5b9d6d06c58c45e2ea6f17e9b987f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 14:31:20 -0700 Subject: HG UAS: Moved hg-session data from memory to DB storage. This makes it so that traveling info survives Robust resets. It should also eliminate the cause of empty IP addresses in agent circuit data that we saw in CC grid. MySQL only. --- OpenSim/Data/IHGTravelingData.cs | 58 ++++++ OpenSim/Data/MySQL/MySQLHGTravelData.cs | 70 +++++++ .../Data/MySQL/Resources/HGTravelStore.migrations | 17 ++ .../Services/HypergridService/UserAgentService.cs | 205 ++++++++++++--------- .../HypergridService/UserAgentServiceBase.cs | 84 +++++++++ 5 files changed, 344 insertions(+), 90 deletions(-) create mode 100644 OpenSim/Data/IHGTravelingData.cs create mode 100644 OpenSim/Data/MySQL/MySQLHGTravelData.cs create mode 100644 OpenSim/Data/MySQL/Resources/HGTravelStore.migrations create mode 100644 OpenSim/Services/HypergridService/UserAgentServiceBase.cs diff --git a/OpenSim/Data/IHGTravelingData.cs b/OpenSim/Data/IHGTravelingData.cs new file mode 100644 index 0000000..dd89935 --- /dev/null +++ b/OpenSim/Data/IHGTravelingData.cs @@ -0,0 +1,58 @@ +/* + * 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 OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Data +{ + // This MUST be a ref type! + public class HGTravelingData + { + public UUID SessionID; + public UUID UserID; + public Dictionary Data; + + public HGTravelingData() + { + Data = new Dictionary(); + } + } + + /// + /// An interface for connecting to the user grid datastore + /// + public interface IHGTravelingData + { + HGTravelingData Get(UUID sessionID); + HGTravelingData[] GetSessions(UUID userID); + bool Store(HGTravelingData data); + bool Delete(UUID sessionID); + } +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLHGTravelData.cs b/OpenSim/Data/MySQL/MySQLHGTravelData.cs new file mode 100644 index 0000000..1efbfc3 --- /dev/null +++ b/OpenSim/Data/MySQL/MySQLHGTravelData.cs @@ -0,0 +1,70 @@ +/* + * 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.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using MySql.Data.MySqlClient; + +namespace OpenSim.Data.MySQL +{ + /// + /// A MySQL Interface for user grid data + /// + public class MySQLHGTravelData : MySQLGenericTableHandler, IHGTravelingData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public MySQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { } + + public HGTravelingData Get(UUID sessionID) + { + HGTravelingData[] ret = Get("SessionID", sessionID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public HGTravelingData[] GetSessions(UUID userID) + { + return base.Get("UserID", userID.ToString()); + } + + public bool Delete(UUID sessionID) + { + return Delete("SessionID", sessionID.ToString()); + } + + } +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations b/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations new file mode 100644 index 0000000..a0c9ebe --- /dev/null +++ b/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations @@ -0,0 +1,17 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE `hg_traveling_data` ( + `SessionID` VARCHAR(36) NOT NULL, + `UserID` VARCHAR(36) NOT NULL, + `GridExternalName` VARCHAR(255) NOT NULL DEFAULT '', + `ServiceToken` VARCHAR(255) NOT NULL DEFAULT '', + `ClientIPAddress` VARCHAR(16) NOT NULL DEFAULT '', + `MyIPAddress` VARCHAR(16) NOT NULL DEFAULT '', + PRIMARY KEY (`SessionID`), + KEY (`UserID`) +) ENGINE=InnoDB; + +COMMIT; + diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 733993f..b597cb9 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.Net; using System.Reflection; +using OpenSim.Data; using OpenSim.Framework; using OpenSim.Services.Connectors.Friends; using OpenSim.Services.Connectors.Hypergrid; @@ -50,14 +51,14 @@ namespace OpenSim.Services.HypergridService /// needs to do it for them. /// Once we have better clients, this shouldn't be needed. /// - public class UserAgentService : IUserAgentService + public class UserAgentService : UserAgentServiceBase, IUserAgentService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); // This will need to go into a DB table - static Dictionary m_TravelingAgents = new Dictionary(); + //static Dictionary m_Database = new Dictionary(); static bool m_Initialized = false; @@ -86,6 +87,7 @@ namespace OpenSim.Services.HypergridService } public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector) + : base(config) { // Let's set this always, because we don't know the sequence // of instantiations @@ -260,7 +262,8 @@ namespace OpenSim.Services.HypergridService // Generate a new service session agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random(); - TravelingAgentInfo old = UpdateTravelInfo(agentCircuit, region); + TravelingAgentInfo old = null; + TravelingAgentInfo travel = CreateTravelInfo(agentCircuit, region, fromLogin, out old); bool success = false; string myExternalIP = string.Empty; @@ -282,23 +285,21 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}", agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason); - // restore the old travel info - lock (m_TravelingAgents) - { - if (old == null) - m_TravelingAgents.Remove(agentCircuit.SessionID); - else - m_TravelingAgents[agentCircuit.SessionID] = old; - } + if (old != null) + StoreTravelInfo(old); + else + m_Database.Delete(agentCircuit.SessionID); return false; } + // Everything is ok + + // Update the perceived IP Address of our grid m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); - // else set the IP addresses associated with this client - if (fromLogin) - m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = agentCircuit.IPAddress; - m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; + travel.MyIpAddress = myExternalIP; + + StoreTravelInfo(travel); return true; } @@ -309,57 +310,39 @@ namespace OpenSim.Services.HypergridService return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, false, out reason); } - private void SetClientIP(UUID sessionID, string ip) + TravelingAgentInfo CreateTravelInfo(AgentCircuitData agentCircuit, GridRegion region, bool fromLogin, out TravelingAgentInfo existing) { - if (m_TravelingAgents.ContainsKey(sessionID)) - { - m_log.DebugFormat("[USER AGENT SERVICE]: Setting IP {0} for session {1}", ip, sessionID); - m_TravelingAgents[sessionID].ClientIPAddress = ip; - } - } + HGTravelingData hgt = m_Database.Get(agentCircuit.SessionID); + existing = null; - TravelingAgentInfo UpdateTravelInfo(AgentCircuitData agentCircuit, GridRegion region) - { - TravelingAgentInfo travel = new TravelingAgentInfo(); - TravelingAgentInfo old = null; - lock (m_TravelingAgents) + if (hgt != null) { - if (m_TravelingAgents.ContainsKey(agentCircuit.SessionID)) - { - // Very important! Override whatever this agent comes with. - // UserAgentService always sets the IP for every new agent - // with the original IP address. - agentCircuit.IPAddress = m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress; - - old = m_TravelingAgents[agentCircuit.SessionID]; - } - - m_TravelingAgents[agentCircuit.SessionID] = travel; + // Very important! Override whatever this agent comes with. + // UserAgentService always sets the IP for every new agent + // with the original IP address. + existing = new TravelingAgentInfo(hgt); + agentCircuit.IPAddress = existing.ClientIPAddress; } + + TravelingAgentInfo travel = new TravelingAgentInfo(existing); + travel.SessionID = agentCircuit.SessionID; travel.UserID = agentCircuit.AgentID; travel.GridExternalName = region.ServerURI; travel.ServiceToken = agentCircuit.ServiceSessionID; - if (old != null) - travel.ClientIPAddress = old.ClientIPAddress; - return old; + if (fromLogin) + travel.ClientIPAddress = agentCircuit.IPAddress; + + StoreTravelInfo(travel); + + return travel; } public void LogoutAgent(UUID userID, UUID sessionID) { m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID); - lock (m_TravelingAgents) - { - List travels = new List(); - foreach (KeyValuePair kvp in m_TravelingAgents) - if (kvp.Value == null) // do some clean up - travels.Add(kvp.Key); - else if (kvp.Value.UserID == userID) - travels.Add(kvp.Key); - foreach (UUID session in travels) - m_TravelingAgents.Remove(session); - } + m_Database.Delete(sessionID); GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString()); if (guinfo != null) @@ -369,10 +352,11 @@ namespace OpenSim.Services.HypergridService // We need to prevent foreign users with the same UUID as a local user public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName) { - if (!m_TravelingAgents.ContainsKey(sessionID)) + HGTravelingData hgt = m_Database.Get(sessionID); + if (hgt == null) return false; - TravelingAgentInfo travel = m_TravelingAgents[sessionID]; + TravelingAgentInfo travel = new TravelingAgentInfo(hgt); return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower(); } @@ -385,31 +369,32 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.", sessionID, reportedIP); - if (m_TravelingAgents.ContainsKey(sessionID)) - { - bool result = m_TravelingAgents[sessionID].ClientIPAddress == reportedIP || - m_TravelingAgents[sessionID].MyIpAddress == reportedIP; // NATed + HGTravelingData hgt = m_Database.Get(sessionID); + if (hgt == null) + return false; - m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}", - reportedIP, m_TravelingAgents[sessionID].ClientIPAddress, m_TravelingAgents[sessionID].MyIpAddress, result); + TravelingAgentInfo travel = new TravelingAgentInfo(hgt); - return result; - } + bool result = travel.ClientIPAddress == reportedIP || travel.MyIpAddress == reportedIP; // NATed - return false; + m_log.DebugFormat("[USER AGENT SERVICE]: Comparing {0} with login IP {1} and MyIP {1}; result is {3}", + reportedIP, travel.ClientIPAddress, travel.MyIpAddress, result); + + return result; } public bool VerifyAgent(UUID sessionID, string token) { - if (m_TravelingAgents.ContainsKey(sessionID)) + HGTravelingData hgt = m_Database.Get(sessionID); + if (hgt == null) { - m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, m_TravelingAgents[sessionID].ServiceToken); - return m_TravelingAgents[sessionID].ServiceToken == token; + m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID); + return false; } - m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID); - - return false; + TravelingAgentInfo travel = new TravelingAgentInfo(hgt); + m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, travel.ServiceToken); + return travel.ServiceToken == token; } [Obsolete] @@ -472,17 +457,17 @@ namespace OpenSim.Services.HypergridService } } - // Lastly, let's notify the rest who may be online somewhere else - foreach (string user in usersToBeNotified) - { - UUID id = new UUID(user); - if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) - { - string url = m_TravelingAgents[id].GridExternalName; - // forward - m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); - } - } + //// Lastly, let's notify the rest who may be online somewhere else + //foreach (string user in usersToBeNotified) + //{ + // UUID id = new UUID(user); + // if (m_Database.ContainsKey(id) && m_Database[id].GridExternalName != m_GridName) + // { + // string url = m_Database[id].GridExternalName; + // // forward + // m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); + // } + //} // and finally, let's send the online friends if (online) @@ -609,16 +594,13 @@ namespace OpenSim.Services.HypergridService public string LocateUser(UUID userID) { - foreach (TravelingAgentInfo t in m_TravelingAgents.Values) - { - if (t == null) - { - m_log.ErrorFormat("[USER AGENT SERVICE]: Oops! Null TravelingAgentInfo. Please report this on mantis"); - continue; - } - if (t.UserID == userID && !m_GridName.Equals(t.GridExternalName)) - return t.GridExternalName; - } + HGTravelingData[] hgts = m_Database.GetSessions(userID); + if (hgts == null) + return string.Empty; + + foreach (HGTravelingData t in hgts) + if (t.Data.ContainsKey("GridExternalName") && !m_GridName.Equals(t.Data["GridExternalName"])) + return t.Data["GridExternalName"]; return string.Empty; } @@ -689,17 +671,60 @@ namespace OpenSim.Services.HypergridService return exception; } + private void StoreTravelInfo(TravelingAgentInfo travel) + { + if (travel == null) + return; + + HGTravelingData hgt = new HGTravelingData(); + hgt.SessionID = travel.SessionID; + hgt.UserID = travel.UserID; + hgt.Data = new Dictionary(); + hgt.Data["GridExternalName"] = travel.GridExternalName; + hgt.Data["ServiceToken"] = travel.ServiceToken; + hgt.Data["ClientIPAddress"] = travel.ClientIPAddress; + hgt.Data["MyIPAddress"] = travel.MyIpAddress; + + m_Database.Store(hgt); + } #endregion } class TravelingAgentInfo { + public UUID SessionID; public UUID UserID; public string GridExternalName = string.Empty; public string ServiceToken = string.Empty; public string ClientIPAddress = string.Empty; // as seen from this user agent service public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper + + public TravelingAgentInfo(HGTravelingData t) + { + if (t.Data != null) + { + SessionID = new UUID(t.SessionID); + UserID = new UUID(t.UserID); + GridExternalName = t.Data["GridExternalName"]; + ServiceToken = t.Data["ServiceToken"]; + ClientIPAddress = t.Data["ClientIPAddress"]; + MyIpAddress = t.Data["MyIPAddress"]; + } + } + + public TravelingAgentInfo(TravelingAgentInfo old) + { + if (old != null) + { + SessionID = old.SessionID; + UserID = old.UserID; + GridExternalName = old.GridExternalName; + ServiceToken = old.ServiceToken; + ClientIPAddress = old.ClientIPAddress; + MyIpAddress = old.MyIpAddress; + } + } } } diff --git a/OpenSim/Services/HypergridService/UserAgentServiceBase.cs b/OpenSim/Services/HypergridService/UserAgentServiceBase.cs new file mode 100644 index 0000000..a00e5a6 --- /dev/null +++ b/OpenSim/Services/HypergridService/UserAgentServiceBase.cs @@ -0,0 +1,84 @@ +/* + * 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.Reflection; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Data; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Base; + +namespace OpenSim.Services.HypergridService +{ + public class UserAgentServiceBase : ServiceBase + { + protected IHGTravelingData m_Database = null; + + public UserAgentServiceBase(IConfigSource config) + : base(config) + { + string dllName = String.Empty; + string connString = String.Empty; + string realm = "hg_traveling_data"; + + // + // 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); + } + + // + // [UserAgentService] section overrides [DatabaseService], if it exists + // + IConfig gridConfig = config.Configs["UserAgentService"]; + if (gridConfig != null) + { + dllName = gridConfig.GetString("StorageProvider", dllName); + connString = gridConfig.GetString("ConnectionString", connString); + realm = gridConfig.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"); + + 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"); + + } + } +} -- cgit v1.1 From b0140383da21de03cb655160a2912d04c5b470e6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 15:47:54 -0700 Subject: Cleanup old hg sessions (older than 2 days) --- OpenSim/Data/IHGTravelingData.cs | 1 + OpenSim/Data/MySQL/MySQLHGTravelData.cs | 10 ++++++++++ OpenSim/Data/MySQL/Resources/HGTravelStore.migrations | 1 + .../Framework/EntityTransfer/HGEntityTransferModule.cs | 7 +++++-- OpenSim/Services/HypergridService/UserAgentService.cs | 3 +++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/IHGTravelingData.cs b/OpenSim/Data/IHGTravelingData.cs index dd89935..452af7b 100644 --- a/OpenSim/Data/IHGTravelingData.cs +++ b/OpenSim/Data/IHGTravelingData.cs @@ -54,5 +54,6 @@ namespace OpenSim.Data HGTravelingData[] GetSessions(UUID userID); bool Store(HGTravelingData data); bool Delete(UUID sessionID); + void DeleteOld(); } } \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLHGTravelData.cs b/OpenSim/Data/MySQL/MySQLHGTravelData.cs index 1efbfc3..e81b880 100644 --- a/OpenSim/Data/MySQL/MySQLHGTravelData.cs +++ b/OpenSim/Data/MySQL/MySQLHGTravelData.cs @@ -66,5 +66,15 @@ namespace OpenSim.Data.MySQL return Delete("SessionID", sessionID.ToString()); } + public void DeleteOld() + { + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 DAY", m_Realm); + + ExecuteNonQuery(cmd); + } + + } } } \ No newline at end of file diff --git a/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations b/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations index a0c9ebe..b4e4422 100644 --- a/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations +++ b/OpenSim/Data/MySQL/Resources/HGTravelStore.migrations @@ -9,6 +9,7 @@ CREATE TABLE `hg_traveling_data` ( `ServiceToken` VARCHAR(255) NOT NULL DEFAULT '', `ClientIPAddress` VARCHAR(16) NOT NULL DEFAULT '', `MyIPAddress` VARCHAR(16) NOT NULL DEFAULT '', + `TMStamp` timestamp NOT NULL, PRIMARY KEY (`SessionID`), KEY (`UserID`) ) ENGINE=InnoDB; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 759155a..76dbc72 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -207,6 +207,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); m_UAS = scene.RequestModuleInterface(); + if (m_UAS == null) + m_UAS = new UserAgentServiceConnector(m_ThisHomeURI); + } } @@ -573,12 +576,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) { // local grid user + m_UAS.LogoutAgent(obj.AgentId, obj.SessionId); return; } AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); - - if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) + if (aCircuit != null && aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("HomeURI")) { string url = aCircuit.ServiceURLs["HomeURI"].ToString(); IUserAgentService security = new UserAgentServiceConnector(url); diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index b597cb9..b414aca 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs @@ -148,6 +148,9 @@ namespace OpenSim.Services.HypergridService if (!m_GridName.EndsWith("/")) m_GridName = m_GridName + "/"; + // Finally some cleanup + m_Database.DeleteOld(); + } } -- cgit v1.1 From af02231a7b334dde1e3dcbea03c93fe11bcc6037 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 16:03:46 -0700 Subject: Added SQLite version of hg travel data store. UNTESTED. Hope it works! --- .../Data/SQLite/Resources/HGTravelStore.migrations | 18 +++++ OpenSim/Data/SQLite/SQLiteHGTravelData.cs | 82 ++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 OpenSim/Data/SQLite/Resources/HGTravelStore.migrations create mode 100644 OpenSim/Data/SQLite/SQLiteHGTravelData.cs diff --git a/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations new file mode 100644 index 0000000..2e73caa --- /dev/null +++ b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations @@ -0,0 +1,18 @@ +:VERSION 1 # -------------------------- + +BEGIN; + +CREATE TABLE hg_traveling_data ( + SessionID VARCHAR(36) NOT NULL, + UserID VARCHAR(36) NOT NULL, + GridExternalName VARCHAR(255) NOT NULL DEFAULT '', + ServiceToken VARCHAR(255) NOT NULL DEFAULT '', + ClientIPAddress VARCHAR(16) NOT NULL DEFAULT '', + MyIPAddress VARCHAR(16) NOT NULL DEFAULT '', + TMStamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`SessionID`), + KEY (`UserID`) +) ENGINE=InnoDB; + +COMMIT; + diff --git a/OpenSim/Data/SQLite/SQLiteHGTravelData.cs b/OpenSim/Data/SQLite/SQLiteHGTravelData.cs new file mode 100644 index 0000000..db288b2 --- /dev/null +++ b/OpenSim/Data/SQLite/SQLiteHGTravelData.cs @@ -0,0 +1,82 @@ +/* + * 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.Data; +using System.Reflection; +using System.Threading; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using Mono.Data.Sqlite; + +namespace OpenSim.Data.SQLite +{ + /// + /// A SQL Interface for user grid data + /// + public class SQLiteHGTravelData : SQLiteGenericTableHandler, IHGTravelingData + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public SQLiteHGTravelData(string connectionString, string realm) + : base(connectionString, realm, "HGTravelStore") {} + + public HGTravelingData Get(UUID sessionID) + { + HGTravelingData[] ret = Get("SessionID", sessionID.ToString()); + + if (ret.Length == 0) + return null; + + return ret[0]; + } + + public HGTravelingData[] GetSessions(UUID userID) + { + return base.Get("UserID", userID.ToString()); + } + + public bool Delete(UUID sessionID) + { + return Delete("SessionID", sessionID.ToString()); + } + + public void DeleteOld() + { + using (SqliteCommand cmd = new SqliteCommand()) + { + cmd.CommandText = String.Format("delete from {0} where TMStamp < datetime('now', '-2 day') ", m_Realm); + + DoQuery(cmd); + } + + } + + } +} \ No newline at end of file -- cgit v1.1 From d48946f9ef368ff72cec00c33bbfb53b6bd35696 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 14 Jul 2013 16:51:07 -0700 Subject: Document obscure Groups config related to the user level required for creating groups --- bin/OpenSim.ini.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 1c53935..4ddefba 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -955,6 +955,10 @@ ;; Enables the groups module ; Enabled = false + ;# {LevelGroupCreate} {Enabled:true} {User level for creating groups} {} 0 + ;; Minimum user level required to create groups + ;LevelGroupCreate = 0 + ;# {Module} {Enabled:true} {Groups module to use? (Use GroupsModule to use Flotsam/Simian)} {Default "Groups Module V2"} Default ;; The default module can use a PHP XmlRpc server from the Flotsam project at ;; http://code.google.com/p/flotsam/ -- cgit v1.1 From 60325f81d81f41ca6a23465468afa940aae397dd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 10:29:42 -0700 Subject: This might address the following observed exception: 17:14:28 - [APPLICATION]: APPLICATION EXCEPTION DETECTED: System.UnhandledExceptionEventArgs Exception: System.InvalidOperationException: Operation is not valid due to the current state of the object at System.Collections.Generic.Queue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Peek () [0x00011] in /root/install/mono-3.1.0/mono/mcs/class/System/System.Collections.Generic/Queue.cs:158 at System.Collections.Generic.Queue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Dequeue () [0x00000] in /root/install/mono-3.1.0/mono/mcs/class/System/System.Collections.Generic/Queue.cs:140 at OpenSim.Framework.DoubleQueue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Dequeue (TimeSpan wait, OpenSim.Region.ClientStack.Linden.aPollRequest& res) [0x0004e] in /home/avacon/opensim_2013-07-14/OpenSim/Framework/Util.cs:2297 --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index cafe103..8cfc4d4 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2293,7 +2293,7 @@ namespace OpenSim.Framework { if (m_highQueue.Count > 0) res = m_highQueue.Dequeue(); - else + else if (m_lowQueue.Count > 0) res = m_lowQueue.Dequeue(); if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) -- cgit v1.1 From ac73e702935dd4607c13aaec3095940fba7932ca Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 11:27:49 -0700 Subject: Trying to hunt the CPU spikes recently experienced. Revert "Comment out old inbound UDP throttling hack. This would cause the UDP" This reverts commit 38e6da5522a53c7f65eac64ae7b0af929afb1ae6. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 85270a6..e20a194 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1615,7 +1615,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { IncomingPacket incomingPacket = null; - /* // HACK: This is a test to try and rate limit packet handling on Mono. // If it works, a more elegant solution can be devised if (Util.FireAndForgetCount() < 2) @@ -1623,7 +1622,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); Thread.Sleep(30); } - */ if (packetInbox.Dequeue(100, ref incomingPacket)) { -- cgit v1.1 From fbb01bd28064cde3e00ddf2a0cc4ce87ddd4cb6e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 11:37:49 -0700 Subject: Protect against null requests --- .../GridServiceThrottle/GridServiceThrottleModule.cs | 10 ++++++---- .../Framework/UserManagement/UserManagementModule.cs | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index f1eb1ad..fd4d48a 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -140,11 +140,13 @@ namespace OpenSim.Region.CoreModules.Framework Watchdog.UpdateThread(); GridRegionRequest request = m_RequestQueue.Dequeue(); - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); - - if (r != null && r.RegionHandle != 0) - request.client.SendRegionHandle(request.regionID, r.RegionHandle); + if (request != null) + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + if (r != null && r.RegionHandle != 0) + request.client.SendRegionHandle(request.regionID, r.RegionHandle); + } } } } diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index a528093..507329e 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -681,17 +681,19 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement Watchdog.UpdateThread(); NameRequest request = m_RequestQueue.Dequeue(); - string[] names; - bool foundRealName = TryGetUserNames(request.uuid, out names); - - if (names.Length == 2) + if (request != null) { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + string[] names; + bool foundRealName = TryGetUserNames(request.uuid, out names); - request.client.SendNameReply(request.uuid, names[0], names[1]); - } + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + request.client.SendNameReply(request.uuid, names[0], names[1]); + } + } } } -- cgit v1.1 From 864f15ce4dfd412df8442a26429b9dd7a2bf9e12 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 11:52:26 -0700 Subject: Revert the revert Revert "Trying to hunt the CPU spikes recently experienced." This reverts commit ac73e702935dd4607c13aaec3095940fba7932ca. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index e20a194..85270a6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1615,6 +1615,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { IncomingPacket incomingPacket = null; + /* // HACK: This is a test to try and rate limit packet handling on Mono. // If it works, a more elegant solution can be devised if (Util.FireAndForgetCount() < 2) @@ -1622,6 +1623,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping"); Thread.Sleep(30); } + */ if (packetInbox.Dequeue(100, ref incomingPacket)) { -- cgit v1.1 From b060ce96d93a33298b59392210af4d336e0d171b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 12:05:31 -0700 Subject: Puts RequestImage (UDP) back to asyn -- CPU spike hunt --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 79c80a7..f57e069 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5373,7 +5373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); - AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); + AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); -- cgit v1.1 From 687c1a420a6f3c254eb7104fee40a79fc6a39e1d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 12:33:31 -0700 Subject: Guard against null ref --- OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index b90df17..5b0859b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -351,7 +351,8 @@ namespace OpenSim.Region.ClientStack.Linden aPollRequest poolreq = m_queue.Dequeue(); - poolreq.thepoll.Process(poolreq); + if (poolreq != null && poolreq.thepoll != null) + poolreq.thepoll.Process(poolreq); } } } -- cgit v1.1 From 68fbf7eebb12bcd22c3e3308a838c5c2e9b1c47f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 12:34:10 -0700 Subject: Revert "Puts RequestImage (UDP) back to asyn -- CPU spike hunt" This reverts commit b060ce96d93a33298b59392210af4d336e0d171b. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index f57e069..79c80a7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5373,7 +5373,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP AddLocalPacketHandler(PacketType.ScriptAnswerYes, HandleScriptAnswerYes, false); AddLocalPacketHandler(PacketType.ObjectClickAction, HandleObjectClickAction, false); AddLocalPacketHandler(PacketType.ObjectMaterial, HandleObjectMaterial, false); - AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage); + AddLocalPacketHandler(PacketType.RequestImage, HandleRequestImage, false); AddLocalPacketHandler(PacketType.TransferRequest, HandleTransferRequest, false); AddLocalPacketHandler(PacketType.AssetUploadRequest, HandleAssetUploadRequest); AddLocalPacketHandler(PacketType.RequestXfer, HandleRequestXfer); -- cgit v1.1 From 1b7b664c8696531fec26378d1386362d8a3da55e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 15 Jul 2013 23:22:39 +0100 Subject: Add request received/handling stats for caps which are served by http poll handlers. This adds explicit cap poll handler supporting to the Caps classes rather than relying on callers to do the complicated coding. Other refactoring was required to get logic into the right places to support this. --- OpenSim/Capabilities/Caps.cs | 93 ++++++++++++++++++++-- OpenSim/Framework/Console/RemoteConsole.cs | 2 +- .../Framework/Servers/HttpServer/BaseHttpServer.cs | 2 + .../Servers/HttpServer/PollServiceEventArgs.cs | 14 ++++ .../Servers/HttpServer/PollServiceHttpRequest.cs | 45 +++++++++++ .../HttpServer/PollServiceRequestManager.cs | 58 ++------------ .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 13 +-- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 2 +- .../Linden/Caps/WebFetchInvDescModule.cs | 66 ++++++++------- .../Framework/Caps/CapabilitiesModule.cs | 92 ++++++++++++++++----- .../CoreModules/Scripting/LSLHttp/UrlModule.cs | 6 +- 11 files changed, 267 insertions(+), 126 deletions(-) diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs index 6c95d8b..bbf3b27 100644 --- a/OpenSim/Capabilities/Caps.cs +++ b/OpenSim/Capabilities/Caps.cs @@ -63,7 +63,11 @@ namespace OpenSim.Framework.Capabilities public string CapsObjectPath { get { return m_capsObjectPath; } } private CapsHandlers m_capsHandlers; - private Dictionary m_externalCapsHandlers; + + private Dictionary m_pollServiceHandlers + = new Dictionary(); + + private Dictionary m_externalCapsHandlers = new Dictionary(); private IHttpServer m_httpListener; private UUID m_agentID; @@ -132,7 +136,6 @@ namespace OpenSim.Framework.Capabilities m_agentID = agent; m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); - m_externalCapsHandlers = new Dictionary(); m_regionName = regionName; } @@ -147,6 +150,27 @@ namespace OpenSim.Framework.Capabilities m_capsHandlers[capName] = handler; } + public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler) + { + m_pollServiceHandlers.Add(capName, pollServiceHandler); + + m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler.Url, pollServiceHandler); + +// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; +// string protocol = "http"; +// string hostName = m_httpListenerHostName; +// +// if (MainServer.Instance.UseSSL) +// { +// hostName = MainServer.Instance.SSLCommonName; +// port = MainServer.Instance.SSLPort; +// protocol = "https"; +// } + +// RegisterHandler( +// capName, String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, pollServiceHandler.Url)); + } + /// /// Register an external handler. The service for this capability is somewhere else /// given by the URL. @@ -163,13 +187,70 @@ namespace OpenSim.Framework.Capabilities /// public void DeregisterHandlers() { - if (m_capsHandlers != null) + foreach (string capsName in m_capsHandlers.Caps) + { + m_capsHandlers.Remove(capsName); + } + + foreach (PollServiceEventArgs handler in m_pollServiceHandlers.Values) + { + m_httpListener.RemovePollServiceHTTPHandler("", handler.Url); + } + } + + public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler) + { + return m_pollServiceHandlers.TryGetValue(name, out pollHandler); + } + + public Dictionary GetPollHandlers() + { + return new Dictionary(m_pollServiceHandlers); + } + + /// + /// Return an LLSD-serializable Hashtable describing the + /// capabilities and their handler details. + /// + /// If true, then exclude the seed cap. + public Hashtable GetCapsDetails(bool excludeSeed, List requestedCaps) + { + Hashtable caps = CapsHandlers.GetCapsDetails(excludeSeed, requestedCaps); + + lock (m_pollServiceHandlers) { - foreach (string capsName in m_capsHandlers.Caps) + foreach (KeyValuePair kvp in m_pollServiceHandlers) { - m_capsHandlers.Remove(capsName); + if (!requestedCaps.Contains(kvp.Key)) + continue; + + string hostName = m_httpListenerHostName; + uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; + string protocol = "http"; + + if (MainServer.Instance.UseSSL) + { + hostName = MainServer.Instance.SSLCommonName; + port = MainServer.Instance.SSLPort; + protocol = "https"; + } + // + // caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + + caps[kvp.Key] = string.Format("{0}://{1}:{2}{3}", protocol, hostName, port, kvp.Value.Url); } } + + // Add the external too + foreach (KeyValuePair kvp in ExternalCapsHandlers) + { + if (!requestedCaps.Contains(kvp.Key)) + continue; + + caps[kvp.Key] = kvp.Value; + } + + return caps; } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 3e3c2b3..8ad7b0d 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs @@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console string uri = "/ReadResponses/" + sessionID.ToString() + "/"; m_Server.AddPollServiceHTTPHandler( - uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout + uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout XmlDocument xmldoc = new XmlDocument(); XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 6863e0e..c4e569d 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -387,6 +387,8 @@ namespace OpenSim.Framework.Servers.HttpServer if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) { + psEvArgs.RequestsReceived++; + PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); if (psEvArgs.Request != null) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 3079a7e..020bfd5 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -55,12 +55,26 @@ namespace OpenSim.Framework.Servers.HttpServer Inventory = 2 } + public string Url { get; set; } + + /// + /// Number of requests received for this poll service. + /// + public int RequestsReceived { get; set; } + + /// + /// Number of requests handled by this poll service. + /// + public int RequestsHandled { get; set; } + public PollServiceEventArgs( RequestMethod pRequest, + string pUrl, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, UUID pId, int pTimeOutms) { Request = pRequest; + Url = pUrl; HasEvents = pHasEvents; GetEvents = pGetEvents; NoEvents = pNoEvents; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 723530a..6aa9479 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -26,13 +26,19 @@ */ using System; +using System.Collections; +using System.Reflection; +using System.Text; using HttpServer; +using log4net; using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { public class PollServiceHttpRequest { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public readonly PollServiceEventArgs PollServiceArgs; public readonly IHttpClientContext HttpContext; public readonly IHttpRequest Request; @@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer RequestTime = System.Environment.TickCount; RequestID = UUID.Random(); } + + internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) + { + OSHttpResponse response + = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); + + byte[] buffer = server.DoHTTPGruntWork(responsedata, response); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); + } + finally + { + //response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.Send(); + + //if (!response.KeepAlive && response.ReuseContext) + // response.FreeContext(); + } + catch (Exception e) + { + m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); + } + + PollServiceArgs.RequestsHandled++; + } + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index aee3e3c..1b9010a 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -157,8 +157,7 @@ namespace OpenSim.Framework.Servers.HttpServer { foreach (PollServiceHttpRequest req in m_retryRequests) { - DoHTTPGruntWork(m_server,req, - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } } catch @@ -179,8 +178,8 @@ namespace OpenSim.Framework.Servers.HttpServer try { wreq = m_requests.Dequeue(0); - DoHTTPGruntWork(m_server,wreq, - wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); + wreq.DoHTTPGruntWork( + m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); } catch { @@ -214,7 +213,7 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - DoHTTPGruntWork(m_server, req, responsedata); + req.DoHTTPGruntWork(m_server, responsedata); } catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream { @@ -227,7 +226,7 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - DoHTTPGruntWork(m_server, req, responsedata); + req.DoHTTPGruntWork(m_server, responsedata); } catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream { @@ -242,8 +241,8 @@ namespace OpenSim.Framework.Servers.HttpServer { if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) { - DoHTTPGruntWork(m_server, req, - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } else { @@ -258,46 +257,5 @@ namespace OpenSim.Framework.Servers.HttpServer } } } - - // DoHTTPGruntWork changed, not sending response - // do the same work around as core - - internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) - { - OSHttpResponse response - = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); - - byte[] buffer = server.DoHTTPGruntWork(responsedata, response); - - response.SendChunked = false; - response.ContentLength64 = buffer.Length; - response.ContentEncoding = Encoding.UTF8; - - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); - } - finally - { - //response.OutputStream.Close(); - try - { - response.OutputStream.Flush(); - response.Send(); - - //if (!response.KeepAlive && response.ReuseContext) - // response.FreeContext(); - } - catch (Exception e) - { - m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); - } - } - } } -} - +} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 5c6bc1c..1d4c7f0 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -285,18 +285,7 @@ namespace OpenSim.Region.ClientStack.Linden foreach (OSD c in capsRequested) validCaps.Add(c.AsString()); - Hashtable caps = m_HostCapsObj.CapsHandlers.GetCapsDetails(true, validCaps); - - // Add the external too - foreach (KeyValuePair kvp in m_HostCapsObj.ExternalCapsHandlers) - { - if (!validCaps.Contains(kvp.Key)) - continue; - - caps[kvp.Key] = kvp.Value; - } - - string result = LLSDHelpers.SerialiseLLSDReply(caps); + string result = LLSDHelpers.SerialiseLLSDReply(m_HostCapsObj.GetCapsDetails(true, validCaps)); //m_log.DebugFormat("[CAPS] CapsRequest {0}", result); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 50bfda1..ca38a97 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -377,7 +377,7 @@ namespace OpenSim.Region.ClientStack.Linden // TODO: Add EventQueueGet name/description for diagnostics MainServer.Instance.AddPollServiceHTTPHandler( eventQueueGetPath, - new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs(null, eventQueueGetPath, HasEvents, GetEvents, NoEvents, agentID, 40000)); // m_log.DebugFormat( // "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index b90df17..86a0298 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -77,7 +77,6 @@ namespace OpenSim.Region.ClientStack.Linden private static WebFetchInvDescHandler m_webFetchHandler; - private Dictionary m_capsDict = new Dictionary(); private static Thread[] m_workerThreads = null; private static DoubleQueue m_queue = @@ -114,7 +113,6 @@ namespace OpenSim.Region.ClientStack.Linden return; m_scene.EventManager.OnRegisterCaps -= RegisterCaps; - m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); @@ -134,7 +132,6 @@ namespace OpenSim.Region.ClientStack.Linden m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); m_scene.EventManager.OnRegisterCaps += RegisterCaps; - m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; if (m_workerThreads == null) { @@ -177,8 +174,8 @@ namespace OpenSim.Region.ClientStack.Linden private Scene m_scene; - public PollServiceInventoryEventArgs(Scene scene, UUID pId) : - base(null, null, null, null, pId, int.MaxValue) + public PollServiceInventoryEventArgs(Scene scene, string url, UUID pId) : + base(null, url, null, null, null, pId, int.MaxValue) { m_scene = scene; @@ -308,40 +305,39 @@ namespace OpenSim.Region.ClientStack.Linden if (m_fetchInventoryDescendents2Url == "") return; - string capUrl = "/CAPS/" + UUID.Random() + "/"; - // Register this as a poll service - PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID); - + PollServiceInventoryEventArgs args + = new PollServiceInventoryEventArgs(m_scene, "/CAPS/" + UUID.Random() + "/", agentID); args.Type = PollServiceEventArgs.EventType.Inventory; - MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); - - string hostName = m_scene.RegionInfo.ExternalHostName; - uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; - string protocol = "http"; - - if (MainServer.Instance.UseSSL) - { - hostName = MainServer.Instance.SSLCommonName; - port = MainServer.Instance.SSLPort; - protocol = "https"; - } - - caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); - m_capsDict[agentID] = capUrl; + caps.RegisterPollHandler("FetchInventoryDescendents2", args); + +// MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); +// +// string hostName = m_scene.RegionInfo.ExternalHostName; +// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; +// string protocol = "http"; +// +// if (MainServer.Instance.UseSSL) +// { +// hostName = MainServer.Instance.SSLCommonName; +// port = MainServer.Instance.SSLPort; +// protocol = "https"; +// } +// +// caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); } - private void DeregisterCaps(UUID agentID, Caps caps) - { - string capUrl; - - if (m_capsDict.TryGetValue(agentID, out capUrl)) - { - MainServer.Instance.RemoveHTTPHandler("", capUrl); - m_capsDict.Remove(agentID); - } - } +// private void DeregisterCaps(UUID agentID, Caps caps) +// { +// string capUrl; +// +// if (m_capsDict.TryGetValue(agentID, out capUrl)) +// { +// MainServer.Instance.RemoveHTTPHandler("", capUrl); +// m_capsDict.Remove(agentID); +// } +// } private void DoInventoryRequests() { @@ -355,4 +351,4 @@ namespace OpenSim.Region.ClientStack.Linden } } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index bd60611..ad1c4ce 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -80,7 +80,7 @@ namespace OpenSim.Region.CoreModules.Framework MainConsole.Instance.Commands.AddCommand( "Comms", false, "show caps stats by user", - "show caps stats [ ]", + "show caps stats by user [ ]", "Shows statistics on capabilities use by user.", "If a user name is given, then prints a detailed breakdown of caps use ordered by number of requests received.", HandleShowCapsStatsByUserCommand); @@ -285,27 +285,31 @@ namespace OpenSim.Region.CoreModules.Framework if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) return; - StringBuilder caps = new StringBuilder(); - caps.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); + StringBuilder capsReport = new StringBuilder(); + capsReport.AppendFormat("Region {0}:\n", m_scene.RegionInfo.RegionName); lock (m_capsObjects) { foreach (KeyValuePair kvp in m_capsObjects) { - caps.AppendFormat("** User {0}:\n", kvp.Key); + capsReport.AppendFormat("** User {0}:\n", kvp.Key); + Caps caps = kvp.Value; - for (IDictionaryEnumerator kvp2 = kvp.Value.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) + for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) { Uri uri = new Uri(kvp2.Value.ToString()); - caps.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); + capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, uri.PathAndQuery); } - foreach (KeyValuePair kvp3 in kvp.Value.ExternalCapsHandlers) - caps.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); + foreach (KeyValuePair kvp2 in caps.GetPollHandlers()) + capsReport.AppendFormat(m_showCapsCommandFormat, kvp2.Key, kvp2.Value.Url); + + foreach (KeyValuePair kvp3 in caps.ExternalCapsHandlers) + capsReport.AppendFormat(m_showCapsCommandFormat, kvp3.Key, kvp3.Value); } } - MainConsole.Instance.Output(caps.ToString()); + MainConsole.Instance.Output(capsReport.ToString()); } private void HandleShowCapsStatsByCapCommand(string module, string[] cmdParams) @@ -362,7 +366,16 @@ namespace OpenSim.Region.CoreModules.Framework { receivedStats[sp.Name] = reqHandler.RequestsReceived; handledStats[sp.Name] = reqHandler.RequestsHandled; - } + } + else + { + PollServiceEventArgs pollHandler = null; + if (caps.TryGetPollHandler(capName, out pollHandler)) + { + receivedStats[sp.Name] = pollHandler.RequestsReceived; + handledStats[sp.Name] = pollHandler.RequestsHandled; + } + } } ); @@ -391,11 +404,9 @@ namespace OpenSim.Region.CoreModules.Framework Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); if (caps == null) - return; - - Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + return; - foreach (IRequestHandler reqHandler in capsHandlers.Values) + foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) { string reqName = reqHandler.Name ?? ""; @@ -410,6 +421,23 @@ namespace OpenSim.Region.CoreModules.Framework handledStats[reqName] += reqHandler.RequestsHandled; } } + + foreach (KeyValuePair kvp in caps.GetPollHandlers()) + { + string name = kvp.Key; + PollServiceEventArgs pollHandler = kvp.Value; + + if (!receivedStats.ContainsKey(name)) + { + receivedStats[name] = pollHandler.RequestsReceived; + handledStats[name] = pollHandler.RequestsHandled; + } + else + { + receivedStats[name] += pollHandler.RequestsReceived; + handledStats[name] += pollHandler.RequestsHandled; + } + } } ); @@ -468,12 +496,16 @@ namespace OpenSim.Region.CoreModules.Framework if (caps == null) return; - Dictionary capsHandlers = caps.CapsHandlers.GetCapsHandlers(); + List capRows = new List(); - foreach (IRequestHandler reqHandler in capsHandlers.Values.OrderByDescending(rh => rh.RequestsReceived)) - { - cdt.AddRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled); - } + foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) + capRows.Add(new CapTableRow(reqHandler.Name, reqHandler.RequestsReceived, reqHandler.RequestsHandled)); + + foreach (KeyValuePair kvp in caps.GetPollHandlers()) + capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled)); + + foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived)) + cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); sb.Append(cdt.ToString()); } @@ -505,6 +537,14 @@ namespace OpenSim.Region.CoreModules.Framework totalRequestsReceived += reqHandler.RequestsReceived; totalRequestsHandled += reqHandler.RequestsHandled; } + + Dictionary capsPollHandlers = caps.GetPollHandlers(); + + foreach (PollServiceEventArgs handler in capsPollHandlers.Values) + { + totalRequestsReceived += handler.RequestsReceived; + totalRequestsHandled += handler.RequestsHandled; + } cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled); } @@ -512,5 +552,19 @@ namespace OpenSim.Region.CoreModules.Framework sb.Append(cdt.ToString()); } + + private class CapTableRow + { + public string Name { get; set; } + public int RequestsReceived { get; set; } + public int RequestsHandled { get; set; } + + public CapTableRow(string name, int requestsReceived, int requestsHandled) + { + Name = name; + RequestsReceived = requestsReceived; + RequestsHandled = requestsHandled; + } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index def8162..99a3122 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -235,7 +235,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string uri = "/lslhttp/" + urlcode.ToString() + "/"; - PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000); + PollServiceEventArgs args + = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000); args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpServer.AddPollServiceHTTPHandler(uri, args); @@ -280,7 +281,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string uri = "/lslhttps/" + urlcode.ToString() + "/"; - PollServiceEventArgs args = new PollServiceEventArgs(HttpRequestHandler, HasEvents, GetEvents, NoEvents, urlcode, 25000); + PollServiceEventArgs args + = new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000); args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpsServer.AddPollServiceHTTPHandler(uri, args); -- cgit v1.1 From e8e073aa97a8f756f42b242dd1cfcd05beb4d8ef Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 16 Jul 2013 00:05:45 +0100 Subject: Simplify EventQueue cap setup so that it is also stat monitored. Curiously, the number of requests received is always one greater than that shown as handled - needs investigation --- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 74 +++++++++------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index ca38a97..1835a72 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -252,29 +252,32 @@ namespace OpenSim.Region.ClientStack.Linden List removeitems = new List(); lock (m_AvatarQueueUUIDMapping) - { - foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) - { -// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); - if (ky == agentID) - { - removeitems.Add(ky); - } - } + m_AvatarQueueUUIDMapping.Remove(agentID); - foreach (UUID ky in removeitems) - { - UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; - m_AvatarQueueUUIDMapping.Remove(ky); - - string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); - MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); - -// m_log.DebugFormat( -// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", -// eqgPath, agentID, m_scene.RegionInfo.RegionName); - } - } +// lock (m_AvatarQueueUUIDMapping) +// { +// foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) +// { +//// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); +// if (ky == agentID) +// { +// removeitems.Add(ky); +// } +// } +// +// foreach (UUID ky in removeitems) +// { +// UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; +// m_AvatarQueueUUIDMapping.Remove(ky); +// +// string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); +// MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); +// +//// m_log.DebugFormat( +//// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", +//// eqgPath, agentID, m_scene.RegionInfo.RegionName); +// } +// } UUID searchval = UUID.Zero; @@ -359,29 +362,10 @@ namespace OpenSim.Region.ClientStack.Linden m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); } - string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); - - // Register this as a caps handler - // FIXME: Confusingly, we need to register separate as a capability so that the client is told about - // EventQueueGet when it receive capability information, but then we replace the rest handler immediately - // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but - // really it should be possible to directly register the poll handler as a capability. - caps.RegisterHandler( - "EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null, "EventQueueGet", null)); -// delegate(Hashtable m_dhttpMethod) -// { -// return ProcessQueue(m_dhttpMethod, agentID, caps); -// })); - - // This will persist this beyond the expiry of the caps handlers - // TODO: Add EventQueueGet name/description for diagnostics - MainServer.Instance.AddPollServiceHTTPHandler( - eventQueueGetPath, - new PollServiceEventArgs(null, eventQueueGetPath, HasEvents, GetEvents, NoEvents, agentID, 40000)); - -// m_log.DebugFormat( -// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", -// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName); + caps.RegisterPollHandler( + "EventQueueGet", + new PollServiceEventArgs( + null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) -- cgit v1.1 From 42e2a0d66eaa7e322bce817e9e2cc9a288de167b Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 16 Jul 2013 01:12:56 -0700 Subject: MSDN documentation is unclear about whether exiting a lock() block will trigger a Monitor.Wait() to exit, so avoid some locks that don't actually affect the state of the internal queues in the BlockingQueue class. --- OpenSim/Framework/BlockingQueue.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 3658161..cc016b0 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -91,6 +91,9 @@ namespace OpenSim.Framework public bool Contains(T item) { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return false; + lock (m_queueSync) { if (m_pqueue.Contains(item)) @@ -101,14 +104,14 @@ namespace OpenSim.Framework public int Count() { - lock (m_queueSync) - { - return m_queue.Count+m_pqueue.Count; - } + return m_queue.Count+m_pqueue.Count; } public T[] GetQueueArray() { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return new T[0]; + lock (m_queueSync) { return m_queue.ToArray(); -- cgit v1.1 From 70aa77f520060a27df1fb7fbdf39685ff866dcf8 Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 16 Jul 2013 01:31:09 -0700 Subject: add locking to internal queue in WebFetchInvDescModule; lack of which caused a random crash in a load test yesterday --- .../ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 164adeb..4ff617f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -254,10 +254,13 @@ namespace OpenSim.Region.ClientStack.Linden } } - if (highPriority) - m_queue.EnqueueHigh(reqinfo); - else - m_queue.EnqueueLow(reqinfo); + lock (m_queue) + { + if (highPriority) + m_queue.EnqueueHigh(reqinfo); + else + m_queue.EnqueueLow(reqinfo); + } }; NoEvents = (x, y) => @@ -345,7 +348,9 @@ namespace OpenSim.Region.ClientStack.Linden { Watchdog.UpdateThread(); - aPollRequest poolreq = m_queue.Dequeue(); + aPollRequest poolreq = null; + lock (m_queue) + poolreq = m_queue.Dequeue(); if (poolreq != null && poolreq.thepoll != null) poolreq.thepoll.Process(poolreq); -- cgit v1.1 From 6dd454240fb962a408c979060701531f0f458e8e Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 16 Jul 2013 02:03:01 -0700 Subject: revert last commit which seems to conflict with DoubleQueue internals. The random crash might be in DoubleQueue instead. See http://pastebin.com/XhNBNqsc --- .../ClientStack/Linden/Caps/WebFetchInvDescModule.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 4ff617f..164adeb 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -254,13 +254,10 @@ namespace OpenSim.Region.ClientStack.Linden } } - lock (m_queue) - { - if (highPriority) - m_queue.EnqueueHigh(reqinfo); - else - m_queue.EnqueueLow(reqinfo); - } + if (highPriority) + m_queue.EnqueueHigh(reqinfo); + else + m_queue.EnqueueLow(reqinfo); }; NoEvents = (x, y) => @@ -348,9 +345,7 @@ namespace OpenSim.Region.ClientStack.Linden { Watchdog.UpdateThread(); - aPollRequest poolreq = null; - lock (m_queue) - poolreq = m_queue.Dequeue(); + aPollRequest poolreq = m_queue.Dequeue(); if (poolreq != null && poolreq.thepoll != null) poolreq.thepoll.Process(poolreq); -- cgit v1.1 From 5a01ffa5150edf4c4f8b4675d8c8c2b2c6ec0684 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 07:15:14 -0700 Subject: High CPU hunt: try a different blocking queue, DoubleQueue --- .../Framework/GridServiceThrottle/GridServiceThrottleModule.cs | 3 ++- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index fd4d48a..a069317 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -49,7 +49,8 @@ namespace OpenSim.Region.CoreModules.Framework private readonly List m_scenes = new List(); - private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); public void Initialise(IConfigSource config) { diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 507329e..ffb8bda 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -60,6 +60,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected Dictionary m_UserCache = new Dictionary(); // Throttle the name requests + //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); -- cgit v1.1 From 6da50d34dfb321e71b5242ab8d82a9801da5d05b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 07:19:13 -0700 Subject: Actually use DoubleQueue in UserManagement/UserManagementModule --- .../Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index ffb8bda..9f5e4ae 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // Throttle the name requests //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); #region ISharedRegionModule -- cgit v1.1 From e0f0b88dece110ca10208a2f826f9e360a9d7826 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 13:01:39 -0700 Subject: In the pursuit of using less CPU: now trying to avoid blocking queues altogether. Instead, this uses a timer. No sure if it's better or worse, but worth the try. --- .../GridServiceThrottleModule.cs | 71 +++++++++++++++++++--- .../UserManagement/UserManagementModule.cs | 64 ++++++++++++++++--- 2 files changed, 120 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index a069317..83be644 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -48,18 +48,26 @@ 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 OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + private Queue m_RequestQueue = new Queue(); public void Initialise(IConfigSource config) { - Watchdog.StartThread( - ProcessQueue, - "GridServiceRequestThread", - ThreadPriority.BelowNormal, - true, - false); + m_timer = new System.Timers.Timer(); + m_timer.AutoReset = false; + m_timer.Interval = 15000; // 15 secs at first + m_timer.Elapsed += ProcessQueue; + m_timer.Start(); + + //Watchdog.StartThread( + // ProcessQueue, + // "GridServiceRequestThread", + // ThreadPriority.BelowNormal, + // true, + // false); } public void AddRegion(Scene scene) @@ -89,6 +97,16 @@ namespace OpenSim.Region.CoreModules.Framework client.OnRegionHandleRequest += OnRegionHandleRequest; } + //void OnMakeRootAgent(ScenePresence obj) + //{ + // lock (m_timer) + // { + // m_timer.Stop(); + // m_timer.Interval = 1000; + // m_timer.Start(); + // } + //} + public void PostInitialise() { } @@ -118,7 +136,8 @@ namespace OpenSim.Region.CoreModules.Framework } GridRegionRequest request = new GridRegionRequest(client, regionID); - m_RequestQueue.Enqueue(request); + lock (m_RequestQueue) + m_RequestQueue.Enqueue(request); } @@ -134,6 +153,41 @@ namespace OpenSim.Region.CoreModules.Framework return false; } + private bool AreThereRootAgents() + { + foreach (Scene s in m_scenes) + { + if (s.GetRootAgentCount() > 0) + return true; + } + + return false; + } + + private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) + { + while (m_RequestQueue.Count > 0) + { + GridRegionRequest request = null; + lock (m_RequestQueue) + request = m_RequestQueue.Dequeue(); + if (request != null) + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + + if (r != null && r.RegionHandle != 0) + request.client.SendRegionHandle(request.regionID, r.RegionHandle); + } + } + + if (AreThereRootAgents()) + m_timer.Interval = 1000; // 1 sec + else + m_timer.Interval = 10000; // 10 secs + + m_timer.Start(); + } + private void ProcessQueue() { while (true) @@ -150,6 +204,7 @@ namespace OpenSim.Region.CoreModules.Framework } } } + } class GridRegionRequest diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 9f5e4ae..61c1e70 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -61,8 +61,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // Throttle the name requests //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + //private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + private Queue m_RequestQueue = new Queue(); + private System.Timers.Timer m_timer; #region ISharedRegionModule @@ -599,12 +601,18 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected void Init() { RegisterConsoleCmds(); - Watchdog.StartThread( - ProcessQueue, - "NameRequestThread", - ThreadPriority.BelowNormal, - true, - false); + //Watchdog.StartThread( + // ProcessQueue, + // "NameRequestThread", + // ThreadPriority.BelowNormal, + // true, + // false); + + m_timer = new System.Timers.Timer(); + m_timer.AutoReset = false; + m_timer.Interval = 15000; // 15 secs at first + m_timer.Elapsed += ProcessQueue; + m_timer.Start(); } @@ -698,6 +706,48 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } + private bool AreThereRootAgents() + { + foreach (Scene s in m_Scenes) + { + if (s.GetRootAgentCount() > 0) + return true; + } + + return false; + } + + private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) + { + while (m_RequestQueue.Count > 0) + { + NameRequest request = null; + lock (m_RequestQueue) + request = m_RequestQueue.Dequeue(); + + if (request != null) + { + string[] names; + bool foundRealName = TryGetUserNames(request.uuid, out names); + + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); + + request.client.SendNameReply(request.uuid, names[0], names[1]); + } + } + } + + if (AreThereRootAgents()) + m_timer.Interval = 1000; // 1 sec + else + m_timer.Interval = 10000; // 10 secs + + m_timer.Start(); + + } } class NameRequest -- cgit v1.1 From 21a09ad3ad42b24bce4fc04c6bcd6f7d9a80af08 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 16 Jul 2013 21:54:00 +0100 Subject: Revert "MSDN documentation is unclear about whether exiting a lock() block will trigger a Monitor.Wait() to exit, so avoid some locks that don't actually affect the state of the internal queues in the BlockingQueue class." This reverts commit 42e2a0d66eaa7e322bce817e9e2cc9a288de167b Reverting because unfortunately this introduces race conditions because Contains(), Count() and GetQueueArray() may now end up returning the wrong result if another thread performs a simultaneous update on m_queue. Code such as PollServiceRequestManager.Stop() relies on the count being correct otherwise a request may be lost. Also, though some of the internal queue methods do not affect state, they are not thread-safe and could return the wrong result generating the same problem lock() generates Monitor.Enter() and Monitor.Exit() under the covers. Monitor.Exit() does not cause Monitor.Wait() to exist, only Pulse() and PulseAll() will do this Reverted with agreement. --- OpenSim/Framework/BlockingQueue.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index cc016b0..3658161 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -91,9 +91,6 @@ namespace OpenSim.Framework public bool Contains(T item) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) - return false; - lock (m_queueSync) { if (m_pqueue.Contains(item)) @@ -104,14 +101,14 @@ namespace OpenSim.Framework public int Count() { - return m_queue.Count+m_pqueue.Count; + lock (m_queueSync) + { + return m_queue.Count+m_pqueue.Count; + } } public T[] GetQueueArray() { - if (m_queue.Count < 1 && m_pqueue.Count < 1) - return new T[0]; - lock (m_queueSync) { return m_queue.ToArray(); -- cgit v1.1 From 50b8ab60f2d4d8a2cc7024012fc1333be7635276 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 16 Jul 2013 23:00:07 +0100 Subject: Revert "Revert "MSDN documentation is unclear about whether exiting a lock() block will trigger a Monitor.Wait() to exit, so avoid some locks that don't actually affect the state of the internal queues in the BlockingQueue class."" This reverts commit 21a09ad3ad42b24bce4fc04c6bcd6f7d9a80af08. After more analysis and discussion, it is apparant that the Count(), Contains() and GetQueueArray() cannot be made thread-safe anyway without external locking And this change appears to have a positive impact on performance. I still believe that Monitor.Exit() will not release any thread for Monitor.Wait(), as per http://msdn.microsoft.com/en-gb/library/vstudio/system.threading.monitor.exit%28v=vs.100%29.aspx so this should in theory make no difference, though mono implementation issues could possibly be coming into play. --- OpenSim/Framework/BlockingQueue.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 3658161..cc016b0 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync); } @@ -91,6 +91,9 @@ namespace OpenSim.Framework public bool Contains(T item) { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return false; + lock (m_queueSync) { if (m_pqueue.Contains(item)) @@ -101,14 +104,14 @@ namespace OpenSim.Framework public int Count() { - lock (m_queueSync) - { - return m_queue.Count+m_pqueue.Count; - } + return m_queue.Count+m_pqueue.Count; } public T[] GetQueueArray() { + if (m_queue.Count < 1 && m_pqueue.Count < 1) + return new T[0]; + lock (m_queueSync) { return m_queue.ToArray(); -- cgit v1.1 From cbc3576ee2ee0afc7cbf66d4d782dfaee9bbdcda Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 16 Jul 2013 23:14:53 +0100 Subject: minor: Add warning method doc about possibly inconsistent results returned from BlockingQueue.Contains(), Count() and GetQueueArray() --- OpenSim/Framework/BlockingQueue.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index cc016b0..aef1192 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -89,6 +89,12 @@ namespace OpenSim.Framework } } + /// + /// Indicate whether this queue contains the given item. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public bool Contains(T item) { if (m_queue.Count < 1 && m_pqueue.Count < 1) @@ -102,11 +108,23 @@ namespace OpenSim.Framework } } + /// + /// Return a count of the number of requests on this queue. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public int Count() { - return m_queue.Count+m_pqueue.Count; + return m_queue.Count + m_pqueue.Count; } + /// + /// Return the array of items on this queue. + /// + /// + /// This method is not thread-safe. Do not rely on the result without consistent external locking. + /// public T[] GetQueueArray() { if (m_queue.Count < 1 && m_pqueue.Count < 1) -- cgit v1.1 From 3fbd2c54bc7357ea61b3a8b0c56473ae6a5a3260 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:04:32 -0700 Subject: Eliminated the UserManagement/UserManagementModule throttle thread. Made the other one generic, taking any continuation. --- .../GridServiceThrottleModule.cs | 160 ++++++++++--------- .../UserManagement/UserManagementModule.cs | 177 +++++++-------------- 2 files changed, 148 insertions(+), 189 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs index 83be644..d805fd3 100644 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs @@ -42,7 +42,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.Framework { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")] - public class GridServiceThrottleModule : ISharedRegionModule + public class ServiceThrottleModule : ISharedRegionModule, IServiceThrottleModule { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); @@ -52,12 +52,16 @@ namespace OpenSim.Region.CoreModules.Framework //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - private Queue m_RequestQueue = new Queue(); + //private Queue m_RequestQueue = new Queue(); + private Queue m_RequestQueue = new Queue(); + + #region ISharedRegionModule public void Initialise(IConfigSource config) { 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(); @@ -75,7 +79,9 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_scenes) { m_scenes.Add(scene); + scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; } } @@ -92,21 +98,6 @@ namespace OpenSim.Region.CoreModules.Framework } } - void OnNewClient(IClientAPI client) - { - client.OnRegionHandleRequest += OnRegionHandleRequest; - } - - //void OnMakeRootAgent(ScenePresence obj) - //{ - // lock (m_timer) - // { - // m_timer.Stop(); - // m_timer.Interval = 1000; - // m_timer.Start(); - // } - //} - public void PostInitialise() { } @@ -117,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Framework public string Name { - get { return "GridServiceThrottleModule"; } + get { return "ServiceThrottleModule"; } } public Type ReplaceableInterface @@ -125,9 +116,31 @@ namespace OpenSim.Region.CoreModules.Framework get { return null; } } + #endregion ISharedRegionMOdule + + #region Events + + void OnNewClient(IClientAPI client) + { + client.OnRegionHandleRequest += OnRegionHandleRequest; + } + + void OnMakeRootAgent(ScenePresence obj) + { + lock (m_timer) + { + if (!m_timer.Enabled) + { + m_timer.Interval = 1000; + m_timer.Enabled = true; + m_timer.Start(); + } + } + } + public void OnRegionHandleRequest(IClientAPI client, UUID regionID) { - //m_log.DebugFormat("[GRIDSERVICE THROTTLE]: RegionHandleRequest {0}", regionID); + //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID); ulong handle = 0; if (IsLocalRegionHandle(regionID, out handle)) { @@ -135,87 +148,90 @@ namespace OpenSim.Region.CoreModules.Framework return; } - GridRegionRequest request = new GridRegionRequest(client, regionID); + Action action = delegate + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); + + if (r != null && r.RegionHandle != 0) + client.SendRegionHandle(regionID, r.RegionHandle); + }; + lock (m_RequestQueue) - m_RequestQueue.Enqueue(request); + m_RequestQueue.Enqueue(action); } - private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle) + #endregion Events + + #region IServiceThrottleModule + + public void Enqueue(Action continuation) { - regionHandle = 0; - foreach (Scene s in m_scenes) - if (s.RegionInfo.RegionID == regionID) - { - regionHandle = s.RegionInfo.RegionHandle; - return true; - } - return false; + m_RequestQueue.Enqueue(continuation); } - private bool AreThereRootAgents() - { - foreach (Scene s in m_scenes) - { - if (s.GetRootAgentCount() > 0) - return true; - } + #endregion IServiceThrottleModule - return false; - } + #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) { - GridRegionRequest request = null; + Action continuation = null; lock (m_RequestQueue) - request = m_RequestQueue.Dequeue(); - if (request != null) - { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + continuation = m_RequestQueue.Dequeue(); - if (r != null && r.RegionHandle != 0) - request.client.SendRegionHandle(request.regionID, r.RegionHandle); - } + if (continuation != null) + continuation(); } if (AreThereRootAgents()) - m_timer.Interval = 1000; // 1 sec + { + lock (m_timer) + { + m_timer.Interval = 1000; // 1 sec + m_timer.Enabled = true; + m_timer.Start(); + } + } else - m_timer.Interval = 10000; // 10 secs + lock (m_timer) + m_timer.Enabled = false; - m_timer.Start(); } - private void ProcessQueue() - { - while (true) - { - Watchdog.UpdateThread(); + #endregion Process Continuation Queue - GridRegionRequest request = m_RequestQueue.Dequeue(); - if (request != null) - { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, request.regionID); + #region Misc - if (r != null && r.RegionHandle != 0) - request.client.SendRegionHandle(request.regionID, r.RegionHandle); + 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; } - } - - class GridRegionRequest - { - public IClientAPI client; - public UUID regionID; - - public GridRegionRequest(IClientAPI c, UUID r) + private bool AreThereRootAgents() { - client = c; - regionID = r; + 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 61c1e70..73b59d3 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -56,16 +56,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected bool m_Enabled; protected List m_Scenes = new List(); + protected IServiceThrottleModule m_ServiceThrottle; // The cache protected Dictionary m_UserCache = new Dictionary(); - // Throttle the name requests - //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - //private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - private Queue m_RequestQueue = new Queue(); - - private System.Timers.Timer m_timer; - #region ISharedRegionModule public void Initialise(IConfigSource config) @@ -118,6 +112,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public void RegionLoaded(Scene s) { + if (m_Enabled && m_ServiceThrottle == null) + m_ServiceThrottle = s.RequestModuleInterface(); } public void PostInitialise() @@ -157,7 +153,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); } - void HandleUUIDNameRequest(UUID uuid, IClientAPI remote_client) + void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", @@ -165,12 +161,33 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) { - remote_client.SendNameReply(uuid, "Mr", "OpenSim"); + client.SendNameReply(uuid, "Mr", "OpenSim"); } else { - NameRequest request = new NameRequest(remote_client, uuid); - m_RequestQueue.Enqueue(request); + string[] names = new string[2]; + if (TryGetUserNamesFromCache(uuid, names)) + { + client.SendNameReply(uuid, names[0], names[1]); + return; + } + + // Not found in cache, get it from services + m_ServiceThrottle.Enqueue(delegate + { + m_log.DebugFormat("[YYY]: Name request {0}", uuid); + bool foundRealName = TryGetUserNamesFromServices(uuid, names); + + if (names.Length == 2) + { + if (!foundRealName) + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, client.Name); + else + m_log.DebugFormat("[YYY]: Found user {0} {1} for uuid {2}", names[0], names[1], uuid); + + client.SendNameReply(uuid, names[0], names[1]); + } + }); } } @@ -286,15 +303,27 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } /// - /// Try to get the names bound to the given uuid. + /// /// - /// True if the name was found, false if not. - /// - /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" - private bool TryGetUserNames(UUID uuid, out string[] names) + /// + /// Caller please provide a properly instantiated array for names, string[2] + /// + private bool TryGetUserNames(UUID uuid, string[] names) { - names = new string[2]; + if (names == null) + names = new string[2]; + + if (TryGetUserNamesFromCache(uuid, names)) + return true; + + if (TryGetUserNamesFromServices(uuid, names)) + return true; + + return false; + } + private bool TryGetUserNamesFromCache(UUID uuid, string[] names) + { lock (m_UserCache) { if (m_UserCache.ContainsKey(uuid)) @@ -306,6 +335,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } + return false; + } + + /// + /// Try to get the names bound to the given uuid, from the services. + /// + /// True if the name was found, false if not. + /// + /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" + private bool TryGetUserNamesFromServices(UUID uuid, string[] names) + { UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); if (account != null) @@ -390,18 +430,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public string GetUserName(UUID uuid) { - string[] names; - TryGetUserNames(uuid, out names); + string[] names = new string[2]; + TryGetUserNames(uuid, names); - if (names.Length == 2) - { - string firstname = names[0]; - string lastname = names[1]; - - return firstname + " " + lastname; - } + return names[0] + " " + names[1]; - return "(hippos)"; } public string GetUserHomeURL(UUID userID) @@ -601,19 +634,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected void Init() { RegisterConsoleCmds(); - //Watchdog.StartThread( - // ProcessQueue, - // "NameRequestThread", - // ThreadPriority.BelowNormal, - // true, - // false); - - m_timer = new System.Timers.Timer(); - m_timer.AutoReset = false; - m_timer.Interval = 15000; // 15 secs at first - m_timer.Elapsed += ProcessQueue; - m_timer.Start(); - } protected void RegisterConsoleCmds() @@ -683,83 +703,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement MainConsole.Instance.Output(cdt.ToString()); } - private void ProcessQueue() - { - while (true) - { - Watchdog.UpdateThread(); - - NameRequest request = m_RequestQueue.Dequeue(); - if (request != null) - { - string[] names; - bool foundRealName = TryGetUserNames(request.uuid, out names); - - if (names.Length == 2) - { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); - - request.client.SendNameReply(request.uuid, names[0], names[1]); - } - } - } - } - - private bool AreThereRootAgents() - { - foreach (Scene s in m_Scenes) - { - if (s.GetRootAgentCount() > 0) - return true; - } - - return false; - } - - private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) - { - while (m_RequestQueue.Count > 0) - { - NameRequest request = null; - lock (m_RequestQueue) - request = m_RequestQueue.Dequeue(); - - if (request != null) - { - string[] names; - bool foundRealName = TryGetUserNames(request.uuid, out names); - - if (names.Length == 2) - { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], request.uuid, request.client.Name); - - request.client.SendNameReply(request.uuid, names[0], names[1]); - } - } - } - - if (AreThereRootAgents()) - m_timer.Interval = 1000; // 1 sec - else - m_timer.Interval = 10000; // 10 secs - - m_timer.Start(); - - } - } - - class NameRequest - { - public IClientAPI client; - public UUID uuid; - - public NameRequest(IClientAPI c, UUID n) - { - client = c; - uuid = n; - } } } \ No newline at end of file -- cgit v1.1 From 99a600753e2013a5e5c4649da78bc5b871461c8e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:06:17 -0700 Subject: Changed the name to ServiceThrottle/ServiceThrottleModule in order to reflect its more generic nature. --- .../GridServiceThrottleModule.cs | 237 --------------------- .../ServiceThrottle/ServiceThrottleModule.cs | 237 +++++++++++++++++++++ 2 files changed, 237 insertions(+), 237 deletions(-) delete mode 100644 OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs create mode 100644 OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs diff --git a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs deleted file mode 100644 index d805fd3..0000000 --- a/OpenSim/Region/CoreModules/Framework/GridServiceThrottle/GridServiceThrottleModule.cs +++ /dev/null @@ -1,237 +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.Generic; -using System.Reflection; -using System.Threading; -using log4net; -using Mono.Addins; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Framework.Monitoring; -using OpenSim.Region.Framework.Scenes; -using GridRegion = OpenSim.Services.Interfaces.GridRegion; - -namespace OpenSim.Region.CoreModules.Framework -{ - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")] - public class ServiceThrottleModule : ISharedRegionModule, IServiceThrottleModule - { - private static readonly ILog m_log = LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - private readonly List m_scenes = new List(); - private System.Timers.Timer m_timer = new System.Timers.Timer(); - - //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - //private Queue m_RequestQueue = new Queue(); - private Queue m_RequestQueue = new Queue(); - - #region ISharedRegionModule - - public void Initialise(IConfigSource config) - { - 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(); - - //Watchdog.StartThread( - // ProcessQueue, - // "GridServiceRequestThread", - // ThreadPriority.BelowNormal, - // true, - // false); - } - - public void AddRegion(Scene scene) - { - lock (m_scenes) - { - m_scenes.Add(scene); - scene.RegisterModuleInterface(this); - scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; - } - } - - public void RegionLoaded(Scene scene) - { - } - - public void RemoveRegion(Scene scene) - { - lock (m_scenes) - { - m_scenes.Remove(scene); - scene.EventManager.OnNewClient -= OnNewClient; - } - } - - public void PostInitialise() - { - } - - public void Close() - { - } - - public string Name - { - get { return "ServiceThrottleModule"; } - } - - public Type ReplaceableInterface - { - get { return null; } - } - - #endregion ISharedRegionMOdule - - #region Events - - void OnNewClient(IClientAPI client) - { - client.OnRegionHandleRequest += OnRegionHandleRequest; - } - - void OnMakeRootAgent(ScenePresence obj) - { - lock (m_timer) - { - if (!m_timer.Enabled) - { - m_timer.Interval = 1000; - 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 - { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); - - if (r != null && r.RegionHandle != 0) - client.SendRegionHandle(regionID, r.RegionHandle); - }; - - lock (m_RequestQueue) - m_RequestQueue.Enqueue(action); - - } - - #endregion Events - - #region IServiceThrottleModule - - public void Enqueue(Action continuation) - { - m_RequestQueue.Enqueue(continuation); - } - - #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/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs new file mode 100644 index 0000000..d805fd3 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -0,0 +1,237 @@ +/* + * 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.Reflection; +using System.Threading; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.Framework.Scenes; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Region.CoreModules.Framework +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GridServiceThrottleModule")] + public class ServiceThrottleModule : ISharedRegionModule, IServiceThrottleModule + { + private static readonly ILog m_log = LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + private readonly List m_scenes = new List(); + private System.Timers.Timer m_timer = new System.Timers.Timer(); + + //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); + // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); + //private Queue m_RequestQueue = new Queue(); + private Queue m_RequestQueue = new Queue(); + + #region ISharedRegionModule + + public void Initialise(IConfigSource config) + { + 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(); + + //Watchdog.StartThread( + // ProcessQueue, + // "GridServiceRequestThread", + // ThreadPriority.BelowNormal, + // true, + // false); + } + + public void AddRegion(Scene scene) + { + lock (m_scenes) + { + m_scenes.Add(scene); + scene.RegisterModuleInterface(this); + scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + } + } + + public void RegionLoaded(Scene scene) + { + } + + public void RemoveRegion(Scene scene) + { + lock (m_scenes) + { + m_scenes.Remove(scene); + scene.EventManager.OnNewClient -= OnNewClient; + } + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "ServiceThrottleModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + #endregion ISharedRegionMOdule + + #region Events + + void OnNewClient(IClientAPI client) + { + client.OnRegionHandleRequest += OnRegionHandleRequest; + } + + void OnMakeRootAgent(ScenePresence obj) + { + lock (m_timer) + { + if (!m_timer.Enabled) + { + m_timer.Interval = 1000; + 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 + { + GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); + + if (r != null && r.RegionHandle != 0) + client.SendRegionHandle(regionID, r.RegionHandle); + }; + + lock (m_RequestQueue) + m_RequestQueue.Enqueue(action); + + } + + #endregion Events + + #region IServiceThrottleModule + + public void Enqueue(Action continuation) + { + m_RequestQueue.Enqueue(continuation); + } + + #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 + } + +} -- cgit v1.1 From a006caabbcfe6e2a2b4a6118d217d3bd9abd4d99 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:06:54 -0700 Subject: Added IServiceThrottleModule.cs --- OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs diff --git a/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs new file mode 100644 index 0000000..bb6a8b4 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IServiceThrottleModule + { + void Enqueue(Action continuation); + } + +} -- cgit v1.1 From 9f578cf0c83ba56d5a999df7411f4065fc17d24b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:18:11 -0700 Subject: Deleted a couple of verbose messages --- .../CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs | 2 +- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index d805fd3..553e4ca 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -176,7 +176,7 @@ namespace OpenSim.Region.CoreModules.Framework private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) { - m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); + //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); while (m_RequestQueue.Count > 0) { diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 73b59d3..da28a53 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -175,15 +175,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // Not found in cache, get it from services m_ServiceThrottle.Enqueue(delegate { - m_log.DebugFormat("[YYY]: Name request {0}", uuid); + //m_log.DebugFormat("[YYY]: Name request {0}", uuid); bool foundRealName = TryGetUserNamesFromServices(uuid, names); if (names.Length == 2) { if (!foundRealName) m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, client.Name); - else - m_log.DebugFormat("[YYY]: Found user {0} {1} for uuid {2}", names[0], names[1], uuid); client.SendNameReply(uuid, names[0], names[1]); } -- cgit v1.1 From 9f129938c9c75bb4513b0b93248985100fe0e921 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Tue, 16 Jul 2013 17:43:36 -0700 Subject: Attachments module only registers when enabled. This enables alternative attachments module implementations. All calls to Scene.AttachmentsModule are checking for null. Ideally, if we support disabling attachments then we need a null attachments module to register with the scene. --- OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 6 ++++-- OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | 6 ++++-- .../RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index f69ec21..2f5a76f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -74,10 +74,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void AddRegion(Scene scene) { m_scene = scene; - m_scene.RegisterModuleInterface(this); - if (Enabled) { + // Only register module with scene if it is enabled. All callers check for a null attachments module. + // Ideally, there should be a null attachments module for when this core attachments module has been + // disabled. Registering only when enabled allows for other attachments module implementations. + m_scene.RegisterModuleInterface(this); m_scene.EventManager.OnNewClient += SubscribeToClientEvents; m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true); m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false); diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 7d46d92..69189b3 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -116,7 +116,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC return false; // Delete existing npc attachments - scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); + if(scene.AttachmentsModule != null) + scene.AttachmentsModule.DeleteAttachmentsFromScene(npc, false); // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet // since it doesn't transfer attachments @@ -125,7 +126,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC npc.Appearance = npcAppearance; // Rez needed npc attachments - scene.AttachmentsModule.RezAttachments(npc); + if (scene.AttachmentsModule != null) + scene.AttachmentsModule.RezAttachments(npc); IAvatarFactoryModule module = scene.RequestModuleInterface(); diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs index f424e7f..83732e2 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs @@ -51,7 +51,8 @@ namespace OpenSim.Region.RegionCombinerModule m_virtScene.UnSubscribeToClientPrimEvents(client); m_virtScene.UnSubscribeToClientPrimRezEvents(client); m_virtScene.UnSubscribeToClientInventoryEvents(client); - ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client); + if(m_virtScene.AttachmentsModule != null) + ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client); //m_virtScene.UnSubscribeToClientTeleportEvents(client); m_virtScene.UnSubscribeToClientScriptEvents(client); @@ -66,7 +67,8 @@ namespace OpenSim.Region.RegionCombinerModule client.OnRezObject += LocalRezObject; m_rootScene.SubscribeToClientInventoryEvents(client); - ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client); + if (m_rootScene.AttachmentsModule != null) + ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client); //m_rootScene.SubscribeToClientTeleportEvents(client); m_rootScene.SubscribeToClientScriptEvents(client); -- cgit v1.1 From d4720bd721b518efbc681df2f4e7d1ca35aa0f3c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 17:53:05 -0700 Subject: Added config var to fiddle with the Interval for the service throttle thread --- .../CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 553e4ca..a3ca6d6 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -54,11 +54,14 @@ namespace OpenSim.Region.CoreModules.Framework // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); //private Queue m_RequestQueue = new Queue(); private Queue m_RequestQueue = new Queue(); + private int m_Interval; #region ISharedRegionModule public void Initialise(IConfigSource config) { + m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 2000); + m_timer = new System.Timers.Timer(); m_timer.AutoReset = false; m_timer.Enabled = true; @@ -131,7 +134,7 @@ namespace OpenSim.Region.CoreModules.Framework { if (!m_timer.Enabled) { - m_timer.Interval = 1000; + m_timer.Interval = m_Interval; m_timer.Enabled = true; m_timer.Start(); } -- cgit v1.1 From 5f27aaa6ddb857dbfbbe0219d0e29c42ad903375 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 18:22:42 -0700 Subject: UserManagementModule: in the continuation, call the method that also looks up the cache, because the resource may be here in the meantime --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index da28a53..e8bdcc9 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -172,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return; } - // Not found in cache, get it from services + // Not found in cache, queue continuation m_ServiceThrottle.Enqueue(delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); - bool foundRealName = TryGetUserNamesFromServices(uuid, names); + bool foundRealName = TryGetUserNames(uuid, names); if (names.Length == 2) { -- cgit v1.1 From 9432f3c94d0b0345132e5ff9eaf966b96cf218c2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 19:04:30 -0700 Subject: Improvements to the ServiceThrottleModule: added a category and an itemid to the interface, so that duplicate requests aren't enqueued more than once. --- .../ServiceThrottle/ServiceThrottleModule.cs | 35 ++++++++++++++++------ .../UserManagement/UserManagementModule.cs | 2 +- .../Framework/Interfaces/IServiceThrottleModule.cs | 10 ++++++- bin/OpenSimDefaults.ini | 4 +++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index a3ca6d6..1554b3e 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -50,17 +50,15 @@ namespace OpenSim.Region.CoreModules.Framework private readonly List m_scenes = new List(); private System.Timers.Timer m_timer = new System.Timers.Timer(); - //private OpenSim.Framework.BlockingQueue m_RequestQueue = new OpenSim.Framework.BlockingQueue(); - // private OpenSim.Framework.DoubleQueue m_RequestQueue = new OpenSim.Framework.DoubleQueue(); - //private Queue m_RequestQueue = new Queue(); private Queue m_RequestQueue = new Queue(); + private Dictionary> m_Pending = new Dictionary>(); private int m_Interval; #region ISharedRegionModule public void Initialise(IConfigSource config) { - m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 2000); + m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 5000); m_timer = new System.Timers.Timer(); m_timer.AutoReset = false; @@ -159,18 +157,37 @@ namespace OpenSim.Region.CoreModules.Framework client.SendRegionHandle(regionID, r.RegionHandle); }; - lock (m_RequestQueue) - m_RequestQueue.Enqueue(action); - + Enqueue("region", regionID.ToString(), action); } #endregion Events #region IServiceThrottleModule - public void Enqueue(Action continuation) + public void Enqueue(string category, string itemid, Action continuation) { - m_RequestQueue.Enqueue(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 + { + continuation(); + lock (m_RequestQueue) + { + m_Pending[category].Remove(itemid); + } + }); + } } #endregion IServiceThrottleModule diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index e8bdcc9..a91adfa 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -173,7 +173,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // Not found in cache, queue continuation - m_ServiceThrottle.Enqueue(delegate + m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); bool foundRealName = TryGetUserNames(uuid, names); diff --git a/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs index bb6a8b4..198256f 100644 --- a/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IServiceThrottleModule.cs @@ -5,7 +5,15 @@ namespace OpenSim.Region.Framework.Interfaces { public interface IServiceThrottleModule { - void Enqueue(Action continuation); + /// + /// Enqueue a continuation meant to get a resource from elsewhere. + /// As usual with CPS, caller beware: if that continuation is a never-ending computation, + /// the whole thread will be blocked, and no requests are processed + /// + /// Category of the resource (e.g. name, region) + /// The resource identifier + /// The continuation to be executed + void Enqueue(string category, string itemid, Action continuation); } } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 4a3104e..8079632 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1727,5 +1727,9 @@ MaxStringSpace = 0 ;; {MaxDistance} {} {Cut-off distance at which sounds will not be sent to users} {100.0} MaxDistance = 100.0 +[ServiceThrottle] + ;; Default time interval (in ms) for the throttle service thread to wake up + Interval = 5000 + [Modules] Include-modules = "addon-modules/*/config/*.ini" -- cgit v1.1 From 894554faf61fe8ae02c1348612845ae2553efbd4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 16 Jul 2013 20:28:48 -0700 Subject: Removed the MapItems thread. Redirected the map items requests to the services throttle thread. Didn't change anything in how that processor is implemented, for better or for worse. --- .../ServiceThrottle/ServiceThrottleModule.cs | 5 +-- .../CoreModules/World/WorldMap/WorldMapModule.cs | 49 +++++++++++++++++++--- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 1554b3e..a70261e 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -181,11 +181,10 @@ namespace OpenSim.Region.CoreModules.Framework m_RequestQueue.Enqueue(delegate { - continuation(); lock (m_RequestQueue) - { m_Pending[category].Remove(itemid); - } + + continuation(); }); } } diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index c50ab64..a26a5f0 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -81,6 +81,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap private List m_rootAgents = new List(); private volatile bool threadrunning = false; + private IServiceThrottleModule m_ServiceThrottle; + //private int CacheRegionsDistance = 256; #region INonSharedRegionModule Members @@ -131,6 +133,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap public virtual void RegionLoaded (Scene scene) { + if (!m_Enabled) + return; + + m_ServiceThrottle = scene.RequestModuleInterface(); } @@ -170,13 +176,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap m_scene.EventManager.OnMakeRootAgent += MakeRootAgent; m_scene.EventManager.OnRegionUp += OnRegionUp; - StartThread(new object()); +// StartThread(new object()); } // this has to be called with a lock on m_scene protected virtual void RemoveHandlers() { - StopThread(); +// StopThread(); m_scene.EventManager.OnRegionUp -= OnRegionUp; m_scene.EventManager.OnMakeRootAgent -= MakeRootAgent; @@ -526,7 +532,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap /// public void process() { - const int MAX_ASYNC_REQUESTS = 20; + //const int MAX_ASYNC_REQUESTS = 20; try { while (true) @@ -571,13 +577,44 @@ namespace OpenSim.Region.CoreModules.World.WorldMap Watchdog.RemoveThread(); } + const int MAX_ASYNC_REQUESTS = 20; + /// - /// Enqueues the map item request into the processing thread + /// Enqueues the map item request into the services throttle processing thread /// /// - public void EnqueueMapItemRequest(MapRequestState state) + public void EnqueueMapItemRequest(MapRequestState st) { - requests.Enqueue(state); + + m_ServiceThrottle.Enqueue("map-item", st.regionhandle.ToString() + st.agentID.ToString(), delegate + { + if (st.agentID != UUID.Zero) + { + bool dorequest = true; + lock (m_rootAgents) + { + if (!m_rootAgents.Contains(st.agentID)) + dorequest = false; + } + + if (dorequest && !m_blacklistedregions.ContainsKey(st.regionhandle)) + { + if (nAsyncRequests >= MAX_ASYNC_REQUESTS) // hit the break + { + // AH!!! Recursive ! + // Put this request back in the queue and return + EnqueueMapItemRequest(st); + return; + } + + RequestMapItemsDelegate d = RequestMapItemsAsync; + d.BeginInvoke(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle, RequestMapItemsCompleted, null); + //OSDMap response = RequestMapItemsAsync(st.agentID, st.flags, st.EstateID, st.godlike, st.itemtype, st.regionhandle); + //RequestMapItemsCompleted(response); + Interlocked.Increment(ref nAsyncRequests); + } + } + }); } /// -- cgit v1.1 From 2c8bf4aaa66a4cc9fc8fd9f89825e7cd1b43f3d6 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 17 Jul 2013 10:19:44 -0700 Subject: BulletSim: fix small bug where everything looked like it was colliding before the first simulator step. --- OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 13 +++++++------ OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index a41eaf8..fc4545f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -103,9 +103,10 @@ public abstract class BSPhysObject : PhysicsActor CollisionsLastTickStep = -1; SubscribedEventsMs = 0; - CollidingStep = 0; - CollidingGroundStep = 0; - CollisionAccumulation = 0; + // Crazy values that will never be true + CollidingStep = BSScene.NotASimulationStep; + CollidingGroundStep = BSScene.NotASimulationStep; + CollisionAccumulation = BSScene.NotASimulationStep; ColliderIsMoving = false; CollisionScore = 0; @@ -349,7 +350,7 @@ public abstract class BSPhysObject : PhysicsActor if (value) CollidingStep = PhysScene.SimulationStep; else - CollidingStep = 0; + CollidingStep = BSScene.NotASimulationStep; } } public override bool CollidingGround { @@ -359,7 +360,7 @@ public abstract class BSPhysObject : PhysicsActor if (value) CollidingGroundStep = PhysScene.SimulationStep; else - CollidingGroundStep = 0; + CollidingGroundStep = BSScene.NotASimulationStep; } } public override bool CollidingObj { @@ -368,7 +369,7 @@ public abstract class BSPhysObject : PhysicsActor if (value) CollidingObjectStep = PhysScene.SimulationStep; else - CollidingObjectStep = 0; + CollidingObjectStep = BSScene.NotASimulationStep; } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 214271b..41aca3b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -97,6 +97,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters internal long m_simulationStep = 0; // The current simulation step. public long SimulationStep { get { return m_simulationStep; } } + // A number to use for SimulationStep that is probably not any step value + // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step. + public static long NotASimulationStep = -1234; internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() -- cgit v1.1 From e46459ef21e1ee5ceaeca70365a7c881d33b09ce Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 11:19:36 -0700 Subject: Cleared up much confusion in PollServiceRequestManager. Here's the history: When Melanie added the web fetch inventory throttle to core, she made the long poll requests (EQs) effectively be handled on an active loop. All those requests, if they existed, were being constantly dequeued, checked for events (which most often they didn't have), and requeued again. This was an active loop thread on a 100ms cycle! This fixes the issue. Now the inventory requests, if they aren't ready to be served, are placed directly back in the queue, but the long poll requests aren't placed there until there are events ready to be sent or timeout has been reached. This puts the LongPollServiceWatcherThread back to 1sec cycle, as it was before. --- OpenSim/Framework/BlockingQueue.cs | 2 +- .../Servers/HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 79 +++++++++------------- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 8 ++- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192..e607e64 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 020bfd5..9477100 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer public enum EventType : int { - Normal = 0, + LongPoll = 0, LslHttp = 1, Inventory = 2 } @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer NoEvents = pNoEvents; Id = pId; TimeOutms = pTimeOutms; - Type = EventType.Normal; + Type = EventType.LongPoll; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 1b9010a..4cb551c 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,12 +47,11 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_slowRequests = new Queue(); - private static Queue m_retryRequests = new Queue(); + private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_retrysThread; + private Thread m_longPollThread; private bool m_running = true; private int slowCount = 0; @@ -84,9 +83,9 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_retrysThread = Watchdog.StartThread( - this.CheckRetries, - string.Format("PollServiceWatcherThread:{0}", m_server.Port), + m_longPollThread = Watchdog.StartThread( + this.CheckLongPollThreads, + string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -97,48 +96,47 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - { - lock (m_retryRequests) - m_retryRequests.Enqueue(req); - } + m_requests.Enqueue(req); } public void Enqueue(PollServiceHttpRequest req) { if (m_running) { - if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) { - m_requests.Enqueue(req); + lock (m_longPollRequests) + m_longPollRequests.Enqueue(req); } else - { - lock (m_slowRequests) - m_slowRequests.Enqueue(req); - } + m_requests.Enqueue(req); } } - private void CheckRetries() + private void CheckLongPollThreads() { + // The only purpose of this thread is to check the EQs for events. + // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. + // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. + // All other types of tasks (Inventory handlers) don't have the long-poll nature, + // so if they aren't ready to be served by a worker thread (no events), they are placed + // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(100); // let the world move .. back to faster rate + Thread.Sleep(1000); Watchdog.UpdateThread(); - lock (m_retryRequests) - { - while (m_retryRequests.Count > 0 && m_running) - m_requests.Enqueue(m_retryRequests.Dequeue()); - } - slowCount++; - if (slowCount >= 10) - { - slowCount = 0; - lock (m_slowRequests) + PollServiceHttpRequest req; + lock (m_longPollRequests) + { + while (m_longPollRequests.Count > 0 && m_running) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + req = m_longPollRequests.Dequeue(); + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ + (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout + m_requests.Enqueue(req); + else + m_longPollRequests.Enqueue(req); } } } @@ -153,24 +151,12 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); - try - { - foreach (PollServiceHttpRequest req in m_retryRequests) - { - req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - } - catch - { - } - PollServiceHttpRequest wreq; - m_retryRequests.Clear(); - lock (m_slowRequests) + lock (m_longPollRequests) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + while (m_longPollRequests.Count > 0 && m_running) + m_requests.Enqueue(m_longPollRequests.Dequeue()); } while (m_requests.Count() > 0) @@ -196,6 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer while (m_running) { PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); Watchdog.UpdateThread(); if (req != null) @@ -209,7 +196,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsedata == null) continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { try { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 1835a72..f0445ff 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -364,8 +364,7 @@ namespace OpenSim.Region.ClientStack.Linden caps.RegisterPollHandler( "EventQueueGet", - new PollServiceEventArgs( - null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -383,7 +382,10 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) + { + //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); return queue.Count > 0; + } return false; } @@ -406,7 +408,7 @@ namespace OpenSim.Region.ClientStack.Linden public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; -- cgit v1.1 From 0f5b616fb0ebf9207b3cc81771622ed1290ea7d6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 12:02:00 -0700 Subject: Didn't mean to commit this change in BlockingQueue.cs --- OpenSim/Framework/BlockingQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e607e64..aef1192 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } -- cgit v1.1 From f4317dc26d670c853d0ea64b401b00f718f09474 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 12:57:34 -0700 Subject: Putting the requests back in the queue while testing for count >0 is not the smartest move... --- .../Framework/Servers/HttpServer/PollServiceRequestManager.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 4cb551c..c50df5a 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -126,18 +126,22 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(1000); Watchdog.UpdateThread(); - PollServiceHttpRequest req; + List not_ready = new List(); lock (m_longPollRequests) { while (m_longPollRequests.Count > 0 && m_running) { - req = m_longPollRequests.Dequeue(); + PollServiceHttpRequest req = m_longPollRequests.Dequeue(); if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout m_requests.Enqueue(req); else - m_longPollRequests.Enqueue(req); + not_ready.Add(req); } + + foreach (PollServiceHttpRequest req in not_ready) + m_longPollRequests.Enqueue(req); + } } } -- cgit v1.1 From af792bc7f2504e9ccf1c8ae7568919785dc397c9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 13:23:29 -0700 Subject: Do the same trick that dahlia did for Dequeue(timeout) --- OpenSim/Framework/BlockingQueue.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192..fb74a24 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,9 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + bool timedout = false; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) { - Monitor.Wait(m_queueSync, msTimeout); + timedout = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) -- cgit v1.1 From 1d3deda10cf85abd68a5f904d6698ae597a67cc0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 13:26:15 -0700 Subject: I confuse myself. Let's try this variable name instead. --- OpenSim/Framework/BlockingQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index fb74a24..3e90fac 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool timedout = false; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) + bool success = true; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) { - timedout = Monitor.Wait(m_queueSync, msTimeout); + success = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) -- cgit v1.1 From 5f95f4d78e8c7d17b8ba866907156fe6d4444c04 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 14:09:04 -0700 Subject: Now trying DoubleQueue instead of BlockingQueue for the PollServiceRequestManager. --- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index c50df5a..bad28e4 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private BlockingQueue m_requests = new BlockingQueue(); + private DoubleQueue m_requests = new DoubleQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count() > 0) + while (m_requests.Count > 0) { try { -- cgit v1.1 From 5232ab0496eb4fe6903a0fd328974ac69df29ad8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 14:36:55 -0700 Subject: This is a completely unreasonable thing to do, effectively defying the purpose of BlockingQueues. Trying this, to see the effect on CPU. --- .../HttpServer/PollServiceRequestManager.cs | 92 ++++++++++++---------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index bad28e4..b8f5743 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private DoubleQueue m_requests = new DoubleQueue(); + private BlockingQueue m_requests = new BlockingQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count > 0) + while (m_requests.Count() > 0) { try { @@ -185,35 +185,33 @@ namespace OpenSim.Framework.Servers.HttpServer { while (m_running) { - PollServiceHttpRequest req = m_requests.Dequeue(5000); - //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); - Watchdog.UpdateThread(); - if (req != null) + + PollServiceHttpRequest req = null; + lock (m_requests) + { + if (m_requests.Count() > 0) + req = m_requests.Dequeue(); + } + if (req == null) + Thread.Sleep(100); + else { - try + //PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); + + if (req != null) { - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) + try { - Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) + { + Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); - if (responsedata == null) - continue; + if (responsedata == null) + continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue - { - try - { - req.DoHTTPGruntWork(m_server, responsedata); - } - catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream - { - // Ignore it, no need to reply - } - } - else - { - m_threadPool.QueueWorkItem(x => + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { try { @@ -223,27 +221,41 @@ namespace OpenSim.Framework.Servers.HttpServer { // Ignore it, no need to reply } + } + else + { + m_threadPool.QueueWorkItem(x => + { + try + { + req.DoHTTPGruntWork(m_server, responsedata); + } + catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + } - return null; - }, null); - } - } - else - { - if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) - { - req.DoHTTPGruntWork( - m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + return null; + }, null); + } } else { - ReQueueEvent(req); + if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) + { + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + else + { + ReQueueEvent(req); + } } } - } - catch (Exception e) - { - m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); + catch (Exception e) + { + m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); + } } } } -- cgit v1.1 From 5c54eb30eddf5ff17769eaa11ab9c5a9ac79caa3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:02:54 -0700 Subject: Revert "This is a completely unreasonable thing to do, effectively defying the purpose of BlockingQueues. Trying this, to see the effect on CPU." This reverts commit 5232ab0496eb4fe6903a0fd328974ac69df29ad8. --- .../HttpServer/PollServiceRequestManager.cs | 92 ++++++++++------------ 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index b8f5743..bad28e4 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private BlockingQueue m_requests = new BlockingQueue(); + private DoubleQueue m_requests = new DoubleQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count() > 0) + while (m_requests.Count > 0) { try { @@ -185,33 +185,35 @@ namespace OpenSim.Framework.Servers.HttpServer { while (m_running) { - Watchdog.UpdateThread(); + PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); - PollServiceHttpRequest req = null; - lock (m_requests) - { - if (m_requests.Count() > 0) - req = m_requests.Dequeue(); - } - if (req == null) - Thread.Sleep(100); - else + Watchdog.UpdateThread(); + if (req != null) { - //PollServiceHttpRequest req = m_requests.Dequeue(5000); - //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); - - if (req != null) + try { - try + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) { - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) - { - Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); + Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); - if (responsedata == null) - continue; + if (responsedata == null) + continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue + { + try + { + req.DoHTTPGruntWork(m_server, responsedata); + } + catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream + { + // Ignore it, no need to reply + } + } + else + { + m_threadPool.QueueWorkItem(x => { try { @@ -221,41 +223,27 @@ namespace OpenSim.Framework.Servers.HttpServer { // Ignore it, no need to reply } - } - else - { - m_threadPool.QueueWorkItem(x => - { - try - { - req.DoHTTPGruntWork(m_server, responsedata); - } - catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream - { - // Ignore it, no need to reply - } - return null; - }, null); - } + return null; + }, null); + } + } + else + { + if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) + { + req.DoHTTPGruntWork( + m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } else { - if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) - { - req.DoHTTPGruntWork( - m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - else - { - ReQueueEvent(req); - } + ReQueueEvent(req); } } - catch (Exception e) - { - m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); - } + } + catch (Exception e) + { + m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); } } } -- cgit v1.1 From 519dba9a69a02980e09268671c030017001a2cd4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:03:16 -0700 Subject: Revert "Now trying DoubleQueue instead of BlockingQueue for the PollServiceRequestManager." This reverts commit 5f95f4d78e8c7d17b8ba866907156fe6d4444c04. --- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index bad28e4..c50df5a 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -46,7 +46,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; - private DoubleQueue m_requests = new DoubleQueue(); + private BlockingQueue m_requests = new BlockingQueue(); private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; @@ -163,7 +163,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_requests.Enqueue(m_longPollRequests.Dequeue()); } - while (m_requests.Count > 0) + while (m_requests.Count() > 0) { try { -- cgit v1.1 From 52dc7b2a96a28798d55d07d79d003ce5e3d35216 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:03:40 -0700 Subject: Revert "I confuse myself. Let's try this variable name instead." This reverts commit 1d3deda10cf85abd68a5f904d6698ae597a67cc0. --- OpenSim/Framework/BlockingQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 3e90fac..fb74a24 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool success = true; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) + bool timedout = false; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) { - success = Monitor.Wait(m_queueSync, msTimeout); + timedout = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) -- cgit v1.1 From 5495df74436d6c0039a1500d979a964b003abfdf Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:04:12 -0700 Subject: Revert "Do the same trick that dahlia did for Dequeue(timeout)" This reverts commit af792bc7f2504e9ccf1c8ae7568919785dc397c9. --- OpenSim/Framework/BlockingQueue.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index fb74a24..aef1192 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,9 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool timedout = false; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { - timedout = Monitor.Wait(m_queueSync, msTimeout); + Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) -- cgit v1.1 From 71278919575b0e0222cdbe3c0cefa5919f9a75bc Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:04:27 -0700 Subject: Revert "Putting the requests back in the queue while testing for count >0 is not the smartest move..." This reverts commit f4317dc26d670c853d0ea64b401b00f718f09474. --- .../Framework/Servers/HttpServer/PollServiceRequestManager.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index c50df5a..4cb551c 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -126,22 +126,18 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(1000); Watchdog.UpdateThread(); - List not_ready = new List(); + PollServiceHttpRequest req; lock (m_longPollRequests) { while (m_longPollRequests.Count > 0 && m_running) { - PollServiceHttpRequest req = m_longPollRequests.Dequeue(); + req = m_longPollRequests.Dequeue(); if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout m_requests.Enqueue(req); else - not_ready.Add(req); + m_longPollRequests.Enqueue(req); } - - foreach (PollServiceHttpRequest req in not_ready) - m_longPollRequests.Enqueue(req); - } } } -- cgit v1.1 From fda91d93dad1fa6f901e8db5829aa8b70477c97e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:05:16 -0700 Subject: Revert "Didn't mean to commit this change in BlockingQueue.cs" This reverts commit 0f5b616fb0ebf9207b3cc81771622ed1290ea7d6. --- OpenSim/Framework/BlockingQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192..e607e64 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } -- cgit v1.1 From f64f07e7c5b115d4005462d976fb60727c6d1cd1 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Wed, 17 Jul 2013 14:55:48 -0700 Subject: command line kick user now uses exact name match instead of substring search to avoid kicking the wrong user or multiple wrong users. --- OpenSim/Region/Application/OpenSim.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 6ff7f01..b071df8 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -423,8 +423,8 @@ namespace OpenSim { RegionInfo regionInfo = presence.Scene.RegionInfo; - if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) && - presence.Lastname.ToLower().Contains(mainParams[3].ToLower())) + if (presence.Firstname.ToLower().Equals(mainParams[2].ToLower()) && + presence.Lastname.ToLower().Equals(mainParams[3].ToLower())) { MainConsole.Instance.Output( String.Format( @@ -438,6 +438,7 @@ namespace OpenSim presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); presence.Scene.IncomingCloseAgent(presence.UUID, force); + break; } } -- cgit v1.1 From fa2370b32ee57a07f27501152c3c705a883b13d8 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 17 Jul 2013 15:05:36 -0700 Subject: Revert "Cleared up much confusion in PollServiceRequestManager. Here's the history:" This reverts commit e46459ef21e1ee5ceaeca70365a7c881d33b09ce. --- OpenSim/Framework/BlockingQueue.cs | 2 +- .../Servers/HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 79 +++++++++++++--------- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 8 +-- 4 files changed, 52 insertions(+), 41 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e607e64..aef1192 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 9477100..020bfd5 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer public enum EventType : int { - LongPoll = 0, + Normal = 0, LslHttp = 1, Inventory = 2 } @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer NoEvents = pNoEvents; Id = pId; TimeOutms = pTimeOutms; - Type = EventType.LongPoll; + Type = EventType.Normal; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 4cb551c..1b9010a 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,11 +47,12 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_longPollRequests = new Queue(); + private static Queue m_slowRequests = new Queue(); + private static Queue m_retryRequests = new Queue(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_longPollThread; + private Thread m_retrysThread; private bool m_running = true; private int slowCount = 0; @@ -83,9 +84,9 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_longPollThread = Watchdog.StartThread( - this.CheckLongPollThreads, - string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), + m_retrysThread = Watchdog.StartThread( + this.CheckRetries, + string.Format("PollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -96,47 +97,48 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - m_requests.Enqueue(req); + { + lock (m_retryRequests) + m_retryRequests.Enqueue(req); + } } public void Enqueue(PollServiceHttpRequest req) { if (m_running) { - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) + if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) { - lock (m_longPollRequests) - m_longPollRequests.Enqueue(req); + m_requests.Enqueue(req); } else - m_requests.Enqueue(req); + { + lock (m_slowRequests) + m_slowRequests.Enqueue(req); + } } } - private void CheckLongPollThreads() + private void CheckRetries() { - // The only purpose of this thread is to check the EQs for events. - // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. - // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. - // All other types of tasks (Inventory handlers) don't have the long-poll nature, - // so if they aren't ready to be served by a worker thread (no events), they are placed - // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(1000); + Thread.Sleep(100); // let the world move .. back to faster rate Watchdog.UpdateThread(); - - PollServiceHttpRequest req; - lock (m_longPollRequests) + lock (m_retryRequests) + { + while (m_retryRequests.Count > 0 && m_running) + m_requests.Enqueue(m_retryRequests.Dequeue()); + } + slowCount++; + if (slowCount >= 10) { - while (m_longPollRequests.Count > 0 && m_running) + slowCount = 0; + + lock (m_slowRequests) { - req = m_longPollRequests.Dequeue(); - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ - (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout - m_requests.Enqueue(req); - else - m_longPollRequests.Enqueue(req); + while (m_slowRequests.Count > 0 && m_running) + m_requests.Enqueue(m_slowRequests.Dequeue()); } } } @@ -151,12 +153,24 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); + try + { + foreach (PollServiceHttpRequest req in m_retryRequests) + { + req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); + } + } + catch + { + } + PollServiceHttpRequest wreq; + m_retryRequests.Clear(); - lock (m_longPollRequests) + lock (m_slowRequests) { - while (m_longPollRequests.Count > 0 && m_running) - m_requests.Enqueue(m_longPollRequests.Dequeue()); + while (m_slowRequests.Count > 0 && m_running) + m_requests.Enqueue(m_slowRequests.Dequeue()); } while (m_requests.Count() > 0) @@ -182,7 +196,6 @@ namespace OpenSim.Framework.Servers.HttpServer while (m_running) { PollServiceHttpRequest req = m_requests.Dequeue(5000); - //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); Watchdog.UpdateThread(); if (req != null) @@ -196,7 +209,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsedata == null) continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue { try { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index f0445ff..1835a72 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -364,7 +364,8 @@ namespace OpenSim.Region.ClientStack.Linden caps.RegisterPollHandler( "EventQueueGet", - new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs( + null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -382,10 +383,7 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) - { - //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); return queue.Count > 0; - } return false; } @@ -408,7 +406,7 @@ namespace OpenSim.Region.ClientStack.Linden public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; -- cgit v1.1 From 077be8b496f00c82353de02be192d2dcd920d6b3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 01:23:33 +0100 Subject: Fix what apepars to be a bug in DoubleQueue.Enqueue(Queue q, T data) where the q parmater is ignored and everyghig is always placed on m_lowQueue. No actual impact presently since nothing ends up calling EnqueueHigh() --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cfc4d4..a39d860 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2253,7 +2253,7 @@ namespace OpenSim.Framework { lock (m_syncRoot) { - m_lowQueue.Enqueue(data); + q.Enqueue(data); m_s.WaitOne(0); m_s.Release(); } -- cgit v1.1 From 6572847518646f3f46959f613e602efc16210dcf Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 18 Jul 2013 02:28:07 -0700 Subject: Added MinPoolThreads to ini [Startup] section to control SmartThreadPool. --- OpenSim/Framework/Util.cs | 8 +++++--- OpenSim/Region/Application/OpenSim.cs | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cfc4d4..27100e6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1779,10 +1779,12 @@ namespace OpenSim.Framework FireAndForget(callback, null); } - public static void InitThreadPool(int maxThreads) + public static void InitThreadPool(int minThreads, int maxThreads) { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (minThreads > maxThreads || minThreads < 2) + throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); if (m_ThreadPool != null) throw new InvalidOperationException("SmartThreadPool is already initialized"); @@ -1790,7 +1792,7 @@ namespace OpenSim.Framework startInfo.ThreadPoolName = "Util"; startInfo.IdleTimeout = 2000; startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 2; + startInfo.MinWorkerThreads = minThreads; m_ThreadPool = new SmartThreadPool(startInfo); } @@ -1865,7 +1867,7 @@ namespace OpenSim.Framework break; case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) - InitThreadPool(15); + InitThreadPool(2, 15); m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); break; case FireAndForgetMethod.Thread: diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index b071df8..9dcc8da 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -86,6 +86,7 @@ namespace OpenSim IConfig startupConfig = Config.Configs["Startup"]; IConfig networkConfig = Config.Configs["Network"]; + int stpMinThreads = 2; int stpMaxThreads = 15; if (startupConfig != null) @@ -112,12 +113,13 @@ namespace OpenSim if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse(asyncCallMethodStr, out asyncCallMethod)) Util.FireAndForgetMethod = asyncCallMethod; + stpMinThreads = startupConfig.GetInt("MinPoolThreads", 15); stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15); m_consolePrompt = startupConfig.GetString("ConsolePrompt", @"Region (\R) "); } if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - Util.InitThreadPool(stpMaxThreads); + Util.InitThreadPool(stpMinThreads, stpMaxThreads); m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } -- cgit v1.1 From 9e35b069a43942285214ff485c8f5ffb53e7c5ec Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:23:27 -0700 Subject: Reverting the reverts I did yesterday. cpu-branch has now been successfully tested, and I'm merging back those changes, which proved to be good. Revert "Revert "Cleared up much confusion in PollServiceRequestManager. Here's the history:"" This reverts commit fa2370b32ee57a07f27501152c3c705a883b13d8. --- OpenSim/Framework/BlockingQueue.cs | 2 +- .../Servers/HttpServer/PollServiceEventArgs.cs | 4 +- .../HttpServer/PollServiceRequestManager.cs | 79 +++++++++------------- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 8 ++- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192..e607e64 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + while (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 020bfd5..9477100 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -50,7 +50,7 @@ namespace OpenSim.Framework.Servers.HttpServer public enum EventType : int { - Normal = 0, + LongPoll = 0, LslHttp = 1, Inventory = 2 } @@ -80,7 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer NoEvents = pNoEvents; Id = pId; TimeOutms = pTimeOutms; - Type = EventType.Normal; + Type = EventType.LongPoll; } } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 1b9010a..4cb551c 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,12 +47,11 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_slowRequests = new Queue(); - private static Queue m_retryRequests = new Queue(); + private static Queue m_longPollRequests = new Queue(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_retrysThread; + private Thread m_longPollThread; private bool m_running = true; private int slowCount = 0; @@ -84,9 +83,9 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_retrysThread = Watchdog.StartThread( - this.CheckRetries, - string.Format("PollServiceWatcherThread:{0}", m_server.Port), + m_longPollThread = Watchdog.StartThread( + this.CheckLongPollThreads, + string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, false, true, @@ -97,48 +96,47 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - { - lock (m_retryRequests) - m_retryRequests.Enqueue(req); - } + m_requests.Enqueue(req); } public void Enqueue(PollServiceHttpRequest req) { if (m_running) { - if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) { - m_requests.Enqueue(req); + lock (m_longPollRequests) + m_longPollRequests.Enqueue(req); } else - { - lock (m_slowRequests) - m_slowRequests.Enqueue(req); - } + m_requests.Enqueue(req); } } - private void CheckRetries() + private void CheckLongPollThreads() { + // The only purpose of this thread is to check the EQs for events. + // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. + // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. + // All other types of tasks (Inventory handlers) don't have the long-poll nature, + // so if they aren't ready to be served by a worker thread (no events), they are placed + // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(100); // let the world move .. back to faster rate + Thread.Sleep(1000); Watchdog.UpdateThread(); - lock (m_retryRequests) - { - while (m_retryRequests.Count > 0 && m_running) - m_requests.Enqueue(m_retryRequests.Dequeue()); - } - slowCount++; - if (slowCount >= 10) - { - slowCount = 0; - lock (m_slowRequests) + PollServiceHttpRequest req; + lock (m_longPollRequests) + { + while (m_longPollRequests.Count > 0 && m_running) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + req = m_longPollRequests.Dequeue(); + if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ + (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout + m_requests.Enqueue(req); + else + m_longPollRequests.Enqueue(req); } } } @@ -153,24 +151,12 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (Thread t in m_workerThreads) Watchdog.AbortThread(t.ManagedThreadId); - try - { - foreach (PollServiceHttpRequest req in m_retryRequests) - { - req.DoHTTPGruntWork(m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); - } - } - catch - { - } - PollServiceHttpRequest wreq; - m_retryRequests.Clear(); - lock (m_slowRequests) + lock (m_longPollRequests) { - while (m_slowRequests.Count > 0 && m_running) - m_requests.Enqueue(m_slowRequests.Dequeue()); + while (m_longPollRequests.Count > 0 && m_running) + m_requests.Enqueue(m_longPollRequests.Dequeue()); } while (m_requests.Count() > 0) @@ -196,6 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer while (m_running) { PollServiceHttpRequest req = m_requests.Dequeue(5000); + //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); Watchdog.UpdateThread(); if (req != null) @@ -209,7 +196,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (responsedata == null) continue; - if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue + if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue { try { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 1835a72..f0445ff 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -364,8 +364,7 @@ namespace OpenSim.Region.ClientStack.Linden caps.RegisterPollHandler( "EventQueueGet", - new PollServiceEventArgs( - null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -383,7 +382,10 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) + { + //m_log.WarnFormat("POLLED FOR EVENTS BY {0} in {1} -- {2}", agentID, m_scene.RegionInfo.RegionName, queue.Count); return queue.Count > 0; + } return false; } @@ -406,7 +408,7 @@ namespace OpenSim.Region.ClientStack.Linden public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; -- cgit v1.1 From ad198a714ca4a659110b1aea2e7bb5dea34a7d13 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:24:43 -0700 Subject: Revert "Revert "Didn't mean to commit this change in BlockingQueue.cs"" This reverts commit fda91d93dad1fa6f901e8db5829aa8b70477c97e. --- OpenSim/Framework/BlockingQueue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index e607e64..aef1192 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework { lock (m_queueSync) { - while (m_queue.Count < 1 && m_pqueue.Count < 1) + if (m_queue.Count < 1 && m_pqueue.Count < 1) { Monitor.Wait(m_queueSync, msTimeout); } -- cgit v1.1 From 552b85d33d4dc465d84fccb0c6e14c2f45213716 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:25:04 -0700 Subject: Revert "Revert "Putting the requests back in the queue while testing for count >0 is not the smartest move..."" This reverts commit 71278919575b0e0222cdbe3c0cefa5919f9a75bc. --- .../Framework/Servers/HttpServer/PollServiceRequestManager.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 4cb551c..c50df5a 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -126,18 +126,22 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(1000); Watchdog.UpdateThread(); - PollServiceHttpRequest req; + List not_ready = new List(); lock (m_longPollRequests) { while (m_longPollRequests.Count > 0 && m_running) { - req = m_longPollRequests.Dequeue(); + PollServiceHttpRequest req = m_longPollRequests.Dequeue(); if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout m_requests.Enqueue(req); else - m_longPollRequests.Enqueue(req); + not_ready.Add(req); } + + foreach (PollServiceHttpRequest req in not_ready) + m_longPollRequests.Enqueue(req); + } } } -- cgit v1.1 From a22a4db5cec02637b7653870d09b69c810d7dfe9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:25:22 -0700 Subject: Revert "Revert "Do the same trick that dahlia did for Dequeue(timeout)"" This reverts commit 5495df74436d6c0039a1500d979a964b003abfdf. --- OpenSim/Framework/BlockingQueue.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192..fb74a24 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,9 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - if (m_queue.Count < 1 && m_pqueue.Count < 1) + bool timedout = false; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) { - Monitor.Wait(m_queueSync, msTimeout); + timedout = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) -- cgit v1.1 From 71b1511db5c697a2748c87adafe94db8ce408a8d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 12:25:47 -0700 Subject: Revert "Revert "I confuse myself. Let's try this variable name instead."" This reverts commit 52dc7b2a96a28798d55d07d79d003ce5e3d35216. --- OpenSim/Framework/BlockingQueue.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index fb74a24..3e90fac 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs @@ -76,10 +76,10 @@ namespace OpenSim.Framework { lock (m_queueSync) { - bool timedout = false; - while (m_queue.Count < 1 && m_pqueue.Count < 1 && !timedout) + bool success = true; + while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) { - timedout = Monitor.Wait(m_queueSync, msTimeout); + success = Monitor.Wait(m_queueSync, msTimeout); } if (m_pqueue.Count > 0) -- cgit v1.1 From d9d995914c5fba00d4ccaf66b899384c8ea3d5eb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 01:17:46 +0100 Subject: try Hacking in an AutoResetEvent to control the outgoing UDP loop instead of a continuous loop with sleeps. Does appear to have a cpu impact but may need further tweaking --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 20 ++++++++++++++++++++ OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 10 ++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 79c80a7..7229d7c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -3776,6 +3776,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP ResendPrimUpdate(update); } +// 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>(); + + private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3788,6 +3799,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdates = new OpenSim.Framework.Lazy>(); +// objectUpdateBlocks.Value.Clear(); +// compressedUpdateBlocks.Value.Clear(); +// terseUpdateBlocks.Value.Clear(); +// terseAgentUpdateBlocks.Value.Clear(); +// objectUpdates.Value.Clear(); +// compressedUpdates.Value.Clear(); +// terseUpdates.Value.Clear(); +// terseAgentUpdates.Value.Clear(); + // Check to see if this is a flush if (maxUpdates <= 0) { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 85270a6..54cafb2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -806,8 +806,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } PacketPool.Instance.ReturnPacket(packet); + m_dataPresentEvent.Set(); + } + private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); + /// /// Start the process of sending a packet to the client. /// @@ -1658,6 +1662,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Action generic every round Action clientPacketHandler = ClientOutgoingPacketHandler; +// while (true) while (base.IsRunningOutbound) { try @@ -1718,8 +1723,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If nothing was sent, sleep for the minimum amount of time before a // token bucket could get more tokens - if (!m_packetSent) - Thread.Sleep((int)TickCountResolution); + //if (!m_packetSent) + // Thread.Sleep((int)TickCountResolution); + m_dataPresentEvent.WaitOne(100); Watchdog.UpdateThread(); } -- cgit v1.1 From b5062ae7ee4067158f255a0d62fb87b8eaf9d1d6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 13:30:04 -0700 Subject: Changed the timoeut of EQ 502s (no events) to 50 secs. The viewer post requests timeout in 60 secs. There's plenty of room for improvement in handling the EQs. Some other time... --- .../Framework/Servers/HttpServer/PollServiceRequestManager.cs | 2 +- .../ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index c50df5a..e811079 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -118,7 +118,7 @@ namespace OpenSim.Framework.Servers.HttpServer // The only purpose of this thread is to check the EQs for events. // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. - // All other types of tasks (Inventory handlers) don't have the long-poll nature, + // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, // so if they aren't ready to be served by a worker thread (no events), they are placed // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index f0445ff..c5e28ad 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -65,6 +65,13 @@ namespace OpenSim.Region.ClientStack.Linden /// public int DebugLevel { get; set; } + // Viewer post requests timeout in 60 secs + // https://bitbucket.org/lindenlab/viewer-release/src/421c20423df93d650cc305dc115922bb30040999/indra/llmessage/llhttpclient.cpp?at=default#cl-44 + // + private const int VIEWER_TIMEOUT = 60 * 1000; + // Just to be safe, we work on a 10 sec shorter cycle + private const int SERVER_EQ_TIME_NO_EVENTS = VIEWER_TIMEOUT - (10 * 1000); + protected Scene m_scene; private Dictionary m_ids = new Dictionary(); @@ -363,8 +370,8 @@ namespace OpenSim.Region.ClientStack.Linden } caps.RegisterPollHandler( - "EventQueueGet", - new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, 40000)); + "EventQueueGet", + new PollServiceEventArgs(null, GenerateEqgCapPath(eventQueueGetUUID), HasEvents, GetEvents, NoEvents, agentID, SERVER_EQ_TIME_NO_EVENTS)); Random rnd = new Random(Environment.TickCount); lock (m_ids) -- cgit v1.1 From edef7472d1060435334d7803728517d559a717e7 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 18 Jul 2013 13:33:50 -0700 Subject: Enable storing of environment settings in NullSimulationData --- OpenSim/Data/Null/NullSimulationData.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs index 4979cf6..d11ad72 100644 --- a/OpenSim/Data/Null/NullSimulationData.cs +++ b/OpenSim/Data/Null/NullSimulationData.cs @@ -77,20 +77,34 @@ namespace OpenSim.Data.Null } #region Environment Settings + + private Dictionary EnvironmentSettings = new Dictionary(); + public string LoadRegionEnvironmentSettings(UUID regionUUID) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + if (EnvironmentSettings.ContainsKey(regionUUID)) + return EnvironmentSettings[regionUUID]; + } return string.Empty; } public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + EnvironmentSettings[regionUUID] = settings; + } } public void RemoveRegionEnvironmentSettings(UUID regionUUID) { - //This connector doesn't support the Environment module yet + lock (EnvironmentSettings) + { + if (EnvironmentSettings.ContainsKey(regionUUID)) + EnvironmentSettings.Remove(regionUUID); + } } #endregion -- cgit v1.1 From 1d65b0d80296a672c8023293aee7d0a01bad4066 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 18 Jul 2013 19:09:55 -0700 Subject: BulletSim: add position resetting for stationary avatars so they don't move around when standing on a stationary object. Create proper linkage between BSCharacter and its actor by generating a UpdatedProperties event the same way BSPrim does. --- .../Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | 17 ++++++++++++++++- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 8 ++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 928b350..0f11c4a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -130,6 +130,7 @@ public class BSActorAvatarMove : BSActor SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); m_physicsScene.BeforeStep += Mover; + m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; m_walkingUpStairs = 0; } @@ -139,6 +140,7 @@ public class BSActorAvatarMove : BSActor { if (m_velocityMotor != null) { + m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; m_physicsScene.BeforeStep -= Mover; m_velocityMotor = null; } @@ -197,7 +199,7 @@ public class BSActorAvatarMove : BSActor { if (m_controllingPrim.Flying) { - // Flying and not collising and velocity nearly zero. + // Flying and not colliding and velocity nearly zero. m_controllingPrim.ZeroMotion(true /* inTaintTime */); } } @@ -266,6 +268,19 @@ public class BSActorAvatarMove : BSActor } } + // Called just as the property update is received from the physics engine. + // Do any mode necessary for avatar movement. + private void Process_OnPreUpdateProperty(ref EntityProperties entprop) + { + // Don't change position if standing on a stationary object. + if (m_controllingPrim.IsStationary) + { + entprop.Position = m_controllingPrim.RawPosition; + m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); + } + + } + // Decide if the character is colliding with a low object and compute a force to pop the // avatar up so it can walk up and over the low objects. private OMV.Vector3 WalkUpStairs() diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index c9e3ca0..59e7f5f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -709,10 +709,10 @@ public sealed class BSCharacter : BSPhysObject // the world that things have changed. public override void UpdateProperties(EntityProperties entprop) { - // Don't change position if standing on a stationary object. - if (!IsStationary) - RawPosition = entprop.Position; + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. + TriggerPreUpdatePropertyAction(ref entprop); + RawPosition = entprop.Position; RawOrientation = entprop.Rotation; // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar @@ -740,7 +740,7 @@ public sealed class BSCharacter : BSPhysObject // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. - // base.RequestPhysicsterseUpdate(); + // PhysScene.PostUpdate(this); DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); -- cgit v1.1 From c1705236c7b0fe779c52b56a4531eb036817de89 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 19 Jul 2013 20:24:56 -0700 Subject: Fix HGTravelStore.migrations in SQLite (mantis #6709) --- .../Data/SQLite/Resources/HGTravelStore.migrations | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations index 2e73caa..02612ce 100644 --- a/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations +++ b/OpenSim/Data/SQLite/Resources/HGTravelStore.migrations @@ -1,18 +1,18 @@ -:VERSION 1 # -------------------------- +:VERSION 2 # -------------------------- BEGIN; -CREATE TABLE hg_traveling_data ( +CREATE TABLE hg_traveling_data( SessionID VARCHAR(36) NOT NULL, UserID VARCHAR(36) NOT NULL, - GridExternalName VARCHAR(255) NOT NULL DEFAULT '', - ServiceToken VARCHAR(255) NOT NULL DEFAULT '', - ClientIPAddress VARCHAR(16) NOT NULL DEFAULT '', - MyIPAddress VARCHAR(16) NOT NULL DEFAULT '', - TMStamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`SessionID`), - KEY (`UserID`) -) ENGINE=InnoDB; + GridExternalName VARCHAR(255) NOT NULL DEFAULT "", + ServiceToken VARCHAR(255) NOT NULL DEFAULT "", + ClientIPAddress VARCHAR(16) NOT NULL DEFAULT "", + MyIPAddress VARCHAR(16) NOT NULL DEFAULT "", + TMStamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(SessionID), + UNIQUE(UserID) +); COMMIT; -- cgit v1.1 From 63c42d66022ea7f1c2805b8f77980af5d4ba1fb4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 21:28:36 +0100 Subject: Do some simple queue empty checks in the main outgoing udp loop instead of always performing these on a separate fired thread. This appears to improve cpu usage since launching a new thread is more expensive than performing a small amount of inline logic. However, needs testing at scale. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 28 +++++++++ .../ClientStack/Linden/UDP/LLImageManager.cs | 7 +++ .../Region/ClientStack/Linden/UDP/LLUDPClient.cs | 69 ++++++++++++++++------ .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 4 +- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 6 +- 5 files changed, 92 insertions(+), 22 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 7229d7c..711a574 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -485,6 +485,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpServer = udpServer; m_udpClient = udpClient; m_udpClient.OnQueueEmpty += HandleQueueEmpty; + m_udpClient.HasUpdates += HandleHasUpdates; m_udpClient.OnPacketStats += PopulateStats; m_prioritizer = new Prioritizer(m_scene); @@ -4133,8 +4134,14 @@ 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; @@ -4160,6 +4167,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP ImageManager.ProcessImageQueue(m_udpServer.TextureSendLimit); } + 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; + } + + if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) + { + if (ImageManager.HasUpdates()) + hasUpdates = true; + } + + return hasUpdates; + } + public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) { AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs index 073c357..41dd4d1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs @@ -206,6 +206,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + public bool HasUpdates() + { + J2KImage image = GetHighestPriorityImage(); + + return image != null && image.IsDecoded; + } + public bool ProcessImageQueue(int packetsToSend) { int packetsSent = 0; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 7749446..202cc62 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -31,6 +31,7 @@ using System.Net; using System.Threading; using log4net; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; using OpenMetaverse; using OpenMetaverse.Packets; @@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// hooked to put more data on the empty queue public event QueueEmpty OnQueueEmpty; + public event Func HasUpdates; + /// AgentID for this client public readonly UUID AgentID; /// The remote address of the connected client @@ -613,15 +616,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Throttle categories to fire the callback for private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) { - if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) +// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) + if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) { + m_isQueueEmptyRunning = true; + + int start = Environment.TickCount & Int32.MaxValue; + const int MIN_CALLBACK_MS = 30; + + m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; + if (m_nextOnQueueEmpty == 0) + m_nextOnQueueEmpty = 1; + // Use a value of 0 to signal that FireQueueEmpty is running - m_nextOnQueueEmpty = 0; - // Asynchronously run the callback - Util.FireAndForget(FireQueueEmpty, categories); +// m_nextOnQueueEmpty = 0; + + m_categories = categories; + + if (HasUpdates(m_categories)) + { + // Asynchronously run the callback + Util.FireAndForget(FireQueueEmpty, categories); + } + else + { + m_isQueueEmptyRunning = false; + } } } + private bool m_isQueueEmptyRunning; + private ThrottleOutPacketTypeFlags m_categories = 0; + /// /// Fires the OnQueueEmpty callback and sets the minimum time that it /// can be called again @@ -631,22 +657,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// signature private void FireQueueEmpty(object o) { - const int MIN_CALLBACK_MS = 30; +// int start = Environment.TickCount & Int32.MaxValue; +// const int MIN_CALLBACK_MS = 30; - ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; - QueueEmpty callback = OnQueueEmpty; - - int start = Environment.TickCount & Int32.MaxValue; +// if (m_udpServer.IsRunningOutbound) +// { + ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; + QueueEmpty callback = OnQueueEmpty; - if (callback != null) - { - try { callback(categories); } - catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } - } + if (callback != null) + { +// if (m_udpServer.IsRunningOutbound) +// { + try { callback(categories); } + catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } +// } + } +// } + +// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; +// if (m_nextOnQueueEmpty == 0) +// m_nextOnQueueEmpty = 1; + +// } - m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; - if (m_nextOnQueueEmpty == 0) - m_nextOnQueueEmpty = 1; + m_isQueueEmptyRunning = false; } /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 54cafb2..e871ca2 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1662,8 +1662,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Action generic every round Action clientPacketHandler = ClientOutgoingPacketHandler; -// while (true) - while (base.IsRunningOutbound) + while (true) +// while (base.IsRunningOutbound) { try { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index f143c32..512f60d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -308,8 +308,8 @@ namespace OpenMetaverse public void AsyncBeginSend(UDPPacketBuffer buf) { - if (IsRunningOutbound) - { +// if (IsRunningOutbound) +// { try { m_udpSocket.BeginSendTo( @@ -323,7 +323,7 @@ namespace OpenMetaverse } catch (SocketException) { } catch (ObjectDisposedException) { } - } +// } } void AsyncEndSend(IAsyncResult result) -- cgit v1.1 From 98d47ea428cd31b302e33dc6015a889d38bcb267 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 18 Jul 2013 17:17:20 -0700 Subject: Delay the enqueueing of non-longpoll requests for 100ms. No need to have these requests actively on the processing queue if it seems they're not ready. --- .../Servers/HttpServer/PollServiceRequestManager.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index e811079..727dbe5 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -96,7 +96,17 @@ namespace OpenSim.Framework.Servers.HttpServer private void ReQueueEvent(PollServiceHttpRequest req) { if (m_running) - m_requests.Enqueue(req); + { + // delay the enqueueing for 100ms. There's no need to have the event + // actively on the queue + Timer t = new Timer(self => { + ((Timer)self).Dispose(); + m_requests.Enqueue(req); + }); + + t.Change(100, Timeout.Infinite); + + } } public void Enqueue(PollServiceHttpRequest req) -- cgit v1.1 From 3a476bf60ce6364f5fd562132625027b73606fea Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 22:42:25 +0100 Subject: Fix up a temporary debugging change from last commit which stopped "lludp stop out" from actually doing anything --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index e871ca2..a1085fa 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1662,8 +1662,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Action generic every round Action clientPacketHandler = ClientOutgoingPacketHandler; - while (true) -// while (base.IsRunningOutbound) + while (base.IsRunningOutbound) { try { -- cgit v1.1 From 66048e1a7024f151739fdb0be2309787a76c8403 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 22:54:10 +0100 Subject: minor: provide user feedback in the log for now when udp in/out bound threads are started/stopped --- OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 512f60d..a919141 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -111,6 +111,8 @@ namespace OpenMetaverse if (!IsRunningInbound) { + m_log.DebugFormat("[UDPBASE]: Starting inbound UDP loop"); + const int SIO_UDP_CONNRESET = -1744830452; IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); @@ -155,6 +157,8 @@ namespace OpenMetaverse /// public void StartOutbound() { + m_log.DebugFormat("[UDPBASE]: Starting outbound UDP loop"); + IsRunningOutbound = true; } @@ -162,10 +166,8 @@ namespace OpenMetaverse { if (IsRunningInbound) { - // wait indefinitely for a writer lock. Once this is called, the .NET runtime - // will deny any more reader locks, in effect blocking all other send/receive - // threads. Once we have the lock, we set IsRunningInbound = false to inform the other - // threads that the socket is closed. + m_log.DebugFormat("[UDPBASE]: Stopping inbound UDP loop"); + IsRunningInbound = false; m_udpSocket.Close(); } @@ -173,6 +175,8 @@ namespace OpenMetaverse public void StopOutbound() { + m_log.DebugFormat("[UDPBASE]: Stopping outbound UDP loop"); + IsRunningOutbound = false; } -- cgit v1.1 From 5a2d4d888c02bef984f42eecaec62164a1e58b72 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 23:05:45 +0100 Subject: Hack in console command "debug lludp toggle agentupdate" to allow AgentUpdate in packets to be discarded at a very early stage. Enabling this will stop anybody from moving on a sim, though all other updates should be unaffected. Appears to make some cpu difference on very basic testing with a static standing avatar (though not all that much). Need to see the results with much higher av numbers. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index a1085fa..78d4165 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -572,6 +572,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP "debug lludp status", "Return status of LLUDP packet processing.", HandleStatusCommand); + + MainConsole.Instance.Commands.AddCommand( + "Debug", + false, + "debug lludp toggle agentupdate", + "debug lludp toggle agentupdate", + "Toggle whether agentupdate packets are processed or simply discarded.", + HandleAgentUpdateCommand); } private void HandlePacketCommand(string module, string[] args) @@ -706,6 +714,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + bool m_discardAgentUpdates; + + private void HandleAgentUpdateCommand(string module, string[] args) + { + if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) + return; + + m_discardAgentUpdates = !m_discardAgentUpdates; + + MainConsole.Instance.OutputFormat( + "Discard AgentUpdates now {0} for {1}", m_discardAgentUpdates, m_scene.Name); + } + private void HandleStatusCommand(string module, string[] args) { if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) @@ -1286,6 +1307,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); #endregion BinaryStats + if (m_discardAgentUpdates && packet.Type == PacketType.AgentUpdate) + return; + #region Ping Check Handling if (packet.Type == PacketType.StartPingCheck) -- cgit v1.1 From e5c677779b8501c245e5399240ffe3ca2519ec72 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 19 Jul 2013 00:16:09 +0100 Subject: Add measure of number of inbound AgentUpdates that were seen as significant to "show client stats" (i.e. sent on for further processing instead of being discarded) Added here since it was the most convenient place Number is in the last column, "Sig. AgentUpdates" along with percentage of all AgentUpdates Percentage largely falls over time, most cpu for processing AgentUpdates may be in UDP processing as turning this off even earlier (with "debug lludp toggle agentupdate" results in a big cpu fall Also tidies up display. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 3 +++ .../OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 711a574..3145275 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5565,6 +5565,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Packet Handlers + public int TotalSignificantAgentUpdates { get; private set; } + #region Scene/Avatar private bool HandleAgentUpdate(IClientAPI sener, Packet packet) @@ -5614,6 +5616,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (update) { // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); + TotalSignificantAgentUpdates++; m_lastAgentUpdateArgs.AgentID = x.AgentID; m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index 79509ab..c208b38 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -611,7 +611,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden // if (showParams.Length <= 4) { - m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,6} {3,11} {4, 10}", "Region", "Name", "Root", "Time", "Reqs/min"); + m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "Sig. AgentUpdates"); foreach (Scene scene in m_scenes.Values) { scene.ForEachClient( @@ -624,9 +624,15 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); - m_log.InfoFormat("[INFO]: {0,-12} {1,20} {2,4} {3,9}min {4,10}", + m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11}/min {5,-16}", scene.RegionInfo.RegionName, llClient.Name, - (llClient.SceneAgent.IsChildAgent ? "N" : "Y"), (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs); + llClient.SceneAgent.IsChildAgent ? "N" : "Y", + (DateTime.Now - cinfo.StartedTime).Minutes, + avg_reqs, + string.Format( + "{0}, {1}%", + llClient.TotalSignificantAgentUpdates, + (float)llClient.TotalSignificantAgentUpdates / cinfo.SyncRequests["AgentUpdate"] * 100)); } }); } -- cgit v1.1 From 61eda1f441092eb12936472de2dc73898e40aa16 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 19 Jul 2013 00:51:13 +0100 Subject: Make the check as to whether any particular inbound AgentUpdate packet is significant much earlier in UDP processing (i.e. before we pointlessly place such packets on internal queues, etc.) Appears to have some impact on cpu but needs testing. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 170 ++++++++++++++------- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 17 ++- .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 4 +- 3 files changed, 131 insertions(+), 60 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 3145275..7e5511f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -357,7 +357,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods /// cannot retain a reference to it outside of that method. /// - private AgentUpdateArgs m_lastAgentUpdateArgs; + private AgentUpdateArgs m_lastAgentUpdateArgs = new AgentUpdateArgs(); + + private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); protected Dictionary m_packetHandlers = new Dictionary(); protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers @@ -5569,80 +5571,136 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Scene/Avatar + /// + /// This checks the update significance against the last update made. + /// + /// Can only be called by one thread at a time, and not at the same time as + /// + /// /returns> + /// + public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + { + bool update = false; + + if (m_lastAgentUpdateArgs != null) + { + // These should be ordered from most-likely to + // least likely to change. I've made an initial + // guess at that. + update = + ( + (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || + (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || + (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || + (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || + (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || + (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || + (x.Far != m_lastAgentUpdateArgs.Far) || + (x.Flags != m_lastAgentUpdateArgs.Flags) || + (x.State != m_lastAgentUpdateArgs.State) || + (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || + (x.SessionID != m_lastAgentUpdateArgs.SessionID) || + (x.AgentID != m_lastAgentUpdateArgs.AgentID) + ); + } + else + { + m_lastAgentUpdateArgs = new AgentUpdateArgs(); + update = true; + } + + if (update) + { +// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); + TotalSignificantAgentUpdates++; + + m_lastAgentUpdateArgs.AgentID = x.AgentID; + m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; + m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; + m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; + m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; + m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; + m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; + m_lastAgentUpdateArgs.Far = x.Far; + m_lastAgentUpdateArgs.Flags = x.Flags; + m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; + m_lastAgentUpdateArgs.SessionID = x.SessionID; + m_lastAgentUpdateArgs.State = x.State; + } + + return update; + } + private bool HandleAgentUpdate(IClientAPI sener, Packet packet) { if (OnAgentUpdate != null) { AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; - #region Packet Session and User Check - if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) - { - PacketPool.Instance.ReturnPacket(packet); - return false; - } - #endregion - - bool update = false; + // Now done earlier +// #region Packet Session and User Check +// if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) +// { +// PacketPool.Instance.ReturnPacket(packet); +// return false; +// } +// #endregion +// +// bool update = false; AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; - - if (m_lastAgentUpdateArgs != null) - { - // These should be ordered from most-likely to - // least likely to change. I've made an initial - // guess at that. - update = - ( - (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || - (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || - (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || - (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || - (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || - (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || - (x.Far != m_lastAgentUpdateArgs.Far) || - (x.Flags != m_lastAgentUpdateArgs.Flags) || - (x.State != m_lastAgentUpdateArgs.State) || - (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || - (x.SessionID != m_lastAgentUpdateArgs.SessionID) || - (x.AgentID != m_lastAgentUpdateArgs.AgentID) - ); - } - else - { - m_lastAgentUpdateArgs = new AgentUpdateArgs(); - update = true; - } - - if (update) - { -// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); +// +// if (m_lastAgentUpdateArgs != null) +// { +// // These should be ordered from most-likely to +// // least likely to change. I've made an initial +// // guess at that. +// update = +// ( +// (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || +// (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || +// (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || +// (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || +// (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || +// (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || +// (x.Far != m_lastAgentUpdateArgs.Far) || +// (x.Flags != m_lastAgentUpdateArgs.Flags) || +// (x.State != m_lastAgentUpdateArgs.State) || +// (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || +// (x.SessionID != m_lastAgentUpdateArgs.SessionID) || +// (x.AgentID != m_lastAgentUpdateArgs.AgentID) +// ); +// } +// +// if (update) +// { +//// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); TotalSignificantAgentUpdates++; - m_lastAgentUpdateArgs.AgentID = x.AgentID; - m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; - m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; - m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; - m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; - m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; - m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; - m_lastAgentUpdateArgs.Far = x.Far; - m_lastAgentUpdateArgs.Flags = x.Flags; - m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; - m_lastAgentUpdateArgs.SessionID = x.SessionID; - m_lastAgentUpdateArgs.State = x.State; + m_thisAgentUpdateArgs.AgentID = x.AgentID; + m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; + m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; + m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; + m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; + m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; + m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; + m_thisAgentUpdateArgs.Far = x.Far; + m_thisAgentUpdateArgs.Flags = x.Flags; + m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; + m_thisAgentUpdateArgs.SessionID = x.SessionID; + m_thisAgentUpdateArgs.State = x.State; UpdateAgent handlerAgentUpdate = OnAgentUpdate; UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; if (handlerPreAgentUpdate != null) - OnPreAgentUpdate(this, m_lastAgentUpdateArgs); + OnPreAgentUpdate(this, m_thisAgentUpdateArgs); if (handlerAgentUpdate != null) - OnAgentUpdate(this, m_lastAgentUpdateArgs); + OnAgentUpdate(this, m_thisAgentUpdateArgs); handlerAgentUpdate = null; handlerPreAgentUpdate = null; - } +// } } PacketPool.Instance.ReturnPacket(packet); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 78d4165..766c2fe 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1307,8 +1307,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); #endregion BinaryStats - if (m_discardAgentUpdates && packet.Type == PacketType.AgentUpdate) - return; + if (packet.Type == PacketType.AgentUpdate) + { + if (m_discardAgentUpdates) + return; + + AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; + + if (agentUpdate.AgentData.SessionID != client.SessionId + || agentUpdate.AgentData.AgentID != client.AgentId + || !((LLClientView)client).CheckAgentUpdateSignificance(agentUpdate.AgentData)) + { + PacketPool.Instance.ReturnPacket(packet); + return; + } + } #region Ping Check Handling diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index c208b38..3e6067d 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -611,7 +611,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden // if (showParams.Length <= 4) { - m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "Sig. AgentUpdates"); + m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "Sig. AgentUpdates"); foreach (Scene scene in m_scenes.Values) { scene.ForEachClient( @@ -624,7 +624,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); - m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11}/min {5,-16}", + m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", scene.RegionInfo.RegionName, llClient.Name, llClient.SceneAgent.IsChildAgent ? "N" : "Y", (DateTime.Now - cinfo.StartedTime).Minutes, -- cgit v1.1 From 866de5397890edbc0355b1925bf8537b40bab6a3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 19 Jul 2013 00:56:45 +0100 Subject: Remove some pointless code in CheckAgentUpdateSignificance() --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 50 +++++++++------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 7e5511f..c5bb697 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5574,40 +5574,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// This checks the update significance against the last update made. /// - /// Can only be called by one thread at a time, and not at the same time as - /// + /// Can only be called by one thread at a time /// /returns> /// public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - bool update = false; - - if (m_lastAgentUpdateArgs != null) - { - // These should be ordered from most-likely to - // least likely to change. I've made an initial - // guess at that. - update = - ( - (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || - (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || - (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || - (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || - (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || - (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || - (x.Far != m_lastAgentUpdateArgs.Far) || - (x.Flags != m_lastAgentUpdateArgs.Flags) || - (x.State != m_lastAgentUpdateArgs.State) || - (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || - (x.SessionID != m_lastAgentUpdateArgs.SessionID) || - (x.AgentID != m_lastAgentUpdateArgs.AgentID) - ); - } - else - { - m_lastAgentUpdateArgs = new AgentUpdateArgs(); - update = true; - } + // These should be ordered from most-likely to + // least likely to change. I've made an initial + // guess at that. + bool update = + ( + (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || + (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || + (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || + (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || + (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || + (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || + (x.Far != m_lastAgentUpdateArgs.Far) || + (x.Flags != m_lastAgentUpdateArgs.Flags) || + (x.State != m_lastAgentUpdateArgs.State) || + (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || + (x.SessionID != m_lastAgentUpdateArgs.SessionID) || + (x.AgentID != m_lastAgentUpdateArgs.AgentID) + ); + if (update) { -- cgit v1.1 From 3a6acbcc149fb359c2be2ee2c646c9b15809c01e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 19 Jul 2013 01:00:38 +0100 Subject: furhter shorten CheckAgentUpdateSignificance(). No real perf impact. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index c5bb697..3d085c3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5582,8 +5582,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // These should be ordered from most-likely to // least likely to change. I've made an initial // guess at that. - bool update = - ( + if ( (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || @@ -5596,10 +5595,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || (x.SessionID != m_lastAgentUpdateArgs.SessionID) || (x.AgentID != m_lastAgentUpdateArgs.AgentID) - ); - - - if (update) + ) { // m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); TotalSignificantAgentUpdates++; @@ -5616,9 +5612,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; m_lastAgentUpdateArgs.SessionID = x.SessionID; m_lastAgentUpdateArgs.State = x.State; + + return true; } - return update; + return false; } private bool HandleAgentUpdate(IClientAPI sener, Packet packet) -- cgit v1.1 From edafea6ae6dd3617520d989fb2fe748e3f0de1b3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 19 Jul 2013 13:17:15 -0700 Subject: PollServiceRequestManager: changed the long poll from a Queue to a List. No need to dequeue and enqueue items every 1sec. --- .../HttpServer/PollServiceRequestManager.cs | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 727dbe5..309b71f 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -47,7 +47,7 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly BaseHttpServer m_server; private BlockingQueue m_requests = new BlockingQueue(); - private static Queue m_longPollRequests = new Queue(); + private static List m_longPollRequests = new List(); private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; @@ -116,7 +116,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) { lock (m_longPollRequests) - m_longPollRequests.Enqueue(req); + m_longPollRequests.Add(req); } else m_requests.Enqueue(req); @@ -139,18 +139,21 @@ namespace OpenSim.Framework.Servers.HttpServer List not_ready = new List(); lock (m_longPollRequests) { - while (m_longPollRequests.Count > 0 && m_running) + if (m_longPollRequests.Count > 0 && m_running) { - PollServiceHttpRequest req = m_longPollRequests.Dequeue(); - if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ + List ready = m_longPollRequests.FindAll(req => + (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout - m_requests.Enqueue(req); - else - not_ready.Add(req); - } + ); - foreach (PollServiceHttpRequest req in not_ready) - m_longPollRequests.Enqueue(req); + ready.ForEach(req => + { + m_log.DebugFormat("[YYY]: --> Enqueuing"); + m_requests.Enqueue(req); + m_longPollRequests.Remove(req); + }); + + } } } @@ -169,8 +172,8 @@ namespace OpenSim.Framework.Servers.HttpServer lock (m_longPollRequests) { - while (m_longPollRequests.Count > 0 && m_running) - m_requests.Enqueue(m_longPollRequests.Dequeue()); + if (m_longPollRequests.Count > 0 && m_running) + m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); } while (m_requests.Count() > 0) @@ -186,6 +189,7 @@ namespace OpenSim.Framework.Servers.HttpServer } } + m_longPollRequests.Clear(); m_requests.Clear(); } -- cgit v1.1 From 18d5d8f5dd6445e232a571c0e346eb862afcffc3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 19 Jul 2013 13:19:36 -0700 Subject: Removed verbose debug from previous commit --- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 309b71f..d83daab 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -148,7 +148,6 @@ namespace OpenSim.Framework.Servers.HttpServer ready.ForEach(req => { - m_log.DebugFormat("[YYY]: --> Enqueuing"); m_requests.Enqueue(req); m_longPollRequests.Remove(req); }); -- cgit v1.1 From 174105ad028c5ed318850238d97aa7c3b1d7f207 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 19 Jul 2013 22:11:32 -0700 Subject: Fixed the stats in show client stats. Also left some comments with observations about AgentUpdates. --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 18 +++++++++++++----- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 ++ .../Agent/UDP/Linden/LindenUDPInfoModule.cs | 8 ++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 3d085c3..66a8ea7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5567,7 +5567,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Packet Handlers - public int TotalSignificantAgentUpdates { get; private set; } + public int TotalAgentUpdates { get; set; } #region Scene/Avatar @@ -5583,11 +5583,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP // least likely to change. I've made an initial // guess at that. if ( - (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || + /* These 4 are the worst offenders! We should consider ignoring most of them. + * With Singularity, there is a bug where sometimes the spam on these doesn't stop */ (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || + /* */ + (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || (x.Far != m_lastAgentUpdateArgs.Far) || (x.Flags != m_lastAgentUpdateArgs.Flags) || @@ -5597,8 +5600,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP (x.AgentID != m_lastAgentUpdateArgs.AgentID) ) { -// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); - TotalSignificantAgentUpdates++; + //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", + // x.CameraAtAxis, x.CameraCenter); + //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", + // x.CameraLeftAxis, x.CameraUpAxis); + //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", + // x.BodyRotation, x.HeadRotation); + //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", + // x.ControlFlags, x.Flags, x.Far, x.State); m_lastAgentUpdateArgs.AgentID = x.AgentID; m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; @@ -5662,7 +5671,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // if (update) // { //// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); - TotalSignificantAgentUpdates++; m_thisAgentUpdateArgs.AgentID = x.AgentID; m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 766c2fe..32282af 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1312,6 +1312,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_discardAgentUpdates) return; + ((LLClientView)client).TotalAgentUpdates++; + AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; if (agentUpdate.AgentData.SessionID != client.SessionId diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index 3e6067d..15dea17 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -611,7 +611,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden // if (showParams.Length <= 4) { - m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "Sig. AgentUpdates"); + m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", "Region", "Name", "Root", "Time", "Reqs/min", "AgentUpdates"); foreach (Scene scene in m_scenes.Values) { scene.ForEachClient( @@ -630,9 +630,9 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs, string.Format( - "{0}, {1}%", - llClient.TotalSignificantAgentUpdates, - (float)llClient.TotalSignificantAgentUpdates / cinfo.SyncRequests["AgentUpdate"] * 100)); + "{0} ({1:0.00}%)", + llClient.TotalAgentUpdates, + (float)cinfo.SyncRequests["AgentUpdate"] / llClient.TotalAgentUpdates * 100)); } }); } -- cgit v1.1 From d5a1779465b6d875ebe5822ce6f15df3378b759f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 20 Jul 2013 12:20:35 -0700 Subject: Manage AgentUpdates more sanely: - The existing event to scene has been split into 2: OnAgentUpdate and OnAgentCameraUpdate, to better reflect the two types of updates that the viewer sends. We can run one without the other, which is what happens when the avie is still but the user is camming around - Added thresholds (as opposed to equality) to determine whether the update is significant or not. I thin these thresholds are ok, but we can play with them later - Ignore updates of HeadRotation, which were problematic and aren't being used up stream --- OpenSim/Framework/IClientAPI.cs | 2 + .../Region/ClientStack/Linden/UDP/LLClientView.cs | 214 +++++++++++---------- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 110 +++++++---- .../Server/IRCClientView.cs | 1 + .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 1 + OpenSim/Tests/Common/Mock/TestClient.cs | 1 + 6 files changed, 183 insertions(+), 146 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 65f8395..f39eb0c 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -825,6 +825,8 @@ namespace OpenSim.Framework /// event UpdateAgent OnAgentUpdate; + event UpdateAgent OnAgentCameraUpdate; + event AgentRequestSit OnAgentRequestSit; event AgentSit OnAgentSit; event AvatarPickerRequest OnAvatarPickerRequest; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 66a8ea7..6c58aac 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -96,6 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; @@ -357,9 +358,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// This does mean that agent updates must be processed synchronously, at least for each client, and called methods /// cannot retain a reference to it outside of that method. /// - private AgentUpdateArgs m_lastAgentUpdateArgs = new AgentUpdateArgs(); - private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); + private float qdelta1; + private float qdelta2; + private float vdelta1; + private float vdelta2; + private float vdelta3; + private float vdelta4; protected Dictionary m_packetHandlers = new Dictionary(); protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers @@ -5571,57 +5576,75 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Scene/Avatar + private const float QDELTA = 0.01f; + private const float VDELTA = 0.01f; + /// /// This checks the update significance against the last update made. /// /// Can only be called by one thread at a time - /// /returns> + /// /// public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - // These should be ordered from most-likely to - // least likely to change. I've made an initial - // guess at that. + return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); + } + + /// + /// This checks the movement/state update significance against the last update made. + /// + /// Can only be called by one thread at a time + /// + /// + public bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + { + qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); + qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); + if ( + (qdelta1 > QDELTA) || + // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack + //(qdelta2 > QDELTA * 10) || + (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) || + (x.Far != m_thisAgentUpdateArgs.Far) || + (x.Flags != m_thisAgentUpdateArgs.Flags) || + (x.State != m_thisAgentUpdateArgs.State) + ) + { + //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", + // qdelta1, qdelta2); + //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3} (Thread {4})", + // x.ControlFlags, x.Flags, x.Far, x.State, Thread.CurrentThread.Name); + return true; + } + + return false; + } + + /// + /// This checks the camera update significance against the last update made. + /// + /// Can only be called by one thread at a time + /// + /// + public bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + { + vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); + vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); + vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); + vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); if ( - /* These 4 are the worst offenders! We should consider ignoring most of them. + /* These 4 are the worst offenders! * With Singularity, there is a bug where sometimes the spam on these doesn't stop */ - (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || - (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || - (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || - (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || - /* */ - (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || - (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || - (x.Far != m_lastAgentUpdateArgs.Far) || - (x.Flags != m_lastAgentUpdateArgs.Flags) || - (x.State != m_lastAgentUpdateArgs.State) || - (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || - (x.SessionID != m_lastAgentUpdateArgs.SessionID) || - (x.AgentID != m_lastAgentUpdateArgs.AgentID) + (vdelta1 > VDELTA) || + (vdelta2 > VDELTA) || + (vdelta3 > VDELTA) || + (vdelta4 > VDELTA) ) { //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", // x.CameraAtAxis, x.CameraCenter); //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", // x.CameraLeftAxis, x.CameraUpAxis); - //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", - // x.BodyRotation, x.HeadRotation); - //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", - // x.ControlFlags, x.Flags, x.Far, x.State); - - m_lastAgentUpdateArgs.AgentID = x.AgentID; - m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation; - m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; - m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter; - m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; - m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; - m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags; - m_lastAgentUpdateArgs.Far = x.Far; - m_lastAgentUpdateArgs.Flags = x.Flags; - m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation; - m_lastAgentUpdateArgs.SessionID = x.SessionID; - m_lastAgentUpdateArgs.State = x.State; - return true; } @@ -5629,75 +5652,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP } private bool HandleAgentUpdate(IClientAPI sener, Packet packet) - { - if (OnAgentUpdate != null) - { - AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; + { + // We got here, which means that something in agent update was significant - // Now done earlier -// #region Packet Session and User Check -// if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId) -// { -// PacketPool.Instance.ReturnPacket(packet); -// return false; -// } -// #endregion -// -// bool update = false; - AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; -// -// if (m_lastAgentUpdateArgs != null) -// { -// // These should be ordered from most-likely to -// // least likely to change. I've made an initial -// // guess at that. -// update = -// ( -// (x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) || -// (x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) || -// (x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) || -// (x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) || -// (x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) || -// (x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) || -// (x.Far != m_lastAgentUpdateArgs.Far) || -// (x.Flags != m_lastAgentUpdateArgs.Flags) || -// (x.State != m_lastAgentUpdateArgs.State) || -// (x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) || -// (x.SessionID != m_lastAgentUpdateArgs.SessionID) || -// (x.AgentID != m_lastAgentUpdateArgs.AgentID) -// ); -// } -// -// if (update) -// { -//// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name); - - m_thisAgentUpdateArgs.AgentID = x.AgentID; - m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; - m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; - m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; - m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; - m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; - m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; - m_thisAgentUpdateArgs.Far = x.Far; - m_thisAgentUpdateArgs.Flags = x.Flags; - m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; - m_thisAgentUpdateArgs.SessionID = x.SessionID; - m_thisAgentUpdateArgs.State = x.State; - - UpdateAgent handlerAgentUpdate = OnAgentUpdate; - UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; - - if (handlerPreAgentUpdate != null) - OnPreAgentUpdate(this, m_thisAgentUpdateArgs); - - if (handlerAgentUpdate != null) - OnAgentUpdate(this, m_thisAgentUpdateArgs); - - handlerAgentUpdate = null; - handlerPreAgentUpdate = null; -// } - } + AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; + AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData; + + if (x.AgentID != AgentId || x.SessionID != SessionId) + return false; + + // Before we update the current m_thisAgentUpdateArgs, let's check this again + // to see what exactly changed + bool movement = CheckAgentMovementUpdateSignificance(x); + bool camera = CheckAgentCameraUpdateSignificance(x); + + m_thisAgentUpdateArgs.AgentID = x.AgentID; + m_thisAgentUpdateArgs.BodyRotation = x.BodyRotation; + m_thisAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis; + m_thisAgentUpdateArgs.CameraCenter = x.CameraCenter; + m_thisAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis; + m_thisAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis; + m_thisAgentUpdateArgs.ControlFlags = x.ControlFlags; + m_thisAgentUpdateArgs.Far = x.Far; + m_thisAgentUpdateArgs.Flags = x.Flags; + m_thisAgentUpdateArgs.HeadRotation = x.HeadRotation; + m_thisAgentUpdateArgs.SessionID = x.SessionID; + m_thisAgentUpdateArgs.State = x.State; + + UpdateAgent handlerAgentUpdate = OnAgentUpdate; + UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate; + UpdateAgent handlerAgentCameraUpdate = OnAgentCameraUpdate; + + // Was there a significant movement/state change? + if (movement) + { + if (handlerPreAgentUpdate != null) + OnPreAgentUpdate(this, m_thisAgentUpdateArgs); + + if (handlerAgentUpdate != null) + OnAgentUpdate(this, m_thisAgentUpdateArgs); + } + // Was there a significant camera(s) change? + if (camera) + if (handlerAgentCameraUpdate != null) + handlerAgentCameraUpdate(this, m_thisAgentUpdateArgs); + + handlerAgentUpdate = null; + handlerPreAgentUpdate = null; + handlerAgentCameraUpdate = null; PacketPool.Instance.ReturnPacket(packet); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 990ef6e..5543964 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -801,6 +801,7 @@ namespace OpenSim.Region.Framework.Scenes { ControllingClient.OnCompleteMovementToRegion += CompleteMovement; ControllingClient.OnAgentUpdate += HandleAgentUpdate; + ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate; ControllingClient.OnAgentRequestSit += HandleAgentRequestSit; ControllingClient.OnAgentSit += HandleAgentSit; ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; @@ -1438,9 +1439,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", -// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); + //m_log.DebugFormat( + // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", + // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); if (IsChildAgent) { @@ -1448,10 +1449,6 @@ namespace OpenSim.Region.Framework.Scenes return; } - ++m_movementUpdateCount; - if (m_movementUpdateCount < 1) - m_movementUpdateCount = 1; - #region Sanity Checking // This is irritating. Really. @@ -1482,21 +1479,6 @@ namespace OpenSim.Region.Framework.Scenes AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; - // Camera location in world. We'll need to raytrace - // from this location from time to time. - CameraPosition = agentData.CameraCenter; - if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance) - { - ReprioritizeUpdates(); - m_lastCameraPosition = CameraPosition; - } - - // Use these three vectors to figure out what the agent is looking at - // Convert it to a Matrix and/or Quaternion - CameraAtAxis = agentData.CameraAtAxis; - CameraLeftAxis = agentData.CameraLeftAxis; - CameraUpAxis = agentData.CameraUpAxis; - // The Agent's Draw distance setting // When we get to the point of re-computing neighbors everytime this // changes, then start using the agent's drawdistance rather than the @@ -1504,12 +1486,6 @@ namespace OpenSim.Region.Framework.Scenes // DrawDistance = agentData.Far; DrawDistance = Scene.DefaultDrawDistance; - // 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; - m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; @@ -1529,17 +1505,6 @@ namespace OpenSim.Region.Framework.Scenes StandUp(); } - //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); - } - } - uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); @@ -1764,9 +1729,74 @@ namespace OpenSim.Region.Framework.Scenes } m_scene.EventManager.TriggerOnClientMovement(this); - TriggerScenePresenceUpdated(); } + + /// + /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering. + /// + public void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) + { + //m_log.DebugFormat( + // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}", + // 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; + + + AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; + + // Camera location in world. We'll need to raytrace + // from this location from time to time. + CameraPosition = agentData.CameraCenter; + if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance) + { + ReprioritizeUpdates(); + m_lastCameraPosition = CameraPosition; + } + + // Use these three vectors to figure out what the agent is looking at + // Convert it to a Matrix and/or Quaternion + CameraAtAxis = agentData.CameraAtAxis; + CameraLeftAxis = agentData.CameraLeftAxis; + CameraUpAxis = agentData.CameraUpAxis; + + // The Agent's Draw distance setting + // When we get to the point of re-computing neighbors everytime this + // changes, then start using the agent's drawdistance rather than the + // region's draw distance. + // DrawDistance = agentData.Far; + DrawDistance = Scene.DefaultDrawDistance; + + // 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; + + + //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); + } + } + + TriggerScenePresenceUpdated(); + } + /// /// Calculate an update to move the presence to the set target. /// diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 3726191..9b69da3 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -687,6 +687,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 592e4e1..6c38b65 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -258,6 +258,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 2fc3f0b..5d7349a 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -106,6 +106,7 @@ namespace OpenSim.Tests.Common.Mock public event Action OnCompleteMovementToRegion; public event UpdateAgent OnPreAgentUpdate; public event UpdateAgent OnAgentUpdate; + public event UpdateAgent OnAgentCameraUpdate; public event AgentRequestSit OnAgentRequestSit; public event AgentSit OnAgentSit; public event AvatarPickerRequest OnAvatarPickerRequest; -- cgit v1.1 From 3919c805054e6ce240c72436414ecee18a6c2947 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 20 Jul 2013 13:42:39 -0700 Subject: A couple of small optimizations over the previous commit --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 18 ++++++++++-------- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 6c58aac..2907580 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5587,6 +5587,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { + // Compute these only once, when this function is called from down below + qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); + //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); + vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); + vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); + vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); + vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); + return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); } @@ -5596,10 +5604,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Can only be called by one thread at a time /// /// - public bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); - qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); if ( (qdelta1 > QDELTA) || // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack @@ -5626,12 +5632,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Can only be called by one thread at a time /// /// - public bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) + private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); - vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); - vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); - vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); if ( /* These 4 are the worst offenders! * With Singularity, there is a bug where sometimes the spam on these doesn't stop */ diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 5543964..2359f55 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1735,7 +1735,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering. /// - public void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) + private void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) { //m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}", -- cgit v1.1 From 032c637c10ee16f5a3b9b690de812701f3badee6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 20 Jul 2013 15:42:01 -0700 Subject: Filter certain viewer effects depending on distance between the avatar that is generating the effect and the cameras of the observers. In particular, this applies to LookAt (which is really verbose and occurs every time users move the mouse) and Beam (which doesn't occur that often, but that can be extremely noisy (10.sec) when it happens) --- .../Framework/Scenes/Scene.PacketHandlers.cs | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index df43271..998c19e 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -390,6 +390,7 @@ namespace OpenSim.Region.Framework.Scenes void ProcessViewerEffect(IClientAPI remoteClient, List args) { // TODO: don't create new blocks if recycling an old packet + bool discardableEffects = true; ViewerEffectPacket.EffectBlock[] effectBlockArray = new ViewerEffectPacket.EffectBlock[args.Count]; for (int i = 0; i < args.Count; i++) { @@ -401,17 +402,34 @@ namespace OpenSim.Region.Framework.Scenes effect.Type = args[i].Type; effect.TypeData = args[i].TypeData; effectBlockArray[i] = effect; + + if ((EffectType)effect.Type != EffectType.LookAt && (EffectType)effect.Type != EffectType.Beam) + discardableEffects = false; + + //m_log.DebugFormat("[YYY]: VE {0} {1} {2}", effect.AgentID, effect.Duration, (EffectType)effect.Type); } - ForEachClient( - delegate(IClientAPI client) + ForEachScenePresence(sp => { - if (client.AgentId != remoteClient.AgentId) - client.SendViewerEffect(effectBlockArray); - } - ); + if (sp.ControllingClient.AgentId != remoteClient.AgentId) + { + if (!discardableEffects || + (discardableEffects && ShouldSendDiscardableEffect(remoteClient, sp))) + { + //m_log.DebugFormat("[YYY]: Sending to {0}", sp.UUID); + sp.ControllingClient.SendViewerEffect(effectBlockArray); + } + //else + // m_log.DebugFormat("[YYY]: Not sending to {0}", sp.UUID); + } + }); } - + + private bool ShouldSendDiscardableEffect(IClientAPI thisClient, ScenePresence other) + { + return Vector3.Distance(other.CameraPosition, thisClient.SceneAgent.AbsolutePosition) < 10; + } + /// /// Tell the client about the various child items and folders contained in the requested folder. /// -- cgit v1.1 From b5ab0698d6328c90d779c2af29914da840335233 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 20 Jul 2013 17:58:32 -0700 Subject: EDIT BEAMS!!! They had been missing from OpenSim since ever. Thanks to lkalif for telling me how to route the information. The viewer effect is under the distance filter, so only avatars with cameras < 10m away see the beams. --- OpenSim/Framework/IClientAPI.cs | 2 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 27 ++++------------------ OpenSim/Region/Framework/Scenes/ScenePresence.cs | 5 +++- .../Server/IRCClientView.cs | 2 +- .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 2 +- OpenSim/Tests/Common/Mock/TestClient.cs | 2 +- 6 files changed, 12 insertions(+), 28 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index f39eb0c..98358e5 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1476,7 +1476,7 @@ namespace OpenSim.Framework void SendChangeUserRights(UUID agentID, UUID friendID, int rights); void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); - void StopFlying(ISceneEntity presence); + void SendAgentTerseUpdate(ISceneEntity presence); void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 2907580..a8759ab 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5016,7 +5016,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ScenePresence presence = (ScenePresence)entity; - attachPoint = 0; + attachPoint = presence.State; collisionPlane = presence.CollisionPlane; position = presence.OffsetPosition; velocity = presence.Velocity; @@ -5040,7 +5040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP SceneObjectPart part = (SceneObjectPart)entity; attachPoint = part.ParentGroup.AttachmentPoint; - + attachPoint = ((attachPoint % 16) * 16 + (attachPoint / 16)); // m_log.DebugFormat( // "[LLCLIENTVIEW]: Sending attachPoint {0} for {1} {2} to {3}", // attachPoint, part.Name, part.LocalId, Name); @@ -5068,7 +5068,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP pos += 4; // Avatar/CollisionPlane - data[pos++] = (byte)((attachPoint % 16) * 16 + (attachPoint / 16)); ; + data[pos++] = (byte) attachPoint; if (avatar) { data[pos++] = 1; @@ -12550,7 +12550,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(dialog, ThrottleOutPacketType.Task); } - public void StopFlying(ISceneEntity p) + public void SendAgentTerseUpdate(ISceneEntity p) { if (p is ScenePresence) { @@ -12564,25 +12564,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP Vector3 pos = presence.AbsolutePosition; - if (presence.Appearance.AvatarHeight != 127.0f) - pos += new Vector3(0f, 0f, (presence.Appearance.AvatarHeight/6f)); - else - pos += new Vector3(0f, 0f, (1.56f/6f)); - - presence.AbsolutePosition = pos; - - // attach a suitable collision plane regardless of the actual situation to force the LLClient to land. - // Collision plane below the avatar's position a 6th of the avatar's height is suitable. - // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a - // certain amount.. because the LLClient wouldn't land in that situation anyway. - - // why are we still testing for this really old height value default??? - if (presence.Appearance.AvatarHeight != 127.0f) - presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - presence.Appearance.AvatarHeight/6f); - else - presence.CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f/6f)); - - ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = CreateImprovedTerseBlock(p, false); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 2359f55..e06cec8 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1125,7 +1125,7 @@ namespace OpenSim.Region.Framework.Scenes public void StopFlying() { - ControllingClient.StopFlying(this); + ControllingClient.SendAgentTerseUpdate(this); } /// @@ -1728,6 +1728,9 @@ namespace OpenSim.Region.Framework.Scenes SendControlsToScripts(flagsForScripts); } + if ((State & 0x10) != 0) + ControllingClient.SendAgentTerseUpdate(this); + m_scene.EventManager.TriggerOnClientMovement(this); } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 9b69da3..23a435d 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1673,7 +1673,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server { } - public void StopFlying(ISceneEntity presence) + public void SendAgentTerseUpdate(ISceneEntity presence) { } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 6c38b65..9a61702 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -1229,7 +1229,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void StopFlying(ISceneEntity presence) + public void SendAgentTerseUpdate(ISceneEntity presence) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 5d7349a..f7220d7 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -1256,7 +1256,7 @@ namespace OpenSim.Tests.Common.Mock { } - public void StopFlying(ISceneEntity presence) + public void SendAgentTerseUpdate(ISceneEntity presence) { } -- cgit v1.1 From 116a449d8945d1d04013860f952841a71df80be7 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 20 Jul 2013 19:20:20 -0700 Subject: The quaternion delta was a bit to high, now that the head rotation is out of the equation. (head rotation was the problematic one) --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index a8759ab..021b7c1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5576,7 +5576,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Scene/Avatar - private const float QDELTA = 0.01f; + private const float QDELTA = 0.000001f; private const float VDELTA = 0.01f; /// -- cgit v1.1 From 8d18ad2f6f75320dfb605b960f74531c1921b91b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 08:50:52 -0700 Subject: Minor aesthetic change to make things more clear. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index e06cec8..33db88b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1728,7 +1728,8 @@ namespace OpenSim.Region.Framework.Scenes SendControlsToScripts(flagsForScripts); } - if ((State & 0x10) != 0) + // We need to send this back to the client in order to see the edit beams + if ((State & (uint)AgentState.Editing) != 0) ControllingClient.SendAgentTerseUpdate(this); m_scene.EventManager.TriggerOnClientMovement(this); -- cgit v1.1 From 99a727600b938383224285d9dad79e2b564cb1fe Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 10:07:35 -0700 Subject: Minor cosmetic changes. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 50 ++++++++++------------ 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 021b7c1..e23e55b 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5595,7 +5595,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); - return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); + bool significant = CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); + + // Emergency debugging + //if (significant) + //{ + //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", + // x.CameraAtAxis, x.CameraCenter); + //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", + // x.CameraLeftAxis, x.CameraUpAxis); + //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", + // qdelta1, qdelta2); + //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", + // x.ControlFlags, x.Flags, x.Far, x.State); + //} + + return significant; + } /// @@ -5606,24 +5622,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - if ( + return ( (qdelta1 > QDELTA) || // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack //(qdelta2 > QDELTA * 10) || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) || (x.Far != m_thisAgentUpdateArgs.Far) || (x.Flags != m_thisAgentUpdateArgs.Flags) || - (x.State != m_thisAgentUpdateArgs.State) - ) - { - //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", - // qdelta1, qdelta2); - //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3} (Thread {4})", - // x.ControlFlags, x.Flags, x.Far, x.State, Thread.CurrentThread.Name); - return true; - } - - return false; + (x.State != m_thisAgentUpdateArgs.State) + ); } /// @@ -5634,23 +5641,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - if ( - /* These 4 are the worst offenders! - * With Singularity, there is a bug where sometimes the spam on these doesn't stop */ + return ( (vdelta1 > VDELTA) || (vdelta2 > VDELTA) || (vdelta3 > VDELTA) || - (vdelta4 > VDELTA) - ) - { - //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", - // x.CameraAtAxis, x.CameraCenter); - //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", - // x.CameraLeftAxis, x.CameraUpAxis); - return true; - } - - return false; + (vdelta4 > VDELTA) + ); } private bool HandleAgentUpdate(IClientAPI sener, Packet packet) -- cgit v1.1 From f81e289a1bc28b85d5e05a8549f9796f72d454ac Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 14:34:43 -0700 Subject: Add the Current Outfit folder as an available folder in the SuitcaseInventory. --- .../HypergridService/HGSuitcaseInventoryService.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index 2567c8f..06c5b89 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -493,6 +493,18 @@ namespace OpenSim.Services.HypergridService return null; } + private XInventoryFolder GetCurrentOutfitXFolder(UUID userID) + { + XInventoryFolder[] folders = m_Database.GetFolders( + new string[] { "agentID", "type" }, + new string[] { userID.ToString(), ((int)AssetType.CurrentOutfitFolder).ToString() }); + + if (folders.Length == 0) + return null; + + return folders[0]; + } + private XInventoryFolder GetSuitcaseXFolder(UUID principalID) { // Warp! Root folder for travelers @@ -531,6 +543,7 @@ namespace OpenSim.Services.HypergridService if (m_SuitcaseTrees.TryGetValue(principalID, out t)) return t; + // Get the tree of the suitcase folder t = GetFolderTreeRecursive(folder); m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes return t; @@ -577,6 +590,9 @@ namespace OpenSim.Services.HypergridService List tree = new List(); tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder tree.AddRange(GetFolderTree(principalID, suitcase.folderID)); + // Also add the Current Outfit folder to the list of available folders + tree.Add(GetCurrentOutfitXFolder(principalID)); + XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl) { if (fl.folderID == folderID) return true; -- cgit v1.1 From df63bfafefe431faf21ec1c52dbff78977f971e6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 14:39:50 -0700 Subject: Better version of previous commit --- OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index 06c5b89..0601ece 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -495,9 +495,13 @@ namespace OpenSim.Services.HypergridService private XInventoryFolder GetCurrentOutfitXFolder(UUID userID) { + XInventoryFolder root = GetRootXFolder(userID); + if (root == null) + return null; + XInventoryFolder[] folders = m_Database.GetFolders( - new string[] { "agentID", "type" }, - new string[] { userID.ToString(), ((int)AssetType.CurrentOutfitFolder).ToString() }); + new string[] { "agentID", "type", "parentFolderID" }, + new string[] { userID.ToString(), ((int)AssetType.CurrentOutfitFolder).ToString(), root.folderID.ToString() }); if (folders.Length == 0) return null; -- cgit v1.1 From 803632f8f32d91bb4aec678d8b45a8430c2703e1 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 9 Jul 2013 16:26:17 -0700 Subject: BulletSim: freshen up the code for constraint based linksets. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 4 +- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 1 + .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 82 ++++++++++++++++------ 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 0204967..4c2c1c1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1029,8 +1029,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", - ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}", + ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity, frictionFactorV); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 1d94142..3668456 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -59,6 +59,7 @@ public sealed class BSLinksetCompound : BSLinkset { DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); + // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index a06a44d..f17d698 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -48,12 +48,22 @@ public sealed class BSLinksetConstraints : BSLinkset { base.Refresh(requestor); - if (HasAnyChildren && IsRoot(requestor)) + } + + private void ScheduleRebuild(BSPrimLinkable requestor) + { + DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", + requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); + + // When rebuilding, it is possible to set properties that would normally require a rebuild. + // If already rebuilding, don't request another rebuild. + // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. + if (!Rebuilding && HasAnyChildren) { // Queue to happen after all the other taint processing m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() { - if (HasAnyChildren && IsRoot(requestor)) + if (HasAnyChildren) RecomputeLinksetConstraints(); }); } @@ -67,8 +77,14 @@ public sealed class BSLinksetConstraints : BSLinkset // Called at taint-time! public override bool MakeDynamic(BSPrimLinkable child) { - // What is done for each object in BSPrim is what we want. - return false; + bool ret = false; + DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + if (IsRoot(child)) + { + // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. + ScheduleRebuild(LinksetRoot); + } + return ret; } // The object is going static (non-physical). Do any setup necessary for a static linkset. @@ -78,8 +94,16 @@ public sealed class BSLinksetConstraints : BSLinkset // Called at taint-time! public override bool MakeStatic(BSPrimLinkable child) { - // What is done for each object in BSPrim is what we want. - return false; + bool ret = false; + + DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); + if (IsRoot(child)) + { + // Schedule a rebuild to verify that the root shape is set to the real shape. + ScheduleRebuild(LinksetRoot); + } + return ret; } // Called at taint-time!! @@ -105,7 +129,7 @@ public sealed class BSLinksetConstraints : BSLinkset // Just undo all the constraints for this linkset. Rebuild at the end of the step. ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); // Cause the constraints, et al to be rebuilt before the next simulation step. - Refresh(LinksetRoot); + ScheduleRebuild(LinksetRoot); } return ret; } @@ -123,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); // Cause constraints and assorted properties to be recomputed before the next simulation step. - Refresh(LinksetRoot); + ScheduleRebuild(LinksetRoot); } return; } @@ -147,7 +171,7 @@ public sealed class BSLinksetConstraints : BSLinkset PhysicallyUnlinkAChildFromRoot(rootx, childx); }); // See that the linkset parameters are recomputed at the end of the taint time. - Refresh(LinksetRoot); + ScheduleRebuild(LinksetRoot); } else { @@ -165,6 +189,7 @@ public sealed class BSLinksetConstraints : BSLinkset Refresh(rootPrim); } + // Create a static constraint between the two passed objects private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) { // Zero motion for children so they don't interpolate @@ -281,24 +306,39 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); - foreach (BSPrimLinkable child in m_children) + try { - // A child in the linkset physically shows the mass of the whole linkset. - // This allows Bullet to apply enough force on the child to move the whole linkset. - // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - child.UpdatePhysicalMassProperties(linksetMass, true); + Rebuilding = true; - BSConstraint constrain; - if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) + // There is no reason to build all this physical stuff for a non-physical linkset. + if (!LinksetRoot.IsPhysicallyActive) { - // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, child); + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); + return; // Note the 'finally' clause at the botton which will get executed. } - constrain.RecomputeConstraintVariables(linksetMass); - // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG - } + foreach (BSPrimLinkable child in m_children) + { + // A child in the linkset physically shows the mass of the whole linkset. + // This allows Bullet to apply enough force on the child to move the whole linkset. + // (Also do the mass stuff before recomputing the constraint so mass is not zero.) + child.UpdatePhysicalMassProperties(linksetMass, true); + + BSConstraint constrain; + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) + { + // If constraint doesn't exist yet, create it. + constrain = BuildConstraint(LinksetRoot, child); + } + constrain.RecomputeConstraintVariables(linksetMass); + // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG + } + } + finally + { + Rebuilding = false; + } } } } -- cgit v1.1 From 13a4a80b3893af13ab748c177b731fed813974ca Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 10 Jul 2013 09:32:26 -0700 Subject: Add experimental stubs for an extension function interface on both PhysicsScene and PhysicsActor. --- OpenSim/Region/Physics/Manager/PhysicsActor.cs | 6 ++++++ OpenSim/Region/Physics/Manager/PhysicsScene.cs | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index bd806eb..2500f27 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -313,6 +313,12 @@ namespace OpenSim.Region.Physics.Manager public abstract void SubscribeEvents(int ms); public abstract void UnSubscribeEvents(); public abstract bool SubscribedEvents(); + + // Extendable interface for new, physics engine specific operations + public virtual object Extension(string pFunct, params object[] pParams) + { + throw new NotImplementedException(); + } } public class NullPhysicsActor : PhysicsActor diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 290b72e..07a1d36 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -25,10 +25,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using System.Collections.Generic; using System.Reflection; + using log4net; using Nini.Config; + using OpenSim.Framework; using OpenMetaverse; @@ -331,5 +334,11 @@ namespace OpenSim.Region.Physics.Manager { return false; } + + // Extendable interface for new, physics engine specific operations + public virtual object Extension(string pFunct, params object[] pParams) + { + throw new NotImplementedException(); + } } } -- cgit v1.1 From b4c3a791aa55390bff071b3fe4bbe70c1d252703 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 11 Jul 2013 14:33:03 -0700 Subject: BulletSim: move collision processing for linksets from BSPrimLinkable into the linkset implementation classes. Add HasSomeCollision attribute that remembers of any component of a linkset has a collision. Update vehicle code (BSDynamic) to use the HasSomeCollision in place of IsColliding to make constraint based linksets properly notice the ground. Add linkset functions to change physical attributes of all the members of a linkset. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 16 ++--- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 75 +++++++++++++++++++++- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 11 ++++ OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 5 +- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 32 +++++++-- 5 files changed, 121 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 4c2c1c1..1540df1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1001,7 +1001,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin else if (newVelocityLengthSq < 0.001f) VehicleVelocity = Vector3.Zero; - VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); + VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity ); } // end MoveLinear() @@ -1062,7 +1062,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation; // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. - if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.IsColliding) + if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision) { linearDeflectionW.Z = 0f; } @@ -1222,7 +1222,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); distanceAboveGround = VehiclePosition.Z - targetHeight; // Not colliding if the vehicle is off the ground - if (!Prim.IsColliding) + if (!Prim.HasSomeCollision) { // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); @@ -1233,12 +1233,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin // be computed with a motor. // TODO: add interaction with banking. VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", - Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); + Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret); */ // Another approach is to measure if we're going up. If going up and not colliding, // the vehicle is in the air. Fix that by pushing down. - if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) + if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1) { // Get rid of any of the velocity vector that is pushing us up. float upVelocity = VehicleVelocity.Z; @@ -1260,7 +1260,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } */ VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", - ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); + ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity); } } } @@ -1270,14 +1270,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; // Hack to reduce downward force if the vehicle is probably sitting on the ground - if (ControllingPrim.IsColliding && IsGroundVehicle) + if (ControllingPrim.HasSomeCollision && IsGroundVehicle) appliedGravity *= BSParam.VehicleGroundGravityFudge; VehicleAddForce(appliedGravity); VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", ControllingPrim.LocalID, m_VehicleGravity, - ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); + ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); } // ======================================================================= diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index ad8e10f..78c0af7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -203,6 +203,33 @@ public abstract class BSLinkset return ret; } + // Called after a simulation step to post a collision with this object. + // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have + // anything to add for the collision and it should be passed through normal processing. + // Default processing for a linkset. + public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // prims in the same linkset cannot collide with each other + BSPrimLinkable convCollidee = collidee as BSPrimLinkable; + if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) + { + // By returning 'true', we tell the caller the collision has been 'handled' so it won't + // do anything about this collision and thus, effectivily, ignoring the collision. + ret = true; + } + else + { + // Not a collision between members of the linkset. Must be a real collision. + // So the linkset root can know if there is a collision anywhere in the linkset. + LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; + } + + return ret; + } + // I am the root of a linkset and a new child is being added // Called while LinkActivity is locked. protected abstract void AddChildToLinkset(BSPrimLinkable child); @@ -251,6 +278,53 @@ public abstract class BSLinkset public abstract bool RemoveDependencies(BSPrimLinkable child); // ================================================================ + // Some physical setting happen to all members of the linkset + public virtual void SetPhysicalFriction(float friction) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(member.PhysBody, friction); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalRestitution(float restitution) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalGravity(OMV.Vector3 gravity) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(member.PhysBody, gravity); + return false; // 'false' says to continue looping + } + ); + } + public virtual void ComputeLocalInertia() + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); + member.Inertia = inertia * BSParam.VehicleInertiaFactor; + m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); + } + return false; // 'false' says to continue looping + } + ); + } + // ================================================================ protected virtual float ComputeLinksetMass() { float mass = LinksetRoot.RawMass; @@ -311,6 +385,5 @@ public abstract class BSLinkset if (m_physicsScene.PhysicsLogging.Enabled) m_physicsScene.DetailLog(msg, args); } - } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index fc4545f..d34b797 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -353,6 +353,16 @@ public abstract class BSPhysObject : PhysicsActor CollidingStep = BSScene.NotASimulationStep; } } + // Complex objects (like linksets) need to know if there is a collision on any part of + // their shape. 'IsColliding' has an existing definition of reporting a collision on + // only this specific prim or component of linksets. + // 'HasSomeCollision' is defined as reporting if there is a collision on any part of + // the complex body that this prim is the root of. + public virtual bool HasSomeCollision + { + get { return IsColliding; } + set { IsColliding = value; } + } public override bool CollidingGround { get { return (CollidingGroundStep == PhysScene.SimulationStep); } set @@ -386,6 +396,7 @@ public abstract class BSPhysObject : PhysicsActor // Return 'true' if a collision was processed and should be sent up. // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. // Called at taint time from within the Step() function + public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); public virtual bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index d43448e..4771934 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -495,8 +495,8 @@ public class BSPrim : BSPhysObject } } - // Find and return a handle to the current vehicle actor. - // Return 'null' if there is no vehicle actor. + // Find and return a handle to the current vehicle actor. + // Return 'null' if there is no vehicle actor. public BSDynamics GetVehicleActor() { BSDynamics ret = null; @@ -507,6 +507,7 @@ public class BSPrim : BSPhysObject } return ret; } + public override int VehicleType { get { int ret = (int)Vehicle.TYPE_NONE; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 1fbcfcc..2f392da 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -200,20 +200,38 @@ public class BSPrimLinkable : BSPrimDisplaced } // Called after a simulation step to post a collision with this object. + // This returns 'true' if the collision has been queued and the SendCollisions call must + // be made at the end of the simulation step. public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { - // prims in the same linkset cannot collide with each other - BSPrimLinkable convCollidee = collidee as BSPrimLinkable; - if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) + bool ret = false; + // Ask the linkset if it wants to handle the collision + if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)) { - return false; + // The linkset didn't handle it so pass the collision through normal processing + ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); } + return ret; + } - // TODO: handle collisions of other objects with with children of linkset. - // This is a problem for LinksetCompound since the children are packed into the root. + // A linkset reports any collision on any part of the linkset. + public long SomeCollisionSimulationStep = 0; + public override bool HasSomeCollision + { + get + { + return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; + } + set + { + if (value) + SomeCollisionSimulationStep = PhysScene.SimulationStep; + else + SomeCollisionSimulationStep = 0; - return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); + base.HasSomeCollision = value; + } } } } -- cgit v1.1 From acb7b4a09ad564d1dfae3ad12adbb593ca3942c9 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 16 Jul 2013 09:59:52 -0700 Subject: BulletSim: only create vehicle prim actor when vehicles are enabled. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 43 ++++++++++++++++------ .../Physics/BulletSPlugin/Tests/BasicVehicles.cs | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 4771934..fdb2925 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -96,7 +96,7 @@ public class BSPrim : BSPhysObject _isVolumeDetect = false; // Add a dynamic vehicle to our set of actors that can move this prim. - PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); + // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); _mass = CalculateMass(); @@ -497,7 +497,7 @@ public class BSPrim : BSPhysObject // Find and return a handle to the current vehicle actor. // Return 'null' if there is no vehicle actor. - public BSDynamics GetVehicleActor() + public BSDynamics GetVehicleActor(bool createIfNone) { BSDynamics ret = null; BSActor actor; @@ -505,13 +505,21 @@ public class BSPrim : BSPhysObject { ret = actor as BSDynamics; } + else + { + if (createIfNone) + { + ret = new BSDynamics(PhysScene, this, VehicleActorName); + PhysicalActors.Add(ret.ActorName, ret); + } + } return ret; } public override int VehicleType { get { int ret = (int)Vehicle.TYPE_NONE; - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); if (vehicleActor != null) ret = (int)vehicleActor.Type; return ret; @@ -525,11 +533,24 @@ public class BSPrim : BSPhysObject // change all the parameters. Like a plane changing to CAR when on the // ground. In this case, don't want to zero motion. // ZeroMotion(true /* inTaintTime */); - BSDynamics vehicleActor = GetVehicleActor(); - if (vehicleActor != null) + if (type == Vehicle.TYPE_NONE) { - vehicleActor.ProcessTypeChange(type); - ActivateIfPhysical(false); + // Vehicle type is 'none' so get rid of any actor that may have been allocated. + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + if (vehicleActor != null) + { + PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); + } + } + else + { + // Vehicle type is not 'none' so create an actor and set it running. + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessTypeChange(type); + ActivateIfPhysical(false); + } } }); } @@ -538,7 +559,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); @@ -550,7 +571,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); @@ -562,7 +583,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); @@ -574,7 +595,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessVehicleFlags(param, remove); diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 48d3742..48e74eb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs @@ -116,7 +116,7 @@ public class BasicVehicles : OpenSimTestCase // Instead the appropriate values are set and calls are made just the parts of the // controller we want to exercise. Stepping the physics engine then applies // the actions of that one feature. - BSDynamics vehicleActor = TestVehicle.GetVehicleActor(); + BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); -- cgit v1.1 From d0d654e2186c8b81c1150da89a549e4f7162a2b4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 16 Jul 2013 10:01:03 -0700 Subject: BulletSim: change BSDynamics to expect to be passed a BSPrimLinkable and start changing the logic to handle the base prim as a complex object (ie, a linkset). --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 1540df1..82d7c44 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin private static string LogHeader = "[BULLETSIM VEHICLE]"; // the prim this dynamic controller belongs to - private BSPrim ControllingPrim { get; set; } + private BSPrimLinkable ControllingPrim { get; set; } private bool m_haveRegisteredForSceneEvents; @@ -128,9 +128,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) : base(myScene, myPrim, actorName) { - ControllingPrim = myPrim; Type = Vehicle.TYPE_NONE; m_haveRegisteredForSceneEvents = false; + + ControllingPrim = myPrim as BSPrimLinkable; + if (ControllingPrim == null) + { + // THIS CANNOT HAPPEN!! + } + VDetailLog("{0},Creation", ControllingPrim.LocalID); } // Return 'true' if this vehicle is doing vehicle things @@ -585,6 +591,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Friction affects are handled by this vehicle code m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); + // ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); + // ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); // Moderate angular movement introduced by Bullet. // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. @@ -595,17 +603,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Vehicles report collision events so we know when it's on the ground m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + // ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); + // ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor); // Set the gravity for the vehicle depending on the buoyancy // TODO: what should be done if prim and vehicle buoyancy differ? m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); + // ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, @@ -617,6 +628,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if (ControllingPrim.PhysBody.HasPhysicalBody) m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); } } @@ -629,6 +641,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // BSActor.Release() public override void Dispose() { + VDetailLog("{0},Dispose", ControllingPrim.LocalID); UnregisterForSceneEvents(); Type = Vehicle.TYPE_NONE; Enabled = false; -- cgit v1.1 From b44f0e1a00eba7f76401692322e48a3b23a81164 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 16 Jul 2013 10:02:14 -0700 Subject: BulletSim: Add logic to linksets to change physical properties for whole linkset. Override physical property setting for BSLinksetCompound as there are not children to the compound spape. --- OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 6 +--- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 24 +++++++++++++-- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 36 ++++++++++++++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index fff63e4..e0ccc50 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -69,7 +69,7 @@ public class BSActorCollection { lock (m_actors) { - Release(); + ForEachActor(a => a.Dispose()); m_actors.Clear(); } } @@ -98,10 +98,6 @@ public class BSActorCollection { ForEachActor(a => a.SetEnabled(enabl)); } - public void Release() - { - ForEachActor(a => a.Dispose()); - } public void Refresh() { ForEachActor(a => a.Refresh()); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 78c0af7..960c0b4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -309,14 +309,14 @@ public abstract class BSLinkset } ); } - public virtual void ComputeLocalInertia() + public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor) { ForEachMember((member) => { if (member.PhysBody.HasPhysicalBody) { OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); - member.Inertia = inertia * BSParam.VehicleInertiaFactor; + member.Inertia = inertia * inertiaFactor; m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); } @@ -324,6 +324,26 @@ public abstract class BSLinkset } ); } + public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } // ================================================================ protected virtual float ComputeLinksetMass() { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 3668456..33ae5a5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -44,6 +44,42 @@ public sealed class BSLinksetCompound : BSLinkset { } + // ================================================================ + // Changing the physical property of the linkset only needs to change the root + public override void SetPhysicalFriction(float friction) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); + } + public override void SetPhysicalRestitution(float restitution) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); + } + public override void SetPhysicalGravity(OMV.Vector3 gravity) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); + } + public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass); + LinksetRoot.Inertia = inertia * inertiaFactor; + m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); + } + public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + // ================================================================ + // When physical properties are changed the linkset needs to recalculate // its internal properties. public override void Refresh(BSPrimLinkable requestor) -- cgit v1.1 From 84d0699761b8da546f9faef084240d7b15f16321 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 12:07:42 -0700 Subject: Revert "BulletSim: Add logic to linksets to change physical properties for" The changes don't seem to be ready for prime time. This reverts commit b44f0e1a00eba7f76401692322e48a3b23a81164. --- OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 6 +++- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 24 ++------------- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 36 ---------------------- 3 files changed, 7 insertions(+), 59 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index e0ccc50..fff63e4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -69,7 +69,7 @@ public class BSActorCollection { lock (m_actors) { - ForEachActor(a => a.Dispose()); + Release(); m_actors.Clear(); } } @@ -98,6 +98,10 @@ public class BSActorCollection { ForEachActor(a => a.SetEnabled(enabl)); } + public void Release() + { + ForEachActor(a => a.Dispose()); + } public void Refresh() { ForEachActor(a => a.Refresh()); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 960c0b4..78c0af7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -309,14 +309,14 @@ public abstract class BSLinkset } ); } - public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor) + public virtual void ComputeLocalInertia() { ForEachMember((member) => { if (member.PhysBody.HasPhysicalBody) { OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); - member.Inertia = inertia * inertiaFactor; + member.Inertia = inertia * BSParam.VehicleInertiaFactor; m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); } @@ -324,26 +324,6 @@ public abstract class BSLinkset } ); } - public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); - return false; // 'false' says to continue looping - } - ); - } - public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); - return false; // 'false' says to continue looping - } - ); - } // ================================================================ protected virtual float ComputeLinksetMass() { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 33ae5a5..3668456 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -44,42 +44,6 @@ public sealed class BSLinksetCompound : BSLinkset { } - // ================================================================ - // Changing the physical property of the linkset only needs to change the root - public override void SetPhysicalFriction(float friction) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); - } - public override void SetPhysicalRestitution(float restitution) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); - } - public override void SetPhysicalGravity(OMV.Vector3 gravity) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); - } - public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor) - { - OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass); - LinksetRoot.Inertia = inertia * inertiaFactor; - m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia); - m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); - } - public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); - } - public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); - } - // ================================================================ - // When physical properties are changed the linkset needs to recalculate // its internal properties. public override void Refresh(BSPrimLinkable requestor) -- cgit v1.1 From 7b187deb19517aa7c880458894643a5448566a94 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 12:08:25 -0700 Subject: Revert "BulletSim: change BSDynamics to expect to be passed a BSPrimLinkable" The changes don't seem to be ready for prime time. This reverts commit d0d654e2186c8b81c1150da89a549e4f7162a2b4. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 82d7c44..1540df1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin private static string LogHeader = "[BULLETSIM VEHICLE]"; // the prim this dynamic controller belongs to - private BSPrimLinkable ControllingPrim { get; set; } + private BSPrim ControllingPrim { get; set; } private bool m_haveRegisteredForSceneEvents; @@ -128,15 +128,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) : base(myScene, myPrim, actorName) { + ControllingPrim = myPrim; Type = Vehicle.TYPE_NONE; m_haveRegisteredForSceneEvents = false; - - ControllingPrim = myPrim as BSPrimLinkable; - if (ControllingPrim == null) - { - // THIS CANNOT HAPPEN!! - } - VDetailLog("{0},Creation", ControllingPrim.LocalID); } // Return 'true' if this vehicle is doing vehicle things @@ -591,8 +585,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Friction affects are handled by this vehicle code m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); - // ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); - // ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); // Moderate angular movement introduced by Bullet. // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. @@ -603,20 +595,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Vehicles report collision events so we know when it's on the ground m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - // ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); - // ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor); // Set the gravity for the vehicle depending on the buoyancy // TODO: what should be done if prim and vehicle buoyancy differ? m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); - // ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, @@ -628,7 +617,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if (ControllingPrim.PhysBody.HasPhysicalBody) m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); } } @@ -641,7 +629,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin // BSActor.Release() public override void Dispose() { - VDetailLog("{0},Dispose", ControllingPrim.LocalID); UnregisterForSceneEvents(); Type = Vehicle.TYPE_NONE; Enabled = false; -- cgit v1.1 From 5f7b2ea81b95a60e882bc65b663a2c9fe134f92a Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 12:08:49 -0700 Subject: Revert "BulletSim: only create vehicle prim actor when vehicles are enabled." The changes don't seem to be ready for prime time. This reverts commit acb7b4a09ad564d1dfae3ad12adbb593ca3942c9. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 43 ++++++---------------- .../Physics/BulletSPlugin/Tests/BasicVehicles.cs | 2 +- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index fdb2925..4771934 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -96,7 +96,7 @@ public class BSPrim : BSPhysObject _isVolumeDetect = false; // Add a dynamic vehicle to our set of actors that can move this prim. - // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); + PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); _mass = CalculateMass(); @@ -497,7 +497,7 @@ public class BSPrim : BSPhysObject // Find and return a handle to the current vehicle actor. // Return 'null' if there is no vehicle actor. - public BSDynamics GetVehicleActor(bool createIfNone) + public BSDynamics GetVehicleActor() { BSDynamics ret = null; BSActor actor; @@ -505,21 +505,13 @@ public class BSPrim : BSPhysObject { ret = actor as BSDynamics; } - else - { - if (createIfNone) - { - ret = new BSDynamics(PhysScene, this, VehicleActorName); - PhysicalActors.Add(ret.ActorName, ret); - } - } return ret; } public override int VehicleType { get { int ret = (int)Vehicle.TYPE_NONE; - BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + BSDynamics vehicleActor = GetVehicleActor(); if (vehicleActor != null) ret = (int)vehicleActor.Type; return ret; @@ -533,24 +525,11 @@ public class BSPrim : BSPhysObject // change all the parameters. Like a plane changing to CAR when on the // ground. In this case, don't want to zero motion. // ZeroMotion(true /* inTaintTime */); - if (type == Vehicle.TYPE_NONE) - { - // Vehicle type is 'none' so get rid of any actor that may have been allocated. - BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); - if (vehicleActor != null) - { - PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); - } - } - else + BSDynamics vehicleActor = GetVehicleActor(); + if (vehicleActor != null) { - // Vehicle type is not 'none' so create an actor and set it running. - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null) - { - vehicleActor.ProcessTypeChange(type); - ActivateIfPhysical(false); - } + vehicleActor.ProcessTypeChange(type); + ActivateIfPhysical(false); } }); } @@ -559,7 +538,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + BSDynamics vehicleActor = GetVehicleActor(); if (vehicleActor != null) { vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); @@ -571,7 +550,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + BSDynamics vehicleActor = GetVehicleActor(); if (vehicleActor != null) { vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); @@ -583,7 +562,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + BSDynamics vehicleActor = GetVehicleActor(); if (vehicleActor != null) { vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); @@ -595,7 +574,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + BSDynamics vehicleActor = GetVehicleActor(); if (vehicleActor != null) { vehicleActor.ProcessVehicleFlags(param, remove); diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 48e74eb..48d3742 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs @@ -116,7 +116,7 @@ public class BasicVehicles : OpenSimTestCase // Instead the appropriate values are set and calls are made just the parts of the // controller we want to exercise. Stepping the physics engine then applies // the actions of that one feature. - BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); + BSDynamics vehicleActor = TestVehicle.GetVehicleActor(); if (vehicleActor != null) { vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); -- cgit v1.1 From c45659863d8821a48a32e5b687c7b2a6d90b0300 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 12:09:17 -0700 Subject: Revert "BulletSim: move collision processing for linksets from BSPrimLinkable" The changes don't seem to be ready for prime time. This reverts commit b4c3a791aa55390bff071b3fe4bbe70c1d252703. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 16 ++--- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 75 +--------------------- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 11 ---- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 5 +- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 32 ++------- 5 files changed, 18 insertions(+), 121 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 1540df1..4c2c1c1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1001,7 +1001,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin else if (newVelocityLengthSq < 0.001f) VehicleVelocity = Vector3.Zero; - VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity ); + VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); } // end MoveLinear() @@ -1062,7 +1062,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation; // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. - if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision) + if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.IsColliding) { linearDeflectionW.Z = 0f; } @@ -1222,7 +1222,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); distanceAboveGround = VehiclePosition.Z - targetHeight; // Not colliding if the vehicle is off the ground - if (!Prim.HasSomeCollision) + if (!Prim.IsColliding) { // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); @@ -1233,12 +1233,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin // be computed with a motor. // TODO: add interaction with banking. VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", - Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret); + Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); */ // Another approach is to measure if we're going up. If going up and not colliding, // the vehicle is in the air. Fix that by pushing down. - if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1) + if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) { // Get rid of any of the velocity vector that is pushing us up. float upVelocity = VehicleVelocity.Z; @@ -1260,7 +1260,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } */ VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", - ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity); + ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); } } } @@ -1270,14 +1270,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; // Hack to reduce downward force if the vehicle is probably sitting on the ground - if (ControllingPrim.HasSomeCollision && IsGroundVehicle) + if (ControllingPrim.IsColliding && IsGroundVehicle) appliedGravity *= BSParam.VehicleGroundGravityFudge; VehicleAddForce(appliedGravity); VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", ControllingPrim.LocalID, m_VehicleGravity, - ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); + ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); } // ======================================================================= diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 78c0af7..ad8e10f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -203,33 +203,6 @@ public abstract class BSLinkset return ret; } - // Called after a simulation step to post a collision with this object. - // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have - // anything to add for the collision and it should be passed through normal processing. - // Default processing for a linkset. - public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, - OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) - { - bool ret = false; - - // prims in the same linkset cannot collide with each other - BSPrimLinkable convCollidee = collidee as BSPrimLinkable; - if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) - { - // By returning 'true', we tell the caller the collision has been 'handled' so it won't - // do anything about this collision and thus, effectivily, ignoring the collision. - ret = true; - } - else - { - // Not a collision between members of the linkset. Must be a real collision. - // So the linkset root can know if there is a collision anywhere in the linkset. - LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; - } - - return ret; - } - // I am the root of a linkset and a new child is being added // Called while LinkActivity is locked. protected abstract void AddChildToLinkset(BSPrimLinkable child); @@ -278,53 +251,6 @@ public abstract class BSLinkset public abstract bool RemoveDependencies(BSPrimLinkable child); // ================================================================ - // Some physical setting happen to all members of the linkset - public virtual void SetPhysicalFriction(float friction) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetFriction(member.PhysBody, friction); - return false; // 'false' says to continue looping - } - ); - } - public virtual void SetPhysicalRestitution(float restitution) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); - return false; // 'false' says to continue looping - } - ); - } - public virtual void SetPhysicalGravity(OMV.Vector3 gravity) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetGravity(member.PhysBody, gravity); - return false; // 'false' says to continue looping - } - ); - } - public virtual void ComputeLocalInertia() - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - { - OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); - member.Inertia = inertia * BSParam.VehicleInertiaFactor; - m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); - m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); - } - return false; // 'false' says to continue looping - } - ); - } - // ================================================================ protected virtual float ComputeLinksetMass() { float mass = LinksetRoot.RawMass; @@ -385,5 +311,6 @@ public abstract class BSLinkset if (m_physicsScene.PhysicsLogging.Enabled) m_physicsScene.DetailLog(msg, args); } + } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index d34b797..fc4545f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -353,16 +353,6 @@ public abstract class BSPhysObject : PhysicsActor CollidingStep = BSScene.NotASimulationStep; } } - // Complex objects (like linksets) need to know if there is a collision on any part of - // their shape. 'IsColliding' has an existing definition of reporting a collision on - // only this specific prim or component of linksets. - // 'HasSomeCollision' is defined as reporting if there is a collision on any part of - // the complex body that this prim is the root of. - public virtual bool HasSomeCollision - { - get { return IsColliding; } - set { IsColliding = value; } - } public override bool CollidingGround { get { return (CollidingGroundStep == PhysScene.SimulationStep); } set @@ -396,7 +386,6 @@ public abstract class BSPhysObject : PhysicsActor // Return 'true' if a collision was processed and should be sent up. // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. // Called at taint time from within the Step() function - public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); public virtual bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 4771934..d43448e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -495,8 +495,8 @@ public class BSPrim : BSPhysObject } } - // Find and return a handle to the current vehicle actor. - // Return 'null' if there is no vehicle actor. + // Find and return a handle to the current vehicle actor. + // Return 'null' if there is no vehicle actor. public BSDynamics GetVehicleActor() { BSDynamics ret = null; @@ -507,7 +507,6 @@ public class BSPrim : BSPhysObject } return ret; } - public override int VehicleType { get { int ret = (int)Vehicle.TYPE_NONE; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 2f392da..1fbcfcc 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -200,38 +200,20 @@ public class BSPrimLinkable : BSPrimDisplaced } // Called after a simulation step to post a collision with this object. - // This returns 'true' if the collision has been queued and the SendCollisions call must - // be made at the end of the simulation step. public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { - bool ret = false; - // Ask the linkset if it wants to handle the collision - if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)) + // prims in the same linkset cannot collide with each other + BSPrimLinkable convCollidee = collidee as BSPrimLinkable; + if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) { - // The linkset didn't handle it so pass the collision through normal processing - ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); + return false; } - return ret; - } - // A linkset reports any collision on any part of the linkset. - public long SomeCollisionSimulationStep = 0; - public override bool HasSomeCollision - { - get - { - return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; - } - set - { - if (value) - SomeCollisionSimulationStep = PhysScene.SimulationStep; - else - SomeCollisionSimulationStep = 0; + // TODO: handle collisions of other objects with with children of linkset. + // This is a problem for LinksetCompound since the children are packed into the root. - base.HasSomeCollision = value; - } + return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); } } } -- cgit v1.1 From 89857378ce79f93a265bc1eb151e17742032abfa Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 12:09:55 -0700 Subject: Revert "Add experimental stubs for an extension function interface on both" The changes don't seem to be ready for prime time. This reverts commit 13a4a80b3893af13ab748c177b731fed813974ca. --- OpenSim/Region/Physics/Manager/PhysicsActor.cs | 6 ------ OpenSim/Region/Physics/Manager/PhysicsScene.cs | 9 --------- 2 files changed, 15 deletions(-) diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 2500f27..bd806eb 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -313,12 +313,6 @@ namespace OpenSim.Region.Physics.Manager public abstract void SubscribeEvents(int ms); public abstract void UnSubscribeEvents(); public abstract bool SubscribedEvents(); - - // Extendable interface for new, physics engine specific operations - public virtual object Extension(string pFunct, params object[] pParams) - { - throw new NotImplementedException(); - } } public class NullPhysicsActor : PhysicsActor diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 07a1d36..290b72e 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -25,13 +25,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System; using System.Collections.Generic; using System.Reflection; - using log4net; using Nini.Config; - using OpenSim.Framework; using OpenMetaverse; @@ -334,11 +331,5 @@ namespace OpenSim.Region.Physics.Manager { return false; } - - // Extendable interface for new, physics engine specific operations - public virtual object Extension(string pFunct, params object[] pParams) - { - throw new NotImplementedException(); - } } } -- cgit v1.1 From 44543ebe638f391fc1c7ff532fe4470006dec55a Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 12:10:23 -0700 Subject: Revert "BulletSim: freshen up the code for constraint based linksets." The changes don't seem to be ready for prime time. This reverts commit 803632f8f32d91bb4aec678d8b45a8430c2703e1. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 4 +- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 1 - .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 82 ++++++---------------- 3 files changed, 23 insertions(+), 64 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 4c2c1c1..0204967 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1029,8 +1029,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}", - ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV, + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", + ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity, frictionFactorV); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 3668456..1d94142 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -59,7 +59,6 @@ public sealed class BSLinksetCompound : BSLinkset { DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); - // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index f17d698..a06a44d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -48,22 +48,12 @@ public sealed class BSLinksetConstraints : BSLinkset { base.Refresh(requestor); - } - - private void ScheduleRebuild(BSPrimLinkable requestor) - { - DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", - requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); - - // When rebuilding, it is possible to set properties that would normally require a rebuild. - // If already rebuilding, don't request another rebuild. - // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. - if (!Rebuilding && HasAnyChildren) + if (HasAnyChildren && IsRoot(requestor)) { // Queue to happen after all the other taint processing m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() { - if (HasAnyChildren) + if (HasAnyChildren && IsRoot(requestor)) RecomputeLinksetConstraints(); }); } @@ -77,14 +67,8 @@ public sealed class BSLinksetConstraints : BSLinkset // Called at taint-time! public override bool MakeDynamic(BSPrimLinkable child) { - bool ret = false; - DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. - ScheduleRebuild(LinksetRoot); - } - return ret; + // What is done for each object in BSPrim is what we want. + return false; } // The object is going static (non-physical). Do any setup necessary for a static linkset. @@ -94,16 +78,8 @@ public sealed class BSLinksetConstraints : BSLinkset // Called at taint-time! public override bool MakeStatic(BSPrimLinkable child) { - bool ret = false; - - DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - child.ClearDisplacement(); - if (IsRoot(child)) - { - // Schedule a rebuild to verify that the root shape is set to the real shape. - ScheduleRebuild(LinksetRoot); - } - return ret; + // What is done for each object in BSPrim is what we want. + return false; } // Called at taint-time!! @@ -129,7 +105,7 @@ public sealed class BSLinksetConstraints : BSLinkset // Just undo all the constraints for this linkset. Rebuild at the end of the step. ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); // Cause the constraints, et al to be rebuilt before the next simulation step. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return ret; } @@ -147,7 +123,7 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); // Cause constraints and assorted properties to be recomputed before the next simulation step. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return; } @@ -171,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset PhysicallyUnlinkAChildFromRoot(rootx, childx); }); // See that the linkset parameters are recomputed at the end of the taint time. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } else { @@ -189,7 +165,6 @@ public sealed class BSLinksetConstraints : BSLinkset Refresh(rootPrim); } - // Create a static constraint between the two passed objects private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) { // Zero motion for children so they don't interpolate @@ -306,39 +281,24 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); - try + foreach (BSPrimLinkable child in m_children) { - Rebuilding = true; + // A child in the linkset physically shows the mass of the whole linkset. + // This allows Bullet to apply enough force on the child to move the whole linkset. + // (Also do the mass stuff before recomputing the constraint so mass is not zero.) + child.UpdatePhysicalMassProperties(linksetMass, true); - // There is no reason to build all this physical stuff for a non-physical linkset. - if (!LinksetRoot.IsPhysicallyActive) + BSConstraint constrain; + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) { - DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); - return; // Note the 'finally' clause at the botton which will get executed. + // If constraint doesn't exist yet, create it. + constrain = BuildConstraint(LinksetRoot, child); } + constrain.RecomputeConstraintVariables(linksetMass); - foreach (BSPrimLinkable child in m_children) - { - // A child in the linkset physically shows the mass of the whole linkset. - // This allows Bullet to apply enough force on the child to move the whole linkset. - // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - child.UpdatePhysicalMassProperties(linksetMass, true); - - BSConstraint constrain; - if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) - { - // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, child); - } - constrain.RecomputeConstraintVariables(linksetMass); - - // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG - } - } - finally - { - Rebuilding = false; + // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG } + } } } -- cgit v1.1 From e6b6af62dd677077664fdc8801b3a7e894a2b8da Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 22 Jul 2013 15:41:14 -0700 Subject: Added check for user movement specification before discarding an incoming AgentUpdate packet. This fixes the problem with vehicles not moving forward after the first up-arrow. Code to fix a potential exception when using different IClientAPIs. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 81 +++++++++++----------- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 3 +- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index e23e55b..32549c8 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -359,12 +359,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// cannot retain a reference to it outside of that method. /// private AgentUpdateArgs m_thisAgentUpdateArgs = new AgentUpdateArgs(); - private float qdelta1; - private float qdelta2; - private float vdelta1; - private float vdelta2; - private float vdelta3; - private float vdelta4; protected Dictionary m_packetHandlers = new Dictionary(); protected Dictionary m_genericPacketHandlers = new Dictionary(); //PauPaw:Local Generic Message handlers @@ -5576,7 +5570,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Scene/Avatar + // Threshold for body rotation to be a significant agent update private const float QDELTA = 0.000001f; + // Threshold for camera rotation to be a significant agent update private const float VDELTA = 0.01f; /// @@ -5587,31 +5583,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public bool CheckAgentUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - // Compute these only once, when this function is called from down below - qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); - //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); - vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); - vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); - vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); - vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); - - bool significant = CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); - - // Emergency debugging - //if (significant) - //{ - //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", - // x.CameraAtAxis, x.CameraCenter); - //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", - // x.CameraLeftAxis, x.CameraUpAxis); - //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", - // qdelta1, qdelta2); - //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", - // x.ControlFlags, x.Flags, x.Far, x.State); - //} - - return significant; - + return CheckAgentMovementUpdateSignificance(x) || CheckAgentCameraUpdateSignificance(x); } /// @@ -5622,15 +5594,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// private bool CheckAgentMovementUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - return ( - (qdelta1 > QDELTA) || + float qdelta1 = 1 - (float)Math.Pow(Quaternion.Dot(x.BodyRotation, m_thisAgentUpdateArgs.BodyRotation), 2); + //qdelta2 = 1 - (float)Math.Pow(Quaternion.Dot(x.HeadRotation, m_thisAgentUpdateArgs.HeadRotation), 2); + + bool movementSignificant = + (qdelta1 > QDELTA) // significant if body rotation above threshold // Ignoring head rotation altogether, because it's not being used for anything interesting up the stack - //(qdelta2 > QDELTA * 10) || - (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) || - (x.Far != m_thisAgentUpdateArgs.Far) || - (x.Flags != m_thisAgentUpdateArgs.Flags) || - (x.State != m_thisAgentUpdateArgs.State) - ); + // || (qdelta2 > QDELTA * 10) // significant if head rotation above threshold + || (x.ControlFlags != m_thisAgentUpdateArgs.ControlFlags) // significant if control flags changed + || (x.ControlFlags != (byte)AgentManager.ControlFlags.NONE) // significant if user supplying any movement update commands + || (x.Far != m_thisAgentUpdateArgs.Far) // significant if far distance changed + || (x.Flags != m_thisAgentUpdateArgs.Flags) // significant if Flags changed + || (x.State != m_thisAgentUpdateArgs.State) // significant if Stats changed + ; + //if (movementSignificant) + //{ + //m_log.DebugFormat("[LLCLIENTVIEW]: Bod {0} {1}", + // qdelta1, qdelta2); + //m_log.DebugFormat("[LLCLIENTVIEW]: St {0} {1} {2} {3}", + // x.ControlFlags, x.Flags, x.Far, x.State); + //} + return movementSignificant; } /// @@ -5641,12 +5625,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// private bool CheckAgentCameraUpdateSignificance(AgentUpdatePacket.AgentDataBlock x) { - return ( + float vdelta1 = Vector3.Distance(x.CameraAtAxis, m_thisAgentUpdateArgs.CameraAtAxis); + float vdelta2 = Vector3.Distance(x.CameraCenter, m_thisAgentUpdateArgs.CameraCenter); + float vdelta3 = Vector3.Distance(x.CameraLeftAxis, m_thisAgentUpdateArgs.CameraLeftAxis); + float vdelta4 = Vector3.Distance(x.CameraUpAxis, m_thisAgentUpdateArgs.CameraUpAxis); + + bool cameraSignificant = (vdelta1 > VDELTA) || (vdelta2 > VDELTA) || (vdelta3 > VDELTA) || (vdelta4 > VDELTA) - ); + ; + + //if (cameraSignificant) + //{ + //m_log.DebugFormat("[LLCLIENTVIEW]: Cam1 {0} {1}", + // x.CameraAtAxis, x.CameraCenter); + //m_log.DebugFormat("[LLCLIENTVIEW]: Cam2 {0} {1}", + // x.CameraLeftAxis, x.CameraUpAxis); + //} + + return cameraSignificant; } private bool HandleAgentUpdate(IClientAPI sener, Packet packet) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 32282af..f5c0b05 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1316,9 +1316,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet; + LLClientView llClient = client as LLClientView; if (agentUpdate.AgentData.SessionID != client.SessionId || agentUpdate.AgentData.AgentID != client.AgentId - || !((LLClientView)client).CheckAgentUpdateSignificance(agentUpdate.AgentData)) + || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) ) { PacketPool.Instance.ReturnPacket(packet); return; -- cgit v1.1 From bf517899a7a63278d4ed22d5485c37d61d47bb58 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 22 Jul 2013 23:30:09 +0100 Subject: Add AverageUDPProcessTime stat to try and get a handle on how long we're taking on the initial processing of a UDP packet. If we're not receiving packets with multiple threads (m_asyncPacketHandling) then this is critical since it will limit the number of incoming UDP requests that the region can handle and affects packet loss. If m_asyncPacketHandling then this is less critical though a long process will increase the scope for threads to race. This is an experimental stat which may be changed. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 19 +++++++++-- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 39 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index f5c0b05..d3823f3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -70,8 +70,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( "IncomingPacketsProcessedCount", - "Number of inbound UDP packets processed", - "Number of inbound UDP packets processed", + "Number of inbound LL protocol packets processed", + "Number of inbound LL protocol packets processed", "", "clientstack", scene.Name, @@ -79,6 +79,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP MeasuresOfInterest.AverageChangeOverTime, stat => stat.Value = m_udpServer.IncomingPacketsProcessed, StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( + "AverageUDPProcessTime", + "Average number of milliseconds taken to process each incoming UDP packet in a sample.", + "This is for initial receive processing which is separate from the later client LL packet processing stage.", + "ms", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.None, + stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, +// stat => +// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod / TimeSpan.TicksPerMillisecond, 7), + StatVerbosity.Debug)); } public bool HandlesRegion(Location x) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index a919141..46a3261 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -78,6 +78,26 @@ namespace OpenMetaverse public bool IsRunningOutbound { get; private set; } /// + /// Number of receives over which to establish a receive time average. + /// + private readonly static int s_receiveTimeSamples = 500; + + /// + /// Current number of samples taken to establish a receive time average. + /// + private int m_currentReceiveTimeSamples; + + /// + /// Cumulative receive time for the sample so far. + /// + private int m_receiveTicksInCurrentSamplePeriod; + + /// + /// The average time taken for each require receive in the last sample. + /// + public float AverageReceiveTicksForLastSamplePeriod { get; private set; } + + /// /// Default constructor /// /// Local IP address to bind the server to @@ -286,6 +306,8 @@ namespace OpenMetaverse try { + int startTick = Util.EnvironmentTickCount(); + // get the length of data actually read from the socket, store it with the // buffer buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); @@ -293,6 +315,23 @@ namespace OpenMetaverse // call the abstract method PacketReceived(), passing the buffer that // has just been filled from the socket read. PacketReceived(buffer); + + // If more than one thread can be calling AsyncEndReceive() at once (e.g. if m_asyncPacketHandler) + // then a particular stat may be inaccurate due to a race condition. We won't worry about this + // since this should be rare and won't cause a runtime problem. + if (m_currentReceiveTimeSamples >= s_receiveTimeSamples) + { + AverageReceiveTicksForLastSamplePeriod + = (float)m_receiveTicksInCurrentSamplePeriod / s_receiveTimeSamples; + + m_receiveTicksInCurrentSamplePeriod = 0; + m_currentReceiveTimeSamples = 0; + } + else + { + m_receiveTicksInCurrentSamplePeriod += Util.EnvironmentTickCountSubtract(startTick); + m_currentReceiveTimeSamples++; + } } catch (SocketException) { } catch (ObjectDisposedException) { } -- cgit v1.1 From 8396f1bd42cf42d412c09e769c491930aaa8bfea Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 22 Jul 2013 23:58:45 +0100 Subject: Record raw number of UDP receives as clientstack.IncomingUDPReceivesCount --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 13 +++++++++++++ OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index d3823f3..5300b1e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -69,6 +69,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( + "IncomingUDPReceivesCount", + "Number of inbound LL protocol packets processed", + "Number of inbound LL protocol packets processed", + "", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = m_udpServer.UdpReceives, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( "IncomingPacketsProcessedCount", "Number of inbound LL protocol packets processed", "Number of inbound LL protocol packets processed", diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 46a3261..b4044b5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -78,6 +78,11 @@ namespace OpenMetaverse public bool IsRunningOutbound { get; private set; } /// + /// Number of UDP receives. + /// + public int UdpReceives { get; private set; } + + /// /// Number of receives over which to establish a receive time average. /// private readonly static int s_receiveTimeSamples = 500; @@ -295,6 +300,8 @@ namespace OpenMetaverse // to AsyncBeginReceive if (IsRunningInbound) { + UdpReceives++; + // Asynchronous mode will start another receive before the // callback for this packet is even fired. Very parallel :-) if (m_asyncPacketHandling) @@ -345,7 +352,6 @@ namespace OpenMetaverse if (!m_asyncPacketHandling) AsyncBeginReceive(); } - } } -- cgit v1.1 From 60732c96efd149bbb0484b327b00463dc5b81aff Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 00:15:58 +0100 Subject: Add clientstack.OutgoingUDPSendsCount stat to show number of outbound UDP packets sent by a region per second --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 18 +++++++++++++++--- .../Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 7 +++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 5300b1e..cc4de10 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -70,8 +70,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( "IncomingUDPReceivesCount", - "Number of inbound LL protocol packets processed", - "Number of inbound LL protocol packets processed", + "Number of UDP receives performed", + "Number of UDP receives performed", "", "clientstack", scene.Name, @@ -95,6 +95,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( + "OutgoingUDPSendsCount", + "Number of UDP sends performed", + "Number of UDP sends performed", + "", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = m_udpServer.UdpSends, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( "AverageUDPProcessTime", "Average number of milliseconds taken to process each incoming UDP packet in a sample.", "This is for initial receive processing which is separate from the later client LL packet processing stage.", @@ -856,7 +869,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP PacketPool.Instance.ReturnPacket(packet); m_dataPresentEvent.Set(); - } private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index b4044b5..d0ed7e8 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -83,6 +83,11 @@ namespace OpenMetaverse public int UdpReceives { get; private set; } /// + /// Number of UDP sends + /// + public int UdpSends { get; private set; } + + /// /// Number of receives over which to establish a receive time average. /// private readonly static int s_receiveTimeSamples = 500; @@ -381,6 +386,8 @@ namespace OpenMetaverse { // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; m_udpSocket.EndSendTo(result); + + UdpSends++; } catch (SocketException) { } catch (ObjectDisposedException) { } -- cgit v1.1 From 9fb9da1b6c86e10b229706fe06f2875c8a63a52f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 00:31:57 +0100 Subject: Add clientstack.InboxPacketsCount stat. This records the number of packets waiting to be processed at the second stage (after initial UDP processing) If this consistently increases then this is a problem since it means the simulator is receiving more requests than it can distribute to other parts of the code. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index cc4de10..0e9f1b7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -500,6 +500,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = (Scene)scene; m_location = new Location(m_scene.RegionInfo.RegionHandle); + StatsManager.RegisterStat( + new Stat( + "InboxPacketsCount", + "Number of LL protocol packets waiting for the second stage of processing after initial receive.", + "Number of LL protocol packets waiting for the second stage of processing after initial receive.", + "", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = packetInbox.Count, + StatVerbosity.Debug)); + // XXX: These stats are also pool stats but we register them separately since they are currently not // turned on and off by EnablePools()/DisablePools() StatsManager.RegisterStat( -- cgit v1.1 From a57a472ab8edf70430a8391909e6078b9ae0f26d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 00:51:59 +0100 Subject: Add proper method doc and comments to m_dataPresentEvent (from d9d9959) --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 0e9f1b7..37fd252 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -223,6 +223,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Flag to signal when clients should send pings protected bool m_sendPing; + /// + /// 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. + /// + private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); + private Pool m_incomingPacketPool; /// @@ -881,11 +890,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP } PacketPool.Instance.ReturnPacket(packet); + m_dataPresentEvent.Set(); } - private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); - /// /// Start the process of sending a packet to the client. /// @@ -1817,6 +1825,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // token bucket could get more tokens //if (!m_packetSent) // Thread.Sleep((int)TickCountResolution); + // + // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with + // modern mono it reduces CPU base load since there is no more continuous polling. m_dataPresentEvent.WaitOne(100); Watchdog.UpdateThread(); -- cgit v1.1 From 90528c23d991cd1fc77823be49e4135cf412b92e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 01:13:13 +0100 Subject: For stats which can show average change over time, show the last sample as well as the average. This is somewhat cryptic at the moment, need to improve documentation. --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 9629b6e..cc2c947 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -253,6 +253,8 @@ namespace OpenSim.Framework.Monitoring == MeasuresOfInterest.AverageChangeOverTime) { double totalChange = 0; + double lastChangeOverTime = 0; + double? penultimateSample = null; double? lastSample = null; lock (m_samples) @@ -266,13 +268,21 @@ namespace OpenSim.Framework.Monitoring if (lastSample != null) totalChange += s - (double)lastSample; + penultimateSample = lastSample; lastSample = s; } } + if (lastSample != null && penultimateSample != null) + lastChangeOverTime = (double)lastSample - (double)penultimateSample; + int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; - sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); + double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); + + sb.AppendFormat( + ", {0:0.##} {1}/s, {2:0.##} {3}/s", + lastChangeOverTime, UnitName, averageChangeOverTime, UnitName); } } } -- cgit v1.1 From af9deed13593a85aef64205f9ca616a06711963c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 08:11:21 -0700 Subject: Revert "Revert "BulletSim: freshen up the code for constraint based linksets."" Found that the vehicle movement problem was not caused by these physics changes. This reverts commit 44543ebe638f391fc1c7ff532fe4470006dec55a. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 4 +- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 1 + .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 82 ++++++++++++++++------ 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 0204967..4c2c1c1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1029,8 +1029,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Add this correction to the velocity to make it faster/slower. VehicleVelocity += linearMotorVelocityW; - VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", - ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, + VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}", + ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity, frictionFactorV); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 1d94142..3668456 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -59,6 +59,7 @@ public sealed class BSLinksetCompound : BSLinkset { DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); + // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index a06a44d..f17d698 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -48,12 +48,22 @@ public sealed class BSLinksetConstraints : BSLinkset { base.Refresh(requestor); - if (HasAnyChildren && IsRoot(requestor)) + } + + private void ScheduleRebuild(BSPrimLinkable requestor) + { + DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", + requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); + + // When rebuilding, it is possible to set properties that would normally require a rebuild. + // If already rebuilding, don't request another rebuild. + // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. + if (!Rebuilding && HasAnyChildren) { // Queue to happen after all the other taint processing m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() { - if (HasAnyChildren && IsRoot(requestor)) + if (HasAnyChildren) RecomputeLinksetConstraints(); }); } @@ -67,8 +77,14 @@ public sealed class BSLinksetConstraints : BSLinkset // Called at taint-time! public override bool MakeDynamic(BSPrimLinkable child) { - // What is done for each object in BSPrim is what we want. - return false; + bool ret = false; + DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + if (IsRoot(child)) + { + // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. + ScheduleRebuild(LinksetRoot); + } + return ret; } // The object is going static (non-physical). Do any setup necessary for a static linkset. @@ -78,8 +94,16 @@ public sealed class BSLinksetConstraints : BSLinkset // Called at taint-time! public override bool MakeStatic(BSPrimLinkable child) { - // What is done for each object in BSPrim is what we want. - return false; + bool ret = false; + + DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); + if (IsRoot(child)) + { + // Schedule a rebuild to verify that the root shape is set to the real shape. + ScheduleRebuild(LinksetRoot); + } + return ret; } // Called at taint-time!! @@ -105,7 +129,7 @@ public sealed class BSLinksetConstraints : BSLinkset // Just undo all the constraints for this linkset. Rebuild at the end of the step. ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); // Cause the constraints, et al to be rebuilt before the next simulation step. - Refresh(LinksetRoot); + ScheduleRebuild(LinksetRoot); } return ret; } @@ -123,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); // Cause constraints and assorted properties to be recomputed before the next simulation step. - Refresh(LinksetRoot); + ScheduleRebuild(LinksetRoot); } return; } @@ -147,7 +171,7 @@ public sealed class BSLinksetConstraints : BSLinkset PhysicallyUnlinkAChildFromRoot(rootx, childx); }); // See that the linkset parameters are recomputed at the end of the taint time. - Refresh(LinksetRoot); + ScheduleRebuild(LinksetRoot); } else { @@ -165,6 +189,7 @@ public sealed class BSLinksetConstraints : BSLinkset Refresh(rootPrim); } + // Create a static constraint between the two passed objects private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) { // Zero motion for children so they don't interpolate @@ -281,24 +306,39 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); - foreach (BSPrimLinkable child in m_children) + try { - // A child in the linkset physically shows the mass of the whole linkset. - // This allows Bullet to apply enough force on the child to move the whole linkset. - // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - child.UpdatePhysicalMassProperties(linksetMass, true); + Rebuilding = true; - BSConstraint constrain; - if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) + // There is no reason to build all this physical stuff for a non-physical linkset. + if (!LinksetRoot.IsPhysicallyActive) { - // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, child); + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); + return; // Note the 'finally' clause at the botton which will get executed. } - constrain.RecomputeConstraintVariables(linksetMass); - // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG - } + foreach (BSPrimLinkable child in m_children) + { + // A child in the linkset physically shows the mass of the whole linkset. + // This allows Bullet to apply enough force on the child to move the whole linkset. + // (Also do the mass stuff before recomputing the constraint so mass is not zero.) + child.UpdatePhysicalMassProperties(linksetMass, true); + + BSConstraint constrain; + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) + { + // If constraint doesn't exist yet, create it. + constrain = BuildConstraint(LinksetRoot, child); + } + constrain.RecomputeConstraintVariables(linksetMass); + // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG + } + } + finally + { + Rebuilding = false; + } } } } -- cgit v1.1 From 401c2e2f2ec7c6001387df505665b19477afd4cf Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 08:12:34 -0700 Subject: Revert "Revert "Add experimental stubs for an extension function interface on both"" Found that the vehicle movement problem was not caused by these physics changes. This reverts commit 89857378ce79f93a265bc1eb151e17742032abfa. --- OpenSim/Region/Physics/Manager/PhysicsActor.cs | 6 ++++++ OpenSim/Region/Physics/Manager/PhysicsScene.cs | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index bd806eb..2500f27 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -313,6 +313,12 @@ namespace OpenSim.Region.Physics.Manager public abstract void SubscribeEvents(int ms); public abstract void UnSubscribeEvents(); public abstract bool SubscribedEvents(); + + // Extendable interface for new, physics engine specific operations + public virtual object Extension(string pFunct, params object[] pParams) + { + throw new NotImplementedException(); + } } public class NullPhysicsActor : PhysicsActor diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 290b72e..07a1d36 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -25,10 +25,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using System.Collections.Generic; using System.Reflection; + using log4net; using Nini.Config; + using OpenSim.Framework; using OpenMetaverse; @@ -331,5 +334,11 @@ namespace OpenSim.Region.Physics.Manager { return false; } + + // Extendable interface for new, physics engine specific operations + public virtual object Extension(string pFunct, params object[] pParams) + { + throw new NotImplementedException(); + } } } -- cgit v1.1 From aec8852af793699a4c1093a38b992daf2dbd97f3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 08:13:01 -0700 Subject: Revert "Revert "BulletSim: move collision processing for linksets from BSPrimLinkable"" Found that the vehicle movement problem was not caused by these physics changes. This reverts commit c45659863d8821a48a32e5b687c7b2a6d90b0300. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 16 ++--- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 75 +++++++++++++++++++++- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 11 ++++ OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 5 +- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 32 +++++++-- 5 files changed, 121 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 4c2c1c1..1540df1 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -1001,7 +1001,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin else if (newVelocityLengthSq < 0.001f) VehicleVelocity = Vector3.Zero; - VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); + VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity ); } // end MoveLinear() @@ -1062,7 +1062,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation; // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall. - if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.IsColliding) + if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision) { linearDeflectionW.Z = 0f; } @@ -1222,7 +1222,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); distanceAboveGround = VehiclePosition.Z - targetHeight; // Not colliding if the vehicle is off the ground - if (!Prim.IsColliding) + if (!Prim.HasSomeCollision) { // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); @@ -1233,12 +1233,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin // be computed with a motor. // TODO: add interaction with banking. VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", - Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); + Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret); */ // Another approach is to measure if we're going up. If going up and not colliding, // the vehicle is in the air. Fix that by pushing down. - if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) + if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1) { // Get rid of any of the velocity vector that is pushing us up. float upVelocity = VehicleVelocity.Z; @@ -1260,7 +1260,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin } */ VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", - ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); + ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity); } } } @@ -1270,14 +1270,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; // Hack to reduce downward force if the vehicle is probably sitting on the ground - if (ControllingPrim.IsColliding && IsGroundVehicle) + if (ControllingPrim.HasSomeCollision && IsGroundVehicle) appliedGravity *= BSParam.VehicleGroundGravityFudge; VehicleAddForce(appliedGravity); VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", ControllingPrim.LocalID, m_VehicleGravity, - ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); + ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); } // ======================================================================= diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index ad8e10f..78c0af7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -203,6 +203,33 @@ public abstract class BSLinkset return ret; } + // Called after a simulation step to post a collision with this object. + // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have + // anything to add for the collision and it should be passed through normal processing. + // Default processing for a linkset. + public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // prims in the same linkset cannot collide with each other + BSPrimLinkable convCollidee = collidee as BSPrimLinkable; + if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) + { + // By returning 'true', we tell the caller the collision has been 'handled' so it won't + // do anything about this collision and thus, effectivily, ignoring the collision. + ret = true; + } + else + { + // Not a collision between members of the linkset. Must be a real collision. + // So the linkset root can know if there is a collision anywhere in the linkset. + LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; + } + + return ret; + } + // I am the root of a linkset and a new child is being added // Called while LinkActivity is locked. protected abstract void AddChildToLinkset(BSPrimLinkable child); @@ -251,6 +278,53 @@ public abstract class BSLinkset public abstract bool RemoveDependencies(BSPrimLinkable child); // ================================================================ + // Some physical setting happen to all members of the linkset + public virtual void SetPhysicalFriction(float friction) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(member.PhysBody, friction); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalRestitution(float restitution) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalGravity(OMV.Vector3 gravity) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(member.PhysBody, gravity); + return false; // 'false' says to continue looping + } + ); + } + public virtual void ComputeLocalInertia() + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); + member.Inertia = inertia * BSParam.VehicleInertiaFactor; + m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); + } + return false; // 'false' says to continue looping + } + ); + } + // ================================================================ protected virtual float ComputeLinksetMass() { float mass = LinksetRoot.RawMass; @@ -311,6 +385,5 @@ public abstract class BSLinkset if (m_physicsScene.PhysicsLogging.Enabled) m_physicsScene.DetailLog(msg, args); } - } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index fc4545f..d34b797 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -353,6 +353,16 @@ public abstract class BSPhysObject : PhysicsActor CollidingStep = BSScene.NotASimulationStep; } } + // Complex objects (like linksets) need to know if there is a collision on any part of + // their shape. 'IsColliding' has an existing definition of reporting a collision on + // only this specific prim or component of linksets. + // 'HasSomeCollision' is defined as reporting if there is a collision on any part of + // the complex body that this prim is the root of. + public virtual bool HasSomeCollision + { + get { return IsColliding; } + set { IsColliding = value; } + } public override bool CollidingGround { get { return (CollidingGroundStep == PhysScene.SimulationStep); } set @@ -386,6 +396,7 @@ public abstract class BSPhysObject : PhysicsActor // Return 'true' if a collision was processed and should be sent up. // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. // Called at taint time from within the Step() function + public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); public virtual bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index d43448e..4771934 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -495,8 +495,8 @@ public class BSPrim : BSPhysObject } } - // Find and return a handle to the current vehicle actor. - // Return 'null' if there is no vehicle actor. + // Find and return a handle to the current vehicle actor. + // Return 'null' if there is no vehicle actor. public BSDynamics GetVehicleActor() { BSDynamics ret = null; @@ -507,6 +507,7 @@ public class BSPrim : BSPhysObject } return ret; } + public override int VehicleType { get { int ret = (int)Vehicle.TYPE_NONE; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 1fbcfcc..2f392da 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -200,20 +200,38 @@ public class BSPrimLinkable : BSPrimDisplaced } // Called after a simulation step to post a collision with this object. + // This returns 'true' if the collision has been queued and the SendCollisions call must + // be made at the end of the simulation step. public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { - // prims in the same linkset cannot collide with each other - BSPrimLinkable convCollidee = collidee as BSPrimLinkable; - if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) + bool ret = false; + // Ask the linkset if it wants to handle the collision + if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth)) { - return false; + // The linkset didn't handle it so pass the collision through normal processing + ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); } + return ret; + } - // TODO: handle collisions of other objects with with children of linkset. - // This is a problem for LinksetCompound since the children are packed into the root. + // A linkset reports any collision on any part of the linkset. + public long SomeCollisionSimulationStep = 0; + public override bool HasSomeCollision + { + get + { + return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; + } + set + { + if (value) + SomeCollisionSimulationStep = PhysScene.SimulationStep; + else + SomeCollisionSimulationStep = 0; - return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); + base.HasSomeCollision = value; + } } } } -- cgit v1.1 From b14156aa6317b2c0ca6801730beb7c51eed97244 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 08:13:29 -0700 Subject: Revert "Revert "BulletSim: only create vehicle prim actor when vehicles are enabled."" Found that the vehicle movement problem was not caused by these physics changes. This reverts commit 5f7b2ea81b95a60e882bc65b663a2c9fe134f92a. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 43 ++++++++++++++++------ .../Physics/BulletSPlugin/Tests/BasicVehicles.cs | 2 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 4771934..fdb2925 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -96,7 +96,7 @@ public class BSPrim : BSPhysObject _isVolumeDetect = false; // Add a dynamic vehicle to our set of actors that can move this prim. - PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); + // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); _mass = CalculateMass(); @@ -497,7 +497,7 @@ public class BSPrim : BSPhysObject // Find and return a handle to the current vehicle actor. // Return 'null' if there is no vehicle actor. - public BSDynamics GetVehicleActor() + public BSDynamics GetVehicleActor(bool createIfNone) { BSDynamics ret = null; BSActor actor; @@ -505,13 +505,21 @@ public class BSPrim : BSPhysObject { ret = actor as BSDynamics; } + else + { + if (createIfNone) + { + ret = new BSDynamics(PhysScene, this, VehicleActorName); + PhysicalActors.Add(ret.ActorName, ret); + } + } return ret; } public override int VehicleType { get { int ret = (int)Vehicle.TYPE_NONE; - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); if (vehicleActor != null) ret = (int)vehicleActor.Type; return ret; @@ -525,11 +533,24 @@ public class BSPrim : BSPhysObject // change all the parameters. Like a plane changing to CAR when on the // ground. In this case, don't want to zero motion. // ZeroMotion(true /* inTaintTime */); - BSDynamics vehicleActor = GetVehicleActor(); - if (vehicleActor != null) + if (type == Vehicle.TYPE_NONE) { - vehicleActor.ProcessTypeChange(type); - ActivateIfPhysical(false); + // Vehicle type is 'none' so get rid of any actor that may have been allocated. + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + if (vehicleActor != null) + { + PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); + } + } + else + { + // Vehicle type is not 'none' so create an actor and set it running. + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessTypeChange(type); + ActivateIfPhysical(false); + } } }); } @@ -538,7 +559,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); @@ -550,7 +571,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); @@ -562,7 +583,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); @@ -574,7 +595,7 @@ public class BSPrim : BSPhysObject { PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() { - BSDynamics vehicleActor = GetVehicleActor(); + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessVehicleFlags(param, remove); diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 48d3742..48e74eb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs @@ -116,7 +116,7 @@ public class BasicVehicles : OpenSimTestCase // Instead the appropriate values are set and calls are made just the parts of the // controller we want to exercise. Stepping the physics engine then applies // the actions of that one feature. - BSDynamics vehicleActor = TestVehicle.GetVehicleActor(); + BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) { vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); -- cgit v1.1 From 75686e0e49308a21ca013d246544f88cd8e90cbd Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 08:13:56 -0700 Subject: Revert "Revert "BulletSim: change BSDynamics to expect to be passed a BSPrimLinkable"" Found that the vehicle movement problem was not caused by these physics changes. This reverts commit 7b187deb19517aa7c880458894643a5448566a94. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 1540df1..82d7c44 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin private static string LogHeader = "[BULLETSIM VEHICLE]"; // the prim this dynamic controller belongs to - private BSPrim ControllingPrim { get; set; } + private BSPrimLinkable ControllingPrim { get; set; } private bool m_haveRegisteredForSceneEvents; @@ -128,9 +128,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) : base(myScene, myPrim, actorName) { - ControllingPrim = myPrim; Type = Vehicle.TYPE_NONE; m_haveRegisteredForSceneEvents = false; + + ControllingPrim = myPrim as BSPrimLinkable; + if (ControllingPrim == null) + { + // THIS CANNOT HAPPEN!! + } + VDetailLog("{0},Creation", ControllingPrim.LocalID); } // Return 'true' if this vehicle is doing vehicle things @@ -585,6 +591,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Friction affects are handled by this vehicle code m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); + // ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); + // ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); // Moderate angular movement introduced by Bullet. // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. @@ -595,17 +603,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Vehicles report collision events so we know when it's on the ground m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + // ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); + // ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor); // Set the gravity for the vehicle depending on the buoyancy // TODO: what should be done if prim and vehicle buoyancy differ? m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); + // ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, @@ -617,6 +628,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if (ControllingPrim.PhysBody.HasPhysicalBody) m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); } } @@ -629,6 +641,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // BSActor.Release() public override void Dispose() { + VDetailLog("{0},Dispose", ControllingPrim.LocalID); UnregisterForSceneEvents(); Type = Vehicle.TYPE_NONE; Enabled = false; -- cgit v1.1 From f499b328c44ef29d92aa2ef8102aad6ff5cbe336 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 08:14:20 -0700 Subject: Revert "Revert "BulletSim: Add logic to linksets to change physical properties for"" Found that the vehicle movement problem was not caused by these physics changes. This reverts commit 84d0699761b8da546f9faef084240d7b15f16321. --- OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | 6 +--- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 24 +++++++++++++-- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 36 ++++++++++++++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs index fff63e4..e0ccc50 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs @@ -69,7 +69,7 @@ public class BSActorCollection { lock (m_actors) { - Release(); + ForEachActor(a => a.Dispose()); m_actors.Clear(); } } @@ -98,10 +98,6 @@ public class BSActorCollection { ForEachActor(a => a.SetEnabled(enabl)); } - public void Release() - { - ForEachActor(a => a.Dispose()); - } public void Refresh() { ForEachActor(a => a.Refresh()); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 78c0af7..960c0b4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -309,14 +309,14 @@ public abstract class BSLinkset } ); } - public virtual void ComputeLocalInertia() + public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor) { ForEachMember((member) => { if (member.PhysBody.HasPhysicalBody) { OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); - member.Inertia = inertia * BSParam.VehicleInertiaFactor; + member.Inertia = inertia * inertiaFactor; m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); } @@ -324,6 +324,26 @@ public abstract class BSLinkset } ); } + public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } // ================================================================ protected virtual float ComputeLinksetMass() { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 3668456..33ae5a5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -44,6 +44,42 @@ public sealed class BSLinksetCompound : BSLinkset { } + // ================================================================ + // Changing the physical property of the linkset only needs to change the root + public override void SetPhysicalFriction(float friction) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); + } + public override void SetPhysicalRestitution(float restitution) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); + } + public override void SetPhysicalGravity(OMV.Vector3 gravity) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); + } + public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass); + LinksetRoot.Inertia = inertia * inertiaFactor; + m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); + } + public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + // ================================================================ + // When physical properties are changed the linkset needs to recalculate // its internal properties. public override void Refresh(BSPrimLinkable requestor) -- cgit v1.1 From aec8d1e6be43422b0f93de47d6e46cc3e17399cc Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 23 Jul 2013 09:09:25 -0700 Subject: BulletSim: Turn on center-of-mass calculation by default. Reduce object density by factor of 100 to bring physical mass computations into a range better suited for Bullet. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 8 +++++--- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index dcf1e83..0bdb5f1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -461,8 +461,9 @@ public static class BSParam (s) => { return MaxAddForceMagnitude; }, (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), // Density is passed around as 100kg/m3. This scales that to 1kg/m3. + // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", - 0.01f ), + 0.0001f ), new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 2200f ), @@ -607,8 +608,9 @@ public static class BSParam 0.0f ), new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", 0.0f ), + // Turn off fudge with DensityScaleFactor = 0.0001. Value used to be 0.2f; new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", - 0.2f ), + 1.0f ), new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 60.0f ), new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", @@ -701,7 +703,7 @@ public static class BSParam new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", (float)BSLinkset.LinksetImplementation.Compound ), new ParameterDefn("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", - false ), + true ), new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", false ), new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index fdb2925..e92a1d2 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -440,8 +440,8 @@ public class BSPrim : BSPhysObject Gravity = ComputeGravity(Buoyancy); PhysScene.PE.SetGravity(PhysBody, Gravity); - OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG - DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG + // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG + // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); -- cgit v1.1 From 76e46d0158461a29e6ef358ba8cb7b7323cc0c05 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 17:23:16 +0100 Subject: Improve spacing between data and units on console stats display --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index cc2c947..f2329ce 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -225,7 +225,13 @@ namespace OpenSim.Framework.Monitoring public virtual string ToConsoleString() { StringBuilder sb = new StringBuilder(); - sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName); + sb.AppendFormat( + "{0}.{1}.{2} : {3}{4}", + Category, + Container, + ShortName, + Value, + UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName)); AppendMeasuresOfInterest(sb); @@ -281,8 +287,11 @@ namespace OpenSim.Framework.Monitoring double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); sb.AppendFormat( - ", {0:0.##} {1}/s, {2:0.##} {3}/s", - lastChangeOverTime, UnitName, averageChangeOverTime, UnitName); + ", {0:0.##}{1}/s, {2:0.##}{3}/s", + lastChangeOverTime, + UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName), + averageChangeOverTime, + UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName)); } } } -- cgit v1.1 From 7c1eb86c7df2e9c9ccfcf4fe6811af29adbef931 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 15:46:00 -0700 Subject: Don't post Link asset types back to the home grid --- .../Framework/InventoryAccess/HGInventoryAccessModule.cs | 9 ++++++--- OpenSim/Region/Framework/Scenes/EventManager.cs | 6 +++--- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index e0c8ea6..460d147 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -185,8 +185,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) + public void UploadInventoryItem(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel) { + if (type == AssetType.Link) + return; + string userAssetServer = string.Empty; if (IsForeignUser(avatarID, out userAssetServer) && userAssetServer != string.Empty && m_OutboundPermission) { @@ -221,7 +224,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); - UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0); + UploadInventoryItem(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0); return newAssetID; } @@ -232,7 +235,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected override void ExportAsset(UUID agentID, UUID assetID) { if (!assetID.Equals(UUID.Zero)) - UploadInventoryItem(agentID, assetID, "", 0); + UploadInventoryItem(agentID, AssetType.Unknown, assetID, "", 0); else m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 61b0ebd..39d7512 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -742,7 +742,7 @@ namespace OpenSim.Region.Framework.Scenes public event OnIncomingSceneObjectDelegate OnIncomingSceneObject; public delegate void OnIncomingSceneObjectDelegate(SceneObjectGroup so); - public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel); + public delegate void NewInventoryItemUploadComplete(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel); public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete; @@ -2146,7 +2146,7 @@ namespace OpenSim.Region.Framework.Scenes } } - public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, UUID AssetID, String AssetName, int userlevel) + public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, AssetType type, UUID AssetID, String AssetName, int userlevel) { NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete; if (handlerNewInventoryItemUpdateComplete != null) @@ -2155,7 +2155,7 @@ namespace OpenSim.Region.Framework.Scenes { try { - d(agentID, AssetID, AssetName, userlevel); + d(agentID, type, AssetID, AssetName, userlevel); } catch (Exception e) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 1e4d558..58fa18c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes { userlevel = 1; } - EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel); + EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel); return true; } @@ -178,7 +178,7 @@ namespace OpenSim.Region.Framework.Scenes { userlevel = 1; } - EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, item.AssetID, item.Name, userlevel); + EventManager.TriggerOnNewInventoryItemUploadComplete(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel); if (originalFolder != UUID.Zero) { -- cgit v1.1 From 42e52f544df5210b41b96176c364d1f1d2d96b00 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 23 Jul 2013 11:29:53 -0700 Subject: Improvement of fetching name in groups --- OpenSim/Addons/Groups/GroupsModule.cs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 82e2d6f..69d03a9 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -1402,19 +1402,18 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); // TODO: All the client update functions need to be reexamined because most do too much and send too much stuff - UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID); - string firstname, lastname; - if (account != null) - { - firstname = account.FirstName; - lastname = account.LastName; - } - else + string firstname = "Unknown", lastname = "Unknown"; + string name = m_UserManagement.GetUserName(dataForAgentID); + if (!string.IsNullOrEmpty(name)) { - firstname = "Unknown"; - lastname = "Unknown"; + string[] parts = name.Split(new char[] { ' ' }); + if (parts.Length >= 2) + { + firstname = parts[0]; + lastname = parts[1]; + } } - + remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname, lastname, activeGroupPowers, activeGroupName, activeGroupTitle); -- cgit v1.1 From 744276dd50daaaba5b4c54ab37f5a034bd48ca3a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 23 Jul 2013 14:17:32 -0700 Subject: In renaming the folders for hypergriding, don't rename the Current Outfit folder. The viewer doesn't like that. --- .../CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 460d147..94ea077 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -384,7 +384,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (InventoryFolderBase f in content.Folders) { - if (f.Name != "My Suitcase") + if (f.Name != "My Suitcase" && f.Name != "Current Outfit") { f.Name = f.Name + " (Unavailable)"; keep.Add(f); -- cgit v1.1 From 901bdfed4093c4d87c59abfbd576e71b2374b7c3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 23 Jul 2013 14:23:22 -0700 Subject: Restoring landing on prims, which had been affected by the edit beams commit. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 33db88b..6433878 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1125,6 +1125,25 @@ namespace OpenSim.Region.Framework.Scenes public void StopFlying() { + Vector3 pos = AbsolutePosition; + if (Appearance.AvatarHeight != 127.0f) + pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f)); + else + pos += new Vector3(0f, 0f, (1.56f / 6f)); + + AbsolutePosition = pos; + + // attach a suitable collision plane regardless of the actual situation to force the LLClient to land. + // Collision plane below the avatar's position a 6th of the avatar's height is suitable. + // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a + // certain amount.. because the LLClient wouldn't land in that situation anyway. + + // why are we still testing for this really old height value default??? + if (Appearance.AvatarHeight != 127.0f) + CollisionPlane = new Vector4(0, 0, 0, pos.Z - Appearance.AvatarHeight / 6f); + else + CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f)); + ControllingClient.SendAgentTerseUpdate(this); } -- cgit v1.1 From 516062ae1fb7417bbd1e206cb412da41094addfb Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 23 Jul 2013 15:04:24 -0700 Subject: Don't touch the Current Outfit folder also on coming back home --- .../Framework/InventoryAccess/HGInventoryAccessModule.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 94ea077..8f9800f 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -351,7 +351,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId); InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); - inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray()); + List keep = new List(); + + foreach (InventoryFolderBase f in content.Folders) + { + if (f.Name != "My Suitcase" && f.Name != "Current Outfit") + keep.Add(f); + } + + inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray()); } } } -- cgit v1.1 From 9a4a513b5e4e2496b32113dcffbeeae776eabb89 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 23:31:35 +0100 Subject: Correct issue where the last instance of a sampled stat was shown 3x larger than it should have been (though internal use was correct) --- OpenSim/Framework/Monitoring/Stats/Stat.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index f2329ce..ffd5132 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -280,7 +280,8 @@ namespace OpenSim.Framework.Monitoring } if (lastSample != null && penultimateSample != null) - lastChangeOverTime = (double)lastSample - (double)penultimateSample; + lastChangeOverTime + = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; -- cgit v1.1 From feef9d64a478695aa9721423c818e57bf4e0dff6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 23 Jul 2013 23:42:34 +0100 Subject: For unknown user issue, bump GUN7 to GUN8 and UMMAU3 to UMMAU4 to assess what looks like a very significant reducing in GUN occurrances --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index a91adfa..53bd2e2 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -389,7 +389,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } names[0] = "Unknown"; - names[1] = "UserUMMTGUN7"; + names[1] = "UserUMMTGUN8"; return false; } @@ -601,7 +601,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or // disappeared. user.FirstName = "Unknown"; - user.LastName = "UserUMMAU3"; + user.LastName = "UserUMMAU4"; } AddUserInternal(user); -- cgit v1.1 From d8a6eb5641f3b16811695ff34d925ae27de8fa38 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 11:13:31 -0700 Subject: Decreased the time of group cache to 1 min, because it was getting on my nerves that it takes so long to let go of old info. --- OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs index 79d6fc5..3ac74fc 100644 --- a/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs +++ b/OpenSim/Addons/Groups/RemoteConnectorCacheWrapper.cs @@ -53,7 +53,7 @@ namespace OpenSim.Groups private ForeignImporter m_ForeignImporter; private Dictionary m_ActiveRequests = new Dictionary(); - private const int GROUPS_CACHE_TIMEOUT = 5 * 60; // 5 minutes + private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes // This all important cache cahces objects of different types: // group- or group- => ExtendedGroupRecord -- cgit v1.1 From e103e34f1d17d218c55ebb1ff19450c018cf73b2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 11:23:19 -0700 Subject: Added config var that we all thought was already there: see_into_region. (Note: different from the defunct see_into_neighboring_sim, which used to control the process from the other end). This enables child agents in neighbors for which the root agent doesn't have permission to be in. --- OpenSim/Region/Framework/Scenes/Scene.cs | 79 ++++++++++++++++++-------------- bin/OpenSimDefaults.ini | 3 ++ 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 9cfe869..e443c1d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -230,6 +230,8 @@ namespace OpenSim.Region.Framework.Scenes public int MaxUndoCount { get; set; } + public bool SeeIntoRegion { get; set; } + // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; public bool LoginLock = false; @@ -839,6 +841,8 @@ namespace OpenSim.Region.Framework.Scenes //Animation states m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); + SeeIntoRegion = startupConfig.GetBoolean("see_into_region", true); + MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20); PhysicalPrims = startupConfig.GetBoolean("physical_prim", PhysicalPrims); @@ -4010,51 +4014,58 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!"); } - List agentGroups = new List(); - - if (m_groupsModule != null) + // We only test the things below when we want to cut off + // child agents from being present in the scene for which their root + // agent isn't allowed. Otherwise, we allow child agents. The test for + // the root is done elsewhere (QueryAccess) + if (!SeeIntoRegion) { - GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); + List agentGroups = new List(); - if (GroupMembership != null) - { - for (int i = 0; i < GroupMembership.Length; i++) - agentGroups.Add(GroupMembership[i].GroupID); - } - else + if (m_groupsModule != null) { - m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); + GroupMembershipData[] GroupMembership = m_groupsModule.GetMembershipData(agent.AgentID); + + if (GroupMembership != null) + { + for (int i = 0; i < GroupMembership.Length; i++) + agentGroups.Add(GroupMembership[i].GroupID); + } + else + { + m_log.ErrorFormat("[CONNECTION BEGIN]: GroupMembership is null!"); + } } - } - bool groupAccess = false; - UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; + bool groupAccess = false; + UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; - if (estateGroups != null) - { - foreach (UUID group in estateGroups) + if (estateGroups != null) { - if (agentGroups.Contains(group)) + foreach (UUID group in estateGroups) { - groupAccess = true; - break; + if (agentGroups.Contains(group)) + { + groupAccess = true; + break; + } } } - } - else - { - m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); - } + else + { + m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); + } - if (!RegionInfo.EstateSettings.PublicAccess && - !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && - !groupAccess) - { - m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", - agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", - RegionInfo.RegionName); - return false; + if (!RegionInfo.EstateSettings.PublicAccess && + !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && + !groupAccess) + { + m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", + agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); + reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", + RegionInfo.RegionName); + return false; + } } // TODO: estate/region settings are not properly hooked up diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 8079632..6aa534a 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -86,6 +86,9 @@ ;; from the selected region_info_source. allow_regionless = false + ;; Allow child agents to see into the region even if their root counterpart isn't allowed in here + see_into_region = true + ; Maximum number of position, rotation and scale changes for each prim that the simulator will store for later undos ; Increasing this number will increase memory usage. MaxPrimUndos = 20 -- cgit v1.1 From 00d4a26eefafbe078af78458c9ca58931e29ecb9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 11:42:35 -0700 Subject: Amend previous commit. --- OpenSim/Region/Framework/Scenes/Scene.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e443c1d..f766140 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3739,7 +3739,7 @@ namespace OpenSim.Region.Framework.Scenes try { - if (!AuthorizeUser(agent, out reason)) + if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) { m_authenticateHandler.RemoveCircuit(agent.circuitcode); return false; @@ -3979,7 +3979,7 @@ namespace OpenSim.Region.Framework.Scenes /// outputs the reason to this string /// True if the region accepts this agent. False if it does not. False will /// also return a reason. - protected virtual bool AuthorizeUser(AgentCircuitData agent, out string reason) + protected virtual bool AuthorizeUser(AgentCircuitData agent, bool bypassAccessControl, out string reason) { reason = String.Empty; @@ -4018,7 +4018,7 @@ namespace OpenSim.Region.Framework.Scenes // child agents from being present in the scene for which their root // agent isn't allowed. Otherwise, we allow child agents. The test for // the root is done elsewhere (QueryAccess) - if (!SeeIntoRegion) + if (!bypassAccessControl) { List agentGroups = new List(); @@ -5588,7 +5588,7 @@ namespace OpenSim.Region.Framework.Scenes try { - if (!AuthorizeUser(aCircuit, out reason)) + if (!AuthorizeUser(aCircuit, false, out reason)) { // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); return false; -- cgit v1.1 From 9ab78d412cdb61b3d5c4727002c3a8eb7f6abb7f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 17:38:01 -0700 Subject: EXPERIMENTAL: yet another variation of ES/EAC/TPFinish --- .../EntityTransfer/EntityTransferModule.cs | 78 +++++++++++----------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 344c8d7..3e7575b 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -744,30 +744,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #endregion capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - if (m_eqModule != null) - { - // The EnableSimulator message makes the client establish a connection with the destination - // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the - // correct circuit code. - m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); - - // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination - // simulator to confirm that it has established communication with the viewer. - Thread.Sleep(200); - - // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears - // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly - // only on TeleportFinish). This is untested for region teleport between different simulators - // though this probably also works. - m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); - } - else - { - // XXX: This is a little misleading since we're information the client of its avatar destination, - // which may or may not be a neighbour region of the source region. This path is probably little - // used anyway (with EQ being the one used). But it is currently being used for test code. - sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); - } + //if (m_eqModule != null) + //{ + // // The EnableSimulator message makes the client establish a connection with the destination + // // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the + // // correct circuit code. + // m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); + + // // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination + // // simulator to confirm that it has established communication with the viewer. + // Thread.Sleep(200); + + // // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears + // // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly + // // only on TeleportFinish). This is untested for region teleport between different simulators + // // though this probably also works. + // m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); + //} + //else + //{ + // // XXX: This is a little misleading since we're information the client of its avatar destination, + // // which may or may not be a neighbour region of the source region. This path is probably little + // // used anyway (with EQ being the one used). But it is currently being used for test code. + // sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); + //} } else { @@ -796,6 +796,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } + // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, + // where that neighbour simulator could otherwise request a child agent create on the source which then + // closes our existing agent which is still signalled as root. + sp.IsChildAgent = true; + + if (m_eqModule != null) + { + m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); + } + else + { + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + } + // A common teleport failure occurs when we can send CreateAgent to the // destination region but the viewer cannot establish the connection (e.g. due to network issues between // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then @@ -838,21 +853,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); - // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, - // where that neighbour simulator could otherwise request a child agent create on the source which then - // closes our existing agent which is still signalled as root. - sp.IsChildAgent = true; - - if (m_eqModule != null) - { - m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); - } - else - { - sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, - teleportFlags, capsPath); - } - // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we close things here. -- cgit v1.1 From aae29c0ee2467a7978df53dba6f8461d1f566c59 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 21 Jul 2013 20:22:13 -0700 Subject: Further tweaks on TPs: not sending the callback URL and instead waiting 15sec before closing the agent. This seems to be working fairly well. The viewer seems to have an 8 sec delay between UseCircuitCode and CompleteMovement. Also added back the position on UpdateAgent, because it's needed for TPing between neighboring regions. --- .../EntityTransfer/EntityTransferModule.cs | 59 ++++++++++++---------- .../Presence/PresenceDetector.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 3e7575b..5124aed 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -684,6 +684,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Contacting destination..."); + // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; @@ -724,8 +726,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); - // OK, it got this agent. Let's close some child agents - sp.CloseChildAgents(newRegionX, newRegionY); + #region old protocol IClientIPEndpoint ipepClient; if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) @@ -775,11 +776,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } + #endregion old protocol + // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); sp.CopyTo(agent); agent.Position = position; - SetCallbackURL(agent, sp.Scene.RegionInfo); + //SetCallbackURL(agent, sp.Scene.RegionInfo); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); @@ -801,6 +804,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // closes our existing agent which is still signalled as root. sp.IsChildAgent = true; + // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid if (m_eqModule != null) { m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); @@ -853,30 +857,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); - // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which - // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation - // that the client contacted the destination before we close things here. - if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) - { - if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) - { - m_interRegionTeleportAborts.Value++; - - 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); - - return; - } - - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", - sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + //// TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which + //// trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation + //// that the client contacted the destination before we close things here. + //if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) + //{ + // if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) + // { + // m_interRegionTeleportAborts.Value++; + + // 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); + + // return; + // } + + // m_log.WarnFormat( + // "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", + // sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); + // Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); - return; - } + // return; + //} m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); @@ -897,6 +901,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Now let's make it officially a child agent sp.MakeChildAgent(); + // OK, it got this agent. Let's close some child agents + sp.CloseChildAgents(newRegionX, newRegionY); + // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) @@ -907,7 +914,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // // This sleep can be increased if necessary. However, whilst it's active, // an agent cannot teleport back to this region if it has teleported away. - Thread.Sleep(2000); + Thread.Sleep(15000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index 172bea1..516ad40 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs @@ -79,7 +79,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence public void OnConnectionClose(IClientAPI client) { - if (!client.SceneAgent.IsChildAgent) + if (client != null && client.SceneAgent != null && !client.SceneAgent.IsChildAgent) { // m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); m_PresenceService.LogoutAgent(client.SessionId); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f766140..d4ef3d9 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4269,7 +4269,7 @@ namespace OpenSim.Region.Framework.Scenes /// protected virtual ScenePresence WaitGetScenePresence(UUID agentID) { - int ntimes = 10; + int ntimes = 20; ScenePresence sp = null; while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) Thread.Sleep(1000); -- cgit v1.1 From 3891a8946bb72c9256d8de4185bf4a72c90be859 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 11:54:35 -0700 Subject: New Teleport protocol (V2), still compatible with V1 and older. (version of the destination is being checked) In this new protocol, and as committed before, the viewer is not sent EnableSimulator/EstablishChildCommunication for the destination. Instead, it is sent TeleportFinish directly. TeleportFinish, in turn, makes the viewer send a UserCircuitCode packet followed by CompleteMovementIntoRegion packet. These 2 packets tend to occur one after the other almost immediately to the point that when CMIR arrives the client is not even connected yet and that packet is ignored (there might have been some race conditions here before); then the viewer sends CMIR again within 5-8 secs. But the delay between them may be higher in busier regions, which may lead to race conditions. This commit improves the process so there are are no race conditions at the destination. CompleteMovement (triggered by the viewer) waits until Update has been sent from the origin. Update, in turn, waits until there is a *root* scene presence -- so making sure CompleteMovement has run MakeRoot. In other words, there are two threadlets at the destination, one from the viewer and one from the origin region, waiting for each other to do the right thing. That makes it safe to close the agent at the origin upon return of the Update call without having to wait for callback, because we are absolutely sure that the viewer knows it is in th new region. Note also that in the V1 protocol, the destination was getting UseCircuitCode from the viewer twice -- once on EstablishAgentCommunication and then again on TeleportFinish. The second UCC was being ignored, but it shows how we were not following the expected steps... --- OpenSim/Framework/ChildAgentDataUpdate.cs | 11 +- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 68 ++++++ .../EntityTransfer/EntityTransferModule.cs | 263 +++++++++++++++------ .../Simulation/LocalSimulationConnector.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 18 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 33 ++- 6 files changed, 316 insertions(+), 79 deletions(-) diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 9fc048b..1c5f558 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -287,7 +287,7 @@ namespace OpenSim.Framework public Vector3 AtAxis; public Vector3 LeftAxis; public Vector3 UpAxis; - public bool ChangedGrid; + public bool SenderWantsToWaitForRoot; public float Far; public float Aspect; @@ -356,8 +356,9 @@ namespace OpenSim.Framework args["left_axis"] = OSD.FromString(LeftAxis.ToString()); args["up_axis"] = OSD.FromString(UpAxis.ToString()); - - args["changed_grid"] = OSD.FromBoolean(ChangedGrid); + //backwards compatibility + args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot); + args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot); args["far"] = OSD.FromReal(Far); args["aspect"] = OSD.FromReal(Aspect); @@ -526,8 +527,8 @@ namespace OpenSim.Framework if (args["up_axis"] != null) Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); - if (args["changed_grid"] != null) - ChangedGrid = args["changed_grid"].AsBoolean(); + if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null) + SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean(); if (args["far"] != null) Far = (float)(args["far"].AsReal()); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 37fd252..1b72b26 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1257,6 +1257,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // UseCircuitCode handling if (packet.Type == PacketType.UseCircuitCode) { + m_log.DebugFormat("[ZZZ]: In the dungeon: UseCircuitCode"); // We need to copy the endpoint so that it doesn't get changed when another thread reuses the // buffer. object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; @@ -1265,6 +1266,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP return; } + else if (packet.Type == PacketType.CompleteAgentMovement) + { + // Send ack straight away to let the viewer know that we got it. + SendAckImmediate(endPoint, packet.Header.Sequence); + + m_log.DebugFormat("[ZZZ]: In the dungeon: CompleteAgentMovement"); + // We need to copy the endpoint so that it doesn't get changed when another thread reuses the + // buffer. + object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; + + Util.FireAndForget(HandleCompleteMovementIntoRegion, array); + + return; + } // Determine which agent this packet came from IClientAPI client; @@ -1604,6 +1619,56 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + private void HandleCompleteMovementIntoRegion(object o) + { + IPEndPoint endPoint = null; + IClientAPI client = null; + + try + { + object[] array = (object[])o; + endPoint = (IPEndPoint)array[0]; + CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; + + // Determine which agent this packet came from + int count = 10; + while (!m_scene.TryGetClient(endPoint, out client) && count-- > 0) + { + m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); + Thread.Sleep(200); + } + + if (client == null) + return; + + IncomingPacket incomingPacket1; + + // Inbox insertion + if (UsePools) + { + incomingPacket1 = m_incomingPacketPool.GetObject(); + incomingPacket1.Client = (LLClientView)client; + incomingPacket1.Packet = packet; + } + else + { + incomingPacket1 = new IncomingPacket((LLClientView)client, packet); + } + + packetInbox.Enqueue(incomingPacket1); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", + endPoint != null ? endPoint.ToString() : "n/a", + client != null ? client.Name : "unknown", + client != null ? client.AgentId.ToString() : "unknown", + e.Message, + e.StackTrace); + } + } + /// /// Send an ack immediately to the given endpoint. /// @@ -1999,6 +2064,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP Packet packet = incomingPacket.Packet; LLClientView client = incomingPacket.Client; + if (packet is CompleteAgentMovementPacket) + m_log.DebugFormat("[ZZZ]: Received CompleteAgentMovementPacket"); + if (client.IsActive) { m_currentIncomingClient = client; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 5124aed..b0c0b1d 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -684,7 +684,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Contacting destination..."); + if (version.Equals("SIMULATION/0.2")) + TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); + else + TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); + + } + + private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, + IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason) + { + ulong destinationHandle = finalDestination.RegionHandle; + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. @@ -707,7 +718,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_interRegionTeleportCancels.Value++; m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", + "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); return; @@ -725,14 +736,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); - - #region old protocol - - IClientIPEndpoint ipepClient; + + IClientIPEndpoint ipepClient; + string capsPath = String.Empty; if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", + "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); @@ -745,30 +755,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #endregion capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - //if (m_eqModule != null) - //{ - // // The EnableSimulator message makes the client establish a connection with the destination - // // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the - // // correct circuit code. - // m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); - - // // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination - // // simulator to confirm that it has established communication with the viewer. - // Thread.Sleep(200); - - // // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears - // // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly - // // only on TeleportFinish). This is untested for region teleport between different simulators - // // though this probably also works. - // m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); - //} - //else - //{ - // // XXX: This is a little misleading since we're information the client of its avatar destination, - // // which may or may not be a neighbour region of the source region. This path is probably little - // // used anyway (with EQ being the one used). But it is currently being used for test code. - // sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); - //} + if (m_eqModule != null) + { + // The EnableSimulator message makes the client establish a connection with the destination + // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the + // correct circuit code. + m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); + + // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination + // simulator to confirm that it has established communication with the viewer. + Thread.Sleep(200); + + // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears + // unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly + // only on TeleportFinish). This is untested for region teleport between different simulators + // though this probably also works. + m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); + } + else + { + // XXX: This is a little misleading since we're information the client of its avatar destination, + // which may or may not be a neighbour region of the source region. This path is probably little + // used anyway (with EQ being the one used). But it is currently being used for test code. + sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); + } } else { @@ -776,15 +786,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } - #endregion old protocol - // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); sp.CopyTo(agent); - agent.Position = position; - //SetCallbackURL(agent, sp.Scene.RegionInfo); + agent.Position = agentCircuit.startpos; + SetCallbackURL(agent, sp.Scene.RegionInfo); - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to // establish th econnection to the destination which makes it return true. @@ -814,7 +821,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, teleportFlags, capsPath); } - + // A common teleport failure occurs when we can send CreateAgent to the // destination region but the viewer cannot establish the connection (e.g. due to network issues between // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then @@ -835,7 +842,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); return; } @@ -845,7 +852,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_interRegionTeleportCancels.Value++; m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", + "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); @@ -857,30 +864,30 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); - //// TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which - //// trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation - //// that the client contacted the destination before we close things here. - //if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) - //{ - // if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) - // { - // m_interRegionTeleportAborts.Value++; - - // 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); - - // return; - // } - - // m_log.WarnFormat( - // "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", - // sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - - // Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); + // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which + // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation + // that the client contacted the destination before we close things here. + if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) + { + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) + { + m_interRegionTeleportAborts.Value++; - // return; - //} + 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); + + return; + } + + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", + sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); + + return; + } m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); @@ -914,7 +921,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // // This sleep can be increased if necessary. However, whilst it's active, // an agent cannot teleport back to this region if it has teleported away. - Thread.Sleep(15000); + Thread.Sleep(2000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } @@ -925,6 +932,126 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } + private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, + IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, string version, out string reason) + { + ulong destinationHandle = finalDestination.RegionHandle; + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + + // Let's create an agent there if one doesn't exist yet. + // NOTE: logout will always be false for a non-HG teleport. + bool logout = false; + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + { + m_interRegionTeleportFailures.Value++; + + sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", + sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); + + return; + } + + // Past this point we have to attempt clean up if the teleport fails, so update transfer state. + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); + + IClientIPEndpoint ipepClient; + string capsPath = String.Empty; + if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) + { + 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); + + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); + #region IP Translation for NAT + // Uses ipepClient above + if (sp.ClientView.TryGet(out ipepClient)) + { + endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); + } + #endregion + capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + } + else + { + agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); + capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + } + + // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, + // where that neighbour simulator could otherwise request a child agent create on the source which then + // closes our existing agent which is still signalled as root. + //sp.IsChildAgent = true; + + // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid + if (m_eqModule != null) + m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); + else + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", + capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); + + // Let's send a full update of the agent. + AgentData agent = new AgentData(); + sp.CopyTo(agent); + agent.Position = agentCircuit.startpos; + agent.SenderWantsToWaitForRoot = true; + //SetCallbackURL(agent, sp.Scene.RegionInfo); + + // Send the Update. If this returns true, we know the client has contacted the destination + // via CompleteMovementIntoRegion, so we can let go. + // If it returns false, something went wrong, and we need to abort. + m_log.DebugFormat("[ZZZ]: Sending Update"); + if (!UpdateAgent(reg, finalDestination, agent, sp)) + { + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) + { + m_interRegionTeleportAborts.Value++; + + 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); + + return; + } + + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", + sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + + Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + return; + } + + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + + // May need to logout or other cleanup + AgentHasMovedAway(sp, logout); + + // Well, this is it. The agent is over there. + KillEntity(sp.Scene, sp.LocalId); + + // Now let's make it officially a child agent + sp.MakeChildAgent(); + + // OK, it got this agent. Let's close some child agents + sp.CloseChildAgents(newRegionX, newRegionY); + + // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone + + if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + sp.Scene.IncomingCloseAgent(sp.UUID, false); + else + // now we have a child agent in this region. + sp.Reset(); + } + /// /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation. /// @@ -938,11 +1065,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - sp.IsChildAgent = false; - ReInstantiateScripts(sp); - - EnableChildAgents(sp); + if (sp.IsChildAgent) // We had set it to child before attempted TP (V1) + { + sp.IsChildAgent = false; + ReInstantiateScripts(sp); + EnableChildAgents(sp); + } // Finally, kill the agent we just created at the destination. // XXX: Possibly this should be done asynchronously. Scene.SimulationService.CloseAgent(finalDestination, sp.UUID, auth_token); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 6d5039b..7dd10f7 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -48,7 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation /// /// Version of this service /// - private const string m_Version = "SIMULATION/0.1"; + private const string m_Version = "SIMULATION/0.2"; /// /// Map region ID to scene. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d4ef3d9..da8a1b8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4221,6 +4221,20 @@ namespace OpenSim.Region.Framework.Scenes } childAgentUpdate.ChildAgentDataUpdate(cAgentData); + + int ntimes = 20; + if (cAgentData.SenderWantsToWaitForRoot) + { + while (childAgentUpdate.IsChildAgent && ntimes-- > 0) + Thread.Sleep(500); + + m_log.DebugFormat( + "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits", + childAgentUpdate.Name, childAgentUpdate.UUID, childAgentUpdate.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 20 - ntimes); + + if (childAgentUpdate.IsChildAgent) + return false; + } return true; } return false; @@ -4278,10 +4292,6 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout", agentID, RegionInfo.RegionName); -// else -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits", -// sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 10 - ntimes); return sp; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 6433878..891e04e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -29,7 +29,9 @@ using System; using System.Xml; using System.Collections.Generic; using System.Reflection; +using System.Threading; using System.Timers; +using Timer = System.Timers.Timer; using OpenMetaverse; using log4net; using Nini.Config; @@ -1311,6 +1313,26 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor.Size = new Vector3(0.45f, 0.6f, height); } + private bool WaitForUpdateAgent(IClientAPI client) + { + // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero + int count = 20; + while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) + { + m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.RegionInfo.RegionName); + Thread.Sleep(200); + } + + if (m_originRegionID.Equals(UUID.Zero)) + { + // Movement into region will fail + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived", client.Name); + return false; + } + + return true; + } + /// /// Complete Avatar's movement into the region. /// @@ -1328,6 +1350,12 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); + if (m_teleportFlags != TeleportFlags.ViaLogin) + // Let's wait until UpdateAgent (called by departing region) is done + if (!WaitForUpdateAgent(client)) + // The sending region never sent the UpdateAgent data, we have to refuse + return; + Vector3 look = Velocity; if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) @@ -1348,10 +1376,11 @@ namespace OpenSim.Region.Framework.Scenes bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); MakeRootAgent(AbsolutePosition, flying); + + // Tell the client that we're totally ready ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + // Remember in HandleUseCircuitCode, we delayed this to here - // This will also send the initial data to clients when TP to a neighboring region. - // Not ideal, but until we know we're TP-ing from a neighboring region, there's not much we can do if (m_teleportFlags > 0) SendInitialDataToMe(); -- cgit v1.1 From aaee63af8241f23c94bc97435a3b1d17425df890 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 13:16:13 -0700 Subject: Minor improvements on TP V1 trying to make it exactly as it was before. --- .../EntityTransfer/EntityTransferModule.cs | 32 ++++++++++++---------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index b0c0b1d..4f11326 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -697,6 +697,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer ulong destinationHandle = finalDestination.RegionHandle; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Using TP V1"); // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; @@ -736,7 +737,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); - + + // OK, it got this agent. Let's close some child agents + sp.CloseChildAgents(newRegionX, newRegionY); + IClientIPEndpoint ipepClient; string capsPath = String.Empty; if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) @@ -811,17 +815,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // closes our existing agent which is still signalled as root. sp.IsChildAgent = true; - // New protocol: send TP Finish directly, without prior ES or EAC. That's what happens in the Linden grid - if (m_eqModule != null) - { - m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); - } - else - { - sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, - teleportFlags, capsPath); - } - // A common teleport failure occurs when we can send CreateAgent to the // destination region but the viewer cannot establish the connection (e.g. due to network issues between // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then @@ -847,6 +840,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } + // OK, send TPFinish to the client, so that it starts the process of contacting the destination region + if (m_eqModule != null) + { + m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); + } + else + { + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + } + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) { m_interRegionTeleportCancels.Value++; @@ -908,9 +912,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Now let's make it officially a child agent sp.MakeChildAgent(); - // OK, it got this agent. Let's close some child agents - sp.CloseChildAgents(newRegionX, newRegionY); - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) @@ -1063,6 +1064,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination) { + m_log.DebugFormat("[ZZZ]: FAIL!"); m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); if (sp.IsChildAgent) // We had set it to child before attempted TP (V1) -- cgit v1.1 From d7984ef775d0854606dadd71eac77d5f487ab8df Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 13:29:58 -0700 Subject: More on putting TP V1 as it was --- .../EntityTransfer/EntityTransferModule.cs | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 4f11326..22b577b 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -810,11 +810,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } - // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, - // where that neighbour simulator could otherwise request a child agent create on the source which then - // closes our existing agent which is still signalled as root. - sp.IsChildAgent = true; - // A common teleport failure occurs when we can send CreateAgent to the // destination region but the viewer cannot establish the connection (e.g. due to network issues between // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then @@ -840,17 +835,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } - // OK, send TPFinish to the client, so that it starts the process of contacting the destination region - if (m_eqModule != null) - { - m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); - } - else - { - sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, - teleportFlags, capsPath); - } - if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) { m_interRegionTeleportCancels.Value++; @@ -868,6 +852,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); + // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, + // where that neighbour simulator could otherwise request a child agent create on the source which then + // closes our existing agent which is still signalled as root. + sp.IsChildAgent = true; + + // OK, send TPFinish to the client, so that it starts the process of contacting the destination region + if (m_eqModule != null) + { + m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); + } + else + { + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + } + // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we close things here. -- cgit v1.1 From 261512606d77747701934e80e150bd55454571f2 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 14:23:50 -0700 Subject: Improve the opening test in CompleteMovement, to account for multiple flags besides ViaLogin. --- 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 891e04e..edd49eb 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1350,7 +1350,7 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); - if (m_teleportFlags != TeleportFlags.ViaLogin) + if ((m_teleportFlags & TeleportFlags.ViaLogin) != 0) // Let's wait until UpdateAgent (called by departing region) is done if (!WaitForUpdateAgent(client)) // The sending region never sent the UpdateAgent data, we have to refuse -- cgit v1.1 From 879cbb45753bf3f3144512748acd8faf120fc626 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 14:35:14 -0700 Subject: This commit message intentionally left blank (last commit was idiotic) --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index edd49eb..7f24174 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1350,7 +1350,8 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); - if ((m_teleportFlags & TeleportFlags.ViaLogin) != 0) + // Make sure it's not a login agent. We don't want to wait for updates during login + if ((m_teleportFlags & TeleportFlags.ViaLogin) == 0) // Let's wait until UpdateAgent (called by departing region) is done if (!WaitForUpdateAgent(client)) // The sending region never sent the UpdateAgent data, we have to refuse -- cgit v1.1 From c0433d5e4c8170de10e16dd09d85bf620a1530ae Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 18:46:51 -0700 Subject: Changed the RegionHandshake packet to the Unknown queue, so that it is sent with high priority and hopefully gets to the client before AgentMovementComplete --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 32549c8..8b2440a 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -811,7 +811,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported - OutPacket(handshake, ThrottleOutPacketType.Task); + OutPacket(handshake, ThrottleOutPacketType.Unknown); } -- cgit v1.1 From 14530b260764372df3627206c531b96b9d817dbe Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 20:20:48 -0700 Subject: Minor adjustment on timings of waits. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 23 ++++++++++++++++++---- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 1b72b26..43167ee 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1631,11 +1631,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; // Determine which agent this packet came from - int count = 10; - while (!m_scene.TryGetClient(endPoint, out client) && count-- > 0) + int count = 20; + bool ready = false; + while (!ready && count-- > 0) { - m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); - Thread.Sleep(200); + if (m_scene.TryGetClient(endPoint, out client) && client.IsActive) + { + LLUDPClient udpClient = ((LLClientView)client).UDPClient; + if (udpClient != null && udpClient.IsConnected) + ready = true; + else + { + m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); + Thread.Sleep(200); + } + } + else + { + m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); + Thread.Sleep(200); + } } if (client == null) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index da8a1b8..84fdef0 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4226,10 +4226,10 @@ namespace OpenSim.Region.Framework.Scenes if (cAgentData.SenderWantsToWaitForRoot) { while (childAgentUpdate.IsChildAgent && ntimes-- > 0) - Thread.Sleep(500); + Thread.Sleep(1000); m_log.DebugFormat( - "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits", + "[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits", childAgentUpdate.Name, childAgentUpdate.UUID, childAgentUpdate.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 20 - ntimes); if (childAgentUpdate.IsChildAgent) -- cgit v1.1 From e6a0f6e428e32356eba14729766aac28cec9989f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 20:49:40 -0700 Subject: One more thing to test in order to let CompleteMovement go up the stack. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 43167ee..f40948f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1635,9 +1635,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP bool ready = false; while (!ready && count-- > 0) { - if (m_scene.TryGetClient(endPoint, out client) && client.IsActive) + if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null) { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; + LLClientView llClientView = (LLClientView)client; + LLUDPClient udpClient = llClientView.UDPClient; if (udpClient != null && udpClient.IsConnected) ready = true; else -- cgit v1.1 From 4e5c7bdeb3222edeff8fbf8c01ce0b5916473e46 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 22 Jul 2013 22:00:20 -0700 Subject: Moved TriggerOnMakeRootAgent back to the end of MakeRootAgent, to see if that eliminates the temporary placement at infinity upon TPs --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7f24174..f9190d9 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1013,9 +1013,8 @@ namespace OpenSim.Region.Framework.Scenes // recorded, which stops the input from being processed. MovementFlag = 0; - // DIVA NOTE: I moved TriggerOnMakeRootAgent out of here and into the end of - // CompleteMovement. We don't want modules doing heavy computation before CompleteMovement - // is over. + m_scene.EventManager.TriggerOnMakeRootAgent(this); + } public int GetStateSource() @@ -1437,10 +1436,6 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); - // DIVA NOTE: moved this here from MakeRoot. We don't want modules making heavy - // computations before CompleteMovement is over - m_scene.EventManager.TriggerOnMakeRootAgent(this); - } /// -- cgit v1.1 From 46d017b19745ccdd5948865de53375a814bf2659 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 12:54:13 -0700 Subject: Today's wild shot at the infinity problem. Wait on the child agent left behind. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 22b577b..29ba5f8 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1047,7 +1047,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + { + Thread.Sleep(5000); sp.Scene.IncomingCloseAgent(sp.UUID, false); + } else // now we have a child agent in this region. sp.Reset(); @@ -1064,7 +1067,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, string auth_token, GridRegion finalDestination) { - m_log.DebugFormat("[ZZZ]: FAIL!"); m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); if (sp.IsChildAgent) // We had set it to child before attempted TP (V1) -- cgit v1.1 From f0320f56520318d20e8aa250c441b72aa1f0019c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 14:22:59 -0700 Subject: The previous commit did fix the infinity problem! I'm putting the same time on TP_V1 and adding a big red warning on top of those lines. --- .../Framework/EntityTransfer/EntityTransferModule.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 29ba5f8..1ea0fd7 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -916,13 +916,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { - // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before - // they regard the new region as the current region after receiving the AgentMovementComplete - // response. If close is sent before then, it will cause the viewer to quit instead. - // - // This sleep can be increased if necessary. However, whilst it's active, - // an agent cannot teleport back to this region if it has teleported away. - Thread.Sleep(2000); + // RED ALERT!!!! + // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. + // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion + // BEFORE THEY SETTLE IN THE NEW REGION. + // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR + // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. + Thread.Sleep(5000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } @@ -1048,6 +1048,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { + // RED ALERT!!!! + // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. + // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion + // BEFORE THEY SETTLE IN THE NEW REGION. + // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR + // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. Thread.Sleep(5000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } -- cgit v1.1 From cac37e298c267e4fa9c8d4306df85d74bff81fbe Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 14:24:17 -0700 Subject: Deleted all [ZZZ] debug messages. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 5 ----- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 1 - 2 files changed, 6 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index f40948f..25e10be 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1257,7 +1257,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // UseCircuitCode handling if (packet.Type == PacketType.UseCircuitCode) { - m_log.DebugFormat("[ZZZ]: In the dungeon: UseCircuitCode"); // We need to copy the endpoint so that it doesn't get changed when another thread reuses the // buffer. object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; @@ -1271,7 +1270,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Send ack straight away to let the viewer know that we got it. SendAckImmediate(endPoint, packet.Header.Sequence); - m_log.DebugFormat("[ZZZ]: In the dungeon: CompleteAgentMovement"); // We need to copy the endpoint so that it doesn't get changed when another thread reuses the // buffer. object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; @@ -2080,9 +2078,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP Packet packet = incomingPacket.Packet; LLClientView client = incomingPacket.Client; - if (packet is CompleteAgentMovementPacket) - m_log.DebugFormat("[ZZZ]: Received CompleteAgentMovementPacket"); - if (client.IsActive) { m_currentIncomingClient = client; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 1ea0fd7..70fbfc3 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1008,7 +1008,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Send the Update. If this returns true, we know the client has contacted the destination // via CompleteMovementIntoRegion, so we can let go. // If it returns false, something went wrong, and we need to abort. - m_log.DebugFormat("[ZZZ]: Sending Update"); if (!UpdateAgent(reg, finalDestination, agent, sp)) { if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) -- cgit v1.1 From 20b989e048fff3215b90af6a34954b7ceb5e9868 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 24 Jul 2013 17:10:26 -0700 Subject: Increased the wait time to 15 secs. In a 0.7.5 standalone where the effect was always present, this seems to have fixed it. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 70fbfc3..ea2d9b5 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -922,7 +922,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // BEFORE THEY SETTLE IN THE NEW REGION. // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. - Thread.Sleep(5000); + Thread.Sleep(15000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } @@ -1053,7 +1053,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // BEFORE THEY SETTLE IN THE NEW REGION. // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. - Thread.Sleep(5000); + Thread.Sleep(15000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } else -- cgit v1.1 From 1fabdcc43cc2d62ff03888166582b25884056e94 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 01:04:16 +0100 Subject: If a returning teleport starts to reuse a downgraded child connection that was a previous root agent, do not close that child agent at the end of the 15 sec teleport timer. This prevents an issue if the user teleports back to the neighbour simulator of a source before 15 seconds have elapsed. This more closely emulates observed linden behaviour, though the timeout there is 50 secs and applies to all the pre-teleport agents. Currently sticks a DoNotClose flag on ScenePresence though this may be temporary as possibly it could be incorporated into the ETM state machine --- .../EntityTransfer/EntityTransferModule.cs | 10 +++++++- OpenSim/Region/Framework/Scenes/Scene.cs | 29 ++++++++++++++-------- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 7 ++++++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ea2d9b5..31db778 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1054,7 +1054,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. Thread.Sleep(15000); - sp.Scene.IncomingCloseAgent(sp.UUID, false); + + if (!sp.DoNotClose) + { + sp.Scene.IncomingCloseAgent(sp.UUID, false); + } + else + { + sp.DoNotClose = false; + } } else // now we have a child agent in this region. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 84fdef0..f4622b6 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3682,19 +3682,26 @@ namespace OpenSim.Region.Framework.Scenes { ScenePresence sp = GetScenePresence(agent.AgentID); - if (sp != null && !sp.IsChildAgent) + if (sp != null) { - // We have a zombie from a crashed session. - // Or the same user is trying to be root twice here, won't work. - // Kill it. - m_log.WarnFormat( - "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", - sp.Name, sp.UUID, RegionInfo.RegionName); - - if (sp.ControllingClient != null) - sp.ControllingClient.Close(true); + if (!sp.IsChildAgent) + { + // We have a zombie from a crashed session. + // Or the same user is trying to be root twice here, won't work. + // Kill it. + m_log.WarnFormat( + "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", + sp.Name, sp.UUID, RegionInfo.RegionName); + + if (sp.ControllingClient != null) + sp.ControllingClient.Close(true); - sp = null; + sp = null; + } + else + { + sp.DoNotClose = true; + } } // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f9190d9..d3e1946 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -717,6 +717,13 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent + /// teleport is reusing the connection. + /// + /// May be refactored or move somewhere else soon. + public bool DoNotClose { get; set; } + private float m_speedModifier = 1.0f; public float SpeedModifier -- cgit v1.1 From 72ed49af5f864e50fa4453849a94dd9d46533cba Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 01:38:04 +0100 Subject: Reset DoNotClose scene presence teleport flag before pausing. Rename DoNotClose to DoNotCloseAfterTeleport --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 6 ++++-- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 31db778..8ce6bb4 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1047,6 +1047,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { + sp.DoNotCloseAfterTeleport = false; + // RED ALERT!!!! // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion @@ -1055,13 +1057,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. Thread.Sleep(15000); - if (!sp.DoNotClose) + if (!sp.DoNotCloseAfterTeleport) { sp.Scene.IncomingCloseAgent(sp.UUID, false); } else { - sp.DoNotClose = false; + sp.DoNotCloseAfterTeleport = false; } } else diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f4622b6..705660d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3700,7 +3700,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - sp.DoNotClose = true; + sp.DoNotCloseAfterTeleport = true; } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d3e1946..4044f0c 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -722,7 +722,7 @@ namespace OpenSim.Region.Framework.Scenes /// teleport is reusing the connection. /// /// May be refactored or move somewhere else soon. - public bool DoNotClose { get; set; } + public bool DoNotCloseAfterTeleport { get; set; } private float m_speedModifier = 1.0f; -- cgit v1.1 From 4cd03d8c314864eeeb9f11b34fc7e687ac96b858 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 01:40:56 +0100 Subject: Return Simulator/0.1 (V1) entity transfer behaviour to waiting only 2 seconds before closing root agent after 15. This is because a returning viewer by teleport before 15 seconds are up will be disrupted by the close. The 2 second delay is within the scope where a normal viewer would not allow a teleport back anyway. Simulator/0.2 (V2) protocol will continue with the longer delay since this is actually the behaviour viewers get from the ll grid and an early close causes other issues (avatar being sent to infinite locations temporarily, etc.) --- .../Framework/EntityTransfer/EntityTransferModule.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 8ce6bb4..3f1686c 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -916,13 +916,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { - // RED ALERT!!!! - // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. - // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion - // BEFORE THEY SETTLE IN THE NEW REGION. - // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR - // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. - Thread.Sleep(15000); + // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before + // they regard the new region as the current region after receiving the AgentMovementComplete + // response. If close is sent before then, it will cause the viewer to quit instead. + // + // This sleep can be increased if necessary. However, whilst it's active, + // an agent cannot teleport back to this region if it has teleported away. + Thread.Sleep(2000); sp.Scene.IncomingCloseAgent(sp.UUID, false); } -- cgit v1.1 From 878ce1e6b2b96043052015732286141f5b71310b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 25 Jul 2013 23:44:58 -0700 Subject: This should fix all issues with teleports. One should be able to TP as fast as needed. (Although sometimes Justin's state machine kicks in and doesn't let you) The EventQueues are a hairy mess, and it's very easy to mess things up. But it looks like this commit makes them work right. Here's what's going on: - Child and root agents are only closed after 15 sec, maybe - If the user comes back, they aren't closed, and everything is reused - On the receiving side, clients and scene presences are reused if they already exist - Caps are always recreated (this is where I spent most of my time!). It turns out that, because the agents carry the seeds around, the seed gets the same URL, except for the root agent coming back to a far away region, which gets a new seed (because we don't know what was its seed in the departing region, and we can't send it back to the client when the agent returns there). --- .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 58 +++++--------------- .../Framework/Caps/CapabilitiesModule.cs | 11 ++-- .../EntityTransfer/EntityTransferModule.cs | 11 ++-- OpenSim/Region/Framework/Scenes/Scene.cs | 61 ++++++++++------------ 4 files changed, 54 insertions(+), 87 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index c5e28ad..d02496f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -91,7 +91,6 @@ namespace OpenSim.Region.ClientStack.Linden scene.RegisterModuleInterface(this); scene.EventManager.OnClientClosed += ClientClosed; - scene.EventManager.OnMakeChildAgent += MakeChildAgent; scene.EventManager.OnRegisterCaps += OnRegisterCaps; MainConsole.Instance.Commands.AddCommand( @@ -120,7 +119,6 @@ namespace OpenSim.Region.ClientStack.Linden return; scene.EventManager.OnClientClosed -= ClientClosed; - scene.EventManager.OnMakeChildAgent -= MakeChildAgent; scene.EventManager.OnRegisterCaps -= OnRegisterCaps; scene.UnregisterModuleInterface(this); @@ -189,14 +187,12 @@ namespace OpenSim.Region.ClientStack.Linden { if (!queues.ContainsKey(agentId)) { - /* m_log.DebugFormat( "[EVENTQUEUE]: Adding new queue for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName); - */ queues[agentId] = new Queue(); } - + return queues[agentId]; } } @@ -228,8 +224,12 @@ namespace OpenSim.Region.ClientStack.Linden { Queue queue = GetQueue(avatarID); if (queue != null) + { lock (queue) queue.Enqueue(ev); + } + else + m_log.WarnFormat("[EVENTQUEUE]: (Enqueue) No queue found for agent {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); } catch (NullReferenceException e) { @@ -244,7 +244,7 @@ namespace OpenSim.Region.ClientStack.Linden private void ClientClosed(UUID agentID, Scene scene) { -// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); + //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); int count = 0; while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5) @@ -261,31 +261,6 @@ namespace OpenSim.Region.ClientStack.Linden lock (m_AvatarQueueUUIDMapping) m_AvatarQueueUUIDMapping.Remove(agentID); -// lock (m_AvatarQueueUUIDMapping) -// { -// foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) -// { -//// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); -// if (ky == agentID) -// { -// removeitems.Add(ky); -// } -// } -// -// foreach (UUID ky in removeitems) -// { -// UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; -// m_AvatarQueueUUIDMapping.Remove(ky); -// -// string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); -// MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); -// -//// m_log.DebugFormat( -//// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", -//// eqgPath, agentID, m_scene.RegionInfo.RegionName); -// } -// } - UUID searchval = UUID.Zero; removeitems.Clear(); @@ -305,19 +280,9 @@ namespace OpenSim.Region.ClientStack.Linden foreach (UUID ky in removeitems) m_QueueUUIDAvatarMapping.Remove(ky); } - } - private void MakeChildAgent(ScenePresence avatar) - { - //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); - //lock (m_ids) - // { - //if (m_ids.ContainsKey(avatar.UUID)) - //{ - // close the event queue. - //m_ids[avatar.UUID] = -1; - //} - //} + // m_log.DebugFormat("[EVENTQUEUE]: Deleted queues for {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); + } /// @@ -417,7 +382,12 @@ namespace OpenSim.Region.ClientStack.Linden if (DebugLevel >= 2) m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); - Queue queue = TryGetQueue(pAgentId); + Queue queue = GetQueue(pAgentId); + if (queue == null) + { + return NoEvents(requestID, pAgentId); + } + OSD element; lock (queue) { diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index ad1c4ce..6545a99 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -132,13 +132,9 @@ namespace OpenSim.Region.CoreModules.Framework { Caps oldCaps = m_capsObjects[agentId]; - m_log.DebugFormat( - "[CAPS]: Recreating caps for agent {0}. Old caps path {1}, new caps path {2}. ", - agentId, oldCaps.CapsObjectPath, capsObjectPath); - // This should not happen. The caller code is confused. We need to fix that. - // CAPs can never be reregistered, or the client will be confused. - // Hence this return here. - //return; + //m_log.WarnFormat( + // "[CAPS]: Recreating caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ", + // agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath); } caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName, @@ -153,6 +149,7 @@ namespace OpenSim.Region.CoreModules.Framework public void RemoveCaps(UUID agentId) { + m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName); lock (m_childrenSeeds) { if (m_childrenSeeds.ContainsKey(agentId)) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 3f1686c..96cd6b9 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -316,7 +316,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.", sp.Name, sp.UUID, position, regionHandle); - + + sp.ControllingClient.SendTeleportFailed("Slow down!"); return; } @@ -1040,9 +1041,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Now let's make it officially a child agent sp.MakeChildAgent(); - // OK, it got this agent. Let's close some child agents - sp.CloseChildAgents(newRegionX, newRegionY); - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) @@ -1059,10 +1057,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!sp.DoNotCloseAfterTeleport) { + // OK, it got this agent. Let's close everything + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.RegionInfo.RegionName); + sp.CloseChildAgents(newRegionX, newRegionY); sp.Scene.IncomingCloseAgent(sp.UUID, false); + } else { + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.RegionInfo.RegionName); sp.DoNotCloseAfterTeleport = false; } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 705660d..6d0b13f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2805,6 +2805,7 @@ namespace OpenSim.Region.Framework.Scenes { ScenePresence sp; bool vialogin; + bool reallyNew = true; // Validation occurs in LLUDPServer // @@ -2856,6 +2857,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); + reallyNew = false; } // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the @@ -2867,7 +2869,9 @@ namespace OpenSim.Region.Framework.Scenes // places. However, we still need to do it here for NPCs. CacheUserName(sp, aCircuit); - EventManager.TriggerOnNewClient(client); + if (reallyNew) + EventManager.TriggerOnNewClient(client); + if (vialogin) EventManager.TriggerOnClientLogin(client); } @@ -3426,15 +3430,8 @@ namespace OpenSim.Region.Framework.Scenes if (closeChildAgents && isChildAgent) { // Tell a single agent to disconnect from the region. - IEventQueue eq = RequestModuleInterface(); - if (eq != null) - { - eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID); - } - else - { - avatar.ControllingClient.SendShutdownConnectionNotice(); - } + // Let's do this via UDP + avatar.ControllingClient.SendShutdownConnectionNotice(); } // Only applies to root agents. @@ -3686,21 +3683,29 @@ namespace OpenSim.Region.Framework.Scenes { if (!sp.IsChildAgent) { - // We have a zombie from a crashed session. - // Or the same user is trying to be root twice here, won't work. - // Kill it. - m_log.WarnFormat( - "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", - sp.Name, sp.UUID, RegionInfo.RegionName); - - if (sp.ControllingClient != null) - sp.ControllingClient.Close(true); + // We have a root agent. Is it in transit? + if (!EntityTransferModule.IsInTransit(sp.UUID)) + { + // We have a zombie from a crashed session. + // Or the same user is trying to be root twice here, won't work. + // Kill it. + m_log.WarnFormat( + "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", + sp.Name, sp.UUID, RegionInfo.RegionName); + + if (sp.ControllingClient != null) + sp.ControllingClient.Close(true); - sp = null; + sp = null; + } + else + m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); } else { + // We have a child agent here sp.DoNotCloseAfterTeleport = true; + //m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName); } } @@ -3785,9 +3790,12 @@ namespace OpenSim.Region.Framework.Scenes agent.AgentID, RegionInfo.RegionName); sp.AdjustKnownSeeds(); - + if (CapsModule != null) + { CapsModule.SetAgentCapsSeeds(agent); + CapsModule.CreateCaps(agent.AgentID); + } } } @@ -5545,17 +5553,6 @@ namespace OpenSim.Region.Framework.Scenes { reason = "You are banned from the region"; - if (EntityTransferModule.IsInTransit(agentID)) - { - reason = "Agent is still in transit from this region"; - - m_log.WarnFormat( - "[SCENE]: Denying agent {0} entry into {1} since region still has them registered as in transit", - agentID, RegionInfo.RegionName); - - return false; - } - if (Permissions.IsGod(agentID)) { reason = String.Empty; -- cgit v1.1 From d5367a219daa0b946b3394e342734945d5ef7f1b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 26 Jul 2013 07:39:57 -0700 Subject: Slight improvement: no need to delay the removal of the queues in EQ, because DisableSimulator is now being sent via UDP --- .../ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index d02496f..c69f758 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -246,16 +246,8 @@ namespace OpenSim.Region.ClientStack.Linden { //m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); - int count = 0; - while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5) - { - Thread.Sleep(1000); - } - lock (queues) - { queues.Remove(agentID); - } List removeitems = new List(); lock (m_AvatarQueueUUIDMapping) -- cgit v1.1 From dd2c211e62b25f19386c1f4b5bc7ace40efa429a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 26 Jul 2013 07:40:55 -0700 Subject: Comment debug message --- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 6d0b13f..dec493b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3698,8 +3698,8 @@ namespace OpenSim.Region.Framework.Scenes sp = null; } - else - m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); + //else + // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); } else { -- cgit v1.1 From a08f01fa8323e18a63e920158c7f51ae78ac0e93 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 18:43:15 +0100 Subject: Fix NPC regression test failures. These were genuine failures caused by ScenePresence.CompleteMovement() waiting for an UpdateAgent from NPC introduction that would never come. Instead, we do not wait if the agent is an NPC. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 4 +++- OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs | 2 +- OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4044f0c..17da0d9 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1357,11 +1357,13 @@ namespace OpenSim.Region.Framework.Scenes client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); // Make sure it's not a login agent. We don't want to wait for updates during login - if ((m_teleportFlags & TeleportFlags.ViaLogin) == 0) + if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0) + { // Let's wait until UpdateAgent (called by departing region) is done if (!WaitForUpdateAgent(client)) // The sending region never sent the UpdateAgent data, we have to refuse return; + } Vector3 look = Velocity; diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index bf23040..f841d5c 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -155,7 +155,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests public void TestCreateWithAttachments() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); UserAccountHelpers.CreateUserWithInventory(m_scene, userId); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index 74f010e..495e684 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs @@ -180,6 +180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests public void TestOsNpcLoadAppearance() { TestHelpers.InMethod(); + //TestHelpers.EnableLogging(); // Store an avatar with a different height from default in a notecard. UUID userId = TestHelpers.ParseTail(0x1); -- cgit v1.1 From ad2ebd2f3dc70d708aa00a5fef59aeb3a3e16a44 Mon Sep 17 00:00:00 2001 From: nebadon Date: Fri, 26 Jul 2013 14:11:42 -0400 Subject: Force map tiler to save Water.jpg as an actual jpeg format it seems even though we specified jpg extention it was actually a png and thus confusing the viewer silently. --- OpenSim/Services/MapImageService/MapImageService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Services/MapImageService/MapImageService.cs b/OpenSim/Services/MapImageService/MapImageService.cs index a85ee70..9ba5dab 100644 --- a/OpenSim/Services/MapImageService/MapImageService.cs +++ b/OpenSim/Services/MapImageService/MapImageService.cs @@ -86,7 +86,7 @@ namespace OpenSim.Services.MapImageService { Bitmap waterTile = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH); FillImage(waterTile, m_Watercolor); - waterTile.Save(m_WaterTileFile); + waterTile.Save(m_WaterTileFile, ImageFormat.Jpeg); } } } -- cgit v1.1 From 9038a503eb91625a2e8a2070007f8d7765ecf86c Mon Sep 17 00:00:00 2001 From: nebadon Date: Fri, 26 Jul 2013 14:17:36 -0400 Subject: Add Aleric to Contributors list, thanks Aleric!! --- CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index f621cd3..8181483 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -65,6 +65,7 @@ what it is today. * A_Biondi * alex_carnell * Alan Webb (IBM) +* Aleric * Allen Kerensky * BigFootAg * BlueWall Slade -- cgit v1.1 From 056a6ee7653b17d8c1d92519f34f029bcd602143 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 19:22:30 +0100 Subject: Fix regression tests relating to agent transfer by making simulator use last week's SIMULATOR/0.1 protocol for now. --- OpenSim/Framework/Servers/MainServer.cs | 5 +++++ .../Avatar/Attachments/Tests/AttachmentsModuleTests.cs | 9 +++++++++ .../Simulation/LocalSimulationConnector.cs | 13 +++++++++---- .../Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | 6 ++++++ OpenSim/Tests/Common/OpenSimTestCase.cs | 12 ++++++++++-- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index d189580..57931d4 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -285,7 +285,12 @@ namespace OpenSim.Framework.Servers public static bool RemoveHttpServer(uint port) { lock (m_Servers) + { + if (instance != null && instance.Port == port) + instance = null; + return m_Servers.Remove(port); + } } /// diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 508743c..4ecae73 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -38,6 +38,8 @@ using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.CoreModules.Avatar.Attachments; using OpenSim.Region.CoreModules.Framework; using OpenSim.Region.CoreModules.Framework.EntityTransfer; @@ -802,6 +804,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests TestHelpers.InMethod(); // TestHelpers.EnableLogging(); + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; + AttachmentsModule attModA = new AttachmentsModule(); AttachmentsModule attModB = new AttachmentsModule(); EntityTransferModule etmA = new EntityTransferModule(); @@ -830,6 +836,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests SceneHelpers.SetupSceneModules( sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); + // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour + lscm.ServiceVersion = "SIMULATION/0.1"; + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 7dd10f7..bee602e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -46,9 +46,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// - /// Version of this service + /// Version of this service. /// - private const string m_Version = "SIMULATION/0.2"; + /// + /// Currently valid versions are "SIMULATION/0.1" and "SIMULATION/0.2" + /// + public string ServiceVersion { get; set; } /// /// Map region ID to scene. @@ -64,6 +67,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation public void Initialise(IConfigSource config) { + ServiceVersion = "SIMULATION/0.2"; + IConfig moduleConfig = config.Configs["Modules"]; if (moduleConfig != null) { @@ -253,7 +258,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) { reason = "Communications failure"; - version = m_Version; + version = ServiceVersion; if (destination == null) return false; @@ -359,4 +364,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation #endregion } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 297c66b..afd2779 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -136,6 +136,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules(sceneB, config, etmB); SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour + lscm.ServiceVersion = "SIMULATION/0.1"; + Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); @@ -454,6 +457,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour + lscm.ServiceVersion = "SIMULATION/0.1"; + Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); diff --git a/OpenSim/Tests/Common/OpenSimTestCase.cs b/OpenSim/Tests/Common/OpenSimTestCase.cs index 8c40923..3c47faa 100644 --- a/OpenSim/Tests/Common/OpenSimTestCase.cs +++ b/OpenSim/Tests/Common/OpenSimTestCase.cs @@ -27,6 +27,7 @@ using System; using NUnit.Framework; +using OpenSim.Framework.Servers; namespace OpenSim.Tests.Common { @@ -40,7 +41,14 @@ namespace OpenSim.Tests.Common // Disable logging for each test so that one where logging is enabled doesn't cause all subsequent tests // to have logging on if it failed with an exception. TestHelpers.DisableLogging(); + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + if (MainServer.Instance != null) + { + MainServer.RemoveHttpServer(MainServer.Instance.Port); +// MainServer.Instance = null; + } } } -} - +} \ No newline at end of file -- cgit v1.1 From 840be97e40179c17d57e1943555643b57f47ae5a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 20:52:30 +0100 Subject: Fix failure in TestCreateDuplicateRootScenePresence(). This is a test setup failure since code paths when adding a duplicate root scene presence now require the EntityTransferModule to be present. Test fixed by adding this module to test setup --- .../Framework/Scenes/Tests/ScenePresenceAgentTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index bbfbbfc..bbe34d2 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -119,7 +119,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID spUuid = TestHelpers.ParseTail(0x1); + // The etm is only invoked by this test to check whether an agent is still in transit if there is a dupe + EntityTransferModule etm = new EntityTransferModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + TestScene scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, etm); SceneHelpers.AddScenePresence(scene, spUuid); SceneHelpers.AddScenePresence(scene, spUuid); -- cgit v1.1 From ba9daf849e7c8db48e7c03e7cdedb77776b2052f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 26 Jul 2013 22:52:08 +0100 Subject: Fix regression from 056a6ee7 because the RemoteSimulationConnector uses a copy of the LocalSimulationConnector but never initializes it (hence ServiceVersion was never set) --- .../ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index bee602e..697ce68 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -63,12 +63,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation /// private bool m_ModuleEnabled = false; + public LocalSimulationConnectorModule() + { + ServiceVersion = "SIMULATION/0.2"; + } + #region Region Module interface public void Initialise(IConfigSource config) { - ServiceVersion = "SIMULATION/0.2"; - IConfig moduleConfig = config.Configs["Modules"]; if (moduleConfig != null) { -- cgit v1.1 From 428916a64d27e5f00e74d34fd4b0453f32c3d2de Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 26 Jul 2013 21:14:21 -0700 Subject: Commented out ChatSessionRequest capability in Vivox and Freeswitch. We aren't processing it in any meaningful way, and it seems to get invoked everytime someone types a message in group chat. --- .../Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 18 +++++++++--------- .../Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index ef1b92e..5a5a70c 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs @@ -326,15 +326,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice "ParcelVoiceInfoRequest", agentID.ToString())); - caps.RegisterHandler( - "ChatSessionRequest", - new RestStreamHandler( - "POST", - capsBase + m_chatSessionRequestPath, - (request, path, param, httpRequest, httpResponse) - => ChatSessionRequest(scene, request, path, param, agentID, caps), - "ChatSessionRequest", - agentID.ToString())); + //caps.RegisterHandler( + // "ChatSessionRequest", + // new RestStreamHandler( + // "POST", + // capsBase + m_chatSessionRequestPath, + // (request, path, param, httpRequest, httpResponse) + // => ChatSessionRequest(scene, request, path, param, agentID, caps), + // "ChatSessionRequest", + // agentID.ToString())); } /// diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs index 2d65530..cdab116 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs @@ -433,15 +433,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice "ParcelVoiceInfoRequest", agentID.ToString())); - caps.RegisterHandler( - "ChatSessionRequest", - new RestStreamHandler( - "POST", - capsBase + m_chatSessionRequestPath, - (request, path, param, httpRequest, httpResponse) - => ChatSessionRequest(scene, request, path, param, agentID, caps), - "ChatSessionRequest", - agentID.ToString())); + //caps.RegisterHandler( + // "ChatSessionRequest", + // new RestStreamHandler( + // "POST", + // capsBase + m_chatSessionRequestPath, + // (request, path, param, httpRequest, httpResponse) + // => ChatSessionRequest(scene, request, path, param, agentID, caps), + // "ChatSessionRequest", + // agentID.ToString())); } /// -- cgit v1.1 From 85428c49bb99484e15dd948ec48a285291e5a74c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 26 Jul 2013 21:27:00 -0700 Subject: Trying to decrease the lag on group chat. (Groups V2 only) --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 40 +++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index d172d48..31e9175 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -264,8 +264,32 @@ namespace OpenSim.Groups int requestStartTick = Environment.TickCount; + // Copy Message + GridInstantMessage msg = new GridInstantMessage(); + msg.imSessionID = groupID.Guid; + msg.fromAgentName = im.fromAgentName; + msg.message = im.message; + msg.dialog = im.dialog; + msg.offline = im.offline; + msg.ParentEstateID = im.ParentEstateID; + msg.Position = im.Position; + msg.RegionID = im.RegionID; + msg.binaryBucket = im.binaryBucket; + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); + + msg.fromAgentID = im.fromAgentID; + msg.fromGroup = true; + + // Send to self first of all + msg.toAgentID = msg.fromAgentID; + ProcessMessageFromGroupSession(msg); + + // Then send to everybody else foreach (GroupMembersData member in groupMembers) { + if (member.AgentID.Guid == im.fromAgentID) + continue; + if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) { // Don't deliver messages to people who have dropped this session @@ -273,22 +297,6 @@ namespace OpenSim.Groups continue; } - // Copy Message - GridInstantMessage msg = new GridInstantMessage(); - msg.imSessionID = groupID.Guid; - msg.fromAgentName = im.fromAgentName; - msg.message = im.message; - msg.dialog = im.dialog; - msg.offline = im.offline; - msg.ParentEstateID = im.ParentEstateID; - msg.Position = im.Position; - msg.RegionID = im.RegionID; - msg.binaryBucket = im.binaryBucket; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - - msg.fromAgentID = im.fromAgentID; - msg.fromGroup = true; - msg.toAgentID = member.AgentID.Guid; IClientAPI client = GetActiveClient(member.AgentID); -- cgit v1.1 From 3dac92f345cf69244cbbd10e65d5a8c04da710f5 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 26 Jul 2013 21:40:04 -0700 Subject: Increased the rate of the PollServiceRequestManager to 0.5 secs (it was 1sec). Group chat is going over the EQ... Hopefully this won't increase CPU when there's nothing going on, but we need to watch for that. --- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index d83daab..6ab05d0 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -133,7 +133,7 @@ namespace OpenSim.Framework.Servers.HttpServer // directly back in the "ready-to-serve" queue by the worker thread. while (m_running) { - Thread.Sleep(1000); + Thread.Sleep(500); Watchdog.UpdateThread(); List not_ready = new List(); -- cgit v1.1 From 1572e91b5f74c991230e15b7ca120e83a6ed3eb4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Jul 2013 08:04:48 -0700 Subject: Clarifications on documentation of Group configs --- bin/OpenSim.ini.example | 12 +++++++++--- bin/OpenSimDefaults.ini | 1 - 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 4ddefba..c30c73d 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -579,9 +579,9 @@ ;; must be set to allow offline messaging to work. ; MuteListURL = http://yourserver/Mute.php - ;; Control whether group messages are forwarded to offline users. + ;; Control whether group invites and notices are stored for offline users. ;; Default is true. - ;; This applies to the core groups module (Flotsam) only. + ;; This applies to both core groups module. ; ForwardOfflineGroupMessages = true @@ -957,7 +957,7 @@ ;# {LevelGroupCreate} {Enabled:true} {User level for creating groups} {} 0 ;; Minimum user level required to create groups - ;LevelGroupCreate = 0 + ; LevelGroupCreate = 0 ;# {Module} {Enabled:true} {Groups module to use? (Use GroupsModule to use Flotsam/Simian)} {Default "Groups Module V2"} Default ;; The default module can use a PHP XmlRpc server from the Flotsam project at @@ -1010,6 +1010,12 @@ ;; Enable Group Notices ; NoticesEnabled = true + ;# {MessageOnlineUsersOnly} {Module:GroupsModule Module:Groups Module V2} {Message online users only?} {true false} false + ; Experimental option to only message online users rather than all users + ; Should make large groups with few online members messaging faster, as the expense of more calls to presence service + ; Applies to both Group modules in core + ; MessageOnlineUsersOnly = false + ;; This makes the Groups modules very chatty on the console. ; DebugEnabled = false diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 6aa534a..e70b9b3 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1612,7 +1612,6 @@ ; Experimental option to only message cached online users rather than all users ; Should make large group with few online members messaging faster, as the expense of more calls to ROBUST presence service - ; This currently only applies to the Flotsam XmlRpc backend MessageOnlineUsersOnly = false ; Service connectors to the Groups Service. Select one depending on whether you're using a Flotsam XmlRpc backend or a SimianGrid backend -- cgit v1.1 From 69975763d2a735eb2696d2e27e5796a472a208ea Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Jul 2013 15:38:56 -0700 Subject: Several major improvements to group (V2) chat. Specifically: handle join/drop appropriately, invitechatboxes. The major departure from flotsam is to send only one message per destination region, as opposed to one message per group member. This reduces messaging considerably in large groups that have clusters of members in certain regions. --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 385 +++++++++++++++------ OpenSim/Addons/Groups/GroupsModule.cs | 26 +- .../Hypergrid/GroupsServiceHGConnectorModule.cs | 22 -- OpenSim/Addons/Groups/IGroupsServicesConnector.cs | 6 - .../Local/GroupsServiceLocalConnectorModule.cs | 22 -- .../Remote/GroupsServiceRemoteConnectorModule.cs | 22 -- OpenSim/Framework/GridInstantMessage.cs | 18 + .../Linden/Caps/EventQueue/EventQueueGetModule.cs | 4 +- .../Avatar/InstantMessage/MessageTransferModule.cs | 4 +- OpenSim/Region/Framework/Interfaces/IEventQueue.cs | 2 +- .../InstantMessageServiceConnector.cs | 1 + 11 files changed, 316 insertions(+), 196 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index 31e9175..be76ef1 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -39,6 +39,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Groups { @@ -79,6 +80,10 @@ namespace OpenSim.Groups private int m_usersOnlineCacheExpirySeconds = 20; + private Dictionary> m_groupsAgentsDroppedFromChatSession = new Dictionary>(); + private Dictionary> m_groupsAgentsInvitedToChatSession = new Dictionary>(); + + #region Region Module interfaceBase Members public void Initialise(IConfigSource config) @@ -227,62 +232,50 @@ namespace OpenSim.Groups public void SendMessageToGroup(GridInstantMessage im, UUID groupID) { - List groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID).ToString(), groupID); + UUID fromAgentID = new UUID(im.fromAgentID); + List groupMembers = m_groupData.GetGroupMembers(fromAgentID.ToString(), groupID); int groupMembersCount = groupMembers.Count; + PresenceInfo[] onlineAgents = null; - if (m_messageOnlineAgentsOnly) - { - string[] t1 = groupMembers.ConvertAll(gmd => gmd.AgentID.ToString()).ToArray(); + // In V2 we always only send to online members. + // Sending to offline members is not an option. + string[] t1 = groupMembers.ConvertAll(gmd => gmd.AgentID.ToString()).ToArray(); - // We cache in order not to overwhlem the presence service on large grids with many groups. This does - // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. - // (assuming this is the same across all grid simulators). - PresenceInfo[] onlineAgents; - if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) - { - onlineAgents = m_presenceService.GetAgents(t1); - m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); - } + // We cache in order not to overwhlem the presence service on large grids with many groups. This does + // mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed. + // (assuming this is the same across all grid simulators). + if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents)) + { + onlineAgents = m_presenceService.GetAgents(t1); + m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); + } - HashSet onlineAgentsUuidSet = new HashSet(); - Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); + HashSet onlineAgentsUuidSet = new HashSet(); + Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); - groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); + groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); - // if (m_debugEnabled) +// if (m_debugEnabled) // m_log.DebugFormat( // "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online", // groupID, groupMembersCount, groupMembers.Count()); - } - else - { - if (m_debugEnabled) - m_log.DebugFormat( - "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members", - groupID, groupMembers.Count); - } int requestStartTick = Environment.TickCount; - // Copy Message - GridInstantMessage msg = new GridInstantMessage(); - msg.imSessionID = groupID.Guid; - msg.fromAgentName = im.fromAgentName; - msg.message = im.message; - msg.dialog = im.dialog; - msg.offline = im.offline; - msg.ParentEstateID = im.ParentEstateID; - msg.Position = im.Position; - msg.RegionID = im.RegionID; - msg.binaryBucket = im.binaryBucket; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - - msg.fromAgentID = im.fromAgentID; - msg.fromGroup = true; + im.imSessionID = groupID.Guid; + im.fromGroup = true; + IClientAPI thisClient = GetActiveClient(fromAgentID); + if (thisClient != null) + { + im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid; + } // Send to self first of all - msg.toAgentID = msg.fromAgentID; - ProcessMessageFromGroupSession(msg); + im.toAgentID = im.fromAgentID; + ProcessMessageFromGroupSession(im); + + List regions = new List(); + List clientsAlreadySent = new List(); // Then send to everybody else foreach (GroupMembersData member in groupMembers) @@ -290,27 +283,50 @@ namespace OpenSim.Groups if (member.AgentID.Guid == im.fromAgentID) continue; - if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) + if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) { // Don't deliver messages to people who have dropped this session if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID); continue; } - msg.toAgentID = member.AgentID.Guid; + im.toAgentID = member.AgentID.Guid; IClientAPI client = GetActiveClient(member.AgentID); if (client == null) { // If they're not local, forward across the grid + // BUT do it only once per region, please! Sim would be even better! if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID); - m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + + bool reallySend = true; + if (onlineAgents != null) + { + PresenceInfo presence = onlineAgents.First(p => p.UserID == member.AgentID.ToString()); + if (regions.Contains(presence.RegionID)) + reallySend = false; + else + regions.Add(presence.RegionID); + } + + if (reallySend) + { + // We have to create a new IM structure because the transfer module + // uses async send + GridInstantMessage msg = new GridInstantMessage(im, true); + m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + } } else { // Deliver locally, directly if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); - ProcessMessageFromGroupSession(msg); + + if (clientsAlreadySent.Contains(member.AgentID)) + continue; + clientsAlreadySent.Add(member.AgentID); + + ProcessMessageFromGroupSession(im); } } @@ -343,21 +359,90 @@ namespace OpenSim.Groups // 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", System.Reflection.MethodBase.GetCurrentMethod().Name); + m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}", + System.Reflection.MethodBase.GetCurrentMethod().Name, regionID); DebugGridInstantMessage(msg); } // Incoming message from a group - if ((msg.fromGroup == true) && - ((msg.dialog == (byte)InstantMessageDialog.SessionSend) - || (msg.dialog == (byte)InstantMessageDialog.SessionAdd) - || (msg.dialog == (byte)InstantMessageDialog.SessionDrop))) + if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend)) { - ProcessMessageFromGroupSession(msg); + // We have to redistribute the message across all members of the group who are here + // on this sim + + UUID GroupID = new UUID(msg.imSessionID); + + Scene aScene = m_sceneList[0]; + GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); + + List groupMembers = m_groupData.GetGroupMembers(new UUID(msg.fromAgentID).ToString(), GroupID); + List alreadySeen = new List(); + + foreach (Scene s in m_sceneList) + { + s.ForEachScenePresence(sp => + { + // We need this, because we are searching through all + // SPs, both root and children + if (alreadySeen.Contains(sp.UUID)) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because we've already seen it", sp.UUID); + return; + } + alreadySeen.Add(sp.UUID); + + GroupMembersData m = groupMembers.Find(gmd => + { + return gmd.AgentID == sp.UUID; + }); + if (m.AgentID == UUID.Zero) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he is not a member of the group", sp.UUID); + return; + } + + // Check if the user has an agent in the region where + // the IM came from, and if so, skip it, because the IM + // was already sent via that agent + if (regionOfOrigin != null) + { + AgentCircuitData aCircuit = s.AuthenticateHandler.GetAgentCircuitData(sp.UUID); + if (aCircuit != null) + { + if (aCircuit.ChildrenCapSeeds.Keys.Contains(regionOfOrigin.RegionHandle)) + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID); + return; + } + else + { + if (m_debugEnabled) + m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID); + } + } + } + + UUID AgentID = sp.UUID; + msg.toAgentID = AgentID.Guid; + + if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID) + && !hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)) + { + AddAgentToSession(AgentID, GroupID, msg); + } + + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name); + + ProcessMessageFromGroupSession(msg); + }); + } } } @@ -367,82 +452,40 @@ namespace OpenSim.Groups UUID AgentID = new UUID(msg.fromAgentID); UUID GroupID = new UUID(msg.imSessionID); + UUID toAgentID = new UUID(msg.toAgentID); switch (msg.dialog) { case (byte)InstantMessageDialog.SessionAdd: - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); break; case (byte)InstantMessageDialog.SessionDrop: - m_groupData.AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID); + AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID); break; case (byte)InstantMessageDialog.SessionSend: - if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID) - && !m_groupData.hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID) - ) + // 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) { - // Agent not in session and hasn't dropped from session - // Add them to the session for now, and Invite them - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + // Deliver locally, directly + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name); - UUID toAgentID = new UUID(msg.toAgentID); - IClientAPI activeClient = GetActiveClient(toAgentID); - if (activeClient != null) + if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID)) { - GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); - if (groupInfo != null) - { - if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message"); - - // Force? open the group session dialog??? - // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); - IEventQueue eq = activeClient.Scene.RequestModuleInterface(); - eq.ChatterboxInvitation( - GroupID - , groupInfo.GroupName - , new UUID(msg.fromAgentID) - , msg.message - , new UUID(msg.toAgentID) - , msg.fromAgentName - , msg.dialog - , msg.timestamp - , msg.offline == 1 - , (int)msg.ParentEstateID - , msg.Position - , 1 - , new UUID(msg.imSessionID) - , msg.fromGroup - , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName) - ); - - eq.ChatterBoxSessionAgentListUpdates( - new UUID(GroupID) - , new UUID(msg.fromAgentID) - , new UUID(msg.toAgentID) - , false //canVoiceChat - , false //isModerator - , false //text mute - ); - } + if (!hasAgentBeenInvitedToGroupChatSession(toAgentID.ToString(), GroupID)) + // This actually sends the message too, so no need to resend it + // with client.SendInstantMessage + AddAgentToSession(toAgentID, GroupID, msg); + else + client.SendInstantMessage(msg); } } - else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)) + else { - // 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) - { - // Deliver locally, directly - if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name); - client.SendInstantMessage(msg); - } - else - { - m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); - } + m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); } break; @@ -452,6 +495,53 @@ namespace OpenSim.Groups } } + private void AddAgentToSession(UUID AgentID, UUID GroupID, GridInstantMessage msg) + { + // Agent not in session and hasn't dropped from session + // Add them to the session for now, and Invite them + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + + IClientAPI activeClient = GetActiveClient(AgentID); + if (activeClient != null) + { + GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null); + if (groupInfo != null) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message"); + + // Force? open the group session dialog??? + // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); + IEventQueue eq = activeClient.Scene.RequestModuleInterface(); + eq.ChatterboxInvitation( + GroupID + , groupInfo.GroupName + , new UUID(msg.fromAgentID) + , msg.message + , AgentID + , msg.fromAgentName + , msg.dialog + , msg.timestamp + , msg.offline == 1 + , (int)msg.ParentEstateID + , msg.Position + , 1 + , new UUID(msg.imSessionID) + , msg.fromGroup + , OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName) + ); + + eq.ChatterBoxSessionAgentListUpdates( + new UUID(GroupID) + , AgentID + , new UUID(msg.toAgentID) + , false //canVoiceChat + , false //isModerator + , false //text mute + ); + } + } + } + #endregion @@ -477,7 +567,7 @@ namespace OpenSim.Groups if (groupInfo != null) { - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID); @@ -503,7 +593,7 @@ namespace OpenSim.Groups 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 - m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); + AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID); SendMessageToGroup(im, GroupID); } @@ -598,5 +688,70 @@ namespace OpenSim.Groups } #endregion + + #region GroupSessionTracking + + public void ResetAgentGroupChatSessions(string agentID) + { + foreach (List agentList in m_groupsAgentsDroppedFromChatSession.Values) + { + agentList.Remove(agentID); + } + } + + public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) + { + // If we're tracking this group, and we can find them in the tracking, then they've been invited + return m_groupsAgentsInvitedToChatSession.ContainsKey(groupID) + && m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID); + } + + public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) + { + // If we're tracking drops for this group, + // and we find them, well... then they've dropped + return m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID) + && m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID); + } + + public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) + { + if (m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) + { + // If not in dropped list, add + if (!m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) + { + m_groupsAgentsDroppedFromChatSession[groupID].Add(agentID); + } + } + } + + public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) + { + // Add Session Status if it doesn't exist for this session + CreateGroupChatSessionTracking(groupID); + + // If nessesary, remove from dropped list + if (m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID)) + { + m_groupsAgentsDroppedFromChatSession[groupID].Remove(agentID); + } + + // Add to invited + if (!m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID)) + m_groupsAgentsInvitedToChatSession[groupID].Add(agentID); + } + + private void CreateGroupChatSessionTracking(UUID groupID) + { + if (!m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)) + { + m_groupsAgentsDroppedFromChatSession.Add(groupID, new List()); + m_groupsAgentsInvitedToChatSession.Add(groupID, new List()); + } + + } + #endregion + } } diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 69d03a9..a14dc6a 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -141,6 +141,8 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRoot; + scene.EventManager.OnMakeChildAgent += OnMakeChild; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; // The InstantMessageModule itself doesn't do this, // so lets see if things explode if we don't do it @@ -194,6 +196,7 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); scene.EventManager.OnNewClient -= OnNewClient; + scene.EventManager.OnMakeRootAgent -= OnMakeRoot; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; lock (m_sceneList) @@ -232,16 +235,31 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); - client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; - client.OnDirFindQuery += OnDirFindQuery; client.OnRequestAvatarProperties += OnRequestAvatarProperties; + } + private void OnMakeRoot(ScenePresence sp) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; + sp.ControllingClient.OnDirFindQuery += OnDirFindQuery; // Used for Notices and Group Invites/Accept/Reject - client.OnInstantMessage += OnInstantMessage; + sp.ControllingClient.OnInstantMessage += OnInstantMessage; // Send client their groups information. - SendAgentGroupDataUpdate(client, client.AgentId); + SendAgentGroupDataUpdate(sp.ControllingClient, sp.UUID); + } + + private void OnMakeChild(ScenePresence sp) + { + if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + + sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest; + sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery; + // Used for Notices and Group Invites/Accept/Reject + sp.ControllingClient.OnInstantMessage -= OnInstantMessage; } private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index c3c759e..daa0728 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -590,28 +590,6 @@ namespace OpenSim.Groups return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID); } - public void ResetAgentGroupChatSessions(string agentID) - { - } - - public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) - { - } - - public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) - { - } - #endregion #region hypergrid groups diff --git a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs index 73deb7a..a09b59e 100644 --- a/OpenSim/Addons/Groups/IGroupsServicesConnector.cs +++ b/OpenSim/Addons/Groups/IGroupsServicesConnector.cs @@ -92,12 +92,6 @@ namespace OpenSim.Groups GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID); List GetGroupNotices(string RequestingAgentID, UUID GroupID); - void ResetAgentGroupChatSessions(string agentID); - bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID); - bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID); - void AgentDroppedFromGroupChatSession(string agentID, UUID groupID); - void AgentInvitedToGroupChatSession(string agentID, UUID groupID); - } public class GroupInviteInfo diff --git a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs index 905bc91..564dec4 100644 --- a/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs +++ b/OpenSim/Addons/Groups/Local/GroupsServiceLocalConnectorModule.cs @@ -320,28 +320,6 @@ namespace OpenSim.Groups return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID); } - public void ResetAgentGroupChatSessions(string agentID) - { - } - - public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) - { - } - - public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) - { - } - #endregion } } diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs index f1cf66c..9b6bfbd 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -406,28 +406,6 @@ namespace OpenSim.Groups }); } - public void ResetAgentGroupChatSessions(string agentID) - { - } - - public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID) - { - return false; - } - - public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID) - { - } - - public void AgentInvitedToGroupChatSession(string agentID, UUID groupID) - { - } - #endregion } diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs index 6ae0488..da3690c 100644 --- a/OpenSim/Framework/GridInstantMessage.cs +++ b/OpenSim/Framework/GridInstantMessage.cs @@ -53,6 +53,24 @@ namespace OpenSim.Framework binaryBucket = new byte[0]; } + public GridInstantMessage(GridInstantMessage im, bool addTimestamp) + { + fromAgentID = im.fromAgentID; + fromAgentName = im.fromAgentName; + toAgentID = im.toAgentID; + dialog = im.dialog; + fromGroup = im.fromGroup; + message = im.message; + imSessionID = im.imSessionID; + offline = im.offline; + Position = im.Position; + binaryBucket = im.binaryBucket; + RegionID = im.RegionID; + + if (addTimestamp) + timestamp = (uint)Util.UnixTimeSinceEpoch(); + } + public GridInstantMessage(IScene scene, UUID _fromAgentID, string _fromAgentName, UUID _toAgentID, byte _dialog, bool _fromGroup, string _message, diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index c69f758..d7afe1a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -750,12 +750,12 @@ namespace OpenSim.Region.ClientStack.Linden } - public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, + public void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, bool isModerator, bool textMute) { OSD item = EventQueueHelper.ChatterBoxSessionAgentListUpdates(sessionID, fromAgent, canVoiceChat, isModerator, textMute); - Enqueue(item, toAgent); + Enqueue(item, fromAgent); //m_log.InfoFormat("########### eq ChatterBoxSessionAgentListUpdates #############\n{0}", item); } diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index fa935cd..40a400f 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -372,7 +372,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage gim.fromAgentName = fromAgentName; gim.fromGroup = fromGroup; gim.imSessionID = imSessionID.Guid; - gim.RegionID = UUID.Zero.Guid; // RegionID.Guid; + gim.RegionID = RegionID.Guid; gim.timestamp = timestamp; gim.toAgentID = toAgentID.Guid; gim.message = message; @@ -672,7 +672,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage gim["position_x"] = msg.Position.X.ToString(); gim["position_y"] = msg.Position.Y.ToString(); gim["position_z"] = msg.Position.Z.ToString(); - gim["region_id"] = msg.RegionID.ToString(); + gim["region_id"] = new UUID(msg.RegionID).ToString(); gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); return gim; } diff --git a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs index 5512642..3780ece 100644 --- a/OpenSim/Region/Framework/Interfaces/IEventQueue.cs +++ b/OpenSim/Region/Framework/Interfaces/IEventQueue.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.Framework.Interfaces UUID fromAgent, string message, UUID toAgent, string fromName, byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl, UUID transactionID, bool fromGroup, byte[] binaryBucket); - void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, + void ChatterBoxSessionAgentListUpdates(UUID sessionID, UUID fromAgent, UUID anotherAgent, bool canVoiceChat, bool isModerator, bool textMute); void ParcelProperties(ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID); void GroupMembership(AgentGroupDataUpdatePacket groupUpdate, UUID avatarID); diff --git a/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs index dbce9f6..e19c23d 100644 --- a/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs +++ b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs @@ -123,6 +123,7 @@ namespace OpenSim.Services.Connectors.InstantMessage gim["position_z"] = msg.Position.Z.ToString(); gim["region_id"] = msg.RegionID.ToString(); gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket, Base64FormattingOptions.None); + gim["region_id"] = new UUID(msg.RegionID).ToString(); return gim; } -- cgit v1.1 From 18eca40af3592d9743cf50267a460968e601859c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Jul 2013 19:12:47 -0700 Subject: More bug fixes on group chat --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 34 ++++++++++++++------------ 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index be76ef1..04e2b80 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -132,7 +132,6 @@ namespace OpenSim.Groups scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; scene.EventManager.OnClientLogin += OnClientLogin; } - public void RegionLoaded(Scene scene) { if (!m_groupMessagingEnabled) @@ -271,7 +270,8 @@ namespace OpenSim.Groups } // Send to self first of all - im.toAgentID = im.fromAgentID; + im.toAgentID = im.fromAgentID; + im.fromGroup = true; ProcessMessageFromGroupSession(im); List regions = new List(); @@ -330,8 +330,7 @@ namespace OpenSim.Groups } } - // Temporary for assessing how long it still takes to send messages to large online groups. - if (m_messageOnlineAgentsOnly) + if (m_debugEnabled) m_log.DebugFormat( "[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); @@ -349,6 +348,7 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); client.OnInstantMessage += OnInstantMessage; + ResetAgentGroupChatSessions(client.AgentId.ToString()); } private void OnGridInstantMessage(GridInstantMessage msg) @@ -432,16 +432,19 @@ namespace OpenSim.Groups UUID AgentID = sp.UUID; msg.toAgentID = AgentID.Guid; - if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID) - && !hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)) + if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)) { - AddAgentToSession(AgentID, GroupID, msg); - } - - if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name); + if (!hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)) + AddAgentToSession(AgentID, GroupID, msg); + else + { + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name); - ProcessMessageFromGroupSession(msg); + ProcessMessageFromGroupSession(msg); + } + } }); + } } } @@ -664,12 +667,12 @@ namespace OpenSim.Groups { if (!sp.IsChildAgent) { - if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name); + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name); return sp.ControllingClient; } else { - if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name); + if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name); child = sp.ControllingClient; } } @@ -694,9 +697,10 @@ namespace OpenSim.Groups public void ResetAgentGroupChatSessions(string agentID) { foreach (List agentList in m_groupsAgentsDroppedFromChatSession.Values) - { agentList.Remove(agentID); - } + + foreach (List agentList in m_groupsAgentsInvitedToChatSession.Values) + agentList.Remove(agentID); } public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID) -- cgit v1.1 From 9cbbb7eddfb3316a2db5bfaa0e81a39850e7163d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Jul 2013 19:16:48 -0700 Subject: Clarification on docs of .ini.examples for Groups (again) --- bin/OpenSim.ini.example | 4 ++-- bin/OpenSimDefaults.ini | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index c30c73d..33f3263 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -1010,10 +1010,10 @@ ;; Enable Group Notices ; NoticesEnabled = true - ;# {MessageOnlineUsersOnly} {Module:GroupsModule Module:Groups Module V2} {Message online users only?} {true false} false + ;# {MessageOnlineUsersOnly} {Module:GroupsModule Module} {Message online users only?} {true false} false ; Experimental option to only message online users rather than all users ; Should make large groups with few online members messaging faster, as the expense of more calls to presence service - ; Applies to both Group modules in core + ; Applies Flotsam Group only. V2 has this always on, no other option ; MessageOnlineUsersOnly = false ;; This makes the Groups modules very chatty on the console. diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index e70b9b3..dbafd5c 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1612,6 +1612,7 @@ ; Experimental option to only message cached online users rather than all users ; Should make large group with few online members messaging faster, as the expense of more calls to ROBUST presence service + ; (Flotsam groups only; in V2 this is always on) MessageOnlineUsersOnly = false ; Service connectors to the Groups Service. Select one depending on whether you're using a Flotsam XmlRpc backend or a SimianGrid backend -- cgit v1.1 From 8dff05a89798543994cb6e5ac5e5f715daf5898b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Jul 2013 20:30:00 -0700 Subject: More on group chat: only root agents should subscribe to OnInstantMessage, or else they'll see an echo of their own messages after teleporting. --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index 04e2b80..ce4f597 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -129,9 +129,12 @@ namespace OpenSim.Groups m_sceneList.Add(scene); scene.EventManager.OnNewClient += OnNewClient; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; scene.EventManager.OnClientLogin += OnClientLogin; } + public void RegionLoaded(Scene scene) { if (!m_groupMessagingEnabled) @@ -347,10 +350,20 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name); - client.OnInstantMessage += OnInstantMessage; ResetAgentGroupChatSessions(client.AgentId.ToString()); } + void OnMakeRootAgent(ScenePresence sp) + { + sp.ControllingClient.OnInstantMessage += OnInstantMessage; + } + + void OnMakeChildAgent(ScenePresence sp) + { + sp.ControllingClient.OnInstantMessage -= OnInstantMessage; + } + + private void OnGridInstantMessage(GridInstantMessage msg) { // The instant message module will only deliver messages of dialog types: -- cgit v1.1 From 170a6f0563c9b9e228dad0b1db5654f2114a05f4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 09:00:28 -0700 Subject: This makes group search work (Groups V2). --- OpenSim/Addons/Groups/GroupsExtendedData.cs | 24 +++++++++++++++++ OpenSim/Addons/Groups/GroupsModule.cs | 4 +++ .../Groups/Remote/GroupsServiceRemoteConnector.cs | 30 ++++++++++++++++++++++ .../Remote/GroupsServiceRemoteConnectorModule.cs | 2 +- .../Groups/Remote/GroupsServiceRobustConnector.cs | 28 ++++++++++++++++++++ OpenSim/Data/MySQL/MySQLGroupsData.cs | 2 +- 6 files changed, 88 insertions(+), 2 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsExtendedData.cs b/OpenSim/Addons/Groups/GroupsExtendedData.cs index 6f4db28..1632aee 100644 --- a/OpenSim/Addons/Groups/GroupsExtendedData.cs +++ b/OpenSim/Addons/Groups/GroupsExtendedData.cs @@ -504,6 +504,30 @@ namespace OpenSim.Groups return notice; } + + public static Dictionary DirGroupsReplyData(DirGroupsReplyData g) + { + Dictionary dict = new Dictionary(); + + dict["GroupID"] = g.groupID; + dict["Name"] = g.groupName; + dict["NMembers"] = g.members; + dict["SearchOrder"] = g.searchOrder; + + return dict; + } + + public static DirGroupsReplyData DirGroupsReplyData(Dictionary dict) + { + DirGroupsReplyData g; + + g.groupID = new UUID(dict["GroupID"].ToString()); + g.groupName = dict["Name"].ToString(); + Int32.TryParse(dict["NMembers"].ToString(), out g.members); + float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder); + + return g; + } } } diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index a14dc6a..7d3c064 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -313,6 +313,10 @@ namespace OpenSim.Groups m_log.DebugFormat( "[Groups]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})", System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart); + + + if (string.IsNullOrEmpty(queryText)) + remoteClient.SendDirGroupsReply(queryID, new DirGroupsReplyData[0]); // TODO: This currently ignores pretty much all the query flags including Mature and sort order remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), queryText).ToArray()); diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs index 04328c9..9a3e125 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs @@ -133,6 +133,36 @@ namespace OpenSim.Groups return GroupsDataUtils.GroupRecord((Dictionary)ret["RESULT"]); } + public List FindGroups(string RequestingAgentID, string query) + { + List hits = new List(); + if (string.IsNullOrEmpty(query)) + return hits; + + Dictionary sendData = new Dictionary(); + sendData["Query"] = query; + sendData["RequestingAgentID"] = RequestingAgentID; + + Dictionary ret = MakeRequest("FINDGROUPS", sendData); + + if (ret == null) + return hits; + + if (!ret.ContainsKey("RESULT")) + return hits; + + if (ret["RESULT"].ToString() == "NULL") + return hits; + + foreach (object v in ((Dictionary)ret["RESULT"]).Values) + { + DirGroupsReplyData m = GroupsDataUtils.DirGroupsReplyData((Dictionary)v); + hits.Add(m); + } + + return hits; + } + public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) { reason = string.Empty; diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs index 9b6bfbd..d3de0e8 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnectorModule.cs @@ -199,7 +199,7 @@ namespace OpenSim.Groups public List FindGroups(string RequestingAgentID, string search) { // TODO! - return new List(); + return m_GroupsService.FindGroups(RequestingAgentID, search); } public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason) diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs index 106c6c4..249d974 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRobustConnector.cs @@ -133,6 +133,8 @@ namespace OpenSim.Groups return HandleAddNotice(request); case "GETNOTICES": return HandleGetNotices(request); + case "FINDGROUPS": + return HandleFindGroups(request); } m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method); } @@ -740,6 +742,32 @@ namespace OpenSim.Groups return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + byte[] HandleFindGroups(Dictionary request) + { + Dictionary result = new Dictionary(); + + if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("Query")) + NullResult(result, "Bad network data"); + + List hits = m_GroupsService.FindGroups(request["RequestingAgentID"].ToString(), request["Query"].ToString()); + + if (hits == null || (hits != null && hits.Count == 0)) + NullResult(result, "No hits"); + else + { + Dictionary dict = new Dictionary(); + int i = 0; + foreach (DirGroupsReplyData n in hits) + dict["n-" + i++] = GroupsDataUtils.DirGroupsReplyData(n); + + result["RESULT"] = dict; + } + + + string xmlString = ServerUtils.BuildXmlResponse(result); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + #region Helpers diff --git a/OpenSim/Data/MySQL/MySQLGroupsData.cs b/OpenSim/Data/MySQL/MySQLGroupsData.cs index 2a1bd6c..0318284 100644 --- a/OpenSim/Data/MySQL/MySQLGroupsData.cs +++ b/OpenSim/Data/MySQL/MySQLGroupsData.cs @@ -88,7 +88,7 @@ namespace OpenSim.Data.MySQL if (string.IsNullOrEmpty(pattern)) pattern = "1 ORDER BY Name LIMIT 100"; else - pattern = string.Format("Name LIKE %{0}% ORDER BY Name LIMIT 100", pattern); + pattern = string.Format("Name LIKE '%{0}%' ORDER BY Name LIMIT 100", pattern); return m_Groups.Get(pattern); } -- cgit v1.1 From 6be614ba844ee988859fe7f63db76ef13b9f4962 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 09:54:34 -0700 Subject: This makes people search work. --- .../UserManagement/UserManagementModule.cs | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 53bd2e2..295ad64 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -46,6 +46,8 @@ using log4net; using Nini.Config; using Mono.Addins; +using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; + namespace OpenSim.Region.CoreModules.Framework.UserManagement { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] @@ -98,6 +100,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); + scene.EventManager.OnMakeRootAgent += new Action(EventManager_OnMakeRootAgent); + scene.EventManager.OnMakeChildAgent += new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent); } } @@ -153,6 +157,43 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); } + void EventManager_OnMakeRootAgent(ScenePresence sp) + { + sp.ControllingClient.OnDirFindQuery += OnDirFindQuery; + } + + void EventManager_OnMakeChildAgent(ScenePresence sp) + { + sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery; + } + + void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) + { + if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People) + { + if (string.IsNullOrEmpty(queryText)) + remoteClient.SendDirPeopleReply(queryID, new DirPeopleReplyData[0]); + + List accounts = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, queryText); + DirPeopleReplyData[] hits = new DirPeopleReplyData[accounts.Count]; + int i = 0; + foreach (UserAccount acc in accounts) + { + DirPeopleReplyData d = new DirPeopleReplyData(); + d.agentID = acc.PrincipalID; + d.firstName = acc.FirstName; + d.lastName = acc.LastName; + d.online = false; + + hits[i++] = d; + } + + // TODO: This currently ignores pretty much all the query flags including Mature and sort order + remoteClient.SendDirPeopleReply(queryID, hits); + } + + } + void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( -- cgit v1.1 From 7b0b5c9d97dea840e1ede6e2318b3c049c804983 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 13:49:58 -0700 Subject: Added BasicSearchModule.cs which handles OnDirFindQuery events. Removed that handler from both Groups modules in core, and replaced them with an operation on IGroupsModule. --- OpenSim/Addons/Groups/GroupsModule.cs | 27 +-- .../Framework/Search/BasicSearchModule.cs | 198 +++++++++++++++++++++ .../UserManagement/UserManagementModule.cs | 39 ---- .../Region/Framework/Interfaces/IGroupsModule.cs | 2 + .../Avatar/XmlRpcGroups/GroupsModule.cs | 22 +-- bin/config-include/Grid.ini | 1 + bin/config-include/GridHypergrid.ini | 1 + bin/config-include/Standalone.ini | 1 + bin/config-include/StandaloneHypergrid.ini | 1 + 9 files changed, 216 insertions(+), 76 deletions(-) create mode 100644 OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 7d3c064..214a131 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -197,6 +197,7 @@ namespace OpenSim.Groups scene.EventManager.OnNewClient -= OnNewClient; scene.EventManager.OnMakeRootAgent -= OnMakeRoot; + scene.EventManager.OnMakeChildAgent -= OnMakeChild; scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; lock (m_sceneList) @@ -244,7 +245,6 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; - sp.ControllingClient.OnDirFindQuery += OnDirFindQuery; // Used for Notices and Group Invites/Accept/Reject sp.ControllingClient.OnInstantMessage += OnInstantMessage; @@ -257,7 +257,6 @@ namespace OpenSim.Groups if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest; - sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery; // Used for Notices and Group Invites/Accept/Reject sp.ControllingClient.OnInstantMessage -= OnInstantMessage; } @@ -305,25 +304,6 @@ namespace OpenSim.Groups } */ - void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) - { - if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups) - { - if (m_debugEnabled) - m_log.DebugFormat( - "[Groups]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})", - System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart); - - - if (string.IsNullOrEmpty(queryText)) - remoteClient.SendDirGroupsReply(queryID, new DirGroupsReplyData[0]); - - // TODO: This currently ignores pretty much all the query flags including Mature and sort order - remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), queryText).ToArray()); - } - - } - private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -1211,6 +1191,11 @@ namespace OpenSim.Groups } } + public List FindGroups(IClientAPI remoteClient, string query) + { + return m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), query); + } + #endregion #region Client/Update Tools diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs new file mode 100644 index 0000000..a089447 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs @@ -0,0 +1,198 @@ +/* + * 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.Threading; + +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Services.Connectors.Hypergrid; + +using OpenMetaverse; +using OpenMetaverse.Packets; +using log4net; +using Nini.Config; +using Mono.Addins; + +using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; + +namespace OpenSim.Region.CoreModules.Framework.Search +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicSearchModule")] + public class BasicSearchModule : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected bool m_Enabled; + protected List m_Scenes = new List(); + + private IGroupsModule m_GroupsService = null; + + #region ISharedRegionModule + + public void Initialise(IConfigSource config) + { + string umanmod = config.Configs["Modules"].GetString("SearchModule", Name); + if (umanmod == Name) + { + m_Enabled = true; + m_log.DebugFormat("[BASIC SEARCH MODULE]: {0} is enabled", Name); + } + } + + public bool IsSharedModule + { + get { return true; } + } + + public virtual string Name + { + get { return "BasicSearchModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void AddRegion(Scene scene) + { + if (m_Enabled) + { + m_Scenes.Add(scene); + + scene.EventManager.OnMakeRootAgent += new Action(EventManager_OnMakeRootAgent); + scene.EventManager.OnMakeChildAgent += new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent); + } + } + + public void RemoveRegion(Scene scene) + { + if (m_Enabled) + { + m_Scenes.Remove(scene); + + scene.EventManager.OnMakeRootAgent -= new Action(EventManager_OnMakeRootAgent); + scene.EventManager.OnMakeChildAgent -= new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent); + } + } + + public void RegionLoaded(Scene s) + { + if (!m_Enabled) + return; + + if (m_GroupsService == null) + { + m_GroupsService = s.RequestModuleInterface(); + + // No Groups Service Connector, then group search won't work... + if (m_GroupsService == null) + m_log.Warn("[BASIC SEARCH MODULE]: Could not get IGroupsModule"); + } + } + + public void PostInitialise() + { + } + + public void Close() + { + m_Scenes.Clear(); + } + + #endregion ISharedRegionModule + + + #region Event Handlers + + void EventManager_OnMakeRootAgent(ScenePresence sp) + { + sp.ControllingClient.OnDirFindQuery += OnDirFindQuery; + } + + void EventManager_OnMakeChildAgent(ScenePresence sp) + { + sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery; + } + + void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) + { + m_log.Debug("[ZZZ]: Got here"); + if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People) + { + if (string.IsNullOrEmpty(queryText)) + remoteClient.SendDirPeopleReply(queryID, new DirPeopleReplyData[0]); + + List accounts = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, queryText); + DirPeopleReplyData[] hits = new DirPeopleReplyData[accounts.Count]; + int i = 0; + foreach (UserAccount acc in accounts) + { + DirPeopleReplyData d = new DirPeopleReplyData(); + d.agentID = acc.PrincipalID; + d.firstName = acc.FirstName; + d.lastName = acc.LastName; + d.online = false; + + hits[i++] = d; + } + + // TODO: This currently ignores pretty much all the query flags including Mature and sort order + remoteClient.SendDirPeopleReply(queryID, hits); + } + else if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups) + { + if (m_GroupsService == null) + { + m_log.Warn("[BASIC SEARCH MODULE]: Groups service is not available. Unable to search groups."); + remoteClient.SendAlertMessage("Groups search is not enabled"); + return; + } + + if (string.IsNullOrEmpty(queryText)) + remoteClient.SendDirGroupsReply(queryID, new DirGroupsReplyData[0]); + + // TODO: This currently ignores pretty much all the query flags including Mature and sort order + remoteClient.SendDirGroupsReply(queryID, m_GroupsService.FindGroups(remoteClient, queryText).ToArray()); + } + + } + + #endregion Event Handlers + + } + +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 295ad64..7adb203 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -100,8 +100,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); - scene.EventManager.OnMakeRootAgent += new Action(EventManager_OnMakeRootAgent); - scene.EventManager.OnMakeChildAgent += new EventManager.OnMakeChildAgentDelegate(EventManager_OnMakeChildAgent); } } @@ -157,43 +155,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); } - void EventManager_OnMakeRootAgent(ScenePresence sp) - { - sp.ControllingClient.OnDirFindQuery += OnDirFindQuery; - } - - void EventManager_OnMakeChildAgent(ScenePresence sp) - { - sp.ControllingClient.OnDirFindQuery -= OnDirFindQuery; - } - - void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) - { - if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People) - { - if (string.IsNullOrEmpty(queryText)) - remoteClient.SendDirPeopleReply(queryID, new DirPeopleReplyData[0]); - - List accounts = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, queryText); - DirPeopleReplyData[] hits = new DirPeopleReplyData[accounts.Count]; - int i = 0; - foreach (UserAccount acc in accounts) - { - DirPeopleReplyData d = new DirPeopleReplyData(); - d.agentID = acc.PrincipalID; - d.firstName = acc.FirstName; - d.lastName = acc.LastName; - d.online = false; - - hits[i++] = d; - } - - // TODO: This currently ignores pretty much all the query flags including Mature and sort order - remoteClient.SendDirPeopleReply(queryID, hits); - } - - } - void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( diff --git a/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs b/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs index 6885327..9ae5e87 100644 --- a/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IGroupsModule.cs @@ -97,5 +97,7 @@ namespace OpenSim.Region.Framework.Interfaces void InviteGroupRequest(IClientAPI remoteClient, UUID GroupID, UUID InviteeID, UUID RoleID); void InviteGroup(IClientAPI remoteClient, UUID agentID, UUID GroupID, UUID InviteeID, UUID RoleID); void NotifyChange(UUID GroupID); + + List FindGroups(IClientAPI remoteClient, string query); } } \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs index 32fb54b..f4734b7 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs @@ -250,7 +250,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; - client.OnDirFindQuery += OnDirFindQuery; client.OnRequestAvatarProperties += OnRequestAvatarProperties; // Used for Notices and Group Invites/Accept/Reject @@ -303,21 +302,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups } */ - void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) - { - if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups) - { - if (m_debugEnabled) - m_log.DebugFormat( - "[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})", - System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart); - - // TODO: This currently ignores pretty much all the query flags including Mature and sort order - remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentID(remoteClient), queryText).ToArray()); - } - - } - private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) { if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -1178,6 +1162,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups } } + public List FindGroups(IClientAPI remoteClient, string query) + { + return m_groupData.FindGroups(GetRequestingAgentID(remoteClient), query); + } + + #endregion #region Client/Update Tools diff --git a/bin/config-include/Grid.ini b/bin/config-include/Grid.ini index cb3a5c8..15ba55a 100644 --- a/bin/config-include/Grid.ini +++ b/bin/config-include/Grid.ini @@ -23,6 +23,7 @@ InventoryAccessModule = "BasicInventoryAccessModule" LandServices = "RemoteLandServicesConnector" MapImageService = "MapImageServiceModule" + SearchModule = "BasicSearchModule" LandServiceInConnector = true NeighbourServiceInConnector = true diff --git a/bin/config-include/GridHypergrid.ini b/bin/config-include/GridHypergrid.ini index 31a4059..7edcafb 100644 --- a/bin/config-include/GridHypergrid.ini +++ b/bin/config-include/GridHypergrid.ini @@ -28,6 +28,7 @@ FriendsModule = "HGFriendsModule" MapImageService = "MapImageServiceModule" UserManagementModule = "HGUserManagementModule" + SearchModule = "BasicSearchModule" LandServiceInConnector = true NeighbourServiceInConnector = true diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index ba72fe7..d3b9cb4 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -19,6 +19,7 @@ EntityTransferModule = "BasicEntityTransferModule" InventoryAccessModule = "BasicInventoryAccessModule" MapImageService = "MapImageServiceModule" + SearchModule = "BasicSearchModule" LibraryModule = true LLLoginServiceInConnector = true diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index 39c33e8..3abf49b 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -25,6 +25,7 @@ InventoryAccessModule = "HGInventoryAccessModule" FriendsModule = "HGFriendsModule" UserManagementModule = "HGUserManagementModule" + SearchModule = "BasicSearchModule" InventoryServiceInConnector = true AssetServiceInConnector = true -- cgit v1.1 From 63f6c8f27ca280a7d362af08ba1716d5f28e3137 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 13:53:47 -0700 Subject: Removed commented lines and useless debug message --- OpenSim/Addons/Groups/GroupsModule.cs | 16 ---------------- .../CoreModules/Framework/Search/BasicSearchModule.cs | 1 - 2 files changed, 17 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 214a131..826fcbf 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -909,23 +909,7 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID); - //GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null); - GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested); - //GridInstantMessage msg = new GridInstantMessage(); - //msg.imSessionID = UUID.Zero.Guid; - //msg.fromAgentID = data.GroupID.Guid; - //msg.toAgentID = GetRequestingAgentID(remoteClient).Guid; - //msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - //msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName; - //msg.message = data.noticeData.Subject + "|" + data.Message; - //msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested; - //msg.fromGroup = true; - //msg.offline = (byte)0; - //msg.ParentEstateID = 0; - //msg.Position = Vector3.Zero; - //msg.RegionID = UUID.Zero.Guid; - //msg.binaryBucket = data.BinaryBucket; OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); } diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs index a089447..8838612 100644 --- a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs @@ -150,7 +150,6 @@ namespace OpenSim.Region.CoreModules.Framework.Search void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) { - m_log.Debug("[ZZZ]: Got here"); if (((DirFindFlags)queryFlags & DirFindFlags.People) == DirFindFlags.People) { if (string.IsNullOrEmpty(queryText)) -- cgit v1.1 From 698b2135eed747c24e3325cc7e5a7bae513a2c25 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 15:59:24 -0700 Subject: Fix an issue where HG members of groups weren't seeing the entire membership for group chat. --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index ce4f597..3cece77 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -52,7 +52,7 @@ namespace OpenSim.Groups private IPresenceService m_presenceService; private IMessageTransferModule m_msgTransferModule = null; - + private IUserManagement m_UserManagement = null; private IGroupsServicesConnector m_groupData = null; // Config Options @@ -162,6 +162,17 @@ namespace OpenSim.Groups return; } + m_UserManagement = scene.RequestModuleInterface(); + + // No groups module, no groups messaging + if (m_UserManagement == null) + { + m_log.Error("[Groups.Messaging]: Could not get IUserManagement, GroupsMessagingModule is now disabled."); + RemoveRegion(scene); + return; + } + + if (m_presenceService == null) m_presenceService = scene.PresenceService; @@ -392,9 +403,16 @@ namespace OpenSim.Groups Scene aScene = m_sceneList[0]; GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); - List groupMembers = m_groupData.GetGroupMembers(new UUID(msg.fromAgentID).ToString(), GroupID); + // Let's find out who sent it + string requestingAgent = m_UserManagement.GetUserUUI(new UUID(msg.fromAgentID)); + + List groupMembers = m_groupData.GetGroupMembers(requestingAgent, GroupID); List alreadySeen = new List(); + if (m_debugEnabled) + foreach (GroupMembersData m in groupMembers) + m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID); + foreach (Scene s in m_sceneList) { s.ForEachScenePresence(sp => -- cgit v1.1 From c442ef346eee83320d92ebc829cf3dec7bd2ed98 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 16:44:31 -0700 Subject: Same issue as previous commit. --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 13 +++++-------- OpenSim/Addons/Groups/Service/GroupsService.cs | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index 3cece77..5de1fb4 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -246,7 +246,7 @@ namespace OpenSim.Groups public void SendMessageToGroup(GridInstantMessage im, UUID groupID) { UUID fromAgentID = new UUID(im.fromAgentID); - List groupMembers = m_groupData.GetGroupMembers(fromAgentID.ToString(), groupID); + List groupMembers = m_groupData.GetGroupMembers("all", groupID); int groupMembersCount = groupMembers.Count; PresenceInfo[] onlineAgents = null; @@ -403,15 +403,12 @@ namespace OpenSim.Groups Scene aScene = m_sceneList[0]; GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); - // Let's find out who sent it - string requestingAgent = m_UserManagement.GetUserUUI(new UUID(msg.fromAgentID)); - - List groupMembers = m_groupData.GetGroupMembers(requestingAgent, GroupID); + List groupMembers = m_groupData.GetGroupMembers("all", GroupID); List alreadySeen = new List(); - if (m_debugEnabled) - foreach (GroupMembersData m in groupMembers) - m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID); + //if (m_debugEnabled) + // foreach (GroupMembersData m in groupMembers) + // m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID); foreach (Scene s in m_sceneList) { diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index a2ef13a..24eb7f3 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -255,13 +255,19 @@ namespace OpenSim.Groups return members; List rolesList = new List(roles); - // Is the requester a member of the group? - bool isInGroup = false; - if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null) - isInGroup = true; + // Check visibility? + // When we don't want to check visibility, we pass it "all" as the requestingAgentID + bool checkVisibility = !RequestingAgentID.Equals("all"); + if (checkVisibility) + { + // Is the requester a member of the group? + bool isInGroup = false; + if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null) + isInGroup = true; - if (!isInGroup) // reduce the roles to the visible ones - rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0); + if (!isInGroup) // reduce the roles to the visible ones + rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0); + } MembershipData[] datas = m_Database.RetrieveMembers(GroupID); if (datas == null || (datas != null && datas.Length == 0)) -- cgit v1.1 From 468ddd23736ce47e1cb881308785414ced504cee Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 17:12:14 -0700 Subject: Same issue. --- OpenSim/Addons/Groups/Service/GroupsService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index 24eb7f3..294b89a 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -258,6 +258,7 @@ namespace OpenSim.Groups // Check visibility? // When we don't want to check visibility, we pass it "all" as the requestingAgentID bool checkVisibility = !RequestingAgentID.Equals("all"); + m_log.DebugFormat("[ZZZ]: AgentID is {0}. checkVisibility is {1}", RequestingAgentID, checkVisibility); if (checkVisibility) { // Is the requester a member of the group? -- cgit v1.1 From 33b54807a1646a9457a7a718f767ccec1c0cb39f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 18:08:50 -0700 Subject: Changing the visibility test in groups service to be UUID.Zero.ToString() instead of "all" because some paths in the code assume there's a UUI in the RequestingAgent string. --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 4 ++-- OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 5 ++++- OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs | 1 + OpenSim/Addons/Groups/Service/GroupsService.cs | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index 5de1fb4..cd45432 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -246,7 +246,7 @@ namespace OpenSim.Groups public void SendMessageToGroup(GridInstantMessage im, UUID groupID) { UUID fromAgentID = new UUID(im.fromAgentID); - List groupMembers = m_groupData.GetGroupMembers("all", groupID); + List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID); int groupMembersCount = groupMembers.Count; PresenceInfo[] onlineAgents = null; @@ -403,7 +403,7 @@ namespace OpenSim.Groups Scene aScene = m_sceneList[0]; GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); - List groupMembers = m_groupData.GetGroupMembers("all", GroupID); + List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID); List alreadySeen = new List(); //if (m_debugEnabled) diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index daa0728..5e53981 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -254,7 +254,10 @@ namespace OpenSim.Groups { string url = string.Empty, gname = string.Empty; if (IsLocal(GroupID, out url, out gname)) - return m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), GroupID); + { + string agentID = AgentUUI(RequestingAgentID); + return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID); + } else if (!string.IsNullOrEmpty(url)) { ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID); diff --git a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs index 9a3e125..161ca0c 100644 --- a/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs +++ b/OpenSim/Addons/Groups/Remote/GroupsServiceRemoteConnector.cs @@ -256,6 +256,7 @@ namespace OpenSim.Groups Dictionary sendData = new Dictionary(); sendData["GroupID"] = GroupID.ToString(); sendData["RequestingAgentID"] = RequestingAgentID; + Dictionary ret = MakeRequest("GETGROUPMEMBERS", sendData); if (ret == null) diff --git a/OpenSim/Addons/Groups/Service/GroupsService.cs b/OpenSim/Addons/Groups/Service/GroupsService.cs index 294b89a..037ef59 100644 --- a/OpenSim/Addons/Groups/Service/GroupsService.cs +++ b/OpenSim/Addons/Groups/Service/GroupsService.cs @@ -257,8 +257,8 @@ namespace OpenSim.Groups // Check visibility? // When we don't want to check visibility, we pass it "all" as the requestingAgentID - bool checkVisibility = !RequestingAgentID.Equals("all"); - m_log.DebugFormat("[ZZZ]: AgentID is {0}. checkVisibility is {1}", RequestingAgentID, checkVisibility); + bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString()); + if (checkVisibility) { // Is the requester a member of the group? -- cgit v1.1 From 1d4bf06fe7731f4ca3d8f27a38d64f67d222c6af Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 18:49:10 -0700 Subject: Group chat: guard against duplicate sends --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index cd45432..83d296e 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -297,6 +297,10 @@ namespace OpenSim.Groups if (member.AgentID.Guid == im.fromAgentID) continue; + if (clientsAlreadySent.Contains(member.AgentID)) + continue; + clientsAlreadySent.Add(member.AgentID); + if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID)) { // Don't deliver messages to people who have dropped this session @@ -336,12 +340,9 @@ namespace OpenSim.Groups // Deliver locally, directly if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); - if (clientsAlreadySent.Contains(member.AgentID)) - continue; - clientsAlreadySent.Add(member.AgentID); - ProcessMessageFromGroupSession(im); } + } if (m_debugEnabled) -- cgit v1.1 From 1b94de8e58434cc882e1dde83919ecd3f1425e3f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 19:31:17 -0700 Subject: Group chat: prevent a situation where dupe IMs could occur. --- OpenSim/Addons/Groups/GroupsMessagingModule.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsMessagingModule.cs b/OpenSim/Addons/Groups/GroupsMessagingModule.cs index 83d296e..be59c62 100644 --- a/OpenSim/Addons/Groups/GroupsMessagingModule.cs +++ b/OpenSim/Addons/Groups/GroupsMessagingModule.cs @@ -405,7 +405,6 @@ namespace OpenSim.Groups GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID); List groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID); - List alreadySeen = new List(); //if (m_debugEnabled) // foreach (GroupMembersData m in groupMembers) @@ -415,15 +414,10 @@ namespace OpenSim.Groups { s.ForEachScenePresence(sp => { - // We need this, because we are searching through all - // SPs, both root and children - if (alreadySeen.Contains(sp.UUID)) - { - if (m_debugEnabled) - m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because we've already seen it", sp.UUID); + // If we got this via grid messaging, it's because the caller thinks + // that the root agent is here. We should only send the IM to root agents. + if (sp.IsChildAgent) return; - } - alreadySeen.Add(sp.UUID); GroupMembersData m = groupMembers.Find(gmd => { -- cgit v1.1 From 7eee9eb312e9f947d201e0ef3e2f34bceec4568d Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 28 Jul 2013 20:47:15 -0700 Subject: Groups: Better warning messages to the user. --- OpenSim/Addons/Groups/GroupsModule.cs | 4 ++++ .../Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 826fcbf..da8030c 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -991,6 +991,10 @@ namespace OpenSim.Groups // Should this send updates to everyone in the group? SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient)); + + if (reason != string.Empty) + // A warning + remoteClient.SendAlertMessage("Warning: " + reason); } else remoteClient.SendJoinGroupReply(groupID, false); diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index 5e53981..c33168c 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -399,17 +399,21 @@ namespace OpenSim.Groups if (success) { + // Here we always return true. The user has been added to the local group, + // independent of whether the remote operation succeeds or not url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI"); if (url == string.Empty) { - reason = "User doesn't have a groups server"; - return false; + reason = "You don't have have an accessible groups server in your home world. You membership to this group in only within this grid."; + return true; } GroupsServiceHGConnector c = GetConnector(url); if (c != null) - return c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason); + c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason); + return true; } + return false; } } else if (m_UserManagement.IsLocalGridUser(uid)) // local user -- cgit v1.1 From 8efe4bfc2ed7086e9fdf4812297e6525f955f6ac Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Jul 2013 23:18:29 +0100 Subject: Make "abnormal thread terminations" into "ClientLogoutsDueToNoReceives" and add this to the StatsManager This reflects the actual use of this stat - it hasn't recorded general exceptions for some time. Make the sim extra stats collector draw the data from the stats manager rather than maintaing this data itself. --- .../Framework/Monitoring/SimExtraStatsCollector.cs | 25 +++------ OpenSim/Framework/Monitoring/StatsManager.cs | 65 ++++++++++++++++++++-- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 26 +++++++-- 3 files changed, 89 insertions(+), 27 deletions(-) diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs index 6a68322..f6f458d 100644 --- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -39,8 +40,6 @@ namespace OpenSim.Framework.Monitoring /// public class SimExtraStatsCollector : BaseStatsCollector { - private long abnormalClientThreadTerminations; - // private long assetsInCache; // private long texturesInCache; // private long assetCacheMemoryUsage; @@ -73,11 +72,6 @@ namespace OpenSim.Framework.Monitoring private volatile float activeScripts; private volatile float scriptLinesPerSecond; - /// - /// Number of times that a client thread terminated because of an exception - /// - public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } } - // /// // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the // /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these @@ -166,11 +160,6 @@ namespace OpenSim.Framework.Monitoring private IDictionary packetQueueStatsCollectors = new Dictionary(); - public void AddAbnormalClientThreadTermination() - { - abnormalClientThreadTerminations++; - } - // public void AddAsset(AssetBase asset) // { // assetsInCache++; @@ -324,10 +313,12 @@ Asset service request failures: {3}" + Environment.NewLine, sb.Append(Environment.NewLine); sb.Append("CONNECTION STATISTICS"); sb.Append(Environment.NewLine); - sb.Append( - string.Format( - "Abnormal client thread terminations: {0}" + Environment.NewLine, - abnormalClientThreadTerminations)); + + List stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives"); + + sb.AppendFormat( + "Client logouts due to no data receive timeout: {0}\n\n", + stats != null ? stats.Sum(s => s.Value).ToString() : "unknown"); // sb.Append(Environment.NewLine); // sb.Append("INVENTORY STATISTICS"); @@ -338,7 +329,7 @@ Asset service request failures: {3}" + Environment.NewLine, // InventoryServiceRetrievalFailures)); sb.Append(Environment.NewLine); - sb.Append("FRAME STATISTICS"); + sb.Append("SAMPLE FRAME STATISTICS"); sb.Append(Environment.NewLine); sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); sb.Append(Environment.NewLine); diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index a5b54c9..e6a2304 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -271,7 +271,7 @@ namespace OpenSim.Framework.Monitoring // Stat name is not unique across category/container/shortname key. // XXX: For now just return false. This is to avoid problems in regression tests where all tests // in a class are run in the same instance of the VM. - if (TryGetStat(stat, out category, out container)) + if (TryGetStatParents(stat, out category, out container)) return false; // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. @@ -307,7 +307,7 @@ namespace OpenSim.Framework.Monitoring lock (RegisteredStats) { - if (!TryGetStat(stat, out category, out container)) + if (!TryGetStatParents(stat, out category, out container)) return false; newContainer = new SortedDictionary(container); @@ -323,12 +323,67 @@ namespace OpenSim.Framework.Monitoring } } - public static bool TryGetStats(string category, out SortedDictionary> stats) + public static bool TryGetStat(string category, string container, string statShortName, out Stat stat) { - return RegisteredStats.TryGetValue(category, out stats); + stat = null; + SortedDictionary> categoryStats; + + lock (RegisteredStats) + { + if (!TryGetStatsForCategory(category, out categoryStats)) + return false; + + SortedDictionary containerStats; + + if (!categoryStats.TryGetValue(container, out containerStats)) + return false; + + return containerStats.TryGetValue(statShortName, out stat); + } + } + + public static bool TryGetStatsForCategory( + string category, out SortedDictionary> stats) + { + lock (RegisteredStats) + return RegisteredStats.TryGetValue(category, out stats); + } + + /// + /// Get the same stat for each container in a given category. + /// + /// + /// The stats if there were any to fetch. Otherwise null. + /// + /// + /// + public static List GetStatsFromEachContainer(string category, string statShortName) + { + SortedDictionary> categoryStats; + + lock (RegisteredStats) + { + if (!RegisteredStats.TryGetValue(category, out categoryStats)) + return null; + + List stats = null; + + foreach (SortedDictionary containerStats in categoryStats.Values) + { + if (containerStats.ContainsKey(statShortName)) + { + if (stats == null) + stats = new List(); + + stats.Add(containerStats[statShortName]); + } + } + + return stats; + } } - public static bool TryGetStat( + public static bool TryGetStatParents( Stat stat, out SortedDictionary> category, out SortedDictionary container) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 25e10be..9e6a401 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -69,9 +69,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( + "ClientLogoutsDueToNoReceives", + "Number of times a client has been logged out because no packets were received before the timeout.", + "", + "", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.None, + stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( "IncomingUDPReceivesCount", "Number of UDP receives performed", - "Number of UDP receives performed", + "", "", "clientstack", scene.Name, @@ -84,7 +97,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP new Stat( "IncomingPacketsProcessedCount", "Number of inbound LL protocol packets processed", - "Number of inbound LL protocol packets processed", + "", "", "clientstack", scene.Name, @@ -97,7 +110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP new Stat( "OutgoingUDPSendsCount", "Number of UDP sends performed", - "Number of UDP sends performed", + "", "", "clientstack", scene.Name, @@ -149,6 +162,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Maximum transmission unit, or UDP packet size, for the LLUDP protocol public const int MTU = 1400; + /// Number of forced client logouts due to no receipt of packets before timeout. + public int ClientLogoutsDueToNoReceives { get; private set; } + /// /// Default packet debug level given to new clients /// @@ -1037,7 +1053,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP timeoutTicks = m_pausedAckTimeout; if (client.IsActive && - (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) + (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > -1) { // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even // though it's set later on by LLClientView.Close() @@ -1778,7 +1794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); - StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); + ClientLogoutsDueToNoReceives++; if (!client.SceneAgent.IsChildAgent) client.Kick("Simulator logged you out due to connection timeout"); -- cgit v1.1 From 8004e6f31cb03abc9b6170622099879ccaf5570b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Jul 2013 23:38:54 +0100 Subject: Fix issue just introduced in 8efe4bfc2ed7086e9fdf4812297e6525f955f6ac where I accidentally left in a test line to force very quick client unack --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 9e6a401..bf50868 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1053,7 +1053,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP timeoutTicks = m_pausedAckTimeout; if (client.IsActive && - (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > -1) + (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) { // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even // though it's set later on by LLClientView.Close() -- cgit v1.1 From 1416c909326d89566cbe785b6dacac228e31a5a0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 29 Jul 2013 23:53:59 +0100 Subject: minor: Add timeout secs to connection timeout message. Change message to reflect it is a timeout due to no data received rather than an ack issue. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index bf50868..85fe1a4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1062,7 +1062,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Fire this out on a different thread so that we don't hold up outgoing packet processing for // everybody else if this is being called due to an ack timeout. // This is the same as processing as the async process of a logout request. - Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); + Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks)); return; } @@ -1786,18 +1786,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// regular client pings. /// /// - private void DeactivateClientDueToTimeout(LLClientView client) + /// + private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) { lock (client.CloseSyncLock) - { - m_log.WarnFormat( - "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", - client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); - + { ClientLogoutsDueToNoReceives++; + + m_log.WarnFormat( + "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", + client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name); if (!client.SceneAgent.IsChildAgent) - client.Kick("Simulator logged you out due to connection timeout"); + client.Kick("Simulator logged you out due to connection timeout."); client.CloseWithoutChecks(); } -- cgit v1.1 From 5a7784a0e6c3f549d0e7b59380ad05729cb93a4f Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 24 Jul 2013 10:52:54 -0700 Subject: BulletSim: make density display and return value consistant with how the simulator expects it (scaled to 100kg/m^3). --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 13 +++++++------ OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 15 ++++++++++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 59e7f5f..58a417e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -75,7 +75,7 @@ public sealed class BSCharacter : BSPhysObject RawVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); Friction = BSParam.AvatarStandingFriction; - Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; + Density = BSParam.AvatarDensity; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 0bdb5f1..4520171 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -463,7 +463,7 @@ public static class BSParam // Density is passed around as 100kg/m3. This scales that to 1kg/m3. // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", - 0.0001f ), + 0.01f ), new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 2200f ), @@ -474,8 +474,9 @@ public static class BSParam 0.2f, (s) => { return DefaultFriction; }, (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), + // For historical reasons, the viewer and simulator multiply the density by 100 new ParameterDefn("DefaultDensity", "Density for new objects" , - 10.000006836f, // Aluminum g/cm3 + 1000.0006836f, // Aluminum g/cm3 * 100 (s) => { return DefaultDensity; }, (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , @@ -555,8 +556,9 @@ public static class BSParam 0.95f ), new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", 1.3f ), - new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", - 3.5f) , + // For historical reasons, density is reported * 100 + new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.", + 3500f) , // 3.5 * 100 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 0f ), new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", @@ -608,9 +610,8 @@ public static class BSParam 0.0f ), new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", 0.0f ), - // Turn off fudge with DensityScaleFactor = 0.0001. Value used to be 0.2f; new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", - 1.0f ), + 0.2f ), new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 60.0f ), new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index d34b797..0704591 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -187,10 +187,23 @@ public abstract class BSPhysObject : PhysicsActor MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); Friction = matAttrib.friction; Restitution = matAttrib.restitution; - Density = matAttrib.density / BSParam.DensityScaleFactor; + Density = matAttrib.density; // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); } + public override float Density + { + get + { + return base.Density; + } + set + { + DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value); + base.Density = value; + } + } + // Stop all physical motion. public abstract void ZeroMotion(bool inTaintTime); public abstract void ZeroAngularMotion(bool inTaintTime); -- cgit v1.1 From 6ad577d32bcb7520a33e4c0c7510d81a7cad674c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 30 Jul 2013 15:22:32 -0700 Subject: BulletSim: test method for debugging of extended physics script operations. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 54 ++++++++++++++++++---- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 6009dc5..0cbc5f9 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -31,10 +31,10 @@ using System.Reflection; using System.Text; using OpenSim.Framework; +using OpenSim.Region.CoreModules; using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.CoreModules; using Mono.Addins; using Nini.Config; @@ -49,6 +49,10 @@ public class ExtendedPhysics : INonSharedRegionModule private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static string LogHeader = "[EXTENDED PHYSICS]"; + // Since BulletSim is a plugin, this these values aren't defined easily in one place. + // This table must coorespond to an identical table in BSScene. + public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; + private IConfig Configuration { get; set; } private bool Enabled { get; set; } private Scene BaseScene { get; set; } @@ -143,13 +147,6 @@ public class ExtendedPhysics : INonSharedRegionModule [ScriptConstant] public static int PHYS_CENTER_OF_MASS = 1 << 0; - [ScriptConstant] - public static int PHYS_LINKSET_TYPE_CONSTRAINT = 1; - [ScriptConstant] - public static int PHYS_LINKSET_TYPE_COMPOUND = 2; - [ScriptConstant] - public static int PHYS_LINKSET_TYPE_MANUAL = 3; - [ScriptInvocation] public string physGetEngineType(UUID hostID, UUID scriptID) { @@ -163,9 +160,50 @@ public class ExtendedPhysics : INonSharedRegionModule return ret; } + [ScriptConstant] + public static int PHYS_LINKSET_TYPE_CONSTRAINT = 0; + [ScriptConstant] + public static int PHYS_LINKSET_TYPE_COMPOUND = 1; + [ScriptConstant] + public static int PHYS_LINKSET_TYPE_MANUAL = 2; + [ScriptInvocation] public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) { + if (!Enabled) return; + + // The part that is requesting the change. + SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); + + if (requestingPart != null) + { + // The change is always made to the root of a linkset. + SceneObjectGroup containingGroup = requestingPart.ParentGroup; + SceneObjectPart rootPart = containingGroup.RootPart; + + if (rootPart != null) + { + Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) + { + rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + } + else + { + m_log.WarnFormat("{0} physSetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physSetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } } } } -- cgit v1.1 From 0d189165a83bb97f243a1f29cfa6896936ca6db0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 30 Jul 2013 15:23:33 -0700 Subject: BulletSim: distribute vehicle physical settings to all members of a linkset. Enables constraint based linksets. Rename some internal variables to clarify whether values world or vehicle relative. --- OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 75 +++++++++++----------- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 18 +++++- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 11 +++- 3 files changed, 61 insertions(+), 43 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 82d7c44..f0d17d3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -589,10 +589,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_vehicleMass = ControllingPrim.TotalMass; // Friction affects are handled by this vehicle code - m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); - m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); - // ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); - // ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); + // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); + // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); + ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); + ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); // Moderate angular movement introduced by Bullet. // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. @@ -602,21 +602,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); // Vehicles report collision events so we know when it's on the ground - m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); - // ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); + // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); + ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); - Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); - ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; - m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); - m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); - // ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor); + // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); + // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; + // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); + // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); + ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass); // Set the gravity for the vehicle depending on the buoyancy // TODO: what should be done if prim and vehicle buoyancy differ? m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. - m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); - // ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); + // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); + ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, @@ -1121,7 +1121,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin { m_VhoverTargetHeight = m_VhoverHeight; } - if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) { // If body is already heigher, use its height as target height @@ -1170,7 +1169,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, verticalError, verticalCorrection); } - } } @@ -1357,6 +1355,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin private void ComputeAngularTurning(float pTimestep) { // The user wants this many radians per second angular change? + Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); @@ -1369,20 +1368,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin // TODO: This is here because this is where ODE put it but documentation says it // is a linear effect. Where should this check go? //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) - // { + // { // angularMotorContributionV.X = 0f; // angularMotorContributionV.Y = 0f; - // } + // } // Reduce any velocity by friction. Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); angularMotorContributionV -= (currentAngularV * frictionFactorW); - VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; - - + Vector3 angularMotorContributionW = angularMotorContributionV * VehicleOrientation; + VehicleRotationalVelocity += angularMotorContributionW; - VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV); + VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}", + ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW); } // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: @@ -1409,7 +1408,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 // since only computing half the distance between the angles. - float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; + float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; // Make a prediction of where the up axis will be when this is applied rather then where it is now as // this makes for a smoother adjustment and less fighting between the various forces. @@ -1419,12 +1418,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared - Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; + Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed; VehicleRotationalVelocity += vertContributionV; - VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", + VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}", ControllingPrim.LocalID, + verticalAttractionSpeed, vehicleUpAxis, predictedUp, torqueVector, @@ -1437,37 +1437,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no // Create a rotation that is only the vehicle's rotation around Z - Vector3 currentEuler = Vector3.Zero; - VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); - Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); + Vector3 currentEulerW = Vector3.Zero; + VehicleOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z); + Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z); // Create the axis that is perpendicular to the up vector and the rotated up vector. - Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); + Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); // Compute the angle between those to vectors. double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. // TODO: add 'efficiency'. - differenceAngle /= m_verticalAttractionTimescale; + // differenceAngle /= m_verticalAttractionTimescale; // Create the quaterian representing the correction angle - Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); + Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle); // Turn that quaternion into Euler values to make it into velocities to apply. - Vector3 vertContributionV = Vector3.Zero; - correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); - vertContributionV *= -1f; + Vector3 vertContributionW = Vector3.Zero; + correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z); + vertContributionW *= -1f; + vertContributionW /= m_verticalAttractionTimescale; - VehicleRotationalVelocity += vertContributionV; + VehicleRotationalVelocity += vertContributionW; VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}", ControllingPrim.LocalID, vehicleUpAxis, - differenceAxis, + differenceAxisW, differenceAngle, - correctionRotation, - vertContributionV); + correctionRotationW, + vertContributionW); break; } case 2: diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 960c0b4..7f94666 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -309,16 +309,18 @@ public abstract class BSLinkset } ); } - public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor) + public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) { ForEachMember((member) => { if (member.PhysBody.HasPhysicalBody) { - OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); member.Inertia = inertia * inertiaFactor; - m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); + m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); + DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); + } return false; // 'false' says to continue looping } @@ -334,6 +336,16 @@ public abstract class BSLinkset } ); } + public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) { ForEachMember((member) => diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 33ae5a5..6359046 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -61,11 +61,11 @@ public sealed class BSLinksetCompound : BSLinkset if (LinksetRoot.PhysBody.HasPhysicalBody) m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); } - public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor) + public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) { - OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass); + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass); LinksetRoot.Inertia = inertia * inertiaFactor; - m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia); + m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia); m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); } public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) @@ -73,6 +73,11 @@ public sealed class BSLinksetCompound : BSLinkset if (LinksetRoot.PhysBody.HasPhysicalBody) m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); } + public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); + } public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) { if (LinksetRoot.PhysBody.HasPhysicalBody) -- cgit v1.1 From 2b5419927143667048bddf0a501e42c093a71147 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 30 Jul 2013 17:26:56 -0700 Subject: After talking to lkalif on the IRC: SimulatorFeatures response: renamed the OSDMap GridServices to OpenSimExtras, normalized the url keys under it, and moved ExportEnabled to under it too. Melanie: change your viewer code accordingly. Documentation at http://opensimulator.org/wiki/SimulatorFeatures_Extras --- .../ClientStack/Linden/Caps/SimulatorFeaturesModule.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 7d9f935..4bd17b1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs @@ -149,15 +149,16 @@ namespace OpenSim.Region.ClientStack.Linden m_features["PhysicsShapeTypes"] = typesMap; // Extra information for viewers that want to use it - OSDMap gridServicesMap = new OSDMap(); + OSDMap extrasMap = new OSDMap(); if (m_MapImageServerURL != string.Empty) - gridServicesMap["map-server-url"] = m_MapImageServerURL; + extrasMap["map-server-url"] = m_MapImageServerURL; if (m_SearchURL != string.Empty) - gridServicesMap["search"] = m_SearchURL; - m_features["GridServices"] = gridServicesMap; - + extrasMap["search-server-url"] = m_SearchURL; if (m_ExportSupported) - m_features["ExportSupported"] = true; + extrasMap["ExportSupported"] = true; + if (extrasMap.Count > 0) + m_features["OpenSimExtras"] = extrasMap; + } } -- cgit v1.1 From fd050fca7caef83d72d00241d0c0db5c1ec5d1ff Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 30 Jul 2013 21:10:00 -0700 Subject: Doing the HG Map / SimulatorFeatures "the right way": moved it to HGMapModule, hooking on to SimulatorFeatures.OnSimulatorFeaturesRequest event (similar to what the DynamicMenuModule does). Only HG Visitors get this var, to avoid spamming local users. The config var is now called MapTileURL, to be consistent with the login one, and its being picked up from either [LoginService], [HGWorldMap] or [SimulatorFeatures], just because I have a bad memory. --- .../Linden/Caps/SimulatorFeaturesModule.cs | 15 ++----- .../CoreModules/Hypergrid/HGWorldMapModule.cs | 47 +++++++++++++++++++++- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 4bd17b1..e4d8a20 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs @@ -68,7 +68,6 @@ namespace OpenSim.Region.ClientStack.Linden /// private OSDMap m_features = new OSDMap(); - private string m_MapImageServerURL = string.Empty; private string m_SearchURL = string.Empty; private bool m_ExportSupported = false; @@ -78,15 +77,7 @@ namespace OpenSim.Region.ClientStack.Linden { IConfig config = source.Configs["SimulatorFeatures"]; if (config != null) - { - m_MapImageServerURL = config.GetString("MapImageServerURI", string.Empty); - if (m_MapImageServerURL != string.Empty) - { - m_MapImageServerURL = m_MapImageServerURL.Trim(); - if (!m_MapImageServerURL.EndsWith("/")) - m_MapImageServerURL = m_MapImageServerURL + "/"; - } - + { m_SearchURL = config.GetString("SearchServerURI", string.Empty); m_ExportSupported = config.GetBoolean("ExportSupported", m_ExportSupported); @@ -149,13 +140,13 @@ namespace OpenSim.Region.ClientStack.Linden m_features["PhysicsShapeTypes"] = typesMap; // Extra information for viewers that want to use it + // TODO: Take these out of here into their respective modules, like map-server-url OSDMap extrasMap = new OSDMap(); - if (m_MapImageServerURL != string.Empty) - extrasMap["map-server-url"] = m_MapImageServerURL; if (m_SearchURL != string.Empty) extrasMap["search-server-url"] = m_SearchURL; if (m_ExportSupported) extrasMap["ExportSupported"] = true; + if (extrasMap.Count > 0) m_features["OpenSimExtras"] = extrasMap; diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index c4255b9..4a5a352 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -31,6 +31,7 @@ using System.Reflection; using log4net; using Nini.Config; using OpenMetaverse; +using OpenMetaverse.StructuredData; using Mono.Addins; using OpenSim.Framework; using OpenSim.Region.CoreModules.World.WorldMap; @@ -48,13 +49,30 @@ namespace OpenSim.Region.CoreModules.Hypergrid // Remember the map area that each client has been exposed to in this region private Dictionary> m_SeenMapBlocks = new Dictionary>(); + private string m_MapImageServerURL = string.Empty; + + private IUserManagement m_UserManagement; + #region INonSharedRegionModule Members - public override void Initialise(IConfigSource config) + public override void Initialise(IConfigSource source) { if (Util.GetConfigVarFromSections( - config, "WorldMapModule", new string[] { "Map", "Startup" }, "WorldMap") == "HGWorldMap") + source, "WorldMapModule", new string[] { "Map", "Startup" }, "WorldMap") == "HGWorldMap") + { m_Enabled = true; + + m_MapImageServerURL = Util.GetConfigVarFromSections(source, "MapTileURL", new string[] {"LoginService", "HGWorldMap", "SimulatorFeatures"}); + + if (m_MapImageServerURL != string.Empty) + { + m_MapImageServerURL = m_MapImageServerURL.Trim(); + if (!m_MapImageServerURL.EndsWith("/")) + m_MapImageServerURL = m_MapImageServerURL + "/"; + } + + + } } public override void AddRegion(Scene scene) @@ -64,6 +82,17 @@ namespace OpenSim.Region.CoreModules.Hypergrid scene.EventManager.OnClientClosed += new EventManager.ClientClosed(EventManager_OnClientClosed); } + public override void RegionLoaded(Scene scene) + { + base.RegionLoaded(scene); + ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface(); + + if (featuresModule != null) + featuresModule.OnSimulatorFeaturesRequest += OnSimulatorFeaturesRequest; + + m_UserManagement = m_scene.RequestModuleInterface(); + + } public override string Name { get { return "HGWorldMap"; } @@ -115,6 +144,20 @@ namespace OpenSim.Region.CoreModules.Hypergrid return mapBlocks; } + private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) + { + if (m_UserManagement != null && !m_UserManagement.IsLocalGridUser(agentID) && m_MapImageServerURL != string.Empty) + { + OSD extras = new OSDMap(); + if (features.ContainsKey("OpenSimExtras")) + extras = features["OpenSimExtras"]; + else + features["OpenSimExtras"] = extras; + + ((OSDMap)extras)["map-server-url"] = m_MapImageServerURL; + + } + } } class MapArea -- cgit v1.1 From e4ecbc2b104959eced649e1620108afca22346dc Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 30 Jul 2013 21:38:41 -0700 Subject: Fix null ref. --- OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index 4a5a352..a7dd44e 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.CoreModules.Hypergrid m_MapImageServerURL = Util.GetConfigVarFromSections(source, "MapTileURL", new string[] {"LoginService", "HGWorldMap", "SimulatorFeatures"}); - if (m_MapImageServerURL != string.Empty) + if (!string.IsNullOrEmpty(m_MapImageServerURL)) { m_MapImageServerURL = m_MapImageServerURL.Trim(); if (!m_MapImageServerURL.EndsWith("/")) -- cgit v1.1 From 3c540f0d33894060d53616aa0aa67bc9d8ab82ec Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 30 Jul 2013 22:07:33 -0700 Subject: Avoid another null ref opportunity. --- OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index a7dd44e..a2aee08 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -146,7 +146,7 @@ namespace OpenSim.Region.CoreModules.Hypergrid private void OnSimulatorFeaturesRequest(UUID agentID, ref OSDMap features) { - if (m_UserManagement != null && !m_UserManagement.IsLocalGridUser(agentID) && m_MapImageServerURL != string.Empty) + if (m_UserManagement != null && !string.IsNullOrEmpty(m_MapImageServerURL) && !m_UserManagement.IsLocalGridUser(agentID)) { OSD extras = new OSDMap(); if (features.ContainsKey("OpenSimExtras")) -- cgit v1.1 From 87fcff9fc39f180ceb7d5511ca8bc23965fab17f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 31 Jul 2013 11:13:55 -0700 Subject: HGWorldMapModule: check whether it's enabled or not. --- OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index a2aee08..cb22f0b 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -77,6 +77,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid public override void AddRegion(Scene scene) { + if (!m_Enabled) + return; + base.AddRegion(scene); scene.EventManager.OnClientClosed += new EventManager.ClientClosed(EventManager_OnClientClosed); @@ -84,6 +87,9 @@ namespace OpenSim.Region.CoreModules.Hypergrid public override void RegionLoaded(Scene scene) { + if (!m_Enabled) + return; + base.RegionLoaded(scene); ISimulatorFeaturesModule featuresModule = m_scene.RequestModuleInterface(); -- cgit v1.1 From ac2ad9690d9e8b8988dc68cf4e2933c7b18a71bc Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 31 Jul 2013 11:20:27 -0700 Subject: HGWorldMapModule: unregister event on RemoveRegion --- OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index cb22f0b..97227b3 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -82,7 +82,7 @@ namespace OpenSim.Region.CoreModules.Hypergrid base.AddRegion(scene); - scene.EventManager.OnClientClosed += new EventManager.ClientClosed(EventManager_OnClientClosed); + scene.EventManager.OnClientClosed += EventManager_OnClientClosed; } public override void RegionLoaded(Scene scene) @@ -99,6 +99,15 @@ namespace OpenSim.Region.CoreModules.Hypergrid m_UserManagement = m_scene.RequestModuleInterface(); } + + public override void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + + scene.EventManager.OnClientClosed -= EventManager_OnClientClosed; + } + public override string Name { get { return "HGWorldMap"; } -- cgit v1.1 From 64f2dc778ad7a080ba89a1077da538c011c7c934 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 31 Jul 2013 11:27:35 -0700 Subject: A pretty major restructuring of the simian method invocations in order to service access capabilities. In conjunction with the corresponding Simian updates, this enables explicit per-simulator capability-based access to grid services. That enables grid owners to add or revoke access to the grid on a simulator by simulator basis. --- .../SimianGrid/SimianAssetServiceConnector.cs | 507 ++++++++++++++------- .../SimianAuthenticationServiceConnector.cs | 12 +- .../SimianGrid/SimianAvatarServiceConnector.cs | 8 +- .../SimianGrid/SimianFriendsServiceConnector.cs | 8 +- .../Services/Connectors/SimianGrid/SimianGrid.cs | 114 +++++ .../SimianGrid/SimianGridMaptileModule.cs | 131 +++--- .../SimianGrid/SimianGridServiceConnector.cs | 18 +- .../SimianGrid/SimianInventoryServiceConnector.cs | 30 +- .../SimianGrid/SimianPresenceServiceConnector.cs | 18 +- .../Connectors/SimianGrid/SimianProfiles.cs | 6 +- .../SimianUserAccountServiceConnector.cs | 8 +- 11 files changed, 578 insertions(+), 282 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 74b980c..6f8d9ed 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.IO; using System.Net; using System.Reflection; @@ -122,7 +123,7 @@ namespace OpenSim.Services.Connectors.SimianGrid m_Enabled = true; } - #region IAssetService +#region IAssetService public AssetBase Get(string id) { @@ -140,8 +141,9 @@ namespace OpenSim.Services.Connectors.SimianGrid return asset; } - return GetRemote(id); + return SimianGetOperation(id); } + public AssetBase GetCached(string id) { @@ -164,8 +166,6 @@ namespace OpenSim.Services.Connectors.SimianGrid throw new InvalidOperationException(); } - AssetMetadata metadata = null; - // Cache fetch if (m_cache != null) { @@ -174,50 +174,18 @@ namespace OpenSim.Services.Connectors.SimianGrid return asset.Metadata; } - Uri url; - - // Determine if id is an absolute URL or a grid-relative UUID - if (!Uri.TryCreate(id, UriKind.Absolute, out url)) - url = new Uri(m_serverUrl + id); - - try - { - HttpWebRequest request = UntrustedHttpWebRequest.Create(url); - request.Method = "HEAD"; - - using (WebResponse response = request.GetResponse()) - { - using (Stream responseStream = response.GetResponseStream()) - { - // Create the metadata object - metadata = new AssetMetadata(); - metadata.ContentType = response.ContentType; - metadata.ID = id; - - UUID uuid; - if (UUID.TryParse(id, out uuid)) - metadata.FullID = uuid; - - string lastModifiedStr = response.Headers.Get("Last-Modified"); - if (!String.IsNullOrEmpty(lastModifiedStr)) - { - DateTime lastModified; - if (DateTime.TryParse(lastModifiedStr, out lastModified)) - metadata.CreationDate = lastModified; - } - } - } - } - catch (Exception ex) - { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message); - } - - return metadata; + // return GetRemoteMetadata(id); + return SimianGetMetadataOperation(id); } - + public byte[] GetData(string id) { + if (String.IsNullOrEmpty(m_serverUrl)) + { + m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); + throw new InvalidOperationException(); + } + AssetBase asset = Get(id); if (asset != null) @@ -255,7 +223,7 @@ namespace OpenSim.Services.Connectors.SimianGrid Util.FireAndForget( delegate(object o) { - AssetBase asset = GetRemote(id); + AssetBase asset = SimianGetOperation(id); handler(id, sender, asset); } ); @@ -278,7 +246,6 @@ namespace OpenSim.Services.Connectors.SimianGrid } bool storedInCache = false; - string errorMessage = null; // AssetID handling if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID) @@ -307,83 +274,9 @@ namespace OpenSim.Services.Connectors.SimianGrid return asset.ID; } - // Distinguish public and private assets - bool isPublic = true; - switch ((AssetType)asset.Type) - { - case AssetType.CallingCard: - case AssetType.Gesture: - case AssetType.LSLBytecode: - case AssetType.LSLText: - isPublic = false; - break; - } - - // Make sure ContentType is set - if (String.IsNullOrEmpty(asset.Metadata.ContentType)) - asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type); - - // Build the remote storage request - List postParameters = new List() - { - new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), - new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), - new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), - new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), - new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) - }; - - // Make the remote storage request - try - { - // Simian does not require the asset ID to be in the URL because it's in the post data. - // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); - - using (HttpWebResponse response = MultipartForm.Post(request, postParameters)) - { - using (Stream responseStream = response.GetResponseStream()) - { - string responseStr = null; - - try - { - responseStr = responseStream.GetStreamString(); - OSD responseOSD = OSDParser.Deserialize(responseStr); - if (responseOSD.Type == OSDType.Map) - { - OSDMap responseMap = (OSDMap)responseOSD; - if (responseMap["Success"].AsBoolean()) - return asset.ID; - else - errorMessage = "Upload failed: " + responseMap["Message"].AsString(); - } - else - { - errorMessage = "Response format was invalid:\n" + responseStr; - } - } - catch (Exception ex) - { - if (!String.IsNullOrEmpty(responseStr)) - errorMessage = "Failed to parse the response:\n" + responseStr; - else - errorMessage = "Failed to retrieve the response: " + ex.Message; - } - } - } - } - catch (WebException ex) - { - errorMessage = ex.Message; - } - - m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", - asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); - - return null; + return SimianStoreOperation(asset); } - + /// /// Update an asset's content /// @@ -393,11 +286,17 @@ namespace OpenSim.Services.Connectors.SimianGrid /// public bool UpdateContent(string id, byte[] data) { + if (String.IsNullOrEmpty(m_serverUrl)) + { + m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); + throw new InvalidOperationException(); + } + AssetBase asset = Get(id); if (asset == null) { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating"); + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset {0} for updating", id); return false; } @@ -420,83 +319,347 @@ namespace OpenSim.Services.Connectors.SimianGrid throw new InvalidOperationException(); } - //string errorMessage = String.Empty; - string url = m_serverUrl + id; - if (m_cache != null) m_cache.Expire(id); + return SimianDeleteOperation(id); + } + +#endregion IAssetService + +#region SimianOperations + /// + /// Invokes the xRemoveAsset operation on the simian server to delete an asset + /// + /// + /// + private bool SimianDeleteOperation(string id) + { try { - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); - request.Method = "DELETE"; + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xRemoveAsset" }, + { "AssetID", id } + }; - using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) { - if (response.StatusCode != HttpStatusCode.NoContent) - { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Unexpected response when deleting asset " + url + ": " + - response.StatusCode + " (" + response.StatusDescription + ")"); - } + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset; {0}",response["Message"].AsString()); + return false; } - + return true; + } catch (Exception ex) { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service: " + ex.Message); - return false; + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset {0}; {1}", id, ex.Message); } - } - #endregion IAssetService + return false; + } - private AssetBase GetRemote(string id) + /// + /// Invokes the xAddAsset operation on the simian server to create or update an asset + /// + /// + /// + private string SimianStoreOperation(AssetBase asset) { - AssetBase asset = null; - Uri url; + try + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xAddAsset" }, + { "ContentType", asset.Metadata.ContentType }, + { "EncodedData", Convert.ToBase64String(asset.Data) }, + { "AssetID", asset.FullID.ToString() }, + { "CreatorID", asset.Metadata.CreatorID }, + { "Temporary", asset.Temporary ? "1" : "0" }, + { "Name", asset.Name } + }; + + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) + { + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",response["Message"].AsString()); + return null; + } - // Determine if id is an absolute URL or a grid-relative UUID - if (!Uri.TryCreate(id, UriKind.Absolute, out url)) - url = new Uri(m_serverUrl + id); + // asset.ID is always set before calling this function + return asset.ID; + + } + catch (Exception ex) + { + m_log.ErrorFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",ex.Message); + } + + return null; + } - try + /// + /// Invokes the xGetAsset operation on the simian server to get data associated with an asset + /// + /// + /// + private AssetBase SimianGetOperation(string id) + { + try { - HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xGetAsset" }, + { "ID", id } + }; - using (WebResponse response = request.GetResponse()) + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) { - using (Stream responseStream = response.GetResponseStream()) - { - string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; - - // Create the asset object - asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); - - UUID assetID; - if (UUID.TryParse(id, out assetID)) - asset.FullID = assetID; - - // Grab the asset data from the response stream - using (MemoryStream stream = new MemoryStream()) - { - responseStream.CopyStream(stream, Int32.MaxValue); - asset.Data = stream.ToArray(); - } - } + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset; {0}",response["Message"].AsString()); + return null; } + + AssetBase asset = new AssetBase(); - // Cache store - if (m_cache != null && asset != null) - m_cache.Cache(asset); + asset.ID = id; + asset.Name = String.Empty; + asset.Metadata.ContentType = response["ContentType"].AsString(); // this will also set the asset Type property + asset.CreatorID = response["CreatorID"].AsString(); + asset.Data = System.Convert.FromBase64String(response["EncodedData"].AsString()); + asset.Local = false; + asset.Temporary = response["Temporary"]; return asset; } catch (Exception ex) { - m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); - return null; + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to retrieve asset {0}; {1}", id, ex.Message); } + + return null; + } + + /// + /// Invokes the xGetAssetMetadata operation on the simian server to retrieve metadata for an asset + /// This operation is generally used to determine if an asset exists in the database + /// + /// + /// + private AssetMetadata SimianGetMetadataOperation(string id) + { + try + { + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xGetAssetMetadata" }, + { "ID", id } + }; + + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) + { + // this is not really an error, this call is used to test existence + // m_log.DebugFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset metadata; {0}",response["Message"].AsString()); + return null; + } + + AssetMetadata metadata = new AssetMetadata(); + metadata.ID = id; + metadata.ContentType = response["ContentType"].AsString(); + metadata.CreatorID = response["CreatorID"].AsString(); + metadata.Local = false; + metadata.Temporary = response["Temporary"]; + + string lastModifiedStr = response["Last-Modified"].AsString(); + if (! String.IsNullOrEmpty(lastModifiedStr)) + { + DateTime lastModified; + if (DateTime.TryParse(lastModifiedStr, out lastModified)) + metadata.CreationDate = lastModified; + } + + return metadata; + } + catch (Exception ex) + { + m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to get asset metadata; {0}", ex.Message); + } + + return null; } +#endregion + + // private AssetMetadata GetRemoteMetadata(string id) + // { + // Uri url; + // AssetMetadata metadata = null; + + // // Determine if id is an absolute URL or a grid-relative UUID + // if (!Uri.TryCreate(id, UriKind.Absolute, out url)) + // url = new Uri(m_serverUrl + id); + + // try + // { + // HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + // request.Method = "HEAD"; + + // using (WebResponse response = request.GetResponse()) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // // Create the metadata object + // metadata = new AssetMetadata(); + // metadata.ContentType = response.ContentType; + // metadata.ID = id; + + // UUID uuid; + // if (UUID.TryParse(id, out uuid)) + // metadata.FullID = uuid; + + // string lastModifiedStr = response.Headers.Get("Last-Modified"); + // if (!String.IsNullOrEmpty(lastModifiedStr)) + // { + // DateTime lastModified; + // if (DateTime.TryParse(lastModifiedStr, out lastModified)) + // metadata.CreationDate = lastModified; + // } + // } + // } + // } + // catch (Exception ex) + // { + // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message); + // } + + // return metadata; + // } + + // private AssetBase GetRemote(string id) + // { + // AssetBase asset = null; + // Uri url; + + // // Determine if id is an absolute URL or a grid-relative UUID + // if (!Uri.TryCreate(id, UriKind.Absolute, out url)) + // url = new Uri(m_serverUrl + id); + + // try + // { + // HttpWebRequest request = UntrustedHttpWebRequest.Create(url); + + // using (WebResponse response = request.GetResponse()) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; + + // // Create the asset object + // asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); + + // UUID assetID; + // if (UUID.TryParse(id, out assetID)) + // asset.FullID = assetID; + + // // Grab the asset data from the response stream + // using (MemoryStream stream = new MemoryStream()) + // { + // responseStream.CopyStream(stream, Int32.MaxValue); + // asset.Data = stream.ToArray(); + // } + // } + // } + + // // Cache store + // if (m_cache != null && asset != null) + // m_cache.Cache(asset); + + // return asset; + // } + // catch (Exception ex) + // { + // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); + // return null; + // } + // } + + // private string StoreRemote(AssetBase asset) + // { + // // Distinguish public and private assets + // bool isPublic = true; + // switch ((AssetType)asset.Type) + // { + // case AssetType.CallingCard: + // case AssetType.Gesture: + // case AssetType.LSLBytecode: + // case AssetType.LSLText: + // isPublic = false; + // break; + // } + + // string errorMessage = null; + + // // Build the remote storage request + // List postParameters = new List() + // { + // new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), + // new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), + // new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), + // new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), + // new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) + // }; + + // // Make the remote storage request + // try + // { + // // Simian does not require the asset ID to be in the URL because it's in the post data. + // // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs + // HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); + + // using (HttpWebResponse response = MultipartForm.Post(request, postParameters)) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // string responseStr = null; + + // try + // { + // responseStr = responseStream.GetStreamString(); + // OSD responseOSD = OSDParser.Deserialize(responseStr); + // if (responseOSD.Type == OSDType.Map) + // { + // OSDMap responseMap = (OSDMap)responseOSD; + // if (responseMap["Success"].AsBoolean()) + // return asset.ID; + // else + // errorMessage = "Upload failed: " + responseMap["Message"].AsString(); + // } + // else + // { + // errorMessage = "Response format was invalid:\n" + responseStr; + // } + // } + // catch (Exception ex) + // { + // if (!String.IsNullOrEmpty(responseStr)) + // errorMessage = "Failed to parse the response:\n" + responseStr; + // else + // errorMessage = "Failed to retrieve the response: " + ex.Message; + // } + // } + // } + // } + // catch (WebException ex) + // { + // errorMessage = ex.Message; + // } + + // m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", + // asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); + + // return null; + // } } } diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs index 6603f6e..3bd11d9 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs @@ -110,7 +110,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Identities"] is OSDArray) { bool md5hashFound = false; @@ -153,7 +153,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "SessionID", token } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { return true; @@ -175,7 +175,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { return true; @@ -198,7 +198,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) { OSDMap userMap = (OSDMap)response["User"]; @@ -218,7 +218,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", principalID.ToString() } }; - response = WebUtil.PostToService(m_serverUrl, requestArgs); + response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -297,7 +297,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) return response["SessionID"].AsUUID().ToString(); else diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs index 841bfa0..a397740 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs @@ -122,7 +122,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap map = null; @@ -168,7 +168,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "LLPackedAppearance", OSDParser.SerializeJsonString(map) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (! success) @@ -189,7 +189,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap map = null; @@ -306,7 +306,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "LLAttachments", OSDParser.SerializeJsonString(items) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index 7422d94..9a8164c 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -153,7 +153,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Value", flags.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -180,7 +180,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Key", friend } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -200,7 +200,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Type", "Friend" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) { return (OSDArray)response["Entries"]; @@ -221,7 +221,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Type", "Friend" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) { return (OSDArray)response["Entries"]; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs index 847319c..a4dd36c 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs @@ -26,8 +26,122 @@ */ using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Reflection; + +using log4net; using Mono.Addins; using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenMetaverse; +using OpenMetaverse.StructuredData; + [assembly: Addin("SimianGrid", "1.0")] [assembly: AddinDependency("OpenSim", "0.5")] + +namespace OpenSim.Services.Connectors.SimianGrid +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianExternalCapsModule")] + public class SimianGrid : ISharedRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig m_config = null; + private bool m_enabled = true; + + private String m_simianURL; + +#region IRegionModule Members + + public string Name + { + get { return this.GetType().Name; } + } + + + public void Initialise(IConfigSource config) + { + try + { + m_config = config.Configs["SimianGrid"]; + + if (m_config != null) + { + m_simianURL = m_config.GetString("SimianServiceURL"); + if (String.IsNullOrEmpty(m_simianURL)) + m_log.ErrorFormat("[SimianGrid] service URL is not defined"); + + InitialiseSimCap(); + SimulatorCapability = SimulatorCapability.Trim(); + m_log.WarnFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[SimianExternalCaps] initialization error: {0}",e.Message); + return; + } + } + + public void PostInitialise() { } + public void Close() { } + public void AddRegion(Scene scene) { } + public void RemoveRegion(Scene scene) { } + public void RegionLoaded(Scene scene) { } + + public Type ReplaceableInterface + { + get { return null; } + } + + /// + /// Try a variety of methods for finding the simian simulator capability; first check the + /// configuration itself, then look for a file that contains the cap, then finally look + /// for an environment variable that contains it. + /// + private void InitialiseSimCap() + { + if (m_config.Contains("SimulatorCapability")) + { + SimulatorCapability = m_config.GetString("SimulatorCapability"); + return; + } + + if (m_config.Contains("SimulatorCapabilityFile")) + { + String filename = m_config.GetString("SimulatorCapabilityFile"); + if (System.IO.File.Exists(filename)) + { + SimulatorCapability = System.IO.File.ReadAllText(filename); + return; + } + } + + if (m_config.Contains("SimulatorCapabilityVariable")) + { + String envname = m_config.GetString("SimulatorCapabilityVariable"); + String envvalue = System.Environment.GetEnvironmentVariable(envname); + if (envvalue != null) + { + SimulatorCapability = envvalue; + return; + } + } + + m_log.WarnFormat("[SimianExternalCaps] no method specified for simulator capability"); + } + +#endregion + public static String SimulatorCapability = UUID.Zero.ToString(); + public static OSDMap PostToService(string url, NameValueCollection data) + { + data["cap"] = SimulatorCapability; + return WebUtil.PostToService(url, data); + } + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs index 93fdae3..b999509 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Reflection; using System.Net; using System.IO; @@ -43,7 +44,8 @@ using OpenSim.Region.Framework.Scenes; using OpenMetaverse; using OpenMetaverse.StructuredData; -namespace OpenSim.Region.OptionalModules.Simian +//namespace OpenSim.Region.OptionalModules.Simian +namespace OpenSim.Services.Connectors.SimianGrid { /// /// @@ -196,67 +198,84 @@ namespace OpenSim.Region.OptionalModules.Simian } } - List postParameters = new List() + NameValueCollection requestArgs = new NameValueCollection + { + { "RequestMethod", "xAddMapTile" }, + { "X", scene.RegionInfo.RegionLocX.ToString() }, + { "Y", scene.RegionInfo.RegionLocY.ToString() }, + { "ContentType", "image/png" }, + { "EncodedData", System.Convert.ToBase64String(pngData) } + }; + + OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs); + if (! response["Success"].AsBoolean()) { - new MultipartForm.Parameter("X", scene.RegionInfo.RegionLocX.ToString()), - new MultipartForm.Parameter("Y", scene.RegionInfo.RegionLocY.ToString()), - new MultipartForm.File("Tile", "tile.png", "image/png", pngData) - }; + m_log.WarnFormat("[SIMIAN MAPTILE] failed to store map tile; {0}",response["Message"].AsString()); + return; + } - string errorMessage = null; - int tickstart = Util.EnvironmentTickCount(); + // List postParameters = new List() + // { + // new MultipartForm.Parameter("X", scene.RegionInfo.RegionLocX.ToString()), + // new MultipartForm.Parameter("Y", scene.RegionInfo.RegionLocY.ToString()), + // new MultipartForm.File("Tile", "tile.png", "image/png", pngData) + // }; - // Make the remote storage request - try - { - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl); - request.Timeout = 20000; - request.ReadWriteTimeout = 5000; + // string errorMessage = null; + // int tickstart = Util.EnvironmentTickCount(); - using (HttpWebResponse response = MultipartForm.Post(request, postParameters)) - { - using (Stream responseStream = response.GetResponseStream()) - { - string responseStr = responseStream.GetStreamString(); - OSD responseOSD = OSDParser.Deserialize(responseStr); - if (responseOSD.Type == OSDType.Map) - { - OSDMap responseMap = (OSDMap)responseOSD; - if (responseMap["Success"].AsBoolean()) - return; + // // Make the remote storage request + // try + // { + // HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl); + // request.Timeout = 20000; + // request.ReadWriteTimeout = 5000; - errorMessage = "Upload failed: " + responseMap["Message"].AsString(); - } - else - { - errorMessage = "Response format was invalid:\n" + responseStr; - } - } - } - } - catch (WebException we) - { - errorMessage = we.Message; - if (we.Status == WebExceptionStatus.ProtocolError) - { - HttpWebResponse webResponse = (HttpWebResponse)we.Response; - errorMessage = String.Format("[{0}] {1}", - webResponse.StatusCode,webResponse.StatusDescription); - } - } - catch (Exception ex) - { - errorMessage = ex.Message; - } - finally - { - // This just dumps a warning for any operation that takes more than 100 ms - int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); - m_log.DebugFormat("[SIMIAN MAPTILE]: map tile uploaded in {0}ms",tickdiff); - } + // using (HttpWebResponse response = MultipartForm.Post(request, postParameters)) + // { + // using (Stream responseStream = response.GetResponseStream()) + // { + // string responseStr = responseStream.GetStreamString(); + // OSD responseOSD = OSDParser.Deserialize(responseStr); + // if (responseOSD.Type == OSDType.Map) + // { + // OSDMap responseMap = (OSDMap)responseOSD; + // if (responseMap["Success"].AsBoolean()) + // return; + + // errorMessage = "Upload failed: " + responseMap["Message"].AsString(); + // } + // else + // { + // errorMessage = "Response format was invalid:\n" + responseStr; + // } + // } + // } + // } + // catch (WebException we) + // { + // errorMessage = we.Message; + // if (we.Status == WebExceptionStatus.ProtocolError) + // { + // HttpWebResponse webResponse = (HttpWebResponse)we.Response; + // errorMessage = String.Format("[{0}] {1}", + // webResponse.StatusCode,webResponse.StatusDescription); + // } + // } + // catch (Exception ex) + // { + // errorMessage = ex.Message; + // } + // finally + // { + // // This just dumps a warning for any operation that takes more than 100 ms + // int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + // m_log.DebugFormat("[SIMIAN MAPTILE]: map tile uploaded in {0}ms",tickdiff); + // } + + // m_log.WarnFormat("[SIMIAN MAPTILE]: Failed to store {0} byte tile for {1}: {2}", + // pngData.Length, scene.RegionInfo.RegionName, errorMessage); - m_log.WarnFormat("[SIMIAN MAPTILE]: Failed to store {0} byte tile for {1}: {2}", - pngData.Length, scene.RegionInfo.RegionName, errorMessage); } } } \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index 038a4bf..bcc1e4a 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -129,7 +129,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ExtraData", OSDParser.SerializeJsonString(extraData) } }; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) return String.Empty; else @@ -145,7 +145,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Enabled", "0" } }; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -192,7 +192,7 @@ namespace OpenSim.Services.Connectors.SimianGrid // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region with uuid {0}",regionID.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] uuid request successful {0}",response["Name"].AsString()); @@ -220,7 +220,7 @@ namespace OpenSim.Services.Connectors.SimianGrid // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request grid at {0}",position.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] position request successful {0}",response["Name"].AsString()); @@ -261,7 +261,7 @@ namespace OpenSim.Services.Connectors.SimianGrid // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions with name {0}",name); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name); @@ -299,7 +299,7 @@ namespace OpenSim.Services.Connectors.SimianGrid //m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions by range {0} to {1}",minPosition.ToString(),maxPosition.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { OSDArray array = response["Scenes"] as OSDArray; @@ -350,7 +350,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Enabled", "1" } }; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name); @@ -380,7 +380,7 @@ namespace OpenSim.Services.Connectors.SimianGrid m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region flags for {0}",regionID.ToString()); - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { OSDMap extraData = response["ExtraData"] as OSDMap; @@ -410,7 +410,7 @@ namespace OpenSim.Services.Connectors.SimianGrid if (onlyEnabled) requestArgs["Enabled"] = "1"; - OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); + OSDMap response = SimianGrid.PostToService(m_ServerURI, requestArgs); if (response["Success"].AsBoolean()) { return ResponseToGridRegion(response); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs index 36325ce..97eaabe 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs @@ -156,7 +156,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "OwnerID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -182,7 +182,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "0" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -244,7 +244,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -274,7 +274,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "OwnerID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Folder"] is OSDMap) { OSDMap folder = (OSDMap)response["Folder"]; @@ -312,7 +312,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { List items = GetItemsFromResponse((OSDArray)response["Items"]); @@ -349,7 +349,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -383,7 +383,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -423,7 +423,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ChildrenOnly", "1" } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["Items"] is OSDArray) { OSDArray items = (OSDArray)response["Items"]; @@ -454,7 +454,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -518,7 +518,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ItemID", itemID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -546,7 +546,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "FolderID", folder.ID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -623,7 +623,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "ExtraData", OSDParser.SerializeJsonString(extraData) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -847,7 +847,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Items", String.Join(",", itemIDs) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -885,7 +885,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_userServerUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap user = response["User"] as OSDMap; @@ -916,7 +916,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "Gestures", OSDParser.SerializeJsonString(gestures) } }; - OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_userServerUrl, requestArgs); if (!response["Success"].AsBoolean()) { m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " + diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs index 01163aa..211b775 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs @@ -149,7 +149,7 @@ namespace OpenSim.Services.Connectors.SimianGrid requestArgs["SecureSessionID"] = secureSessionID.ToString(); } - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -168,7 +168,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "SessionID", sessionID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -187,7 +187,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "SceneID", regionID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -232,7 +232,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserIDList", String.Join(",",userIDs) } }; - OSDMap sessionListResponse = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap sessionListResponse = SimianGrid.PostToService(m_serverUrl, requestArgs); if (! sessionListResponse["Success"].AsBoolean()) { m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString()); @@ -275,7 +275,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -295,7 +295,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "HomeLocation", SerializeLocation(regionID, position, lookAt) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -340,7 +340,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) return response; @@ -356,7 +356,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "SessionID", sessionID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) return response; @@ -376,7 +376,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "SceneLookAt", lastLookAt.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs index bd8069f..684a0db 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs @@ -392,7 +392,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", client.AgentId.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); string email = response["Email"].AsString(); if (!response["Success"].AsBoolean()) @@ -443,7 +443,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { key, OSDParser.SerializeJsonString(value) } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (!success) @@ -462,7 +462,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserID", userID.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean() && response["User"] is OSDMap) { return (OSDMap)response["User"]; diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs index 6e32b3a..7e36c69 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs @@ -165,7 +165,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "NameQuery", query } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDArray array = response["Users"] as OSDArray; @@ -204,7 +204,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "AccessLevel", data.UserLevel.ToString() } }; - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { @@ -219,7 +219,7 @@ namespace OpenSim.Services.Connectors.SimianGrid { "UserTitle", data.UserTitle } }; - response = WebUtil.PostToService(m_serverUrl, requestArgs); + response = SimianGrid.PostToService(m_serverUrl, requestArgs); bool success = response["Success"].AsBoolean(); if (success) @@ -252,7 +252,7 @@ namespace OpenSim.Services.Connectors.SimianGrid string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)"; // m_log.DebugFormat("[SIMIAN ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue); - OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); + OSDMap response = SimianGrid.PostToService(m_serverUrl, requestArgs); if (response["Success"].AsBoolean()) { OSDMap user = response["User"] as OSDMap; -- cgit v1.1 From d82126b651d07893c701c8477630aabf022b30d0 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 31 Jul 2013 11:42:22 -0700 Subject: Add the Simian service config to the GridCommon example --- bin/config-include/GridCommon.ini.example | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example index d12ea5b..920a691 100644 --- a/bin/config-include/GridCommon.ini.example +++ b/bin/config-include/GridCommon.ini.example @@ -205,3 +205,12 @@ ; DisallowResidents -- only Admins and Managers allowed ; Example: ; Region_Test_1 = "DisallowForeigners" + + +;; Uncomment if you are using SimianGrid for grid services +[SimianGrid] + ;; SimianGrid services URL + ;; SimianServiceURL = "http://grid.sciencesim.com/Grid/" + + ;; Capability assigned by the grid administrator for the simulator + ;; SimulatorCapability = "00000000-0000-0000-0000-000000000000" \ No newline at end of file -- cgit v1.1 From 12995924052a1804f01dceb80803447fccc1d9fe Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 31 Jul 2013 15:37:15 -0700 Subject: Experimental comment to eneralize the handling of Linden caps when the cap is something other than "localhost". A new interface for handling external caps is supported with an example implemented for Simian. The only linden cap supporting this interface right now is the GetTexture cap. --- .../ClientStack/Linden/Caps/GetTextureModule.cs | 6 +- .../Framework/Interfaces/IExternalCapsModule.cs | 48 ++++++ .../SimianGrid/SimianExternalCapsModule.cs | 179 +++++++++++++++++++++ prebuild.xml | 1 + 4 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs create mode 100644 OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index 13415f8..54cf285 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs @@ -137,7 +137,11 @@ namespace OpenSim.Region.ClientStack.Linden else { // m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); - caps.RegisterHandler("GetTexture", m_URL); + IExternalCapsModule handler = m_scene.RequestModuleInterface(); + if (handler != null) + handler.RegisterExternalUserCapsHandler(agentID,caps,"GetTexture",m_URL); + else + caps.RegisterHandler("GetTexture", m_URL); } } diff --git a/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs b/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs new file mode 100644 index 0000000..a730cfd --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs @@ -0,0 +1,48 @@ +/* + * 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 OpenMetaverse; +using OpenSim.Framework; +using Caps=OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IExternalCapsModule + { + /// + /// This function extends the simple URL configuration in the caps handlers + /// to facilitate more interesting computation when an external handler is + /// sent to the viewer. + /// + /// New user UUID + /// Internal caps registry, where the external handler will be registered + /// Name of the specific cap we are registering + /// The skeleton URL provided in the caps configuration + bool RegisterExternalUserCapsHandler(UUID agentID, Caps caps, String capName, String urlSkel); + } +} diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs new file mode 100644 index 0000000..8226705 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs @@ -0,0 +1,179 @@ +/* + * 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.Generic; +using System.Reflection; +using System.IO; +using System.Web; + +using log4net; +using Nini.Config; +using Mono.Addins; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Services.Connectors.SimianGrid +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianExternalCapsModule")] + public class SimianExternalCapsModule : INonSharedRegionModule, IExternalCapsModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_enabled = true; + private Scene m_scene; + private String m_simianURL; + + private IGridUserService m_GridUserService; + +#region IRegionModule Members + + + public string Name + { + get { return this.GetType().Name; } + } + + public void Initialise(IConfigSource config) + { + try + { + IConfig m_config; + + if ((m_config = config.Configs["SimianExternalCaps"]) != null) + { + m_enabled = m_config.GetBoolean("Enabled", m_enabled); + if ((m_config = config.Configs["SimianGrid"]) != null) + { + m_simianURL = m_config.GetString("SimianServiceURL"); + if (String.IsNullOrEmpty(m_simianURL)) + m_log.ErrorFormat("[SimianGrid] service URL is not defined"); + } + } + else + m_enabled = false; + } + catch (Exception e) + { + m_log.ErrorFormat("[SimianExternalCaps] initialization error: {0}",e.Message); + return; + } + } + + public void PostInitialise() { } + public void Close() { } + + public void AddRegion(Scene scene) + { + if (! m_enabled) + return; + + m_scene = scene; + m_scene.RegisterModuleInterface(this); + } + + public void RemoveRegion(Scene scene) + { + if (! m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps -= RegisterCapsEventHandler; + m_scene.EventManager.OnDeregisterCaps -= DeregisterCapsEventHandler; + } + + public void RegionLoaded(Scene scene) + { + if (! m_enabled) + return; + + m_scene.EventManager.OnRegisterCaps += RegisterCapsEventHandler; + m_scene.EventManager.OnDeregisterCaps += DeregisterCapsEventHandler; + } + + public Type ReplaceableInterface + { + get { return null; } + } + +#endregion + +#region IExternalCapsModule + // Eg http://grid.sciencesim.com/GridPublic/%CAP%/%OP%/" + public bool RegisterExternalUserCapsHandler(UUID agentID, Caps caps, String capName, String urlSkel) + { + UUID cap = UUID.Random(); + + // Call to simian to register the cap we generated + // NameValueCollection requestArgs = new NameValueCollection + // { + // { "RequestMethod", "AddCapability" }, + // { "Resource", "user" }, + // { "Expiration", 0 }, + // { "OwnerID", agentID.ToString() }, + // { "CapabilityID", cap.ToString() } + // }; + + // OSDMap response = SimianGrid.PostToService(m_simianURL, requestArgs); + + Dictionary subs = new Dictionary(); + subs["%OP%"] = capName; + subs["%USR%"] = agentID.ToString(); + subs["%CAP%"] = cap.ToString(); + subs["%SIM%"] = m_scene.RegionInfo.RegionID.ToString(); + + caps.RegisterHandler(capName,ExpandSkeletonURL(urlSkel,subs)); + return true; + } + +#endregion + +#region EventHandlers + public void RegisterCapsEventHandler(UUID agentID, Caps caps) { } + public void DeregisterCapsEventHandler(UUID agentID, Caps caps) { } +#endregion + + private String ExpandSkeletonURL(String urlSkel, Dictionary subs) + { + String result = urlSkel; + + foreach (KeyValuePair kvp in subs) + { + result = result.Replace(kvp.Key,kvp.Value); + } + + return result; + } + } +} \ No newline at end of file diff --git a/prebuild.xml b/prebuild.xml index 91c326c..b376e86 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -869,6 +869,7 @@ + -- cgit v1.1 From 9f05a7ac7bfba66989b053af06dca051a522a9b1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 1 Aug 2013 00:25:59 +0100 Subject: Include missing reference that probably stops windows build from commit 12995924052a1804f01dceb80803447fccc1d9fe --- prebuild.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/prebuild.xml b/prebuild.xml index b376e86..af8f686 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -872,6 +872,7 @@ + -- cgit v1.1 From 59b461ac0eaae1cc34bb82431106fdf0476037f3 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 1 Aug 2013 09:27:44 -0700 Subject: Issue: painfully slow terrain loading. The cause is commit d9d995914c5fba00d4ccaf66b899384c8ea3d5eb (r/23185) -- the WaitOne on the UDPServer. Putting it back to how it was done solves the issue. But this may impact CPU usage, so I'm pushing it to test if it does. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 85fe1a4..942c044 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -246,7 +246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 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. /// - private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); + //private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); private Pool m_incomingPacketPool; @@ -907,7 +907,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP PacketPool.Instance.ReturnPacket(packet); - m_dataPresentEvent.Set(); + //m_dataPresentEvent.Set(); } /// @@ -1919,12 +1919,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If nothing was sent, sleep for the minimum amount of time before a // token bucket could get more tokens - //if (!m_packetSent) - // Thread.Sleep((int)TickCountResolution); + if (!m_packetSent) + Thread.Sleep((int)TickCountResolution); // // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with // modern mono it reduces CPU base load since there is no more continuous polling. - m_dataPresentEvent.WaitOne(100); + //m_dataPresentEvent.WaitOne(100); Watchdog.UpdateThread(); } -- cgit v1.1 From 932c382737d155176bd7e0dcfaf9395d997a88fb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 1 Aug 2013 18:11:50 +0100 Subject: Revert "Issue: painfully slow terrain loading. The cause is commit d9d995914c5fba00d4ccaf66b899384c8ea3d5eb (r/23185) -- the WaitOne on the UDPServer. Putting it back to how it was done solves the issue. But this may impact CPU usage, so I'm pushing it to test if it does." This reverts commit 59b461ac0eaae1cc34bb82431106fdf0476037f3. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 942c044..85fe1a4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -246,7 +246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// 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. /// - //private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); + private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false); private Pool m_incomingPacketPool; @@ -907,7 +907,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP PacketPool.Instance.ReturnPacket(packet); - //m_dataPresentEvent.Set(); + m_dataPresentEvent.Set(); } /// @@ -1919,12 +1919,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP // If nothing was sent, sleep for the minimum amount of time before a // token bucket could get more tokens - if (!m_packetSent) - Thread.Sleep((int)TickCountResolution); + //if (!m_packetSent) + // Thread.Sleep((int)TickCountResolution); // // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with // modern mono it reduces CPU base load since there is no more continuous polling. - //m_dataPresentEvent.WaitOne(100); + m_dataPresentEvent.WaitOne(100); Watchdog.UpdateThread(); } -- cgit v1.1 From 0c4c084bed5175d8a5b25b8f915363f3b15b6e3a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 1 Aug 2013 18:12:28 +0100 Subject: Try a different approach to slow terrain update by always cycling the loop immediately if any data was sent, rather than waiting. What I believe is happening is that on initial terrain send, this is done one packet at a time. With WaitOne, the outbound loop has enough time to loop and wait again after the first packet before the second, leading to a slower send. This approach instead does not wait if a packet was just sent but instead loops again, which appears to lead to a quicker send without losing the cpu benefit of not continually looping when there is no outbound data. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 85fe1a4..558fcb7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1924,7 +1924,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with // modern mono it reduces CPU base load since there is no more continuous polling. - m_dataPresentEvent.WaitOne(100); + if (!m_packetSent) + m_dataPresentEvent.WaitOne(100); Watchdog.UpdateThread(); } -- cgit v1.1 From 216e785ca9ca7dee51c32e69952a79b6e87733d1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 1 Aug 2013 21:16:53 +0100 Subject: Add experimental "debug attachments throttle " setting (command line) and ThrottlePer100PrimsRezzed in [Attachments] in config This is an experimental setting to control cpu spikes when an attachment heavy avatar logs in or avatars with medium attachments lgoin simultaneously. It inserts a ms sleep specified in terms of attachments prims after each rez when an avatar logs in. Default is 0 (no throttling). "debug attachments " changes to "debug attachments log " which controls logging. A logging level of 1 will show the throttling performed if applicable. Also adds "debug attachments status" command to show current throttle and debug logging levels. --- .../Avatar/Attachments/AttachmentsModule.cs | 102 ++++++++++++++++++--- bin/OpenSimDefaults.ini | 7 ++ 2 files changed, 94 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 2f5a76f..97477d4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Reflection; using System.IO; +using System.Threading; using System.Xml; using log4net; using Mono.Addins; @@ -50,6 +51,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public int DebugLevel { get; set; } + + /// + /// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in + /// or many avatars with a medium levels of attachments login simultaneously. + /// + /// + /// A value of 0 will apply no pause. The pause is specified in milliseconds. + /// + public int ThrottlePer100PrimsRezzed { get; set; } private Scene m_scene; private IInventoryAccessModule m_invAccessModule; @@ -66,9 +76,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { IConfig config = source.Configs["Attachments"]; if (config != null) + { Enabled = config.GetBoolean("Enabled", true); + + ThrottlePer100PrimsRezzed = config.GetInt("ThrottlePer100PrimsRezzed", 0); + } else + { Enabled = true; + } } public void AddRegion(Scene scene) @@ -87,24 +103,43 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments MainConsole.Instance.Commands.AddCommand( "Debug", false, - "debug attachments", - "debug attachments [0|1]", - "Turn on attachments debugging\n" - + " <= 0 - turns off debugging\n" - + " >= 1 - turns on attachment message logging\n", - HandleDebugAttachments); + "debug attachments log", + "debug attachments log [0|1]", + "Turn on attachments debug logging", + " <= 0 - turns off debug logging\n" + + " >= 1 - turns on attachment message debug logging", + HandleDebugAttachmentsLog); + + MainConsole.Instance.Commands.AddCommand( + "Debug", + false, + "debug attachments throttle", + "debug attachments throttle ", + "Turn on attachments throttling.", + "This requires a millisecond value. " + + " == 0 - disable throttling.\n" + + " > 0 - sleeps for this number of milliseconds per 100 prims rezzed.", + HandleDebugAttachmentsThrottle); + + MainConsole.Instance.Commands.AddCommand( + "Debug", + false, + "debug attachments status", + "debug attachments status", + "Show current attachments debug status", + HandleDebugAttachmentsStatus); } // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI } - private void HandleDebugAttachments(string module, string[] args) + private void HandleDebugAttachmentsLog(string module, string[] args) { int debugLevel; - if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) + if (!(args.Length == 4 && int.TryParse(args[3], out debugLevel))) { - MainConsole.Instance.OutputFormat("Usage: debug attachments [0|1]"); + MainConsole.Instance.OutputFormat("Usage: debug attachments log [0|1]"); } else { @@ -114,6 +149,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } + private void HandleDebugAttachmentsThrottle(string module, string[] args) + { + int ms; + + if (args.Length == 4 && int.TryParse(args[3], out ms)) + { + ThrottlePer100PrimsRezzed = ms; + MainConsole.Instance.OutputFormat( + "Attachments rez throttle per 100 prims is now {0} in {1}", ThrottlePer100PrimsRezzed, m_scene.Name); + + return; + } + + MainConsole.Instance.OutputFormat("Usage: debug attachments throttle "); + } + + private void HandleDebugAttachmentsStatus(string module, string[] args) + { + MainConsole.Instance.OutputFormat("Settings for {0}", m_scene.Name); + MainConsole.Instance.OutputFormat("Debug logging level: {0}", DebugLevel); + MainConsole.Instance.OutputFormat("Throttle per 100 prims: {0}ms", ThrottlePer100PrimsRezzed); + } + /// /// Listen for client triggered running state changes so that we can persist the script's object if necessary. /// @@ -240,7 +298,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments List attachments = sp.Appearance.GetAttachments(); foreach (AvatarAttachment attach in attachments) { - uint p = (uint)attach.AttachPoint; + uint attachmentPt = (uint)attach.AttachPoint; // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}", @@ -258,14 +316,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { // If we're an NPC then skip all the item checks and manipulations since we don't have an // inventory right now. - RezSingleAttachmentFromInventoryInternal( - sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, p, true); + SceneObjectGroup objatt + = RezSingleAttachmentFromInventoryInternal( + sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true); + + + if (ThrottlePer100PrimsRezzed > 0) + { + int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed); + + if (DebugLevel > 0) + m_log.DebugFormat( + "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}", + throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); + + Thread.Sleep(throttleMs); + } } catch (Exception e) { UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId; m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}", - attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace); + attach.ItemID, attach.AssetID, attachmentPt, agentId, e.Message, e.StackTrace); } } } @@ -919,8 +991,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (DebugLevel > 0) m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", - objatt.Name, sp.Name, attachmentPt, m_scene.Name); + "[ATTACHMENTS MODULE]: Rezzed single object {0} with {1} prims for attachment to {2} on point {3} in {4}", + objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. objatt.HasGroupChanged = false; diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index dbafd5c..2488bf1 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -703,11 +703,18 @@ ; on every login ReuseTextures = false + [Attachments] ; Controls whether avatar attachments are enabled. ; Defaults to true - only set to false for debugging purposes Enabled = true + ; Controls the number of milliseconds that are slept per 100 prims rezzed in attachments + ; Experimental setting to control CPU spiking when avatars with many attachments login + ; or when multiple avatars with medium level attachments login simultaneously. + ; If 0 then no throttling is performed. + ThrottlePer100PrimsRezzed = 0; + [Mesh] ; enable / disable Collada mesh support -- cgit v1.1 From 7b9a50721da3ac51ee3aa60ea946278d38a18426 Mon Sep 17 00:00:00 2001 From: teravus Date: Thu, 1 Aug 2013 16:30:29 -0500 Subject: * Thanks Plugh for pointing out that the constructor that takes a ulong regionhandle and saves it to to X,Y vars in the OpenSim.Framework.Location object was inverting the X and Y resulting in X and Y confusion. The test also used 256x256 in the uint,uint constructor so it was unable to determine if the X and Y components swapped. I don't expect much upheaval from this commit, not a lot of features were using the ulong Location object constructor. The database never stores the ulong regionhandle... the prims are loaded by region Guid. LLUDPServer used it to determine regions that it handled in a service definition where there was simply a X == X test which has the same logical result un-switched as it did switched. Again, thanks LibOMV for the regionhandle code. --- OpenSim/Framework/Location.cs | 16 ++++++++-------- OpenSim/Framework/Tests/LocationTest.cs | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/OpenSim/Framework/Location.cs b/OpenSim/Framework/Location.cs index 9504e03..0b88834 100644 --- a/OpenSim/Framework/Location.cs +++ b/OpenSim/Framework/Location.cs @@ -33,10 +33,10 @@ namespace OpenSim.Framework [Serializable] public class Location : ICloneable { - private readonly int m_x; - private readonly int m_y; + private readonly uint m_x; + private readonly uint m_y; - public Location(int x, int y) + public Location(uint x, uint y) { m_x = x; m_y = y; @@ -44,21 +44,21 @@ namespace OpenSim.Framework public Location(ulong regionHandle) { - m_x = (int) regionHandle; - m_y = (int) (regionHandle >> 32); + m_x = (uint)(regionHandle >> 32); + m_y = (uint)(regionHandle & (ulong)uint.MaxValue); } public ulong RegionHandle { - get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); } + get { return Utils.UIntsToLong(m_x, m_y); } } - public int X + public uint X { get { return m_x; } } - public int Y + public uint Y { get { return m_y; } } diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs index a56ecb4..af5f164 100644 --- a/OpenSim/Framework/Tests/LocationTest.cs +++ b/OpenSim/Framework/Tests/LocationTest.cs @@ -51,21 +51,21 @@ namespace OpenSim.Framework.Tests [Test] public void locationXYRegionHandle() { - Location TestLocation1 = new Location(256000,256000); - Location TestLocation2 = new Location(1099511628032000); + Location TestLocation1 = new Location(255000,256000); + Location TestLocation2 = new Location(1095216660736000); Assert.That(TestLocation1 == TestLocation2); - Assert.That(TestLocation2.X == 256000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); + Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); - Assert.That(TestLocation2.RegionHandle == 1099511628032000, + Assert.That(TestLocation2.RegionHandle == 1095216660736000, "Location RegionHandle Property didn't match regionhandle provided in constructor"); - TestLocation1 = new Location(256001, 256001); - TestLocation2 = new Location(1099511628032000); + TestLocation1 = new Location(255001, 256001); + TestLocation2 = new Location(1095216660736000); Assert.That(TestLocation1 != TestLocation2); - Assert.That(TestLocation1.Equals(256001, 256001), "Equals(x,y) failed to match the position in the constructor"); + Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor"); Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); -- cgit v1.1 From 68b98a8003e0ea7ed082b105ae82a644fb706796 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 1 Aug 2013 23:16:41 +0100 Subject: minor: Add name to debug lludp packet level feedback on console --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 558fcb7..5c38399 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -694,7 +694,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { DefaultClientPacketDebugLevel = newDebug; MainConsole.Instance.OutputFormat( - "Debug packet debug for new clients set to {0}", DefaultClientPacketDebugLevel); + "Debug packet debug for new clients set to {0} in {1}", DefaultClientPacketDebugLevel, m_scene.Name); } else { -- cgit v1.1 From c9695a0a59cba91a184683efaa7802338d68e4bd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 2 Aug 2013 00:00:00 +0100 Subject: Move experimental attachments throttling further down the chain so that multiple attachments changes (e.g. change outfit) are also throttled --- .../Avatar/Attachments/AttachmentsModule.cs | 31 +++++++++++----------- bin/OpenSimDefaults.ini | 4 +-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 97477d4..675fccc 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -53,8 +53,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public int DebugLevel { get; set; } /// - /// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in - /// or many avatars with a medium levels of attachments login simultaneously. + /// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in/changes + /// outfit or many avatars with a medium levels of attachments login/change outfit simultaneously. /// /// /// A value of 0 will apply no pause. The pause is specified in milliseconds. @@ -319,19 +319,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments SceneObjectGroup objatt = RezSingleAttachmentFromInventoryInternal( sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true); - - - if (ThrottlePer100PrimsRezzed > 0) - { - int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed); - - if (DebugLevel > 0) - m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}", - throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); - - Thread.Sleep(throttleMs); - } } catch (Exception e) { @@ -1023,7 +1010,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } if (tainted) - objatt.HasGroupChanged = true; + objatt.HasGroupChanged = true; + + if (ThrottlePer100PrimsRezzed > 0) + { + int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed); + + if (DebugLevel > 0) + m_log.DebugFormat( + "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}", + throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); + + Thread.Sleep(throttleMs); + } return objatt; } diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 2488bf1..d5d29ec 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -710,8 +710,8 @@ Enabled = true ; Controls the number of milliseconds that are slept per 100 prims rezzed in attachments - ; Experimental setting to control CPU spiking when avatars with many attachments login - ; or when multiple avatars with medium level attachments login simultaneously. + ; Experimental setting to control CPU spiking when avatars with many attachments login/change outfit + ; or when multiple avatars with medium level attachments login/change outfit simultaneously. ; If 0 then no throttling is performed. ThrottlePer100PrimsRezzed = 0; -- cgit v1.1 From 598f63e984222a89ded65465674868df452cbeed Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 2 Aug 2013 00:06:39 +0100 Subject: Make atachment state load work again --- OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 7b12c81..e1ca6cd 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -363,7 +363,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // inventory right now. SceneObjectGroup objatt = RezSingleAttachmentFromInventoryInternal( - sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true, null); + sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true, d); if (ThrottlePer100PrimsRezzed > 0) -- cgit v1.1 From d4c506e453b1115142eac237d3a1c4f65fa36e26 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 2 Aug 2013 00:08:14 +0100 Subject: minor: replace veclist.Add(new Vector3(0,0,0)) with Vector3.Zero in InventoryAccessModules.RezObject() - structs are passed by value --- .../CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 1203192..68e4e26 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -771,7 +771,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); objlist.Add(g); - veclist.Add(new Vector3(0, 0, 0)); + veclist.Add(Vector3.Zero); float offsetHeight = 0; pos = m_Scene.GetNewRezLocation( -- cgit v1.1 From 07e4958b19b0b9dc9e1955b79e735230ccc6ea6f Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 1 Aug 2013 20:40:13 -0700 Subject: Turn off edit beams when object is derezed while being edited. (mantis #6722) --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 17da0d9..456c8cc 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1568,8 +1568,14 @@ namespace OpenSim.Region.Framework.Scenes // Here's where you get them. m_AgentControlFlags = flags; m_headrotation = agentData.HeadRotation; + byte oldState = State; State = agentData.State; + // We need to send this back to the client in order to stop the edit beams + if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None) + ControllingClient.SendAgentTerseUpdate(this); + + PhysicsActor actor = PhysicsActor; if (actor == null) { -- cgit v1.1 From 87ee0c395ed82f27c2a52b5023d8036eb7e355c9 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 2 Aug 2013 09:44:01 -0700 Subject: Fix problem with modInvoke defined integer constants being build into scripts as boxed integers rather than proper reference to a new LSLInteger. This fixes an exception when using a registered integer constant in a script. --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs | 4 ++-- OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 21bae27..92dd813 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -319,7 +319,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api object[] convertedParms = new object[parms.Length]; for (int i = 0; i < parms.Length; i++) - convertedParms[i] = ConvertFromLSL(parms[i],signature[i], fname); + convertedParms[i] = ConvertFromLSL(parms[i], signature[i], fname); // now call the function, the contract with the function is that it will always return // non-null but don't trust it completely @@ -444,7 +444,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - MODError(String.Format("{1}: parameter type mismatch; expecting {0}",type.Name, fname)); + MODError(String.Format("{0}: parameter type mismatch; expecting {1}, type(parm)={2}", fname, type.Name, lslparm.GetType())); return null; } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 9e32f40..6aa717d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -937,7 +937,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools { string retval = null; if (value is int) - retval = ((int)value).ToString(); + retval = String.Format("new LSL_Types.LSLInteger({0})",((int)value).ToString()); else if (value is float) retval = String.Format("new LSL_Types.LSLFloat({0})",((float)value).ToString()); else if (value is string) -- cgit v1.1 From 5bcccfc305ae4f5a74b9b816781a2a643daa23b3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 1 Aug 2013 12:35:22 -0700 Subject: BulletSim: add BSLinkInfo structure to remember link specific information for each link in a linkset. Extend BSLinksetConstraint to create and use BSLinkInfo with the default static constraint. --- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 51 +++-- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 4 +- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 205 ++++++++++++++------- 3 files changed, 174 insertions(+), 86 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 7f94666..9613fe0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -70,6 +70,15 @@ public abstract class BSLinkset return ret; } + public class BSLinkInfo + { + public BSPrimLinkable member; + public BSLinkInfo(BSPrimLinkable pMember) + { + member = pMember; + } + } + public BSPrimLinkable LinksetRoot { get; protected set; } protected BSScene m_physicsScene { get; private set; } @@ -78,7 +87,8 @@ public abstract class BSLinkset public int LinksetID { get; private set; } // The children under the root in this linkset. - protected HashSet m_children; + // protected HashSet m_children; + protected Dictionary m_children; // We lock the diddling of linkset classes to prevent any badness. // This locks the modification of the instances of this class. Changes @@ -109,7 +119,7 @@ public abstract class BSLinkset m_nextLinksetID = 1; m_physicsScene = scene; LinksetRoot = parent; - m_children = new HashSet(); + m_children = new Dictionary(); LinksetMass = parent.RawMass; Rebuilding = false; @@ -170,17 +180,7 @@ public abstract class BSLinkset bool ret = false; lock (m_linksetActivityLock) { - ret = m_children.Contains(child); - /* Safer version but the above should work - foreach (BSPrimLinkable bp in m_children) - { - if (child.LocalID == bp.LocalID) - { - ret = true; - break; - } - } - */ + ret = m_children.ContainsKey(child); } return ret; } @@ -194,7 +194,24 @@ public abstract class BSLinkset lock (m_linksetActivityLock) { action(LinksetRoot); - foreach (BSPrimLinkable po in m_children) + foreach (BSPrimLinkable po in m_children.Keys) + { + if (action(po)) + break; + } + } + return ret; + } + + // Perform an action on each member of the linkset including root prim. + // Depends on the action on whether this should be done at taint time. + public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); + public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) + { + bool ret = false; + lock (m_linksetActivityLock) + { + foreach (BSLinkInfo po in m_children.Values) { if (action(po)) break; @@ -364,7 +381,7 @@ public abstract class BSLinkset { lock (m_linksetActivityLock) { - foreach (BSPrimLinkable bp in m_children) + foreach (BSPrimLinkable bp in m_children.Keys) { mass += bp.RawMass; } @@ -382,7 +399,7 @@ public abstract class BSLinkset com = LinksetRoot.Position * LinksetRoot.RawMass; float totalMass = LinksetRoot.RawMass; - foreach (BSPrimLinkable bp in m_children) + foreach (BSPrimLinkable bp in m_children.Keys) { com += bp.Position * bp.RawMass; totalMass += bp.RawMass; @@ -401,7 +418,7 @@ public abstract class BSLinkset { com = LinksetRoot.Position; - foreach (BSPrimLinkable bp in m_children) + foreach (BSPrimLinkable bp in m_children.Keys) { com += bp.Position; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 6359046..53c3584 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -257,7 +257,7 @@ public sealed class BSLinksetCompound : BSLinkset { if (!HasChild(child)) { - m_children.Add(child); + m_children.Add(child, new BSLinkInfo(child)); DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); @@ -353,7 +353,7 @@ public sealed class BSLinksetCompound : BSLinkset // Add the shapes of all the components of the linkset int memberIndex = 1; - ForEachMember(delegate(BSPrimLinkable cPrim) + ForEachMember((cPrim) => { if (IsRoot(cPrim)) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index f17d698..d98bf77 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -36,6 +36,75 @@ public sealed class BSLinksetConstraints : BSLinkset { // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; + public class BSLinkInfoConstraint : BSLinkInfo + { + public ConstraintType constraintType; + public BSConstraint constraint; + public OMV.Vector3 linearLimitLow; + public OMV.Vector3 linearLimitHigh; + public OMV.Vector3 angularLimitLow; + public OMV.Vector3 angularLimitHigh; + public bool useFrameOffset; + public bool enableTransMotor; + public float transMotorMaxVel; + public float transMotorMaxForce; + public float cfm; + public float erp; + public float solverIterations; + + public BSLinkInfoConstraint(BSPrimLinkable pMember) + : base(pMember) + { + constraint = null; + ResetToFixedConstraint(); + } + + // Set all the parameters for this constraint to a fixed, non-movable constraint. + public void ResetToFixedConstraint() + { + constraintType = ConstraintType.D6_CONSTRAINT_TYPE; + linearLimitLow = OMV.Vector3.Zero; + linearLimitHigh = OMV.Vector3.Zero; + angularLimitLow = OMV.Vector3.Zero; + angularLimitHigh = OMV.Vector3.Zero; + useFrameOffset = BSParam.LinkConstraintUseFrameOffset; + enableTransMotor = BSParam.LinkConstraintEnableTransMotor; + transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; + transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; + cfm = BSParam.LinkConstraintCFM; + erp = BSParam.LinkConstraintERP; + solverIterations = BSParam.LinkConstraintSolverIterations; + } + + // Given a constraint, apply the current constraint parameters to same. + public void SetConstraintParameters(BSConstraint constrain) + { + switch (constraintType) + { + case ConstraintType.D6_CONSTRAINT_TYPE: + BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; + if (constrain6dof != null) + { + // zero linear and angular limits makes the objects unable to move in relation to each other + constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); + constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); + + // tweek the constraint to increase stability + constrain6dof.UseFrameOffset(useFrameOffset); + constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); + constrain6dof.SetCFMAndERP(cfm, erp); + if (solverIterations != 0f) + { + constrain6dof.SetSolverIterations(solverIterations); + } + } + break; + default: + break; + } + } + } + public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) { } @@ -142,7 +211,7 @@ public sealed class BSLinksetConstraints : BSLinkset { if (!HasChild(child)) { - m_children.Add(child); + m_children.Add(child, new BSLinkInfoConstraint(child)); DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); @@ -190,73 +259,74 @@ public sealed class BSLinksetConstraints : BSLinkset } // Create a static constraint between the two passed objects - private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) + private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) { + BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint; + if (liConstraint == null) + return null; + // Zero motion for children so they don't interpolate - childPrim.ZeroMotion(true); - - // Relative position normalized to the root prim - // Essentually a vector pointing from center of rootPrim to center of childPrim - OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; - - // real world coordinate of midpoint between the two objects - OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); - - DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.AddrString, - childPrim.LocalID, childPrim.PhysBody.AddrString, - rootPrim.Position, childPrim.Position, midPoint); - - // create a constraint that allows no freedom of movement between the two objects - // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 - - BSConstraint6Dof constrain = new BSConstraint6Dof( - m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); - // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); - - /* NOTE: below is an attempt to build constraint with full frame computation, etc. - * Using the midpoint is easier since it lets the Bullet code manipulate the transforms - * of the objects. - * Code left for future programmers. - // ================================================================================== - // relative position normalized to the root prim - OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); - OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; - - // relative rotation of the child to the parent - OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; - OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); - - DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); - BS6DofConstraint constrain = new BS6DofConstraint( - PhysicsScene.World, rootPrim.Body, childPrim.Body, - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(rootPrim.Orientation), - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(childPrim.Orientation), - true, - true - ); - // ================================================================================== - */ + li.member.ZeroMotion(true); - m_physicsScene.Constraints.AddConstraint(constrain); + BSConstraint constrain = null; - // zero linear and angular limits makes the objects unable to move in relation to each other - constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); - constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); - - // tweek the constraint to increase stability - constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset); - constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor, - BSParam.LinkConstraintTransMotorMaxVel, - BSParam.LinkConstraintTransMotorMaxForce); - constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); - if (BSParam.LinkConstraintSolverIterations != 0f) + switch (liConstraint.constraintType) { - constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); + case ConstraintType.D6_CONSTRAINT_TYPE: + // Relative position normalized to the root prim + // Essentually a vector pointing from center of rootPrim to center of li.member + OMV.Vector3 childRelativePosition = liConstraint.member.Position - rootPrim.Position; + + // real world coordinate of midpoint between the two objects + OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); + + DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", + rootPrim.LocalID, + rootPrim.LocalID, rootPrim.PhysBody.AddrString, + liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString, + rootPrim.Position, liConstraint.member.Position, midPoint); + + // create a constraint that allows no freedom of movement between the two objects + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 + + constrain = new BSConstraint6Dof( + m_physicsScene.World, rootPrim.PhysBody, liConstraint.member.PhysBody, midPoint, true, true ); + + /* NOTE: below is an attempt to build constraint with full frame computation, etc. + * Using the midpoint is easier since it lets the Bullet code manipulate the transforms + * of the objects. + * Code left for future programmers. + // ================================================================================== + // relative position normalized to the root prim + OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); + OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; + + // relative rotation of the child to the parent + OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; + OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); + + DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); + constrain = new BS6DofConstraint( + PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, + OMV.Vector3.Zero, + OMV.Quaternion.Inverse(rootPrim.Orientation), + OMV.Vector3.Zero, + OMV.Quaternion.Inverse(liConstraint.member.Orientation), + true, + true + ); + // ================================================================================== + */ + + break; + default: + break; } + + liConstraint.SetConstraintParameters(constrain); + + m_physicsScene.Constraints.AddConstraint(constrain); + return constrain; } @@ -317,23 +387,24 @@ public sealed class BSLinksetConstraints : BSLinkset return; // Note the 'finally' clause at the botton which will get executed. } - foreach (BSPrimLinkable child in m_children) + ForEachLinkInfo((li) => { // A child in the linkset physically shows the mass of the whole linkset. // This allows Bullet to apply enough force on the child to move the whole linkset. // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - child.UpdatePhysicalMassProperties(linksetMass, true); + li.member.UpdatePhysicalMassProperties(linksetMass, true); BSConstraint constrain; - if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) { // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, child); + constrain = BuildConstraint(LinksetRoot, li); } constrain.RecomputeConstraintVariables(linksetMass); // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG - } + return false; // 'false' says to keep processing other members + }); } finally { -- cgit v1.1 From 24df15dab7befd50f7a45eb54f001e6e481f0ec4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 1 Aug 2013 17:43:06 -0700 Subject: BulletSim: add implementation of 'physSetLinksetType' and 'physGetLinksetType' and processing routines in BulletSim. Add linkset rebuild/conversion routine in BSLinkset. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 65 ++++++++++++++++++++-- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 2 + .../Physics/BulletSPlugin/BSLinksetCompound.cs | 1 + .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 1 + OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 44 +++++++++++++++ .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 30 ++++++++++ OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 17 ++++++ OpenSim/Region/Physics/Manager/PhysicsActor.cs | 3 +- OpenSim/Region/Physics/Manager/PhysicsScene.cs | 3 +- 9 files changed, 159 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 0cbc5f9..d1d318c 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -49,10 +49,20 @@ public class ExtendedPhysics : INonSharedRegionModule private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static string LogHeader = "[EXTENDED PHYSICS]"; + // ============================================================= // Since BulletSim is a plugin, this these values aren't defined easily in one place. - // This table must coorespond to an identical table in BSScene. + // This table must correspond to an identical table in BSScene. + + // Per scene functions. See BSScene. + + // Per avatar functions. See BSCharacter. + + // Per prim functions. See BSPrim. + public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; + // ============================================================= + private IConfig Configuration { get; set; } private bool Enabled { get; set; } private Scene BaseScene { get; set; } @@ -123,6 +133,7 @@ public class ExtendedPhysics : INonSharedRegionModule // Register as LSL functions all the [ScriptInvocation] marked methods. Comms.RegisterScriptInvocations(this); + Comms.RegisterConstants(this); // When an object is modified, we might need to update its extended physics parameters BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene; @@ -136,7 +147,6 @@ public class ExtendedPhysics : INonSharedRegionModule private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) { - throw new NotImplementedException(); } // Event generated when some property of a prim changes. @@ -168,9 +178,11 @@ public class ExtendedPhysics : INonSharedRegionModule public static int PHYS_LINKSET_TYPE_MANUAL = 2; [ScriptInvocation] - public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) + public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) { - if (!Enabled) return; + int ret = -1; + + if (!Enabled) return ret; // The part that is requesting the change. SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); @@ -186,7 +198,7 @@ public class ExtendedPhysics : INonSharedRegionModule Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; if (rootPhysActor != null) { - rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); } else { @@ -204,6 +216,49 @@ public class ExtendedPhysics : INonSharedRegionModule { m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); } + return ret; + } + + [ScriptInvocation] + public int physGetLinksetType(UUID hostID, UUID scriptID) + { + int ret = -1; + + if (!Enabled) return ret; + + // The part that is requesting the change. + SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); + + if (requestingPart != null) + { + // The type is is always on the root of a linkset. + SceneObjectGroup containingGroup = requestingPart.ParentGroup; + SceneObjectPart rootPart = containingGroup.RootPart; + + if (rootPart != null) + { + Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) + { + ret = (int)rootPhysActor.Extension(PhysFunctGetLinksetType); + } + else + { + m_log.WarnFormat("{0} physGetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physGetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } + return ret; } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 9613fe0..3afd52e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -79,6 +79,8 @@ public abstract class BSLinkset } } + public LinksetImplementation LinksetImpl { get; protected set; } + public BSPrimLinkable LinksetRoot { get; protected set; } protected BSScene m_physicsScene { get; private set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 53c3584..085d195 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -42,6 +42,7 @@ public sealed class BSLinksetCompound : BSLinkset public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) : base(scene, parent) { + LinksetImpl = LinksetImplementation.Compound; } // ================================================================ diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index d98bf77..4bac222 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -107,6 +107,7 @@ public sealed class BSLinksetConstraints : BSLinkset public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) { + LinksetImpl = LinksetImplementation.Constraint; } // When physical properties are changed the linkset needs to recalculate diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e92a1d2..a0b6abc 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -1541,6 +1541,50 @@ public class BSPrim : BSPhysObject PhysicalActors.RemoveDependencies(); } + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + object ret = null; + switch (pFunct) + { + case BSScene.PhysFunctGetLinksetType: + { + BSPrimLinkable myHandle = this as BSPrimLinkable; + if (myHandle != null) + { + ret = (object)myHandle.LinksetType; + } + m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); + break; + } + case BSScene.PhysFunctSetLinksetType: + { + if (pParams.Length > 0) + { + BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0]; + BSPrimLinkable myHandle = this as BSPrimLinkable; + if (myHandle != null && myHandle.Linkset.IsRoot(myHandle)) + { + PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate() + { + // Cause the linkset type to change + m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}", + LogHeader, myHandle.Linkset.LinksetImpl, linksetType); + myHandle.ConvertLinkset(linksetType); + }); + } + ret = (object)(int)linksetType; + } + break; + } + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + #endregion // Extension + // The physics engine says that properties have updated. Update same and inform // the world that things have changed. // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 2f392da..c565998 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -233,5 +233,35 @@ public class BSPrimLinkable : BSPrimDisplaced base.HasSomeCollision = value; } } + + // Convert the existing linkset of this prim into a new type. + public bool ConvertLinkset(BSLinkset.LinksetImplementation newType) + { + bool ret = false; + if (LinksetType != newType) + { + BSLinkset oldLinkset = Linkset; + BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); + + // Pick up any physical dependencies this linkset might have in the physics engine. + oldLinkset.RemoveDependencies(this); + + // Copy the linkset children from the old linkset to the new (will be a new instance from the factory) + oldLinkset.ForEachLinkInfo((li) => + { + oldLinkset.RemoveMeFromLinkset(li.member); + newLinkset.AddMeToLinkset(li.member); + li.member.Linkset = newLinkset; + return false; + }); + + this.Linkset = newLinkset; + + // Force the shape and linkset to get reconstructed + newLinkset.Refresh(this); + this.ForceBodyShapeRebuild(true); + } + return ret; + } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 41aca3b..79ac5a5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -862,6 +862,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public override bool IsThreaded { get { return false; } } + #region Extensions + // ============================================================= + // Per scene functions. See below. + + // Per avatar functions. See BSCharacter. + + // Per prim functions. See BSPrim. + public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; + public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; + // ============================================================= + + public override object Extension(string pFunct, params object[] pParams) + { + return base.Extension(pFunct, pParams); + } + #endregion // Extensions + #region Taints // The simulation execution order is: // Simulate() diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs index 2500f27..1750853 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs @@ -317,7 +317,8 @@ namespace OpenSim.Region.Physics.Manager // Extendable interface for new, physics engine specific operations public virtual object Extension(string pFunct, params object[] pParams) { - throw new NotImplementedException(); + // A NOP of the physics engine does not implement this feature + return null; } } diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 07a1d36..c93206d 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -338,7 +338,8 @@ namespace OpenSim.Region.Physics.Manager // Extendable interface for new, physics engine specific operations public virtual object Extension(string pFunct, params object[] pParams) { - throw new NotImplementedException(); + // A NOP if the extension thing is not implemented by the physics engine + return null; } } } -- cgit v1.1 From 5bdfd55ace4b673d8aaa3f25fd4bb675b1b28263 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 2 Aug 2013 10:32:43 -0700 Subject: BulletSim: When converting linkset types, don't try to change the list of linkset children while iterating through the list. --- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index c565998..7179a6d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -240,26 +240,37 @@ public class BSPrimLinkable : BSPrimDisplaced bool ret = false; if (LinksetType != newType) { - BSLinkset oldLinkset = Linkset; + // Set the implementation type first so the call to BSLinkset.Factory gets the new type. + this.LinksetType = newType; + + BSLinkset oldLinkset = this.Linkset; BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); + this.Linkset = newLinkset; + // Pick up any physical dependencies this linkset might have in the physics engine. oldLinkset.RemoveDependencies(this); - // Copy the linkset children from the old linkset to the new (will be a new instance from the factory) - oldLinkset.ForEachLinkInfo((li) => + // Create a list of the children (mainly because can't interate through a list that's changing) + List children = new List(); + oldLinkset.ForEachMember((child) => { - oldLinkset.RemoveMeFromLinkset(li.member); - newLinkset.AddMeToLinkset(li.member); - li.member.Linkset = newLinkset; - return false; + if (!oldLinkset.IsRoot(child)) + children.Add(child); + return false; // 'false' says to continue to next member }); - this.Linkset = newLinkset; + // Remove the children from the old linkset and add to the new (will be a new instance from the factory) + foreach (BSPrimLinkable child in children) + { + oldLinkset.RemoveMeFromLinkset(child); + newLinkset.AddMeToLinkset(child); + child.Linkset = newLinkset; + } // Force the shape and linkset to get reconstructed newLinkset.Refresh(this); - this.ForceBodyShapeRebuild(true); + this.ForceBodyShapeRebuild(true /* inTaintTime */); } return ret; } -- cgit v1.1 From 54b1071556edf264835f990bb3595064d2b2e2f0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 2 Aug 2013 23:12:54 +0100 Subject: Allow older teleport ConnectorProtocolVersion of "SIMULATION/0.1" to be manually forced in a new [SimulationService] config setting. This is for testing and debugging purposes to help determine whether a particular issue may be teleport related or not "SIMULATION/0.2" (the newer teleport protocol) remains the default. If the source simulator only implements "SIMULATION/0.1" this will correctly allow fallback to the older protocol. Specifying "SIMULATION/0.1" will force the older, less efficient protocol to always be used. --- .../Simulation/LocalSimulationConnector.cs | 33 +++++++++++++--------- .../Simulation/RemoteSimulationConnector.cs | 21 ++++++-------- bin/config-include/Grid.ini | 11 ++++++++ bin/config-include/Standalone.ini | 11 ++++++++ 4 files changed, 49 insertions(+), 27 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 697ce68..7aadb87 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -63,35 +63,40 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation /// private bool m_ModuleEnabled = false; - public LocalSimulationConnectorModule() - { - ServiceVersion = "SIMULATION/0.2"; - } - #region Region Module interface - public void Initialise(IConfigSource config) + public void Initialise(IConfigSource configSource) { - IConfig moduleConfig = config.Configs["Modules"]; + IConfig moduleConfig = configSource.Configs["Modules"]; if (moduleConfig != null) { string name = moduleConfig.GetString("SimulationServices", ""); if (name == Name) { - //IConfig userConfig = config.Configs["SimulationService"]; - //if (userConfig == null) - //{ - // m_log.Error("[AVATAR CONNECTOR]: SimulationService missing from OpenSim.ini"); - // return; - //} + InitialiseService(configSource); m_ModuleEnabled = true; - m_log.Info("[SIMULATION CONNECTOR]: Local simulation enabled"); + m_log.Info("[LOCAL SIMULATION CONNECTOR]: Local simulation enabled."); } } } + public void InitialiseService(IConfigSource configSource) + { + IConfig config = configSource.Configs["SimulationService"]; + if (config != null) + { + ServiceVersion = config.GetString("ConnectorProtocolVersion", "SIMULATION/0.2"); + + if (ServiceVersion != "SIMULATION/0.1" && ServiceVersion != "SIMULATION/0.2") + throw new Exception(string.Format("Invalid ConnectorProtocolVersion {0}", ServiceVersion)); + + m_log.InfoFormat( + "[LOCAL SIMULATION CONNECTOR]: Initialzied with connector protocol version {0}", ServiceVersion); + } + } + public void PostInitialise() { } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index 8722b80..f45f560 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -50,9 +50,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteSimulationConnectorModule")] public class RemoteSimulationConnectorModule : ISharedRegionModule, ISimulationService { - private bool initialized = false; private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private bool initialized = false; protected bool m_enabled = false; protected Scene m_aScene; // RemoteSimulationConnector does not care about local regions; it delegates that to the Local module @@ -64,27 +64,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation #region Region Module interface - public virtual void Initialise(IConfigSource config) + public virtual void Initialise(IConfigSource configSource) { - - IConfig moduleConfig = config.Configs["Modules"]; + IConfig moduleConfig = configSource.Configs["Modules"]; if (moduleConfig != null) { string name = moduleConfig.GetString("SimulationServices", ""); if (name == Name) { - //IConfig userConfig = config.Configs["SimulationService"]; - //if (userConfig == null) - //{ - // m_log.Error("[AVATAR CONNECTOR]: SimulationService missing from OpenSim.ini"); - // return; - //} + m_localBackend = new LocalSimulationConnectorModule(); + + m_localBackend.InitialiseService(configSource); m_remoteConnector = new SimulationServiceConnector(); m_enabled = true; - m_log.Info("[SIMULATION CONNECTOR]: Remote simulation enabled"); + m_log.Info("[REMOTE SIMULATION CONNECTOR]: Remote simulation enabled."); } } } @@ -142,8 +138,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation } protected virtual void InitOnce(Scene scene) - { - m_localBackend = new LocalSimulationConnectorModule(); + { m_aScene = scene; //m_regionClient = new RegionToRegionClient(m_aScene, m_hyperlinkService); m_thisIP = Util.GetHostFromDNS(scene.RegionInfo.ExternalHostName); diff --git a/bin/config-include/Grid.ini b/bin/config-include/Grid.ini index 15ba55a..1837bdd 100644 --- a/bin/config-include/Grid.ini +++ b/bin/config-include/Grid.ini @@ -30,6 +30,17 @@ SimulationServiceInConnector = true LibraryModule = true +[SimulationService] + ; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport + ; It is used to control the teleport handoff process. + ; Valid values are + ; "SIMULATION/0.2" + ; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol + ; - this protocol is more efficient than "SIMULATION/0.1" + ; "SIMULATION/0.1" + ; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. + ConnectorProtocolVersion = "SIMULATION/0.2" + [SimulationDataStore] LocalServiceModule = "OpenSim.Services.Connectors.dll:SimulationDataService" diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index d3b9cb4..7b7beb2 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -26,6 +26,17 @@ GridInfoServiceInConnector = true MapImageServiceInConnector = true +[SimulationService] + ; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport + ; It is used to control the teleport handoff process. + ; Valid values are + ; "SIMULATION/0.2" + ; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol + ; - this protocol is more efficient than "SIMULATION/0.1" + ; "SIMULATION/0.1" + ; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. + ConnectorProtocolVersion = "SIMULATION/0.2" + [SimulationDataStore] LocalServiceModule = "OpenSim.Services.Connectors.dll:SimulationDataService" -- cgit v1.1 From 5198df3aa03eb47bc26b3c86924687612c015dce Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 2 Aug 2013 17:00:18 -0700 Subject: Issue: 10 simultaneous TPs, many not making it. Now bypassing the per-url lock -- we should be "ok" (or, more "ok") now that we have increased the connection limit on the http library. But this is a sensitive part of the code, so it may need reverting. --- OpenSim/Framework/WebUtil.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 6fb1e0c..0e9de59 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -145,10 +145,10 @@ namespace OpenSim.Framework public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) { - lock (EndPointLock(url)) - { + //lock (EndPointLock(url)) + //{ return ServiceOSDRequestWorker(url,data,method,timeout,compressed); - } + //} } public static void LogOutgoingDetail(Stream outputStream) -- cgit v1.1 From 847c01f406359289097a6ad8d681002a4beff086 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 2 Aug 2013 17:38:08 -0700 Subject: Amend Justin's last commit regarding the new config var ServiceVersion. The section may not exist at all. --- .../ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 7aadb87..e86d186 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -84,10 +84,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation public void InitialiseService(IConfigSource configSource) { + ServiceVersion = "SIMULATION/0.2"; IConfig config = configSource.Configs["SimulationService"]; if (config != null) { - ServiceVersion = config.GetString("ConnectorProtocolVersion", "SIMULATION/0.2"); + ServiceVersion = config.GetString("ConnectorProtocolVersion", ServiceVersion); if (ServiceVersion != "SIMULATION/0.1" && ServiceVersion != "SIMULATION/0.2") throw new Exception(string.Format("Invalid ConnectorProtocolVersion {0}", ServiceVersion)); -- cgit v1.1 From b857353fc932bdf775abce2a3d34140cafe916ce Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 3 Aug 2013 15:42:25 -0700 Subject: Making the J2KDecoderModule decoder function async. Could this be the cause of sim freeze? -- HandleRequestImage in LLClientView is now sync, which means that it cannot take too long to complete. However, its execution path may end up in J2KDecoderModule.Decode, which is heavy and could stop the packet processing thread while it's at it. --- OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs index 3764685..d9b0eff 100644 --- a/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs +++ b/OpenSim/Region/CoreModules/Agent/TextureSender/J2KDecoderModule.cs @@ -166,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender // Do Decode! if (decode) - Decode(assetID, j2kData); + Util.FireAndForget(delegate { Decode(assetID, j2kData); }); } } -- cgit v1.1 From dcfeb95e98ca7b002170a5916f556f54f300678c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 3 Aug 2013 20:13:44 -0700 Subject: HG: If OutboundPermission is set to false, let's enforce stricter permissions by not allowing objects to be taken to inventory. --- .../InventoryAccess/HGInventoryAccessModule.cs | 31 ++++++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 3 +++ 2 files changed, 34 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 8f9800f..978c288 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -62,6 +62,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess private string m_ThisGatekeeper; private bool m_RestrictInventoryAccessAbroad; + private bool m_bypassPermissions = true; + // private bool m_Initialized = false; #region INonSharedRegionModule @@ -100,6 +102,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); + + m_bypassPermissions = !Util.GetConfigVarFromSections(source, "serverside_object_permissions", + new string[] { "Startup", "Permissions" }, true); + } } } @@ -114,6 +120,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; scene.EventManager.OnTeleportStart += TeleportStart; scene.EventManager.OnTeleportFail += TeleportFail; + + // We're fgoing to enforce some stricter permissions if Outbound is false + scene.Permissions.OnTakeObject += CanTakeObject; + scene.Permissions.OnTakeCopyObject += CanTakeObject; + } #endregion @@ -417,5 +428,25 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } #endregion + + #region Permissions + + private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) + { + if (m_bypassPermissions) return true; + + if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer)) + { + SceneObjectGroup sog = null; + if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer) + return true; + + return false; + } + + return true; + } + + #endregion } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 58fa18c..2d1a3ef 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2068,7 +2068,10 @@ namespace OpenSim.Region.Framework.Scenes { // If we don't have permission, stop right here if (!permissionToTakeCopy) + { + remoteClient.SendAlertMessage("You don't have permission to take the object"); return; + } permissionToTake = true; // Don't delete -- cgit v1.1 From 09cb2a37dd73296290c306f38412c1743b9eb820 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 3 Aug 2013 20:36:30 -0700 Subject: More on HG inventory and OutboundPermission: disallowing giving inventory to foreigners if OutboundPermission is false --- .../Framework/InventoryAccess/HGInventoryAccessModule.cs | 13 ++++++++++++- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 978c288..ce7ed26 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -124,7 +124,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // We're fgoing to enforce some stricter permissions if Outbound is false scene.Permissions.OnTakeObject += CanTakeObject; scene.Permissions.OnTakeCopyObject += CanTakeObject; - + scene.Permissions.OnTransferUserInventory += OnTransferUserInventory; } #endregion @@ -447,6 +447,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return true; } + private bool OnTransferUserInventory(UUID itemID, UUID userID, UUID recipientID) + { + if (m_bypassPermissions) return true; + + if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(recipientID)) + return false; + + return true; + } + + #endregion } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 2d1a3ef..8e4e307 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -556,6 +556,9 @@ namespace OpenSim.Region.Framework.Scenes { //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem"); + if (!Permissions.CanTransferUserInventory(itemId, senderId, recipient)) + return null; + InventoryItemBase item = new InventoryItemBase(itemId, senderId); item = InventoryService.GetItem(item); -- cgit v1.1 From 5b4b349776613d9054e85727f8f6a1f079a5225a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 3 Aug 2013 21:27:32 -0700 Subject: Fix the failing TestSendImage. J2K decoding is async. --- .../Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 83144e3..6aa8bcc 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs @@ -29,6 +29,7 @@ using System; using System.IO; using System.Net; using System.Reflection; +using System.Threading; using log4net.Config; using Nini.Config; using NUnit.Framework; @@ -105,7 +106,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests args.requestSequence = 1; llim.EnqueueReq(args); - llim.ProcessImageQueue(20); + + // We now have to wait and hit the processing wheel, because the decoding is async + int i = 10; + while (i-- > 0) + { + llim.ProcessImageQueue(20); + Thread.Sleep(100); + } Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(1)); } -- cgit v1.1 From 05012bb0df9b109f792b83e82779d3f69fb37ecb Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 5 Aug 2013 08:09:30 -0700 Subject: Group notices bug fix: use a new IM for each member of the group, otherwise the fields get messed up because the transfer is async --- OpenSim/Addons/Groups/GroupsModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index da8030c..830c671 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -467,12 +467,12 @@ namespace OpenSim.Groups } // Send notice out to everyone that wants notices - // Build notice IIM - GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID)) { if (member.AcceptNotices) { + // Build notice IIM, one of reach, because the sending may be async + GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); msg.toAgentID = member.AgentID.Guid; OutgoingInstantMessage(msg, member.AgentID); } -- cgit v1.1 From 76bd3de2fd243d0c910404af8a9998de746b04c4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 19:22:47 +0100 Subject: Add checks monitoring framework to provide alerts if certain conditions do not hold. Not yet in use. --- OpenSim/Framework/Monitoring/Checks/Check.cs | 118 ++++++++++++ OpenSim/Framework/Monitoring/ChecksManager.cs | 262 ++++++++++++++++++++++++++ OpenSim/Framework/Monitoring/StatsManager.cs | 6 +- OpenSim/Framework/Monitoring/Watchdog.cs | 1 + OpenSim/Framework/Servers/ServerBase.cs | 1 + 5 files changed, 385 insertions(+), 3 deletions(-) create mode 100644 OpenSim/Framework/Monitoring/Checks/Check.cs create mode 100644 OpenSim/Framework/Monitoring/ChecksManager.cs diff --git a/OpenSim/Framework/Monitoring/Checks/Check.cs b/OpenSim/Framework/Monitoring/Checks/Check.cs new file mode 100644 index 0000000..594386a --- /dev/null +++ b/OpenSim/Framework/Monitoring/Checks/Check.cs @@ -0,0 +1,118 @@ +/* + * 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.Text; + +namespace OpenSim.Framework.Monitoring +{ + public class Check + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static readonly char[] DisallowedShortNameCharacters = { '.' }; + + /// + /// Category of this stat (e.g. cache, scene, etc). + /// + public string Category { get; private set; } + + /// + /// Containing name for this stat. + /// FIXME: In the case of a scene, this is currently the scene name (though this leaves + /// us with a to-be-resolved problem of non-unique region names). + /// + /// + /// The container. + /// + public string Container { get; private set; } + + /// + /// Action used to check whether alert should go off. + /// + /// + /// Should return true if check passes. False otherwise. + /// + public Func CheckFunc { get; private set; } + + /// + /// Message from the last failure, if any. If there is no message or no failure then will be null. + /// + /// + /// Should be set by the CheckFunc when applicable. + /// + public string LastFailureMessage { get; set; } + + public StatVerbosity Verbosity { get; private set; } + public string ShortName { get; private set; } + public string Name { get; private set; } + public string Description { get; private set; } + + public Check( + string shortName, + string name, + string description, + string category, + string container, + Func checkFunc, + StatVerbosity verbosity) + { + if (ChecksManager.SubCommands.Contains(category)) + throw new Exception( + string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category)); + + foreach (char c in DisallowedShortNameCharacters) + { + if (shortName.IndexOf(c) != -1) + throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c)); + } + + ShortName = shortName; + Name = name; + Description = description; + Category = category; + Container = container; + CheckFunc = checkFunc; + Verbosity = verbosity; + } + + public bool CheckIt() + { + return CheckFunc(this); + } + + public virtual string ToConsoleString() + { + return string.Format( + "{0}.{1}.{2} - {3}", + Category, + Container, + ShortName, + Description); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/ChecksManager.cs b/OpenSim/Framework/Monitoring/ChecksManager.cs new file mode 100644 index 0000000..e4a7f8c --- /dev/null +++ b/OpenSim/Framework/Monitoring/ChecksManager.cs @@ -0,0 +1,262 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using log4net; + +namespace OpenSim.Framework.Monitoring +{ + /// + /// Static class used to register/deregister checks on runtime conditions. + /// + public static class ChecksManager + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // Subcommand used to list other stats. + public const string ListSubCommand = "list"; + + // All subcommands + public static HashSet SubCommands = new HashSet { ListSubCommand }; + + /// + /// Checks categorized by category/container/shortname + /// + /// + /// Do not add or remove directly from this dictionary. + /// + public static SortedDictionary>> RegisteredChecks + = new SortedDictionary>>(); + + public static void RegisterConsoleCommands(ICommandConsole console) + { + console.Commands.AddCommand( + "General", + false, + "show checks", + "show checks", + "Show checks configured for this server", + "If no argument is specified then info on all checks will be shown.\n" + + "'list' argument will show check categories.\n" + + "THIS FACILITY IS EXPERIMENTAL", + HandleShowchecksCommand); + } + + public static void HandleShowchecksCommand(string module, string[] cmd) + { + ICommandConsole con = MainConsole.Instance; + + if (cmd.Length > 2) + { + foreach (string name in cmd.Skip(2)) + { + string[] components = name.Split('.'); + + string categoryName = components[0]; +// string containerName = components.Length > 1 ? components[1] : null; + + if (categoryName == ListSubCommand) + { + con.Output("check categories available are:"); + + foreach (string category in RegisteredChecks.Keys) + con.OutputFormat(" {0}", category); + } +// else +// { +// SortedDictionary> category; +// if (!Registeredchecks.TryGetValue(categoryName, out category)) +// { +// con.OutputFormat("No such category as {0}", categoryName); +// } +// else +// { +// if (String.IsNullOrEmpty(containerName)) +// { +// OutputConfiguredToConsole(con, category); +// } +// else +// { +// SortedDictionary container; +// if (category.TryGetValue(containerName, out container)) +// { +// OutputContainerChecksToConsole(con, container); +// } +// else +// { +// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); +// } +// } +// } +// } + } + } + else + { + OutputAllChecksToConsole(con); + } + } + + /// + /// Registers a statistic. + /// + /// + /// + public static bool RegisterCheck(Check check) + { + SortedDictionary> category = null, newCategory; + SortedDictionary container = null, newContainer; + + lock (RegisteredChecks) + { + // Check name is not unique across category/container/shortname key. + // XXX: For now just return false. This is to avoid problems in regression tests where all tests + // in a class are run in the same instance of the VM. + if (TryGetCheckParents(check, out category, out container)) + return false; + + // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. + // This means that we don't need to lock or copy them on iteration, which will be a much more + // common operation after startup. + if (container != null) + newContainer = new SortedDictionary(container); + else + newContainer = new SortedDictionary(); + + if (category != null) + newCategory = new SortedDictionary>(category); + else + newCategory = new SortedDictionary>(); + + newContainer[check.ShortName] = check; + newCategory[check.Container] = newContainer; + RegisteredChecks[check.Category] = newCategory; + } + + return true; + } + + /// + /// Deregister an check + /// > + /// + /// + public static bool DeregisterCheck(Check check) + { + SortedDictionary> category = null, newCategory; + SortedDictionary container = null, newContainer; + + lock (RegisteredChecks) + { + if (!TryGetCheckParents(check, out category, out container)) + return false; + + newContainer = new SortedDictionary(container); + newContainer.Remove(check.ShortName); + + newCategory = new SortedDictionary>(category); + newCategory.Remove(check.Container); + + newCategory[check.Container] = newContainer; + RegisteredChecks[check.Category] = newCategory; + + return true; + } + } + + public static bool TryGetCheckParents( + Check check, + out SortedDictionary> category, + out SortedDictionary container) + { + category = null; + container = null; + + lock (RegisteredChecks) + { + if (RegisteredChecks.TryGetValue(check.Category, out category)) + { + if (category.TryGetValue(check.Container, out container)) + { + if (container.ContainsKey(check.ShortName)) + return true; + } + } + } + + return false; + } + + public static void CheckChecks() + { + lock (RegisteredChecks) + { + foreach (SortedDictionary> category in RegisteredChecks.Values) + { + foreach (SortedDictionary container in category.Values) + { + foreach (Check check in container.Values) + { + if (!check.CheckIt()) + m_log.WarnFormat( + "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage); + } + } + } + } + } + + private static void OutputAllChecksToConsole(ICommandConsole con) + { + foreach (var category in RegisteredChecks.Values) + { + OutputCategoryChecksToConsole(con, category); + } + } + + private static void OutputCategoryChecksToConsole( + ICommandConsole con, SortedDictionary> category) + { + foreach (var container in category.Values) + { + OutputContainerChecksToConsole(con, container); + } + } + + private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary container) + { + foreach (Check check in container.Values) + { + con.Output(check.ToConsoleString()); + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index e6a2304..87197f4 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -35,9 +35,9 @@ using OpenMetaverse.StructuredData; namespace OpenSim.Framework.Monitoring { /// - /// Singleton used to provide access to statistics reporters + /// Static class used to register/deregister/fetch statistics /// - public class StatsManager + public static class StatsManager { // Subcommand used to list other stats. public const string AllSubCommand = "all"; @@ -257,7 +257,7 @@ namespace OpenSim.Framework.Monitoring // } /// - /// Registers a statistic. + /// Register a statistic. /// /// /// diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs index 3f992b1..45762a6 100644 --- a/OpenSim/Framework/Monitoring/Watchdog.cs +++ b/OpenSim/Framework/Monitoring/Watchdog.cs @@ -380,6 +380,7 @@ namespace OpenSim.Framework.Monitoring if (MemoryWatchdog.Enabled) MemoryWatchdog.Update(); + ChecksManager.CheckChecks(); StatsManager.RecordStats(); m_watchdogTimer.Start(); diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 029b848..a8e0f81 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -272,6 +272,7 @@ namespace OpenSim.Framework.Servers "shutdown", "Quit the application", (mod, args) => Shutdown()); + ChecksManager.RegisterConsoleCommands(m_console); StatsManager.RegisterConsoleCommands(m_console); } -- cgit v1.1 From 03698121ed1e605a126f9bba37088f145a0ef2fb Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 5 Aug 2013 12:34:53 -0700 Subject: Remove some debugging from simian connectors. --- .../Services/Connectors/SimianGrid/SimianExternalCapsModule.cs | 6 +++++- OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs index 8226705..e85b0b7 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs @@ -79,7 +79,11 @@ namespace OpenSim.Services.Connectors.SimianGrid { m_simianURL = m_config.GetString("SimianServiceURL"); if (String.IsNullOrEmpty(m_simianURL)) - m_log.ErrorFormat("[SimianGrid] service URL is not defined"); + { + //m_log.DebugFormat("[SimianGrid] service URL is not defined"); + m_enabled = false; + return; + } } } else diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs index a4dd36c..e7d2f86 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs @@ -74,11 +74,15 @@ namespace OpenSim.Services.Connectors.SimianGrid { m_simianURL = m_config.GetString("SimianServiceURL"); if (String.IsNullOrEmpty(m_simianURL)) - m_log.ErrorFormat("[SimianGrid] service URL is not defined"); + { + // m_log.DebugFormat("[SimianGrid] service URL is not defined"); + m_enabled = false; + return; + } InitialiseSimCap(); SimulatorCapability = SimulatorCapability.Trim(); - m_log.WarnFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability); + m_log.InfoFormat("[SimianExternalCaps] using {0} as simulator capability",SimulatorCapability); } } catch (Exception e) -- cgit v1.1 From 7f0d9ad64473ad0defb8d534a8ddadc6d471e4a5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 20:36:46 +0100 Subject: Make test AssetsClient print out more information about any failure to set thread numbers and immediate post config thread numbers --- OpenSim/Tests/Clients/Assets/AssetsClient.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tests/Clients/Assets/AssetsClient.cs b/OpenSim/Tests/Clients/Assets/AssetsClient.cs index 26d740b..e988d0e 100644 --- a/OpenSim/Tests/Clients/Assets/AssetsClient.cs +++ b/OpenSim/Tests/Clients/Assets/AssetsClient.cs @@ -68,8 +68,18 @@ namespace OpenSim.Tests.Clients.AssetsClient m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} max threads = {1} - {2}", serverURI, max1, max2); ThreadPool.GetMinThreads(out max1, out max2); m_log.InfoFormat("[ASSET CLIENT]: Connecting to {0} min threads = {1} - {2}", serverURI, max1, max2); - ThreadPool.SetMinThreads(1, 1); - ThreadPool.SetMaxThreads(10, 3); + + if (!ThreadPool.SetMinThreads(1, 1)) + m_log.WarnFormat("[ASSET CLIENT]: Failed to set min threads"); + + if (!ThreadPool.SetMaxThreads(10, 3)) + m_log.WarnFormat("[ASSET CLIENT]: Failed to set max threads"); + + ThreadPool.GetMaxThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Post set max threads = {1} - {2}", serverURI, max1, max2); + ThreadPool.GetMinThreads(out max1, out max2); + m_log.InfoFormat("[ASSET CLIENT]: Post set min threads = {1} - {2}", serverURI, max1, max2); + ServicePointManager.DefaultConnectionLimit = 12; AssetServicesConnector m_Connector = new AssetServicesConnector(serverURI); -- cgit v1.1 From b8612e005a2f85da2bde2d555f910934cccb218a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 20:47:47 +0100 Subject: At OpenSimulator startup, print out default min built-in threadpool threads as well as max. Make it clear that we only try to adjust max, and log at warn level if this fails. Other minor logging cleanup. --- OpenSim/Region/Application/Application.cs | 41 ++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index e451aa8..2e155ec 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -103,26 +103,38 @@ 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 - // Max IO Completion threads are 1000 on all 3 CLRs. + // .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 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", + currentMinWorkerThreads, currentMinIocpThreads); + } + int workerThreads, iocpThreads; System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); - m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} worker threads and {1} IOCP threads", workerThreads, iocpThreads); + m_log.InfoFormat("[OPENSIM MAIN]: Runtime gave us {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads); + if (workerThreads < workerThreadsMin) { workerThreads = workerThreadsMin; - m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to worker threads to {0}",workerThreads); + m_log.InfoFormat("[OPENSIM MAIN]: Bumping up to max worker threads to {0}",workerThreads); } if (workerThreads > workerThreadsMax) { workerThreads = workerThreadsMax; - m_log.InfoFormat("[OPENSIM MAIN]: Limiting worker threads to {0}",workerThreads); + m_log.InfoFormat("[OPENSIM MAIN]: Limiting max worker threads to {0}",workerThreads); } // Increase the number of IOCP threads available. @@ -130,22 +142,24 @@ namespace OpenSim if (iocpThreads < iocpThreadsMin) { iocpThreads = iocpThreadsMin; - m_log.InfoFormat("[OPENSIM MAIN]: Bumping up IO completion threads to {0}",iocpThreads); + m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IO completion threads to {0}",iocpThreads); } // Make sure we don't overallocate IOCP threads and thrash system resources if ( iocpThreads > iocpThreadsMax ) { iocpThreads = iocpThreadsMax; - m_log.InfoFormat("[OPENSIM MAIN]: Limiting IO completion threads to {0}",iocpThreads); + m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IO completion threads to {0}",iocpThreads); } // set the resulting worker and IO completion thread counts back to ThreadPool if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) { - m_log.InfoFormat("[OPENSIM MAIN]: Threadpool set to {0} worker threads and {1} IO completion threads", workerThreads, iocpThreads); + m_log.InfoFormat( + "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IO completion threads", + workerThreads, iocpThreads); } else { - m_log.Info("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect."); + m_log.Warn("[OPENSIM MAIN]: Threadpool reconfiguration failed, runtime defaults still in effect."); } // Check if the system is compatible with OpenSimulator. @@ -153,17 +167,16 @@ namespace OpenSim string supported = String.Empty; if (Util.IsEnvironmentSupported(ref supported)) { - m_log.Info("Environment is compatible.\n"); + m_log.Info("[OPENSIM MAIN]: Environment is supported by OpenSimulator."); } else { - m_log.Warn("Environment is unsupported (" + supported + ")\n"); + m_log.Warn("[OPENSIM MAIN]: Environment is not supported by OpenSimulator (" + supported + ")\n"); } // Configure nIni aliases and localles 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 // reading these files. -- cgit v1.1 From 24dcf3cf6a95596ce0ac188a63bb5c2c4c47dcee Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 20:51:40 +0100 Subject: Comment out debug log lines about script modules comms for now. If this is an issue, could change log4net config instead to allow re-enablement --- .../Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index 6bf50d2..a515346 100644 --- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs @@ -163,7 +163,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms public void RegisterScriptInvocation(object target, MethodInfo mi) { - m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); +// m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); Type delegateType; List typeArgs = mi.GetParameters() @@ -323,7 +323,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms /// public void RegisterConstant(string cname, object value) { - m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString()); +// m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString()); lock (m_constants) { m_constants.Add(cname,value); -- cgit v1.1 From 946b37096698c818104405cb511579e810a62973 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 5 Aug 2013 14:21:17 -0700 Subject: Child agent updates: remove the dependency on the root agent's camera position. That was a complete overkill that is unnecessary at this point. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 456c8cc..0ba2dab 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2989,8 +2989,7 @@ namespace OpenSim.Region.Framework.Scenes } // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m - if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance || - Util.GetDistanceTo(CameraPosition, m_lastChildAgentUpdateCamPosition) >= Scene.ChildReprioritizationDistance) + if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance) { m_lastChildAgentUpdatePosition = AbsolutePosition; m_lastChildAgentUpdateCamPosition = CameraPosition; -- cgit v1.1 From 160659f68382187d7e949ca11c2942907671fe86 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 23:04:36 +0100 Subject: Make it possible to set worker/iocp min/max threadpool limits on the fly with the console command "debug threadpool set" --- OpenSim/Framework/Servers/ServerBase.cs | 78 +++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index a8e0f81..55b6c58 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -256,6 +256,12 @@ namespace OpenSim.Framework.Servers "Show thread status. Synonym for \"show threads\"", (string module, string[] args) => Notice(GetThreadsReport())); + m_console.Commands.AddCommand ( + "Debug", false, "debug threadpool set", + "debug threadpool set worker|iocp min|max ", + "Set threadpool parameters. For debug purposes.", + HandleDebugThreadpoolSet); + m_console.Commands.AddCommand( "General", false, "force gc", "force gc", @@ -283,6 +289,78 @@ namespace OpenSim.Framework.Servers m_serverStatsCollector.Start(); } + private void HandleDebugThreadpoolSet(string module, string[] args) + { + if (args.Length != 6) + { + Notice("Usage: debug threadpool set worker|iocp min|max "); + return; + } + + int newThreads; + + if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads)) + return; + + string poolType = args[3]; + string bound = args[4]; + + bool fail = false; + int workerThreads, iocpThreads; + + if (poolType == "worker") + { + if (bound == "min") + { + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMinThreads(newThreads, iocpThreads)) + fail = true; + } + else + { + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads)) + fail = true; + } + } + else + { + if (bound == "min") + { + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMinThreads(workerThreads, newThreads)) + fail = true; + } + else + { + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + + if (!ThreadPool.SetMaxThreads(workerThreads, newThreads)) + fail = true; + } + } + + if (fail) + { + Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads); + } + else + { + int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads; + + ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads); + ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads); + + Notice("Min worker threads now {0}", minWorkerThreads); + Notice("Min IOCP threads now {0}", minIocpThreads); + Notice("Max worker threads now {0}", maxWorkerThreads); + Notice("Max IOCP threads now {0}", maxIocpThreads); + } + } + private void HandleForceGc(string module, string[] args) { Notice("Manually invoking runtime garbage collection"); -- cgit v1.1 From 139dcf1246b933f76bf72d2306f3f70d2ca61479 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 23:06:17 +0100 Subject: minor: move "threads abort" and "force gc" console commands into debug category - these are not things one needs to do in normal operation --- OpenSim/Framework/Servers/ServerBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 55b6c58..0545bea 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -246,7 +246,7 @@ namespace OpenSim.Framework.Servers "Show thread status", HandleShow); m_console.Commands.AddCommand( - "General", false, "threads abort", + "Debug", false, "threads abort", "threads abort ", "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); @@ -263,7 +263,7 @@ namespace OpenSim.Framework.Servers HandleDebugThreadpoolSet); m_console.Commands.AddCommand( - "General", false, "force gc", + "Debug", false, "force gc", "force gc", "Manually invoke runtime garbage collection. For debugging purposes", HandleForceGc); -- cgit v1.1 From f9dc5815c4788aefed7eab01fa79709d3921e22a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 23:15:30 +0100 Subject: For LLImageManagerTests, make tests execute under synchronous fire and forget conditions. I generally prefer this approach for regression tests because of the complexity of accounting for different threading conditions. --- .../Linden/UDP/Tests/LLImageManagerTests.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 6aa8bcc..575e54c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs @@ -54,6 +54,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests [TestFixtureSetUp] public void FixtureInit() { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + using ( Stream resource = GetType().Assembly.GetManifestResourceStream( @@ -73,6 +76,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests } } + [TestFixtureTearDown] + public void TearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + [SetUp] public override void SetUp() { @@ -106,14 +117,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests args.requestSequence = 1; llim.EnqueueReq(args); - - // We now have to wait and hit the processing wheel, because the decoding is async - int i = 10; - while (i-- > 0) - { - llim.ProcessImageQueue(20); - Thread.Sleep(100); - } + llim.ProcessImageQueue(20); Assert.That(tc.SentImageDataPackets.Count, Is.EqualTo(1)); } -- cgit v1.1 From 9bcf07279513294d58c3076e7d8a6eb5ee64c759 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 23:44:48 +0100 Subject: Make it possible to switch whether we serialize osd requests per endpoint or not, either via config (SerializeOSDRequests in [Network]) or via the "debug comms set" console command. For debug purposes to assess what impact this has on network response in a heavy test environment. --- OpenSim/Framework/Console/ConsoleUtil.cs | 22 ++++++++++++++++++- OpenSim/Framework/Servers/ServerBase.cs | 37 ++++++++++++++++++++++++++++++++ OpenSim/Framework/WebUtil.cs | 20 +++++++++++++---- 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs index 97a86a8..c0ff454 100644 --- a/OpenSim/Framework/Console/ConsoleUtil.cs +++ b/OpenSim/Framework/Console/ConsoleUtil.cs @@ -156,7 +156,27 @@ namespace OpenSim.Framework.Console } /// - /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 + /// Convert a console integer to an int, automatically complaining if a console is given. + /// + /// Can be null if no console is available. + /// /param> + /// + /// + public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b) + { + if (!bool.TryParse(rawConsoleString, out b)) + { + if (console != null) + console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString); + + return false; + } + + return true; + } + + /// + /// Convert a console integer to an int, automatically complaining if a console is given. /// /// Can be null if no console is available. /// /param> diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 0545bea..824c7e2 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -257,6 +257,12 @@ namespace OpenSim.Framework.Servers (string module, string[] args) => Notice(GetThreadsReport())); m_console.Commands.AddCommand ( + "Debug", false, "debug comms set", + "debug comms set serialosdreq true|false", + "Set comms parameters. For debug purposes.", + HandleDebugCommsSet); + + m_console.Commands.AddCommand ( "Debug", false, "debug threadpool set", "debug threadpool set worker|iocp min|max ", "Set threadpool parameters. For debug purposes.", @@ -284,11 +290,42 @@ namespace OpenSim.Framework.Servers public void RegisterCommonComponents(IConfigSource configSource) { + IConfig networkConfig = configSource.Configs["Network"]; + + if (networkConfig != null) + { + WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false); + } + m_serverStatsCollector = new ServerStatsCollector(); m_serverStatsCollector.Initialise(configSource); m_serverStatsCollector.Start(); } + private void HandleDebugCommsSet(string module, string[] args) + { + if (args.Length != 5) + { + Notice("Usage: debug comms set serialosdreq true|false"); + return; + } + + if (args[3] != "serialosdreq") + { + Notice("Usage: debug comms set serialosdreq true|false"); + return; + } + + bool setSerializeOsdRequests; + + if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests)) + return; + + WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests; + + Notice("serialosdreq is now {0}", setSerializeOsdRequests); + } + private void HandleDebugThreadpoolSet(string module, string[] args) { if (args.Length != 6) diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 0e9de59..706b33f 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -67,6 +67,11 @@ namespace OpenSim.Framework public static int RequestNumber { get; internal set; } /// + /// Control where OSD requests should be serialized per endpoint. + /// + public static bool SerializeOSDRequestsPerEndpoint { get; set; } + + /// /// this is the header field used to communicate the local request id /// used for performance and debugging /// @@ -145,10 +150,17 @@ namespace OpenSim.Framework public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) { - //lock (EndPointLock(url)) - //{ - return ServiceOSDRequestWorker(url,data,method,timeout,compressed); - //} + if (SerializeOSDRequestsPerEndpoint) + { + lock (EndPointLock(url)) + { + return ServiceOSDRequestWorker(url, data, method, timeout, compressed); + } + } + else + { + return ServiceOSDRequestWorker(url, data, method, timeout, compressed); + } } public static void LogOutgoingDetail(Stream outputStream) -- cgit v1.1 From 4581bdd929d84abe2dbdc46c819d015e391a5b6d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 5 Aug 2013 23:49:33 +0100 Subject: Add "debug comms status" command to show current debug comms settings --- OpenSim/Framework/Servers/ServerBase.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 824c7e2..1bee6a3 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -263,6 +263,12 @@ namespace OpenSim.Framework.Servers HandleDebugCommsSet); m_console.Commands.AddCommand ( + "Debug", false, "debug comms status", + "debug comms status", + "Show current debug comms parameters.", + HandleDebugCommsStatus); + + m_console.Commands.AddCommand ( "Debug", false, "debug threadpool set", "debug threadpool set worker|iocp min|max ", "Set threadpool parameters. For debug purposes.", @@ -302,6 +308,11 @@ namespace OpenSim.Framework.Servers m_serverStatsCollector.Start(); } + private void HandleDebugCommsStatus(string module, string[] args) + { + Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint); + } + private void HandleDebugCommsSet(string module, string[] args) { if (args.Length != 5) -- cgit v1.1 From ac198068ab7bb3895d95c6d1902b2c6af575a32a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 6 Aug 2013 00:00:12 +0100 Subject: Add "debug threadpool status" console command to show min/max/current worker/iocp threadpool numbers --- OpenSim/Framework/Servers/ServerBase.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 1bee6a3..c258ff6 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs @@ -274,6 +274,12 @@ namespace OpenSim.Framework.Servers "Set threadpool parameters. For debug purposes.", HandleDebugThreadpoolSet); + m_console.Commands.AddCommand ( + "Debug", false, "debug threadpool status", + "debug threadpool status", + "Show current debug threadpool parameters.", + HandleDebugThreadpoolStatus); + m_console.Commands.AddCommand( "Debug", false, "force gc", "force gc", @@ -337,6 +343,23 @@ namespace OpenSim.Framework.Servers Notice("serialosdreq is now {0}", setSerializeOsdRequests); } + private void HandleDebugThreadpoolStatus(string module, string[] args) + { + int workerThreads, iocpThreads; + + ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); + Notice("Min worker threads: {0}", workerThreads); + Notice("Min IOCP threads: {0}", iocpThreads); + + ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); + Notice("Max worker threads: {0}", workerThreads); + Notice("Max IOCP threads: {0}", iocpThreads); + + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + Notice("Available worker threads: {0}", workerThreads); + Notice("Available IOCP threads: {0}", iocpThreads); + } + private void HandleDebugThreadpoolSet(string module, string[] args) { if (args.Length != 6) -- cgit v1.1 From 4c2f6de8e4957df3c7186437089ba0925edb1a08 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 6 Aug 2013 18:29:33 +0100 Subject: Add the experimental ability to dump stats (result of command "show stats all") to file OpenSimStats.log every 5 seconds. This can currently only be activated with the console command "debug stats record start". Off by default. Records to file OpenSimStats.log for simulator and RobustStats.log for ROBUST --- OpenSim/Framework/Monitoring/StatsManager.cs | 52 +++++++++++++++++++++------- bin/OpenSim.32BitLaunch.exe.config | 36 ++++++++++++++++++- bin/OpenSim.exe.config | 21 +++++++++++ bin/Robust.32BitLaunch.exe.config | 22 ++++++++++++ bin/Robust.exe.config | 21 +++++++++++ 5 files changed, 139 insertions(+), 13 deletions(-) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 87197f4..c8e838c 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -81,6 +81,8 @@ namespace OpenSim.Framework.Monitoring + "More than one name can be given separated by spaces.\n" + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", HandleShowStatsCommand); + + StatsLogger.RegisterConsoleCommands(console); } public static void HandleShowStatsCommand(string module, string[] cmd) @@ -145,29 +147,55 @@ namespace OpenSim.Framework.Monitoring } } - private static void OutputAllStatsToConsole(ICommandConsole con) + public static List GetAllStatsReports() { + List reports = new List(); + foreach (var category in RegisteredStats.Values) - { - OutputCategoryStatsToConsole(con, category); - } + reports.AddRange(GetCategoryStatsReports(category)); + + return reports; + } + + private static void OutputAllStatsToConsole(ICommandConsole con) + { + foreach (string report in GetAllStatsReports()) + con.Output(report); + } + + private static List GetCategoryStatsReports( + SortedDictionary> category) + { + List reports = new List(); + + foreach (var container in category.Values) + reports.AddRange(GetContainerStatsReports(container)); + + return reports; } private static void OutputCategoryStatsToConsole( ICommandConsole con, SortedDictionary> category) { - foreach (var container in category.Values) - { - OutputContainerStatsToConsole(con, container); - } + foreach (string report in GetCategoryStatsReports(category)) + con.Output(report); } - private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary container) + private static List GetContainerStatsReports(SortedDictionary container) { + List reports = new List(); + foreach (Stat stat in container.Values) - { - con.Output(stat.ToConsoleString()); - } + reports.Add(stat.ToConsoleString()); + + return reports; + } + + private static void OutputContainerStatsToConsole( + ICommandConsole con, SortedDictionary container) + { + foreach (string report in GetContainerStatsReports(container)) + con.Output(report); } // Creates an OSDMap of the format: diff --git a/bin/OpenSim.32BitLaunch.exe.config b/bin/OpenSim.32BitLaunch.exe.config index 6ac0206..6a6b3c8 100644 --- a/bin/OpenSim.32BitLaunch.exe.config +++ b/bin/OpenSim.32BitLaunch.exe.config @@ -11,22 +11,56 @@ + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/OpenSim.exe.config b/bin/OpenSim.exe.config index 8a891f4..b2cb4e5 100755 --- a/bin/OpenSim.exe.config +++ b/bin/OpenSim.exe.config @@ -11,6 +11,10 @@ + + + + @@ -21,11 +25,23 @@ + + + + + + + + + + + + @@ -42,5 +58,10 @@ + + + + + diff --git a/bin/Robust.32BitLaunch.exe.config b/bin/Robust.32BitLaunch.exe.config index dae45ff..ec17049 100644 --- a/bin/Robust.32BitLaunch.exe.config +++ b/bin/Robust.32BitLaunch.exe.config @@ -11,22 +11,44 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/Robust.exe.config b/bin/Robust.exe.config index 4914f55..62975fd 100644 --- a/bin/Robust.exe.config +++ b/bin/Robust.exe.config @@ -11,6 +11,10 @@ + + + + @@ -19,15 +23,32 @@ + + + + + + + + + + + + + + + + + -- cgit v1.1 From d6d5d4ebd033d47886c6e31ae87c0be527f5545e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 6 Aug 2013 18:32:16 +0100 Subject: Add file missing from last commit 4c2f6de --- OpenSim/Framework/Monitoring/StatsLogger.cs | 108 ++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 OpenSim/Framework/Monitoring/StatsLogger.cs diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs new file mode 100644 index 0000000..fa2e1b6 --- /dev/null +++ b/OpenSim/Framework/Monitoring/StatsLogger.cs @@ -0,0 +1,108 @@ +/* + * 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.Reflection; +using System.Timers; +using log4net; + +namespace OpenSim.Framework.Monitoring +{ + /// + /// Provides a means to continuously log stats for debugging purposes. + /// + public static class StatsLogger + { + private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger"); + + private static Timer m_loggingTimer; + private static int m_statsLogIntervalMs = 5000; + + public static void RegisterConsoleCommands(ICommandConsole console) + { + console.Commands.AddCommand( + "Debug", + false, + "debug stats record", + "debug stats record start|stop", + "Control whether stats are being regularly recorded to a separate file.", + "For debug purposes. Experimental.", + HandleStatsRecordCommand); + } + + public static void HandleStatsRecordCommand(string module, string[] cmd) + { + ICommandConsole con = MainConsole.Instance; + + if (cmd.Length != 4) + { + con.Output("Usage: debug stats record start|stop"); + return; + } + + if (cmd[3] == "start") + { + Start(); + con.OutputFormat("Now recording all stats very {0}ms to file", m_statsLogIntervalMs); + } + else if (cmd[3] == "stop") + { + Stop(); + con.Output("Stopped recording stats to file."); + } + } + + public static void Start() + { + if (m_loggingTimer != null) + Stop(); + + m_loggingTimer = new Timer(m_statsLogIntervalMs); + m_loggingTimer.AutoReset = false; + m_loggingTimer.Elapsed += Log; + m_loggingTimer.Start(); + } + + public static void Stop() + { + if (m_loggingTimer != null) + { + m_loggingTimer.Stop(); + } + } + + private static void Log(object sender, ElapsedEventArgs e) + { + m_statsLog.InfoFormat("*** STATS REPORT AT {0} ***", DateTime.Now); + + foreach (string report in StatsManager.GetAllStatsReports()) + m_statsLog.Info(report); + + m_loggingTimer.Start(); + } + } +} \ No newline at end of file -- cgit v1.1 From 3194ffdab8d54723ad1546846c1d45472d6a8464 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 7 Aug 2013 08:01:59 -0700 Subject: Fixed incomplete commit r/23317 -- see_into_region. Put the guard around estate bans also, and delete the obsolete config var. --- OpenSim/Region/Application/ConfigurationLoader.cs | 1 - OpenSim/Region/Framework/Scenes/Scene.cs | 32 +++++++++++------------ OpenSim/Tools/Configger/ConfigurationLoader.cs | 1 - 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index fc3999f..3e93638 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -337,7 +337,6 @@ namespace OpenSim config.Set("physics", "OpenDynamicsEngine"); config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); - config.Set("see_into_this_sim_from_neighbor", true); config.Set("serverside_object_permissions", true); config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index dec493b..503b81a 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4013,28 +4013,28 @@ namespace OpenSim.Region.Framework.Scenes } } - if (RegionInfo.EstateSettings != null) - { - if (RegionInfo.EstateSettings.IsBanned(agent.AgentID)) - { - m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", - agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); - reason = String.Format("Denied access to region {0}: You have been banned from that region.", - RegionInfo.RegionName); - return false; - } - } - else - { - m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!"); - } - // We only test the things below when we want to cut off // child agents from being present in the scene for which their root // agent isn't allowed. Otherwise, we allow child agents. The test for // the root is done elsewhere (QueryAccess) if (!bypassAccessControl) { + if (RegionInfo.EstateSettings != null) + { + if (RegionInfo.EstateSettings.IsBanned(agent.AgentID)) + { + m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", + agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); + reason = String.Format("Denied access to region {0}: You have been banned from that region.", + RegionInfo.RegionName); + return false; + } + } + else + { + m_log.ErrorFormat("[CONNECTION BEGIN]: Estate Settings is null!"); + } + List agentGroups = new List(); if (m_groupsModule != null) diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index 28bcc99..72ba185 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -239,7 +239,6 @@ namespace OpenSim.Tools.Configger config.Set("physics", "OpenDynamicsEngine"); config.Set("meshing", "Meshmerizer"); config.Set("physical_prim", true); - config.Set("see_into_this_sim_from_neighbor", true); config.Set("serverside_object_permissions", true); config.Set("storage_plugin", "OpenSim.Data.SQLite.dll"); config.Set("storage_connection_string", "URI=file:OpenSim.db,version=3"); -- cgit v1.1 From dbd773e89e1956144d0358033e560fbd36c89ecd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Wed, 7 Aug 2013 10:04:53 -0700 Subject: Amend to last commit -- remove the obsolete var from OpenSim.ini.example --- bin/OpenSim.ini.example | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 33f3263..d6de777 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -184,10 +184,6 @@ ;; if the first change occurred this number of seconds ago. ; MaximumTimeBeforePersistenceConsidered = 600 - ;# {see_into_this_sim_from_neighbor} {} {Should avatars in neighbor sims see objects in this sim?} {true false} true - ;; Should avatars in neighbor sims see objects in this sim? - ; see_into_this_sim_from_neighbor = true - ;# {physical_prim} {} {Allow prims to be physical?} {true false} true ;; if you would like to allow prims to be physical and move by physics ;; with the physical checkbox in the client set this to true. -- cgit v1.1 From a33a1ac958b3158c9ce009e5d2915c165fb11c23 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 7 Aug 2013 18:52:30 +0100 Subject: Add post-CreateAgent teleport cancellation/abortion functionality from v1 transfer protocol into v2. This stops OpenSimulator still trying to teleport the user if they hit cancel on the teleport screen or closed the viewer whilst the protocol was trying to create an agent on the remote region. Ideally, the code may also attempt to tell the destination simulator that the agent should be removed (accounting for issues where the destination was not responding in the first place, etc.) --- .../EntityTransfer/EntityTransferModule.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 96cd6b9..80c125a 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -956,6 +956,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } + if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) + { + m_interRegionTeleportCancels.Value++; + + 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); + + return; + } + else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) + { + m_interRegionTeleportAborts.Value++; + + 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); + + return; + } + // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); -- cgit v1.1 From b10710d4a5f7fb33ee9b90aefac16ac3d4647db6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 7 Aug 2013 23:17:31 +0100 Subject: minor: add some method doc to ScenePresence fields used for entity transfer, add minor details to some log messages, rename a misleading local variable name. No functional changes. --- OpenSim/Framework/ChildAgentDataUpdate.cs | 6 +++++ .../EntityTransfer/EntityTransferModule.cs | 14 +++++++---- OpenSim/Region/Framework/Scenes/Scene.cs | 26 +++++++++++++-------- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 27 ++++++++++++++-------- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 1c5f558..18d008c 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -287,6 +287,12 @@ namespace OpenSim.Framework public Vector3 AtAxis; public Vector3 LeftAxis; public Vector3 UpAxis; + + /// + /// 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). + /// public bool SenderWantsToWaitForRoot; public float Far; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 80c125a..01ef710 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -688,8 +688,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (version.Equals("SIMULATION/0.2")) TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); else - TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); - + TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); } private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, @@ -698,7 +697,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer ulong destinationHandle = finalDestination.RegionHandle; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Using TP V1"); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", + sp.Name, Scene.Name, finalDestination.RegionName); + // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; @@ -1079,20 +1081,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!sp.DoNotCloseAfterTeleport) { // OK, it got this agent. Let's close everything - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.RegionInfo.RegionName); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.Name); sp.CloseChildAgents(newRegionX, newRegionY); sp.Scene.IncomingCloseAgent(sp.UUID, false); } else { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.RegionInfo.RegionName); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.Name); sp.DoNotCloseAfterTeleport = false; } } else + { // now we have a child agent in this region. sp.Reset(); + } } /// diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 503b81a..56cd57e 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4222,36 +4222,42 @@ namespace OpenSim.Region.Framework.Scenes } // We have to wait until the viewer contacts this region - // after receiving the EnableSimulator HTTP Event Queue message. This triggers the viewer to send + // after receiving the EnableSimulator HTTP Event Queue message (for the v1 teleport protocol) + // or TeleportFinish (for the v2 teleport protocol). This triggers the viewer to send // a UseCircuitCode packet which in turn calls AddNewClient which finally creates the ScenePresence. - ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); + ScenePresence sp = WaitGetScenePresence(cAgentData.AgentID); - if (childAgentUpdate != null) + if (sp != null) { - if (cAgentData.SessionID != childAgentUpdate.ControllingClient.SessionId) + if (cAgentData.SessionID != sp.ControllingClient.SessionId) { - m_log.WarnFormat("[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", childAgentUpdate.UUID, cAgentData.SessionID); + m_log.WarnFormat( + "[SCENE]: Attempt to update agent {0} with invalid session id {1} (possibly from simulator in older version; tell them to update).", + sp.UUID, cAgentData.SessionID); + Console.WriteLine(String.Format("[SCENE]: Attempt to update agent {0} ({1}) with invalid session id {2}", - childAgentUpdate.UUID, childAgentUpdate.ControllingClient.SessionId, cAgentData.SessionID)); + sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID)); } - childAgentUpdate.ChildAgentDataUpdate(cAgentData); + sp.ChildAgentDataUpdate(cAgentData); int ntimes = 20; if (cAgentData.SenderWantsToWaitForRoot) { - while (childAgentUpdate.IsChildAgent && ntimes-- > 0) + while (sp.IsChildAgent && ntimes-- > 0) Thread.Sleep(1000); m_log.DebugFormat( "[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits", - childAgentUpdate.Name, childAgentUpdate.UUID, childAgentUpdate.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 20 - ntimes); + sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", Name, 20 - ntimes); - if (childAgentUpdate.IsChildAgent) + if (sp.IsChildAgent) return false; } + return true; } + return false; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 0ba2dab..7fd1302 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -285,10 +285,24 @@ namespace OpenSim.Region.Framework.Scenes /// private Vector3 posLastSignificantMove; - // For teleports and crossings callbacks + #region For teleports and crossings callbacks + + /// + /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address. + /// string m_callbackURI; + UUID m_originRegionID; + /// + /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent + /// teleport is reusing the connection. + /// + /// May be refactored or move somewhere else soon. + public bool DoNotCloseAfterTeleport { get; set; } + + #endregion + /// /// Script engines present in the scene /// @@ -717,13 +731,6 @@ namespace OpenSim.Region.Framework.Scenes } } - /// - /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent - /// teleport is reusing the connection. - /// - /// May be refactored or move somewhere else soon. - public bool DoNotCloseAfterTeleport { get; set; } - private float m_speedModifier = 1.0f; public float SpeedModifier @@ -1325,14 +1332,14 @@ namespace OpenSim.Region.Framework.Scenes int count = 20; while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) { - m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.RegionInfo.RegionName); + m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); Thread.Sleep(200); } if (m_originRegionID.Equals(UUID.Zero)) { // Movement into region will fail - m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived", client.Name); + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name); return false; } -- cgit v1.1 From 638c3d25b0787c2fbdabbe80519389ad8ddb944d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 8 Aug 2013 00:48:22 +0100 Subject: Remove never implemented stub modules commands (list, load, unload) from back in 2009. "show modules" is the functional console command that will show currently loaded modules. Addresses http://opensimulator.org/mantis/view.php?id=6730 --- OpenSim/Region/Application/OpenSim.cs | 40 ----------------------------------- 1 file changed, 40 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 9dcc8da..58f9368 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -348,18 +348,6 @@ namespace OpenSim m_console.Commands.AddCommand("Regions", false, "delete-region", "delete-region ", "Delete a region from disk", RunCommand); - - m_console.Commands.AddCommand("General", false, "modules list", - "modules list", - "List modules", HandleModules); - - m_console.Commands.AddCommand("General", false, "modules load", - "modules load ", - "Load a module", HandleModules); - - m_console.Commands.AddCommand("General", false, "modules unload", - "modules unload ", - "Unload a module", HandleModules); } protected override void ShutdownSpecific() @@ -557,34 +545,6 @@ namespace OpenSim } /// - /// Load, Unload, and list Region modules in use - /// - /// - /// - private void HandleModules(string module, string[] cmd) - { - List args = new List(cmd); - args.RemoveAt(0); - string[] cmdparams = args.ToArray(); - - if (cmdparams.Length > 0) - { - switch (cmdparams[0].ToLower()) - { - case "list": - //TODO: Convert to new region modules - break; - case "unload": - //TODO: Convert to new region modules - break; - case "load": - //TODO: Convert to new region modules - break; - } - } - } - - /// /// Runs commands issued by the server console from the operator /// /// The first argument of the parameter (the command) -- cgit v1.1 From e4da8d74d8b0e04a5439638c8868367d4b20050f Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Mon, 5 Aug 2013 19:28:11 -0400 Subject: Additional regression tests for the location routines in Location.cs --- OpenSim/Framework/Tests/LocationTest.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs index af5f164..3d5d1d2 100644 --- a/OpenSim/Framework/Tests/LocationTest.cs +++ b/OpenSim/Framework/Tests/LocationTest.cs @@ -55,11 +55,18 @@ namespace OpenSim.Framework.Tests Location TestLocation2 = new Location(1095216660736000); Assert.That(TestLocation1 == TestLocation2); + Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor"); Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); Assert.That(TestLocation2.RegionHandle == 1095216660736000, "Location RegionHandle Property didn't match regionhandle provided in constructor"); + ulong RegionHandle = TestLocation1.RegionHandle; + Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor"); + + TestLocation2 = new Location(RegionHandle); + Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor"); + TestLocation1 = new Location(255001, 256001); TestLocation2 = new Location(1095216660736000); -- cgit v1.1 From 43da879ea2123707190875fe2615e01be19ecced Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Mon, 5 Aug 2013 19:29:38 -0400 Subject: Added regression tests for the routines related to fake parcel IDs. --- OpenSim/Framework/Tests/UtilTest.cs | 84 +++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 11ca068..c83651c 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs @@ -282,5 +282,89 @@ namespace OpenSim.Framework.Tests String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); } } + + [Test] + public void FakeParcelIDTests() + { + byte[] hexBytes8 = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; + byte[] hexBytes16 = { + 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, + 0x77, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f }; + UInt64 var64Bit = (UInt64)0xfedcba9876543210; + + //Region handle is for location 255000,256000. + ulong regionHandle1 = 1095216660736000; + uint x1 = 100; + uint y1 = 200; + uint z1 = 22; + ulong regionHandle2; + uint x2, y2, z2; + UUID fakeParcelID1, fakeParcelID2, uuid; + + ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8); + Assert.AreEqual(var64Bit, bigInt64, + "BytesToUint64Bit conversion of 8 bytes to UInt64 failed."); + + //Test building and decoding using some typical input values + fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1); + Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2); + Assert.AreEqual(regionHandle1, regionHandle2, + "region handle decoded from FakeParcelID wth X/Y failed."); + Assert.AreEqual(x1, x2, + "X coordinate decoded from FakeParcelID wth X/Y failed."); + Assert.AreEqual(y1, y2, + "Y coordinate decoded from FakeParcelID wth X/Y failed."); + + fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1, z1); + Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2); + Assert.AreEqual(regionHandle1, regionHandle2, + "region handle decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(x1, x2, + "X coordinate decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(y1, y2, + "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(z1, z2, + "Z coordinate decoded from FakeParcelID with X/Y/Z failed."); + + //Do some more extreme tests to check the encoding and decoding + x1 = 0x55aa; + y1 = 0x9966; + z1 = 0x5a96; + + fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1); + Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2); + Assert.AreEqual(var64Bit, regionHandle2, + "region handle decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(x1, x2, + "X coordinate decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(y1, y2, + "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); + + fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1, z1); + Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2); + Assert.AreEqual(var64Bit, regionHandle2, + "region handle decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(x1, x2, + "X coordinate decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(y1, y2, + "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); + Assert.AreEqual(z1, z2, + "Z coordinate decoded from FakeParcelID with X/Y/Z failed."); + + + x1 = 64; + y1 = 192; + fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1); + Util.FakeParcelIDToGlobalPosition(fakeParcelID1, out x2, out y2); + Assert.AreEqual(255000+x1, x2, + "Global X coordinate decoded from regionHandle failed."); + Assert.AreEqual(256000+y1, y2, + "Global Y coordinate decoded from regionHandle failed."); + + uuid = new UUID("00dd0700-00d1-0700-3800-000032000000"); + Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2); +System.Console.WriteLine("uuid: " + uuid); +System.Console.WriteLine("x2/y2: " + x2 + "," + y2); + } } } -- cgit v1.1 From 64216b34a49377f6999f6d2cf624d3c537d3f9d5 Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Mon, 5 Aug 2013 19:30:46 -0400 Subject: Fixed error in BuildFakeParcelID() which was detected by regression tests. --- OpenSim/Framework/Util.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 6a15734..f0e5bc1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1247,7 +1247,7 @@ namespace OpenSim.Framework byte[] bytes = { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), (byte)x, (byte)(x >> 8), 0, 0, (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); @@ -1258,7 +1258,7 @@ namespace OpenSim.Framework byte[] bytes = { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); -- cgit v1.1 From ce1361f2fea9c650cc774941b5cd95b14b8f01f5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 8 Aug 2013 01:07:30 +0100 Subject: minor: Remove console lines at bottom of FakeParcelIDTests() regression test that were accidentally left in --- OpenSim/Framework/Tests/UtilTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index c83651c..3b7f252 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs @@ -363,8 +363,6 @@ namespace OpenSim.Framework.Tests uuid = new UUID("00dd0700-00d1-0700-3800-000032000000"); Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2); -System.Console.WriteLine("uuid: " + uuid); -System.Console.WriteLine("x2/y2: " + x2 + "," + y2); } } } -- cgit v1.1 From 99a4a914887c16483074b0145b9b6da765ac024a Mon Sep 17 00:00:00 2001 From: teravus Date: Wed, 7 Aug 2013 21:22:04 -0500 Subject: * This makes in-world terrain editing smoother, even in MegaRegions. This change only affects the editing user's experience. Non-editing users will see nothing different from the current 'slow' result. See comments for the thought process and how the issues surrounding terrain editing, cache, bandwidth, threading, terrain patch reliability and throttling were balanced. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 8b2440a..0dbce2f 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -327,7 +327,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private PriorityQueue m_entityProps; private Prioritizer m_prioritizer; private bool m_disableFacelights = false; - + private volatile bool m_justEditedTerrain = false; /// /// List used in construction of data blocks for an object update packet. This is to stop us having to /// continually recreate it. @@ -1239,9 +1239,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP LLHeightFieldMoronize(map); LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); - layerpack.Header.Reliable = true; + + // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. + // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. + // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area + // invalidating previous packets for that area. - OutPacket(layerpack, ThrottleOutPacketType.Land); + // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a + // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. + + // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will + // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain + // patches. + + // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. + if (m_justEditedTerrain) + { + layerpack.Header.Reliable = false; + OutPacket(layerpack, + ThrottleOutPacketType.Unknown ); + } + else + { + layerpack.Header.Reliable = true; + OutPacket(layerpack, + ThrottleOutPacketType.Land); + } } catch (Exception e) { @@ -6263,6 +6286,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP //m_log.Info("[LAND]: LAND:" + modify.ToString()); if (modify.ParcelData.Length > 0) { + // Note: the ModifyTerrain event handler sends out updated packets before the end of this event. Therefore, + // a simple boolean value should work and perhaps queue up just a few terrain patch packets at the end of the edit. + m_justEditedTerrain = true; // Prevent terrain packet (Land layer) from being queued, make it unreliable if (OnModifyTerrain != null) { for (int i = 0; i < modify.ParcelData.Length; i++) @@ -6278,6 +6304,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } } + m_justEditedTerrain = false; // Queue terrain packet (Land layer) if necessary, make it reliable again } return true; -- cgit v1.1 From 4e86674a3a671561c3a9c85925308f2004fcc922 Mon Sep 17 00:00:00 2001 From: teravus Date: Wed, 7 Aug 2013 23:33:23 -0500 Subject: * Added set water height [] [] console command following the set terrain heights console command as an example. --- .../World/Estate/EstateManagementCommands.cs | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index 4d49794..173b603 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs @@ -76,6 +76,13 @@ namespace OpenSim.Region.CoreModules.World.Estate " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", consoleSetTerrainHeights); + m_module.Scene.AddCommand("Regions", m_module, "set water height", + "set water height [] []", + "Sets the water height in meters. If and are specified, it will only set it on regions with a matching coordinate. " + + "Specify -1 in or to wildcard that coordinate.", + consoleSetWaterHeight); + + m_module.Scene.AddCommand( "Estates", m_module, "estate show", "estate show", "Shows all estates on the simulator.", ShowEstatesCommand); } @@ -121,7 +128,29 @@ namespace OpenSim.Region.CoreModules.World.Estate } } } - + protected void consoleSetWaterHeight(string module, string[] args) + { + string heightstring = args[3]; + + int x = (args.Length > 4 ? int.Parse(args[4]) : -1); + int y = (args.Length > 5 ? int.Parse(args[5]) : -1); + + if (x == -1 || m_module.Scene.RegionInfo.RegionLocX == x) + { + if (y == -1 || m_module.Scene.RegionInfo.RegionLocY == y) + { + double selectedheight = double.Parse(heightstring); + + m_log.Debug("[ESTATEMODULE]: Setting water height in " + m_module.Scene.RegionInfo.RegionName + " to " + + string.Format(" {0}", selectedheight)); + m_module.Scene.RegionInfo.RegionSettings.WaterHeight = selectedheight; + + m_module.Scene.RegionInfo.RegionSettings.Save(); + m_module.TriggerRegionInfoChange(); + m_module.sendRegionHandshakeToAll(); + } + } + } protected void consoleSetTerrainHeights(string module, string[] args) { string num = args[3]; -- cgit v1.1 From 50c163ae6ca734610694f4edcc109ff0bdc65ba1 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 6 Aug 2013 08:21:16 -0700 Subject: Add a JSON web fetch of the statististics managed by StatsManager. Disabled by default. Enable by setting [Startup]ManagedStatsRemoteFetchURI="Something" and thereafter "http://ServerHTTPPort/Something/" will return all the managed stats (equivilent to "show stats all" console command). Accepts queries "cat=", "cont=" and "stat=" to specify statistic category, container and statistic names. The special name "all" is the default and returns all values in that group. --- OpenSim/Framework/Monitoring/StatsManager.cs | 31 ++++++++++++++++++++++++++++ OpenSim/Region/Application/OpenSim.cs | 7 +++++++ OpenSim/Region/Application/OpenSimBase.cs | 2 ++ 3 files changed, 40 insertions(+) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index c8e838c..23c6f18 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -26,10 +26,12 @@ */ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; +using OpenSim.Framework; using OpenMetaverse.StructuredData; namespace OpenSim.Framework.Monitoring @@ -262,6 +264,35 @@ namespace OpenSim.Framework.Monitoring return map; } + public static Hashtable HandleStatsRequest(Hashtable request) + { + Hashtable responsedata = new Hashtable(); + string regpath = request["uri"].ToString(); + int response_code = 200; + string contenttype = "text/json"; + + string pCategoryName = StatsManager.AllSubCommand; + string pContainerName = StatsManager.AllSubCommand; + string pStatName = StatsManager.AllSubCommand; + + if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); + if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); + if (request.ContainsKey("stat")) pStatName = request["cat"].ToString(); + + string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); + + // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}", + // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut); + + responsedata["int_response_code"] = response_code; + responsedata["content_type"] = contenttype; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = strOut; + responsedata["access_control_allow_origin"] = "*"; + + return responsedata; + } + // /// // /// Start collecting statistics related to assets. // /// Should only be called once. diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 58f9368..13fdb3b 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -172,6 +172,13 @@ namespace OpenSim if (userStatsURI != String.Empty) MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); + if (managedStatsURI != String.Empty) + { + string urlBase = String.Format("/{0}/", managedStatsURI); + MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest); + m_log.WarnFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase); + } + if (m_console is RemoteConsole) { if (m_consolePort == 0) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index f0c088a..b032e7f 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -75,6 +75,7 @@ namespace OpenSim protected int proxyOffset = 0; public string userStatsURI = String.Empty; + public string managedStatsURI = String.Empty; protected bool m_autoCreateClientStack = true; @@ -188,6 +189,7 @@ namespace OpenSim CreatePIDFile(pidFile); userStatsURI = startupConfig.GetString("Stats_URI", String.Empty); + managedStatsURI = startupConfig.GetString("ManagedStatsRemoteFetchURI", String.Empty); } // Load the simulation data service -- cgit v1.1 From c67c55e0fcd93e5b68e61e5f1bc4341af48568d3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 8 Aug 2013 08:56:22 -0700 Subject: Better error reporting when registering LSL function extensions (comms module). For unknown reasons, a dynamic function signature cannot have more than 5 parameters. Error message now tells you this fact so you can curse MS and then go change your function definitions. --- .../ScriptModuleComms/ScriptModuleCommsModule.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index a515346..6da2222 100644 --- a/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs @@ -45,6 +45,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static string LogHeader = "[MODULE COMMS]"; private Dictionary m_constants = new Dictionary(); @@ -148,7 +149,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true); if (mi == null) { - m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", meth); + m_log.WarnFormat("{0} Failed to register method {1}", LogHeader, meth); return; } @@ -165,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms { // m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name); - Type delegateType; + Type delegateType = typeof(void); List typeArgs = mi.GetParameters() .Select(p => p.ParameterType) .ToList(); @@ -176,8 +177,16 @@ namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms } else { - typeArgs.Add(mi.ReturnType); - delegateType = Expression.GetFuncType(typeArgs.ToArray()); + try + { + typeArgs.Add(mi.ReturnType); + delegateType = Expression.GetFuncType(typeArgs.ToArray()); + } + catch (Exception e) + { + m_log.ErrorFormat("{0} Failed to create function signature. Most likely more than 5 parameters. Method={1}. Error={2}", + LogHeader, mi.Name, e); + } } Delegate fcall; -- cgit v1.1 From d9bd6e6b5be3100141a3b1202f859c65a302d4ee Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 8 Aug 2013 09:41:11 -0700 Subject: Add parameter and explanation of ManagedStats return to OpenSimDefaults.ini. Add 'callback' query parameter to managed stats return to return function form of JSON data. --- OpenSim/Framework/Monitoring/StatsManager.cs | 6 ++++++ OpenSim/Region/Application/OpenSim.cs | 4 ++-- bin/OpenSimDefaults.ini | 7 +++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 23c6f18..7cf1fa7 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -281,6 +281,12 @@ namespace OpenSim.Framework.Monitoring string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); + // If requestor wants it as a callback function, build response as a function rather than just the JSON string. + if (request.ContainsKey("callback")) + { + strOut = request["callback"].ToString() + "(" + strOut + ");"; + } + // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}", // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut); diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 13fdb3b..1cdd868 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -175,8 +175,8 @@ namespace OpenSim if (managedStatsURI != String.Empty) { string urlBase = String.Format("/{0}/", managedStatsURI); - MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest); - m_log.WarnFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase); + MainServer.Instance.AddHTTPHandler(urlBase, StatsManager.HandleStatsRequest); + m_log.InfoFormat("[OPENSIM] Enabling remote managed stats fetch. URL = {0}", urlBase); } if (m_console is RemoteConsole) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index d5d29ec..0a85085 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -264,8 +264,15 @@ ; Simulator Stats URI ; Enable JSON simulator data by setting a URI name (case sensitive) + ; Returns regular sim stats (SimFPS, ...) ; Stats_URI = "jsonSimStats" + ; Simulator StatsManager URI + ; Enable fetch of StatsManager registered stats. Fetch is query which can optionally + ; specify category, container and stat to fetch. If not selected, returns all of that type. + ; http://simulatorHTTPport/ManagedStats/?cat=Category&cont=Container&stat=Statistic + ; ManagedStatsRemoteFetchURI = "ManagedStats" + ; Make OpenSim start all regions woth logins disabled. They will need ; to be enabled from the console if this is set ; StartDisabled = false -- cgit v1.1 From 9fc97cbbf77f269d69aaa6234dd6e12ebf3b9563 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 8 Aug 2013 12:44:03 -0700 Subject: Make m_originRegionID in ScenePresence public to allow DSG module to work for now. Once the code churn on teleport ends, I can find a better solution --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7fd1302..1b8c276 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -290,9 +290,9 @@ namespace OpenSim.Region.Framework.Scenes /// /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address. /// - string m_callbackURI; + private string m_callbackURI; - UUID m_originRegionID; + public UUID m_originRegionID; /// /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent -- cgit v1.1 From 6410a25cefcb1e7f87b76f273f8c6569fbe17670 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 8 Aug 2013 13:53:12 -0700 Subject: BulletSim: adjust avatar position when the avatar's size is changed. This fixes the problem of avatars bouncing when logged in. Added a little height to the avatar height fudges to eliminate a problem of feet being in the ground a bit. --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 12 ++++++++++-- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 58a417e..9af3dce 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -96,8 +96,8 @@ public sealed class BSCharacter : BSPhysObject m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); PhysicalActors.Add(AvatarMoveActorName, m_moveActor); - DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, Density, _avatarVolume, RawMass); + DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}", + LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos); // do actual creation in taint time PhysScene.TaintedObject("BSCharacter.create", delegate() @@ -190,6 +190,10 @@ public sealed class BSCharacter : BSPhysObject } set { + // This is how much the avatar size is changing. Positive means getting bigger. + // The avatar altitude must be adjusted for this change. + float heightChange = value.Z - _size.Z; + _size = value; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. @@ -207,6 +211,10 @@ public sealed class BSCharacter : BSPhysObject { PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); UpdatePhysicalMassProperties(RawMass, true); + + // Adjust the avatar's position to account for the increase/decrease in size + ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); + // Make sure this change appears as a property update event PhysScene.PE.PushUpdate(PhysBody); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 4520171..fcb892a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -570,9 +570,9 @@ public static class BSParam new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", -0.2f ), new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", - 0.1f ), + 0.2f ), new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", - 0.1f ), + 0.2f ), new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", -- cgit v1.1 From b1c26a56b3d615f3709363e3a2f91b5423f5891f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 8 Aug 2013 23:29:30 +0100 Subject: Fix an issue where under teleport v2 protocol, teleporting from regions in an line from A->B->C would not close region A when reaching C The root cause was that v2 was only closing neighbour agents if the root connection also needed a close. However, fixing this requires the neighbour regions also detect when they should not close due to re-teleports re-establishing the child connection. This involves restructuring the code to introduce a scene presence state machine that can serialize the different add and remove client calls that are now possible with the late close of the This commit appears to fix these issues and improve teleport, but still has holes on at least quick reteleporting (and possibly occasionally on ordinary teleports). Also, has not been completely tested yet in scenarios where regions are running on different simulators --- .../Caps/EventQueue/Tests/EventQueueTests.cs | 2 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 6 + .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 6 +- .../Linden/UDP/Tests/BasicCircuitTests.cs | 2 +- .../EntityTransfer/EntityTransferModule.cs | 48 ++-- .../World/Estate/EstateManagementModule.cs | 6 +- OpenSim/Region/Framework/Scenes/Scene.cs | 308 +++++++++++++-------- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 36 ++- 8 files changed, 267 insertions(+), 147 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 141af8a..626932f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -91,7 +91,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests public void RemoveForClient() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); UUID spId = TestHelpers.ParseTail(0x1); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 8b2440a..e775a81 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -512,7 +512,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP // We still perform a force close inside the sync lock since this is intended to attempt close where // there is some unidentified connection problem, not where we have issues due to deadlock if (!IsActive && !force) + { + m_log.DebugFormat( + "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set", + Name, m_scene.Name); + return; + } IsActive = false; CloseWithoutChecks(); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 5c38399..de2f9d4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1799,9 +1799,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!client.SceneAgent.IsChildAgent) client.Kick("Simulator logged you out due to connection timeout."); - - client.CloseWithoutChecks(); } + + m_scene.IncomingCloseAgent(client.AgentId, true); } private void IncomingPacketHandler() @@ -2142,7 +2142,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!client.IsLoggingOut) { client.IsLoggingOut = true; - client.Close(); + m_scene.IncomingCloseAgent(client.AgentId, false); } } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index b47ff54..9700224 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs @@ -200,7 +200,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests public void TestLogoutClientDueToAck() { TestHelpers.InMethod(); -// TestHelpers.EnableLogging(); + TestHelpers.EnableLogging(); IniConfigSource ics = new IniConfigSource(); IConfig config = ics.AddConfig("ClientStack.LindenUDP"); diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 01ef710..2f74253 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1064,8 +1064,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Now let's make it officially a child agent sp.MakeChildAgent(); - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone + // May still need to signal neighbours whether child agents may need closing irrespective of whether this + // one needed closing. Neighbour regions also contain logic to prevent a close if a subsequent move or + // teleport re-established the child connection. + sp.CloseChildAgents(newRegionX, newRegionY); + // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { sp.DoNotCloseAfterTeleport = false; @@ -1081,14 +1085,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!sp.DoNotCloseAfterTeleport) { // OK, it got this agent. Let's close everything - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing in agent {0} in region {1}", sp.Name, Scene.Name); - sp.CloseChildAgents(newRegionX, newRegionY); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing agent {0} in {1}", sp.Name, Scene.Name); sp.Scene.IncomingCloseAgent(sp.UUID, false); - } else { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {0}", sp.Name, Scene.Name); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {1}", sp.Name, Scene.Name); sp.DoNotCloseAfterTeleport = false; } } @@ -1863,10 +1865,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer List newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); List oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); - //Dump("Current Neighbors", neighbourHandles); - //Dump("Previous Neighbours", previousRegionNeighbourHandles); - //Dump("New Neighbours", newRegions); - //Dump("Old Neighbours", oldRegions); + Dump("Current Neighbors", neighbourHandles); + Dump("Previous Neighbours", previousRegionNeighbourHandles); + Dump("New Neighbours", newRegions); + Dump("Old Neighbours", oldRegions); /// Update the scene presence's known regions here on this region sp.DropOldNeighbours(oldRegions); @@ -1874,8 +1876,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// Collect as many seeds as possible Dictionary seeds; if (sp.Scene.CapsModule != null) - seeds - = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); + seeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); else seeds = new Dictionary(); @@ -1945,6 +1946,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer newAgent = true; else newAgent = false; +// continue; if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) { @@ -2178,18 +2180,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return handles; } -// private void Dump(string msg, List handles) -// { -// m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); -// foreach (ulong handle in handles) -// { -// uint x, y; -// Utils.LongToUInts(handle, out x, out y); -// x = x / Constants.RegionSize; -// y = y / Constants.RegionSize; -// m_log.InfoFormat("({0}, {1})", x, y); -// } -// } + private void Dump(string msg, List handles) + { + m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); + foreach (ulong handle in handles) + { + uint x, y; + Utils.LongToUInts(handle, out x, out y); + x = x / Constants.RegionSize; + y = y / Constants.RegionSize; + m_log.InfoFormat("({0}, {1})", x, y); + } + } #endregion diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 121b2aa..31547a6 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -562,7 +562,7 @@ namespace OpenSim.Region.CoreModules.World.Estate if (!Scene.TeleportClientHome(user, s.ControllingClient)) { s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out."); - s.ControllingClient.Close(); + Scene.IncomingCloseAgent(s.UUID, false); } } } @@ -797,7 +797,7 @@ namespace OpenSim.Region.CoreModules.World.Estate if (!Scene.TeleportClientHome(prey, s.ControllingClient)) { s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); - s.ControllingClient.Close(); + Scene.IncomingCloseAgent(s.UUID, false); } } } @@ -820,7 +820,7 @@ namespace OpenSim.Region.CoreModules.World.Estate if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient)) { p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out."); - p.ControllingClient.Close(); + Scene.IncomingCloseAgent(p.UUID, false); } } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 56cd57e..5f10869 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -151,7 +151,7 @@ namespace OpenSim.Region.Framework.Scenes public SynchronizeSceneHandler SynchronizeScene; /// - /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. + /// Used to prevent simultaneous calls to code that adds and removes agents. /// private object m_removeClientLock = new object(); @@ -1312,7 +1312,7 @@ namespace OpenSim.Region.Framework.Scenes Thread.Sleep(500); // Stop all client threads. - ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); + ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); }); m_log.Debug("[SCENE]: Persisting changed objects"); EventManager.TriggerSceneShuttingDown(this); @@ -2972,7 +2972,7 @@ namespace OpenSim.Region.Framework.Scenes { PresenceService.LogoutAgent(sp.ControllingClient.SessionId); - sp.ControllingClient.Close(); + IncomingCloseAgent(sp.UUID, false); } else { @@ -3384,47 +3384,48 @@ namespace OpenSim.Region.Framework.Scenes public override void RemoveClient(UUID agentID, bool closeChildAgents) { -// CheckHeartbeat(); - bool isChildAgent = false; - AgentCircuitData acd; + AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); - lock (m_removeClientLock) + // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which + // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not + // However, will keep for now just in case. + if (acd == null) { - acd = m_authenticateHandler.GetAgentCircuitData(agentID); + m_log.ErrorFormat( + "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name); - if (acd == null) - { - m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); - return; - } - else - { - // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred - // simultaneously. - // We also need to remove by agent ID since NPCs will have no circuit code. - m_authenticateHandler.RemoveCircuit(agentID); - } + return; + } + else + { + m_authenticateHandler.RemoveCircuit(agentID); } + // TODO: Can we now remove this lock? lock (acd) - { + { + bool isChildAgent = false; + ScenePresence avatar = GetScenePresence(agentID); - + + // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which + // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not + // However, will keep for now just in case. if (avatar == null) { - m_log.WarnFormat( + m_log.ErrorFormat( "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); return; } - + try { isChildAgent = avatar.IsChildAgent; m_log.DebugFormat( "[SCENE]: Removing {0} agent {1} {2} from {3}", - (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); + isChildAgent ? "child" : "root", avatar.Name, agentID, Name); // Don't do this to root agents, it's not nice for the viewer if (closeChildAgents && isChildAgent) @@ -3587,13 +3588,13 @@ namespace OpenSim.Region.Framework.Scenes /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of /// the LLUDP stack). /// - /// CircuitData of the agent who is connecting + /// CircuitData of the agent who is connecting /// Outputs the reason for the false response on this string /// True for normal presence. False for NPC /// or other applications where a full grid/Hypergrid presence may not be required. /// True if the region accepts this agent. False if it does not. False will /// also return a reason. - public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) + public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup) { bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); @@ -3613,15 +3614,15 @@ namespace OpenSim.Region.Framework.Scenes m_log.DebugFormat( "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", RegionInfo.RegionName, - (agent.child ? "child" : "root"), - agent.firstname, - agent.lastname, - agent.AgentID, - agent.circuitcode, - agent.IPAddress, - agent.Viewer, + (acd.child ? "child" : "root"), + acd.firstname, + acd.lastname, + acd.AgentID, + acd.circuitcode, + acd.IPAddress, + acd.Viewer, ((TPFlags)teleportFlags).ToString(), - agent.startpos + acd.startpos ); if (!LoginsEnabled) @@ -3639,7 +3640,7 @@ namespace OpenSim.Region.Framework.Scenes { foreach (string viewer in m_AllowedViewers) { - if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) + if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) { ViewerDenied = false; break; @@ -3656,7 +3657,7 @@ namespace OpenSim.Region.Framework.Scenes { foreach (string viewer in m_BannedViewers) { - if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) + if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) { ViewerDenied = true; break; @@ -3668,61 +3669,104 @@ namespace OpenSim.Region.Framework.Scenes { m_log.DebugFormat( "[SCENE]: Access denied for {0} {1} using {2}", - agent.firstname, agent.lastname, agent.Viewer); + acd.firstname, acd.lastname, acd.Viewer); reason = "Access denied, your viewer is banned by the region owner"; return false; } ILandObject land; + ScenePresence sp; - lock (agent) + lock (m_removeClientLock) { - ScenePresence sp = GetScenePresence(agent.AgentID); - - if (sp != null) + sp = GetScenePresence(acd.AgentID); + + // We need to ensure that we are not already removing the scene presence before we ask it not to be + // closed. + if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running) { - if (!sp.IsChildAgent) - { - // We have a root agent. Is it in transit? - if (!EntityTransferModule.IsInTransit(sp.UUID)) - { - // We have a zombie from a crashed session. - // Or the same user is trying to be root twice here, won't work. - // Kill it. - m_log.WarnFormat( - "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", - sp.Name, sp.UUID, RegionInfo.RegionName); + m_log.DebugFormat( + "[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name); - if (sp.ControllingClient != null) - sp.ControllingClient.Close(true); + // In the case where, for example, an A B C D region layout, an avatar may + // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C + // renews the lease on the child agent at B, we must make sure that the close from A does not succeed. + if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) + { + m_log.DebugFormat( + "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", + sp.Name, Name); - sp = null; - } - //else - // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); + sp.DoNotCloseAfterTeleport = true; } - else + } + } + + // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will + // allow unpredictable things to happen. + if (sp != null) + { + const int polls = 10; + const int pollInterval = 1000; + int pollsLeft = polls; + + while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0) + Thread.Sleep(pollInterval); + + if (sp.LifecycleState == ScenePresenceState.Removing) + { + m_log.WarnFormat( + "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.", + sp.Name, Name, polls * pollInterval / 1000); + + return false; + } + else if (polls != pollsLeft) + { + m_log.DebugFormat( + "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.", + sp.Name, Name, polls * pollInterval / 1000); + } + } + + // TODO: can we remove this lock? + lock (acd) + { + if (sp != null && !sp.IsChildAgent) + { + // We have a root agent. Is it in transit? + if (!EntityTransferModule.IsInTransit(sp.UUID)) { - // We have a child agent here - sp.DoNotCloseAfterTeleport = true; - //m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName); + // We have a zombie from a crashed session. + // Or the same user is trying to be root twice here, won't work. + // Kill it. + m_log.WarnFormat( + "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", + sp.Name, sp.UUID, RegionInfo.RegionName); + + if (sp.ControllingClient != null) + IncomingCloseAgent(sp.UUID, true); + + sp = null; } + //else + // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); } // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. // We need the circuit data here for some of the subsequent checks. (groups, for example) // If the checks fail, we remove the circuit. - agent.teleportFlags = teleportFlags; - m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); + acd.teleportFlags = teleportFlags; + m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd); - land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); + land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y); // On login test land permisions if (vialogin) { - if (land != null && !TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) + if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y)) { - m_authenticateHandler.RemoveCircuit(agent.circuitcode); + m_authenticateHandler.RemoveCircuit(acd.circuitcode); return false; } } @@ -3733,9 +3777,9 @@ namespace OpenSim.Region.Framework.Scenes { try { - if (!VerifyUserPresence(agent, out reason)) + if (!VerifyUserPresence(acd, out reason)) { - m_authenticateHandler.RemoveCircuit(agent.circuitcode); + m_authenticateHandler.RemoveCircuit(acd.circuitcode); return false; } } @@ -3744,16 +3788,16 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat( "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); - m_authenticateHandler.RemoveCircuit(agent.circuitcode); + m_authenticateHandler.RemoveCircuit(acd.circuitcode); return false; } } try { - if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) + if (!AuthorizeUser(acd, SeeIntoRegion, out reason)) { - m_authenticateHandler.RemoveCircuit(agent.circuitcode); + m_authenticateHandler.RemoveCircuit(acd.circuitcode); return false; } } @@ -3762,19 +3806,19 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat( "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); - m_authenticateHandler.RemoveCircuit(agent.circuitcode); + m_authenticateHandler.RemoveCircuit(acd.circuitcode); return false; } m_log.InfoFormat( "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", - RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, - agent.AgentID, agent.circuitcode); + Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname, + acd.AgentID, acd.circuitcode); if (CapsModule != null) { - CapsModule.SetAgentCapsSeeds(agent); - CapsModule.CreateCaps(agent.AgentID); + CapsModule.SetAgentCapsSeeds(acd); + CapsModule.CreateCaps(acd.AgentID); } } else @@ -3787,14 +3831,14 @@ namespace OpenSim.Region.Framework.Scenes { m_log.DebugFormat( "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", - agent.AgentID, RegionInfo.RegionName); + acd.AgentID, RegionInfo.RegionName); sp.AdjustKnownSeeds(); if (CapsModule != null) { - CapsModule.SetAgentCapsSeeds(agent); - CapsModule.CreateCaps(agent.AgentID); + CapsModule.SetAgentCapsSeeds(acd); + CapsModule.CreateCaps(acd.AgentID); } } } @@ -3802,23 +3846,23 @@ namespace OpenSim.Region.Framework.Scenes // Try caching an incoming user name much earlier on to see if this helps with an issue // where HG users are occasionally seen by others as "Unknown User" because their UUIDName // request for the HG avatar appears to trigger before the user name is cached. - CacheUserName(null, agent); + CacheUserName(null, acd); } if (vialogin) { // CleanDroppedAttachments(); - if (TestBorderCross(agent.startpos, Cardinals.E)) + if (TestBorderCross(acd.startpos, Cardinals.E)) { - Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); - agent.startpos.X = crossedBorder.BorderLine.Z - 1; + Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E); + acd.startpos.X = crossedBorder.BorderLine.Z - 1; } - if (TestBorderCross(agent.startpos, Cardinals.N)) + if (TestBorderCross(acd.startpos, Cardinals.N)) { - Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N); - agent.startpos.Y = crossedBorder.BorderLine.Z - 1; + Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N); + acd.startpos.Y = crossedBorder.BorderLine.Z - 1; } //Mitigate http://opensimulator.org/mantis/view.php?id=3522 @@ -3828,39 +3872,39 @@ namespace OpenSim.Region.Framework.Scenes { lock (EastBorders) { - if (agent.startpos.X > EastBorders[0].BorderLine.Z) + if (acd.startpos.X > EastBorders[0].BorderLine.Z) { m_log.Warn("FIX AGENT POSITION"); - agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; - if (agent.startpos.Z > 720) - agent.startpos.Z = 720; + acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; + if (acd.startpos.Z > 720) + acd.startpos.Z = 720; } } lock (NorthBorders) { - if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) + if (acd.startpos.Y > NorthBorders[0].BorderLine.Z) { m_log.Warn("FIX Agent POSITION"); - agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; - if (agent.startpos.Z > 720) - agent.startpos.Z = 720; + acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; + if (acd.startpos.Z > 720) + acd.startpos.Z = 720; } } } else { - if (agent.startpos.X > EastBorders[0].BorderLine.Z) + if (acd.startpos.X > EastBorders[0].BorderLine.Z) { m_log.Warn("FIX AGENT POSITION"); - agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; - if (agent.startpos.Z > 720) - agent.startpos.Z = 720; + acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; + if (acd.startpos.Z > 720) + acd.startpos.Z = 720; } - if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) + if (acd.startpos.Y > NorthBorders[0].BorderLine.Z) { m_log.Warn("FIX Agent POSITION"); - agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; - if (agent.startpos.Z > 720) - agent.startpos.Z = 720; + acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; + if (acd.startpos.Z > 720) + acd.startpos.Z = 720; } } @@ -3876,12 +3920,12 @@ namespace OpenSim.Region.Framework.Scenes { // We have multiple SpawnPoints, Route the agent to a random or sequential one if (SpawnPointRouting == "random") - agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( + acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( telehub.AbsolutePosition, telehub.GroupRotation ); else - agent.startpos = spawnpoints[SpawnPoint()].GetLocation( + acd.startpos = spawnpoints[SpawnPoint()].GetLocation( telehub.AbsolutePosition, telehub.GroupRotation ); @@ -3889,7 +3933,7 @@ namespace OpenSim.Region.Framework.Scenes else { // We have a single SpawnPoint and will route the agent to it - agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); } return true; @@ -3900,7 +3944,7 @@ namespace OpenSim.Region.Framework.Scenes { if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) { - agent.startpos = land.LandData.UserLocation; + acd.startpos = land.LandData.UserLocation; } } } @@ -4359,11 +4403,51 @@ namespace OpenSim.Region.Framework.Scenes /// public bool IncomingCloseAgent(UUID agentID, bool force) { - //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); - ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); - if (presence != null) + ScenePresence sp; + + lock (m_removeClientLock) + { + sp = GetScenePresence(agentID); + + if (sp == null) + { + m_log.DebugFormat( + "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}", + agentID, Name); + + return false; + } + + if (sp.LifecycleState != ScenePresenceState.Running) + { + m_log.DebugFormat( + "[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}", + sp.Name, Name, sp.LifecycleState); + + return false; + } + + // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may + // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not + // want to obey this close since C may have renewed the child agent lease on B. + if (sp.DoNotCloseAfterTeleport) + { + m_log.DebugFormat( + "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection", + sp.IsChildAgent ? "child" : "root", sp.Name, Name); + + // Need to reset the flag so that a subsequent close after another teleport can succeed. + sp.DoNotCloseAfterTeleport = false; + + return false; + } + + sp.LifecycleState = ScenePresenceState.Removing; + } + + if (sp != null) { - presence.ControllingClient.Close(force); + sp.ControllingClient.Close(force); return true; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7fd1302..bdcdf03 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -74,6 +74,8 @@ namespace OpenSim.Region.Framework.Scenes public class ScenePresence : EntityBase, IScenePresence { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // ~ScenePresence() // { // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); @@ -85,10 +87,27 @@ namespace OpenSim.Region.Framework.Scenes m_scene.EventManager.TriggerScenePresenceUpdated(this); } - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public PresenceType PresenceType { get; private set; } + private ScenePresenceStateMachine m_stateMachine; + + /// + /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine + /// for more details. + /// + public ScenePresenceState LifecycleState + { + get + { + return m_stateMachine.GetState(); + } + + set + { + m_stateMachine.SetState(value); + } + } + // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); @@ -766,7 +785,7 @@ namespace OpenSim.Region.Framework.Scenes public ScenePresence( IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) - { + { AttachmentsSyncLock = new Object(); AllowMovement = true; IsChildAgent = true; @@ -811,6 +830,8 @@ namespace OpenSim.Region.Framework.Scenes SetDirectionVectors(); Appearance = appearance; + + m_stateMachine = new ScenePresenceStateMachine(this); } public void RegisterToEvents() @@ -879,7 +900,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void MakeRootAgent(Vector3 pos, bool isFlying) { - m_log.DebugFormat( + m_log.InfoFormat( "[SCENE]: Upgrading child to root agent for {0} in {1}", Name, m_scene.RegionInfo.RegionName); @@ -887,6 +908,11 @@ namespace OpenSim.Region.Framework.Scenes IsChildAgent = false; + // Must reset this here so that a teleport to a region next to an existing region does not keep the flag + // set and prevent the close of the connection on a subsequent re-teleport. + // Should not be needed if we are not trying to tell this region to close +// DoNotCloseAfterTeleport = false; + IGroupsModule gm = m_scene.RequestModuleInterface(); if (gm != null) Grouptitle = gm.GetGroupTitle(m_uuid); @@ -3738,6 +3764,8 @@ namespace OpenSim.Region.Framework.Scenes // m_reprioritizationTimer.Dispose(); RemoveFromPhysicalScene(); + + LifecycleState = ScenePresenceState.Removed; } public void AddAttachment(SceneObjectGroup gobj) -- cgit v1.1 From 99bce9d87723af1958a76cf8ac5e765ca804549d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 9 Aug 2013 00:24:22 +0100 Subject: Fix an issue with an A->C->B->A teleport where these regions are in a row (A,B,C) where the A root agent is still closed, terminating the connection. This was occuring because teleport to B did not set DoNotCloseAfterTeleport on A as it was a neighbour (where it isn't set to avoid the issue where the source region doesn't send Close() to regions that are still neighbours (hence not resetting DoNotCloseAfterTeleport). Fix here is to still set DoNotCloseAfterTeleport if scene presence is still registered as in transit from A --- OpenSim/Region/Framework/Scenes/Scene.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 5f10869..a3ea7d9 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3699,6 +3699,14 @@ namespace OpenSim.Region.Framework.Scenes sp.DoNotCloseAfterTeleport = true; } + else if (EntityTransferModule.IsInTransit(sp.UUID)) + { + m_log.DebugFormat( + "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.", + sp.Name, Name); + + sp.DoNotCloseAfterTeleport = true; + } } } -- cgit v1.1 From 7e01213bf2dba1f771cc49b3d27ad97e93c35961 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 9 Aug 2013 08:31:15 -0700 Subject: Go easy on enforcing session ids in position updates --- OpenSim/Region/Framework/Scenes/Scene.cs | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 503b81a..1633e07 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4267,24 +4267,25 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); if (childAgentUpdate != null) { - if (childAgentUpdate.ControllingClient.SessionId == cAgentData.SessionID) + if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) + // Only warn for now + m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", + childAgentUpdate.UUID, cAgentData.SessionID); + + // I can't imagine *yet* why we would get an update if the agent is a root agent.. + // however to avoid a race condition crossing borders.. + if (childAgentUpdate.IsChildAgent) { - // I can't imagine *yet* why we would get an update if the agent is a root agent.. - // however to avoid a race condition crossing borders.. - if (childAgentUpdate.IsChildAgent) - { - uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); - uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); - uint tRegionX = RegionInfo.RegionLocX; - uint tRegionY = RegionInfo.RegionLocY; - //Send Data to ScenePresence - childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); - // Not Implemented: - //TODO: Do we need to pass the message on to one of our neighbors? - } + uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); + uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); + uint tRegionX = RegionInfo.RegionLocX; + uint tRegionY = RegionInfo.RegionLocY; + //Send Data to ScenePresence + childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); + // Not Implemented: + //TODO: Do we need to pass the message on to one of our neighbors? } - else - m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID); + return true; } -- cgit v1.1 From 6fcbf219da1d5095d6f37e8e44031db9ef108c39 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 9 Aug 2013 17:48:35 +0100 Subject: Comment back out seed dump code enabled in b1c26a56. Also adds a few teleport comments. --- .../EntityTransfer/EntityTransferModule.cs | 38 +++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 2f74253..87f0264 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1067,6 +1067,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // May still need to signal neighbours whether child agents may need closing irrespective of whether this // one needed closing. Neighbour regions also contain logic to prevent a close if a subsequent move or // teleport re-established the child connection. + // + // It may be possible to also close child agents after a pause but one needs to be very careful about + // race conditions between different regions on rapid teleporting (e.g. from A1 to a non-neighbour B, back + // to a neighbour A2 then off to a non-neighbour C. Also, closing child agents early may be more compatible + // with complicated scenarios where there a mixture of V1 and V2 teleports, though this is conjecture. It's + // easier to close immediately and greatly reduce the scope of race conditions if possible. sp.CloseChildAgents(newRegionX, newRegionY); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone @@ -1865,10 +1871,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer List newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); List oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); - Dump("Current Neighbors", neighbourHandles); - Dump("Previous Neighbours", previousRegionNeighbourHandles); - Dump("New Neighbours", newRegions); - Dump("Old Neighbours", oldRegions); +// Dump("Current Neighbors", neighbourHandles); +// Dump("Previous Neighbours", previousRegionNeighbourHandles); +// Dump("New Neighbours", newRegions); +// Dump("Old Neighbours", oldRegions); /// Update the scene presence's known regions here on this region sp.DropOldNeighbours(oldRegions); @@ -2180,18 +2186,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return handles; } - private void Dump(string msg, List handles) - { - m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); - foreach (ulong handle in handles) - { - uint x, y; - Utils.LongToUInts(handle, out x, out y); - x = x / Constants.RegionSize; - y = y / Constants.RegionSize; - m_log.InfoFormat("({0}, {1})", x, y); - } - } +// private void Dump(string msg, List handles) +// { +// m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); +// foreach (ulong handle in handles) +// { +// uint x, y; +// Utils.LongToUInts(handle, out x, out y); +// x = x / Constants.RegionSize; +// y = y / Constants.RegionSize; +// m_log.InfoFormat("({0}, {1})", x, y); +// } +// } #endregion -- cgit v1.1 From aec701972844d4e006bb5d50e7983b818fb39249 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 9 Aug 2013 17:57:24 +0100 Subject: Add missing file from b1c26a56 --- .../Framework/Scenes/ScenePresenceStateMachine.cs | 102 +++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs diff --git a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs new file mode 100644 index 0000000..dc3a212 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs @@ -0,0 +1,102 @@ +/* + * 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; + +namespace OpenSim.Region.Framework.Scenes +{ + /// + /// The possible states that a scene presence can be in. This is currently orthagonal to whether a scene presence + /// is root or child. + /// + /// + /// This is a state machine. + /// + /// [Entry] => Running + /// Running => Removing + /// Removing => Removed + /// + /// All other methods should only see the scene presence in running state - this is the normal operational state + /// Removed state occurs when the presence has been removed. This is the end state with no exit. + /// + public enum ScenePresenceState + { + Running, // Normal operation state. The scene presence is available. + Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient. + Removed, // The presence has been removed from the scene and is effectively dead. + // There is no exit from this state. + } + + internal class ScenePresenceStateMachine + { + private ScenePresence m_sp; + private ScenePresenceState m_state; + + internal ScenePresenceStateMachine(ScenePresence sp) + { + m_sp = sp; + m_state = ScenePresenceState.Running; + } + + internal ScenePresenceState GetState() + { + return m_state; + } + + /// + /// Updates the state of an agent that is already in transit. + /// + /// + /// + /// + /// Illegal transitions will throw an Exception + internal void SetState(ScenePresenceState newState) + { + bool transitionOkay = false; + + lock (this) + { + if (newState == ScenePresenceState.Removing && m_state == ScenePresenceState.Running) + transitionOkay = true; + else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing) + transitionOkay = true; + } + + if (!transitionOkay) + { + throw new Exception( + string.Format( + "Scene presence {0} is not allowed to move from state {1} to new state {2} in {3}", + m_sp.Name, m_state, newState, m_sp.Scene.Name)); + } + else + { + m_state = newState; + } + } + } +} \ No newline at end of file -- cgit v1.1 From bfdcdbb2f3f568c3ef829f30b8326dbc8a835f03 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 9 Aug 2013 17:59:58 +0100 Subject: Increase wait for source region to sent UpdateAgent to 10 seconds instead of 4. This is giving much better results on teleports between simulators over my lan where for some reason there is a pause before the receiving simulator processes UpdateAgent() At this point, v2 teleports between neighbour and non-neighbour regions on a single simulator and between v2 simulators and between a v1 and v2 simulator are working okay for me in different scenarios (e.g. simple teleport, teleport back to original quickly and re-teleport, teleport back to neighbour and re-teleport. etc.) --- 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 aac80f7..69339b7 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1355,7 +1355,7 @@ namespace OpenSim.Region.Framework.Scenes private bool WaitForUpdateAgent(IClientAPI client) { // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero - int count = 20; + int count = 50; while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) { m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); -- cgit v1.1 From 23ca1f859e20e537572cb774943784d50d3cacb8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 9 Aug 2013 18:27:26 +0100 Subject: minor: Consistently log IOCP for IO completion thread startup log information instead of mixing this with "IO Completion Threads" --- OpenSim/Region/Application/Application.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index 2e155ec..3a4e5df 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -142,19 +142,19 @@ namespace OpenSim if (iocpThreads < iocpThreadsMin) { iocpThreads = iocpThreadsMin; - m_log.InfoFormat("[OPENSIM MAIN]: Bumping up max IO completion threads to {0}",iocpThreads); + 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 if ( iocpThreads > iocpThreadsMax ) { iocpThreads = iocpThreadsMax; - m_log.InfoFormat("[OPENSIM MAIN]: Limiting max IO completion threads to {0}",iocpThreads); + 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 if ( System.Threading.ThreadPool.SetMaxThreads(workerThreads, iocpThreads) ) { m_log.InfoFormat( - "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IO completion threads", + "[OPENSIM MAIN]: Threadpool set to {0} max worker threads and {1} max IOCP threads", workerThreads, iocpThreads); } else -- cgit v1.1 From 216f5afe54576c4852974b8479ac95654dc9e08e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 10 Aug 2013 09:09:52 -0700 Subject: Stats treaking. Update ToOSDMap for Stat and PercentageStat to return all the various numbers that have been added to the console output. Break out EventHistogram from CounterStat. --- OpenSim/Framework/Monitoring/Stats/CounterStat.cs | 150 ++---------------- .../Framework/Monitoring/Stats/EventHistogram.cs | 173 +++++++++++++++++++++ .../Framework/Monitoring/Stats/PercentageStat.cs | 16 ++ OpenSim/Framework/Monitoring/Stats/Stat.cs | 46 ++++-- 4 files changed, 235 insertions(+), 150 deletions(-) create mode 100755 OpenSim/Framework/Monitoring/Stats/EventHistogram.cs diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs index 04442c3..318cf1c 100755 --- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs @@ -34,142 +34,6 @@ using OpenMetaverse.StructuredData; namespace OpenSim.Framework.Monitoring { -// Create a time histogram of events. The histogram is built in a wrap-around -// array of equally distributed buckets. -// For instance, a minute long histogram of second sized buckets would be: -// new EventHistogram(60, 1000) -public class EventHistogram -{ - private int m_timeBase; - private int m_numBuckets; - private int m_bucketMilliseconds; - private int m_lastBucket; - private int m_totalHistogramMilliseconds; - private long[] m_histogram; - private object histoLock = new object(); - - public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) - { - m_numBuckets = numberOfBuckets; - m_bucketMilliseconds = millisecondsPerBucket; - m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; - - m_histogram = new long[m_numBuckets]; - Zero(); - m_lastBucket = 0; - m_timeBase = Util.EnvironmentTickCount(); - } - - public void Event() - { - this.Event(1); - } - - // Record an event at time 'now' in the histogram. - public void Event(int cnt) - { - lock (histoLock) - { - // The time as displaced from the base of the histogram - int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); - - // If more than the total time of the histogram, we just start over - if (bucketTime > m_totalHistogramMilliseconds) - { - Zero(); - m_lastBucket = 0; - m_timeBase = Util.EnvironmentTickCount(); - } - else - { - // To which bucket should we add this event? - int bucket = bucketTime / m_bucketMilliseconds; - - // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. - while (bucket != m_lastBucket) - { - // Zero from just after the last bucket to the new bucket or the end - for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) - { - m_histogram[jj] = 0; - } - m_lastBucket = bucket; - // If the new bucket is off the end, wrap around to the beginning - if (bucket > m_numBuckets) - { - bucket -= m_numBuckets; - m_lastBucket = 0; - m_histogram[m_lastBucket] = 0; - m_timeBase += m_totalHistogramMilliseconds; - } - } - } - m_histogram[m_lastBucket] += cnt; - } - } - - // Get a copy of the current histogram - public long[] GetHistogram() - { - long[] ret = new long[m_numBuckets]; - lock (histoLock) - { - int indx = m_lastBucket + 1; - for (int ii = 0; ii < m_numBuckets; ii++, indx++) - { - if (indx >= m_numBuckets) - indx = 0; - ret[ii] = m_histogram[indx]; - } - } - return ret; - } - - public OSDMap GetHistogramAsOSDMap() - { - OSDMap ret = new OSDMap(); - - ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); - ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); - ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); - - // Compute a number for the first bucket in the histogram. - // This will allow readers to know how this histogram relates to any previously read histogram. - int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; - ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); - - ret.Add("Values", GetHistogramAsOSDArray()); - - return ret; - } - // Get a copy of the current histogram - public OSDArray GetHistogramAsOSDArray() - { - OSDArray ret = new OSDArray(m_numBuckets); - lock (histoLock) - { - int indx = m_lastBucket + 1; - for (int ii = 0; ii < m_numBuckets; ii++, indx++) - { - if (indx >= m_numBuckets) - indx = 0; - ret[ii] = OSD.FromLong(m_histogram[indx]); - } - } - return ret; - } - - // Zero out the histogram - public void Zero() - { - lock (histoLock) - { - for (int ii = 0; ii < m_numBuckets; ii++) - m_histogram[ii] = 0; - } - } -} - // A statistic that wraps a counter. // Built this way mostly so histograms and history can be created. public class CounterStat : Stat @@ -236,12 +100,18 @@ public class CounterStat : Stat // If there are any histograms, add a new field that is an array of histograms as OSDMaps if (m_histograms.Count > 0) { - OSDArray histos = new OSDArray(); - foreach (EventHistogram histo in m_histograms.Values) + lock (counterLock) { - histos.Add(histo.GetHistogramAsOSDMap()); + if (m_histograms.Count > 0) + { + OSDArray histos = new OSDArray(); + foreach (EventHistogram histo in m_histograms.Values) + { + histos.Add(histo.GetHistogramAsOSDMap()); + } + map.Add("Histograms", histos); + } } - map.Add("Histograms", histos); } return map; } diff --git a/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs new file mode 100755 index 0000000..f51f322 --- /dev/null +++ b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs @@ -0,0 +1,173 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Monitoring +{ +// Create a time histogram of events. The histogram is built in a wrap-around +// array of equally distributed buckets. +// For instance, a minute long histogram of second sized buckets would be: +// new EventHistogram(60, 1000) +public class EventHistogram +{ + private int m_timeBase; + private int m_numBuckets; + private int m_bucketMilliseconds; + private int m_lastBucket; + private int m_totalHistogramMilliseconds; + private long[] m_histogram; + private object histoLock = new object(); + + public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) + { + m_numBuckets = numberOfBuckets; + m_bucketMilliseconds = millisecondsPerBucket; + m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; + + m_histogram = new long[m_numBuckets]; + Zero(); + m_lastBucket = 0; + m_timeBase = Util.EnvironmentTickCount(); + } + + public void Event() + { + this.Event(1); + } + + // Record an event at time 'now' in the histogram. + public void Event(int cnt) + { + lock (histoLock) + { + // The time as displaced from the base of the histogram + int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); + + // If more than the total time of the histogram, we just start over + if (bucketTime > m_totalHistogramMilliseconds) + { + Zero(); + m_lastBucket = 0; + m_timeBase = Util.EnvironmentTickCount(); + } + else + { + // To which bucket should we add this event? + int bucket = bucketTime / m_bucketMilliseconds; + + // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. + while (bucket != m_lastBucket) + { + // Zero from just after the last bucket to the new bucket or the end + for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) + { + m_histogram[jj] = 0; + } + m_lastBucket = bucket; + // If the new bucket is off the end, wrap around to the beginning + if (bucket > m_numBuckets) + { + bucket -= m_numBuckets; + m_lastBucket = 0; + m_histogram[m_lastBucket] = 0; + m_timeBase += m_totalHistogramMilliseconds; + } + } + } + m_histogram[m_lastBucket] += cnt; + } + } + + // Get a copy of the current histogram + public long[] GetHistogram() + { + long[] ret = new long[m_numBuckets]; + lock (histoLock) + { + int indx = m_lastBucket + 1; + for (int ii = 0; ii < m_numBuckets; ii++, indx++) + { + if (indx >= m_numBuckets) + indx = 0; + ret[ii] = m_histogram[indx]; + } + } + return ret; + } + + public OSDMap GetHistogramAsOSDMap() + { + OSDMap ret = new OSDMap(); + + ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); + ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); + ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); + + // Compute a number for the first bucket in the histogram. + // This will allow readers to know how this histogram relates to any previously read histogram. + int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; + ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); + + ret.Add("Values", GetHistogramAsOSDArray()); + + return ret; + } + // Get a copy of the current histogram + public OSDArray GetHistogramAsOSDArray() + { + OSDArray ret = new OSDArray(m_numBuckets); + lock (histoLock) + { + int indx = m_lastBucket + 1; + for (int ii = 0; ii < m_numBuckets; ii++, indx++) + { + if (indx >= m_numBuckets) + indx = 0; + ret[ii] = OSD.FromLong(m_histogram[indx]); + } + } + return ret; + } + + // Zero out the histogram + public void Zero() + { + lock (histoLock) + { + for (int ii = 0; ii < m_numBuckets; ii++) + m_histogram[ii] = 0; + } + } +} + +} diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs index 60bed55..55ddf06 100644 --- a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs @@ -29,6 +29,8 @@ using System; using System.Collections.Generic; using System.Text; +using OpenMetaverse.StructuredData; + namespace OpenSim.Framework.Monitoring { public class PercentageStat : Stat @@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring return sb.ToString(); } + + // PercentageStat is a basic stat plus percent calc + public override OSDMap ToOSDMap() + { + // Get the foundational instance + OSDMap map = base.ToOSDMap(); + + map["StatType"] = "PercentageStat"; + + map.Add("Antecedent", OSD.FromLong(Antecedent)); + map.Add("Consequent", OSD.FromLong(Consequent)); + + return map; + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index ffd5132..2b34493 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs @@ -241,6 +241,8 @@ namespace OpenSim.Framework.Monitoring public virtual OSDMap ToOSDMap() { OSDMap ret = new OSDMap(); + ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat + ret.Add("Category", OSD.FromString(Category)); ret.Add("Container", OSD.FromString(Container)); ret.Add("ShortName", OSD.FromString(ShortName)); @@ -248,26 +250,36 @@ namespace OpenSim.Framework.Monitoring ret.Add("Description", OSD.FromString(Description)); ret.Add("UnitName", OSD.FromString(UnitName)); ret.Add("Value", OSD.FromReal(Value)); - ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat + + double lastChangeOverTime, averageChangeOverTime; + if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) + { + ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime)); + ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime)); + } return ret; } - protected void AppendMeasuresOfInterest(StringBuilder sb) + // Compute the averages over time and return same. + // Return 'true' if averages were actually computed. 'false' if no average info. + public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime) { - if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) - == MeasuresOfInterest.AverageChangeOverTime) + bool ret = false; + lastChangeOverTime = 0; + averageChangeOverTime = 0; + + if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime) { double totalChange = 0; - double lastChangeOverTime = 0; double? penultimateSample = null; double? lastSample = null; lock (m_samples) { -// m_log.DebugFormat( -// "[STAT]: Samples for {0} are {1}", -// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); + // m_log.DebugFormat( + // "[STAT]: Samples for {0} are {1}", + // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); foreach (double s in m_samples) { @@ -280,13 +292,27 @@ namespace OpenSim.Framework.Monitoring } if (lastSample != null && penultimateSample != null) - lastChangeOverTime + { + lastChangeOverTime = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); + } int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; - double averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); + averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); + ret = true; + } + + return ret; + } + protected void AppendMeasuresOfInterest(StringBuilder sb) + { + double lastChangeOverTime = 0; + double averageChangeOverTime = 0; + + if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) + { sb.AppendFormat( ", {0:0.##}{1}/s, {2:0.##}{3}/s", lastChangeOverTime, -- cgit v1.1 From b64d3ecaed2c4cc0ffab2e44d02745de4e8f5717 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 12 Aug 2013 18:15:12 +0100 Subject: Create TestSameSimulatorNeighbouringRegionsTeleportV2() regression test for V2 transfer protocol. --- .../Attachments/Tests/AttachmentsModuleTests.cs | 113 ++++++++++++++++++++- OpenSim/Tests/Common/Mock/TestClient.cs | 26 +++-- 2 files changed, 130 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 4ecae73..f4bf6b3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -799,7 +799,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests } [Test] - public void TestSameSimulatorNeighbouringRegionsTeleport() + public void TestSameSimulatorNeighbouringRegionsTeleportV1() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -904,5 +904,116 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Check events Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); } + + [Test] + public void TestSameSimulatorNeighbouringRegionsTeleportV2() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + BaseHttpServer httpServer = new BaseHttpServer(99999); + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; + + AttachmentsModule attModA = new AttachmentsModule(); + AttachmentsModule attModB = new AttachmentsModule(); + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules( + sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule()); + SceneHelpers.SetupSceneModules( + sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + + ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); + + Assert.That(destinationTestClients.Count, Is.EqualTo(1)); + Assert.That(destinationTestClients[0], Is.Not.Null); + + InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); + + sceneA.AttachmentsModule.RezSingleAttachmentFromInventory( + beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This + // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to + // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt + // Both these operations will occur on different threads and will wait for each other. + // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 + // test protocol, where we are trying to avoid unpredictable async operations in regression tests. + ((TestClient)beforeTeleportSp.ControllingClient).OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) + => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); + + m_numberOfAttachEventsFired = 0; + sceneA.RequestTeleportLocation( + beforeTeleportSp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + // Check attachments have made it into sceneB + ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); + + // This is appearance data, as opposed to actually rezzed attachments + List sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments(); + Assert.That(sceneBAttachments.Count, Is.EqualTo(1)); + Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID)); + Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); + Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment + List actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments(); + Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1)); + SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; + Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); + Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); + + Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check attachments have been removed from sceneA + ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID); + + // Since this is appearance data, it is still present on the child avatar! + List sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments(); + Assert.That(sceneAAttachments.Count, Is.EqualTo(1)); + Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment, which should no longer exist + List actualSceneAAttachments = afterTeleportSceneASp.GetAttachments(); + Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); + + Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); + + // Check events + Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); + } } } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index f7220d7..9370102 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -61,8 +61,13 @@ namespace OpenSim.Tests.Common.Mock // Test client specific events - for use by tests to implement some IClientAPI behaviour. public event Action OnReceivedMoveAgentIntoRegion; public event Action OnTestClientInformClientOfNeighbour; + public event TestClientOnSendRegionTeleportDelegate OnTestClientSendRegionTeleport; public event Action OnReceivedInstantMessage; + public delegate void TestClientOnSendRegionTeleportDelegate( + ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL); + // disable warning: public events, part of the public API #pragma warning disable 67 @@ -472,7 +477,8 @@ namespace OpenSim.Tests.Common.Mock public void CompleteMovement() { - OnCompleteMovementToRegion(this, true); + if (OnCompleteMovementToRegion != null) + OnCompleteMovementToRegion(this, true); } /// @@ -608,21 +614,25 @@ namespace OpenSim.Tests.Common.Mock OnTestClientInformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint); } - public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, - uint locationID, uint flags, string capsURL) + public virtual void SendRegionTeleport( + ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, + uint locationID, uint flags, string capsURL) { - m_log.DebugFormat("[TEST CLIENT]: Received SendRegionTeleport"); + m_log.DebugFormat( + "[TEST CLIENT]: Received SendRegionTeleport for {0} {1} on {2}", m_firstName, m_lastName, m_scene.Name); CapsSeedUrl = capsURL; - // We don't do this here so that the source region can complete processing first in a single-threaded - // regression test scenario. The test itself will have to call CompleteTeleportClientSide() after a teleport - // CompleteTeleportClientSide(); + if (OnTestClientSendRegionTeleport != null) + OnTestClientSendRegionTeleport( + regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL); } public virtual void SendTeleportFailed(string reason) { - m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason); + m_log.DebugFormat( + "[TEST CLIENT]: Teleport failed for {0} {1} on {2} with reason {3}", + m_firstName, m_lastName, m_scene.Name, reason); } public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, -- cgit v1.1 From e5b1688913d0fb9e72f67d0b476778a733ddb4b5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 12 Aug 2013 18:48:18 +0100 Subject: Add none behaviour to pCampbot when one wants bots to just stand around --- OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs | 43 ++++++++++++++++++++++ OpenSim/Tools/pCampBot/BotManager.cs | 17 +++++---- OpenSim/Tools/pCampBot/pCampBot.cs | 7 ++-- 3 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs diff --git a/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs new file mode 100644 index 0000000..9cf8a54 --- /dev/null +++ b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs @@ -0,0 +1,43 @@ +/* + * 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 OpenMetaverse; +using System; +using System.Collections.Generic; +using System.Linq; +using pCampBot.Interfaces; + +namespace pCampBot +{ + /// + /// Do nothing + /// + public class NoneBehaviour : AbstractBehaviour + { + public NoneBehaviour() { Name = "None"; } + } +} \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index d615b3f..1a46380 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -177,18 +177,21 @@ namespace pCampBot // We must give each bot its own list of instantiated behaviours since they store state. List behaviours = new List(); - // Hard-coded for now - if (behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - + // Hard-coded for now + if (behaviourSwitches.Contains("c")) + behaviours.Add(new CrossBehaviour()); + if (behaviourSwitches.Contains("g")) behaviours.Add(new GrabbingBehaviour()); + + if (behaviourSwitches.Contains("n")) + behaviours.Add(new NoneBehaviour()); + + if (behaviourSwitches.Contains("p")) + behaviours.Add(new PhysicsBehaviour()); if (behaviourSwitches.Contains("t")) behaviours.Add(new TeleportBehaviour()); - - if (behaviourSwitches.Contains("c")) - behaviours.Add(new CrossBehaviour()); StartBot(this, behaviours, firstName, lastName, password, loginUri); } diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index 9e82577..2707a49 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -123,9 +123,10 @@ namespace pCampBot " -password password for the bots\n" + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" + " current options are:\n" + - " p (physics)\n" + - " g (grab)\n" + - " t (teleport)\n" + + " p (physics - bots constantly move and jump around)\n" + + " g (grab - bots randomly click prims whether set clickable or not)\n" + + " n (none - bots do nothing)\n" + + " t (teleport - bots regularly teleport between regions on the grid)\n" + // " c (cross)" + " -wear set appearance folder to load from (default: no)\n" + " -h, -help show this message"); -- cgit v1.1 From de6ad380f659edbc102e9bde01033acd19034c2d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 12 Aug 2013 19:31:45 +0100 Subject: Get rid of issue where removing NPCs would through an exception by routing close through Scene.IncomingCloseAgent() and NPCAvatar.Close() rather than directly to Scene.RemoveClient(). This exception was actually harmless since it occurred at the very last stage of the remove client process. --- OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 69189b3..c26fdfc 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -385,7 +385,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC m_log.DebugFormat("[NPC MODULE]: Found {0} {1} to remove", agentID, av.Name); */ - scene.RemoveClient(agentID, false); + + scene.IncomingCloseAgent(agentID, false); +// scene.RemoveClient(agentID, false); m_avatars.Remove(agentID); /* m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}", -- cgit v1.1 From f3edc0d8b795f665dcf2ea2feb2b7886c8a451e1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 12 Aug 2013 19:38:23 +0100 Subject: minor: Extend warning message when adding trying to add an event for a client without a queue to include the event message name. --- .../ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index d7afe1a..c28ba94 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -229,7 +229,12 @@ namespace OpenSim.Region.ClientStack.Linden queue.Enqueue(ev); } else - m_log.WarnFormat("[EVENTQUEUE]: (Enqueue) No queue found for agent {0} in region {1}", avatarID, m_scene.RegionInfo.RegionName); + { + OSDMap evMap = (OSDMap)ev; + m_log.WarnFormat( + "[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}", + avatarID, evMap["message"], m_scene.Name); + } } catch (NullReferenceException e) { @@ -365,14 +370,14 @@ namespace OpenSim.Region.ClientStack.Linden OSDMap ev = (OSDMap)element; m_log.DebugFormat( "Eq OUT {0,-30} to {1,-20} {2,-20}", - ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); + ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.Name); } } public Hashtable GetEvents(UUID requestID, UUID pAgentId) { if (DebugLevel >= 2) - m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); + m_log.WarnFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.Name); Queue queue = GetQueue(pAgentId); if (queue == null) -- cgit v1.1 From 377fe63c60b6632777da5f0a8a0c4c2d32a1f4ac Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 12 Aug 2013 21:02:50 +0100 Subject: Don't try and send group updates to NPCs via event queue, since NPCs have no event queue. I think there is an argument for sending this information to NPCs anyway since in some cases it appears a lot easier to write server-side bots by hooking into such internal events. However, would need to stop event messages building up on NPC queues if they are never retrieved. --- OpenSim/Addons/Groups/GroupsModule.cs | 10 +++++++--- .../Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenSim/Addons/Groups/GroupsModule.cs b/OpenSim/Addons/Groups/GroupsModule.cs index 830c671..b0493fa 100644 --- a/OpenSim/Addons/Groups/GroupsModule.cs +++ b/OpenSim/Addons/Groups/GroupsModule.cs @@ -1223,12 +1223,16 @@ namespace OpenSim.Groups { if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + // NPCs currently don't have a CAPs structure or event queues. There is a strong argument for conveying this information + // to them anyway since it makes writing server-side bots a lot easier, but for now we don't do anything. + if (remoteClient.SceneAgent.PresenceType == PresenceType.Npc) + return; + OSDArray AgentData = new OSDArray(1); OSDMap AgentDataMap = new OSDMap(1); AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); AgentData.Add(AgentDataMap); - OSDArray GroupData = new OSDArray(data.Length); OSDArray NewGroupData = new OSDArray(data.Length); @@ -1274,8 +1278,7 @@ namespace OpenSim.Groups if (queue != null) { queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient)); - } - + } } private void SendScenePresenceUpdate(UUID AgentID, string Title) @@ -1337,6 +1340,7 @@ namespace OpenSim.Groups GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, dataForAgentID); SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipArray); + //remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipArray); if (remoteClient.AgentId == dataForAgentID) remoteClient.RefreshGroupMembership(); diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs index f4734b7..d744a14 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs @@ -1212,7 +1212,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); AgentData.Add(AgentDataMap); - OSDArray GroupData = new OSDArray(data.Length); OSDArray NewGroupData = new OSDArray(data.Length); -- cgit v1.1 From 2c31fe4614fc193f2600b36eac892ceee86f61e0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 12 Aug 2013 13:44:53 -0700 Subject: BulletSim: add check in avatar stair step code to verify the collision is not with a volume detect object. This fixes a problem of avatars trying to step over a volume detect object that they collide with. This appeared as the avatar popping up as it started to step up but then continuing on since the object wasn't physically interacting. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 33 +++++++++++++--------- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 1 + .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 1 + OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 4 +++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 0f11c4a..5f232a4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -311,21 +311,28 @@ public class BSActorAvatarMove : BSActor // Don't care about collisions with the terrain if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) { - OMV.Vector3 touchPosition = kvp.Value.Position; - m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", - m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); - if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) + BSPhysObject collisionObject; + if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject)) { - // This contact is within the 'near the feet' range. - // The normal should be our contact point to the object so it is pointing away - // thus the difference between our facing orientation and the normal should be small. - OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; - OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); - float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); - if (diff < BSParam.AvatarStepApproachFactor) + if (!collisionObject.IsVolumeDetect) { - if (highestTouchPosition.Z < touchPosition.Z) - highestTouchPosition = touchPosition; + OMV.Vector3 touchPosition = kvp.Value.Position; + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", + m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); + if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) + { + // This contact is within the 'near the feet' range. + // The normal should be our contact point to the object so it is pointing away + // thus the difference between our facing orientation and the normal should be small. + OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; + OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); + float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); + if (diff < BSParam.AvatarStepApproachFactor) + { + if (highestTouchPosition.Z < touchPosition.Z) + highestTouchPosition = touchPosition; + } + } } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 9af3dce..d584782 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -404,6 +404,7 @@ public sealed class BSCharacter : BSPhysObject // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more public override void SetVolumeDetect(int param) { return; } + public override bool IsVolumeDetect { get { return false; } } public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 0704591..27caf62 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -175,6 +175,7 @@ public abstract class BSPhysObject : PhysicsActor public abstract bool IsSolid { get; } public abstract bool IsStatic { get; } public abstract bool IsSelected { get; } + public abstract bool IsVolumeDetect { get; } // Materialness public MaterialAttributes.Material Material { get; private set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index a0b6abc..6b5dea3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -617,6 +617,10 @@ public class BSPrim : BSPhysObject } return; } + public override bool IsVolumeDetect + { + get { return _isVolumeDetect; } + } public override void SetMaterial(int material) { base.SetMaterial(material); -- cgit v1.1 From c49ea491a3d081ff788cc33ca29030690db3a939 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 12 Aug 2013 22:49:17 +0100 Subject: Make show bots pCampbot console command print connected, connecting, etc. bot totals at end. --- OpenSim/Tools/pCampBot/BotManager.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 1a46380..74bd36a 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -330,17 +330,30 @@ namespace pCampBot string outputFormat = "{0,-30} {1, -30} {2,-14}"; MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status"); + Dictionary totals = new Dictionary(); + foreach (object o in Enum.GetValues(typeof(ConnectionState))) + totals[(ConnectionState)o] = 0; + lock (m_lBot) { foreach (Bot pb in m_lBot) { Simulator currentSim = pb.Client.Network.CurrentSim; + totals[pb.ConnectionState]++; MainConsole.Instance.OutputFormat( outputFormat, pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState); } } + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + + foreach (KeyValuePair kvp in totals) + cdl.AddRow(kvp.Key, kvp.Value); + + + MainConsole.Instance.OutputFormat("\n{0}", cdl.ToString()); } /* -- cgit v1.1 From a90351cd2ce2f1a3245244d46db7d98102729a58 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 13 Aug 2013 11:49:09 -0700 Subject: Remove exception when printing error for failure removing script state. --- OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 229180f..6264f5d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -525,7 +525,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_log.Warn( string.Format( "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ", - ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name), + savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name), e); } } -- cgit v1.1 From e311f902ffeb0c1f36d6d4288e65d965d13a9fbe Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 13 Aug 2013 20:13:12 +0100 Subject: minor: Eliminate one of the duplicate 'have's in the HG message telling the user if no GroupsServerURI has been given in user data by the home grid --- OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index c33168c..4642b2a 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -404,7 +404,7 @@ namespace OpenSim.Groups url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI"); if (url == string.Empty) { - reason = "You don't have have an accessible groups server in your home world. You membership to this group in only within this grid."; + reason = "You don't have an accessible groups server in your home world. You membership to this group in only within this grid."; return true; } -- cgit v1.1 From 5933f9448d839b9f6db391dedc493bb5cc951d66 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 13 Aug 2013 23:54:50 +0100 Subject: Add a SendAgentUpdates setting to a new pCampbot.ini.example file which can control whether bots send agent updates pCampbot.ini.example is used by copying to pCampbot.ini, like other ini files --- OpenSim/Tools/pCampBot/Bot.cs | 20 +------------------- OpenSim/Tools/pCampBot/BotManager.cs | 35 ++++++++++++++++++++--------------- OpenSim/Tools/pCampBot/pCampBot.cs | 35 +++++++++++++++++++++++++++++------ bin/pCampbot.ini.example | 9 +++++++++ 4 files changed, 59 insertions(+), 40 deletions(-) create mode 100644 bin/pCampbot.ini.example diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 9821180..c56d29b 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -64,11 +64,6 @@ namespace pCampBot public BotManager Manager { get; private set; } /// - /// Bot config, passed from BotManager. - /// - private IConfig startupConfig; - - /// /// Behaviours implemented by this bot. /// /// @@ -153,9 +148,6 @@ namespace pCampBot LoginUri = loginUri; Manager = bm; - startupConfig = bm.Config; - readconfig(); - Behaviours = behaviours; } @@ -177,14 +169,6 @@ namespace pCampBot } /// - /// Read the Nini config and initialize - /// - public void readconfig() - { - wear = startupConfig.GetString("wear", "no"); - } - - /// /// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes. /// public void shutdown() @@ -207,6 +191,7 @@ namespace pCampBot Client.Settings.AVATAR_TRACKING = false; Client.Settings.OBJECT_TRACKING = false; Client.Settings.SEND_AGENT_THROTTLE = true; + Client.Settings.SEND_AGENT_UPDATES = false; Client.Settings.SEND_PINGS = true; Client.Settings.STORE_LAND_PATCHES = false; Client.Settings.USE_ASSET_CACHE = false; @@ -481,9 +466,6 @@ namespace pCampBot public void Objects_NewPrim(object sender, PrimEventArgs args) { -// if (Name.EndsWith("4")) -// throw new Exception("Aaargh"); - Primitive prim = args.Prim; if (prim != null) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 74bd36a..16b02b9 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -63,6 +63,11 @@ namespace pCampBot protected CommandConsole m_console; /// + /// Controls whether bots start out sending agent updates on connection. + /// + public bool BotsInitSendAgentUpdates { get; set; } + + /// /// Created bots, whether active or inactive. /// protected List m_lBot; @@ -73,11 +78,6 @@ namespace pCampBot public Random Rng { get; private set; } /// - /// Overall configuration. - /// - public IConfig Config { get; private set; } - - /// /// Track the assets we have and have not received so we don't endlessly repeat requests. /// public Dictionary AssetsReceived { get; private set; } @@ -92,6 +92,8 @@ namespace pCampBot /// public BotManager() { + BotsInitSendAgentUpdates = true; + LoginDelay = DefaultLoginDelay; Rng = new Random(Environment.TickCount); @@ -148,18 +150,17 @@ namespace pCampBot /// /// How many bots to start up /// The configuration for the bots to use - public void dobotStartup(int botcount, IConfig cs) + public void dobotStartup(int botcount, IConfig startupConfig) { - Config = cs; - - string firstName = cs.GetString("firstname"); - string lastNameStem = cs.GetString("lastname"); - string password = cs.GetString("password"); - string loginUri = cs.GetString("loginuri"); + string firstName = startupConfig.GetString("firstname"); + string lastNameStem = startupConfig.GetString("lastname"); + string password = startupConfig.GetString("password"); + string loginUri = startupConfig.GetString("loginuri"); + string wearSetting = startupConfig.GetString("wear", "no"); HashSet behaviourSwitches = new HashSet(); Array.ForEach( - cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); + startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); MainConsole.Instance.OutputFormat( "[BOT MANAGER]: Starting {0} bots connecting to {1}, named {2} {3}_", @@ -169,6 +170,7 @@ namespace pCampBot lastNameStem); MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); + MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", BotsInitSendAgentUpdates); for (int i = 0; i < botcount; i++) { @@ -193,7 +195,7 @@ namespace pCampBot if (behaviourSwitches.Contains("t")) behaviours.Add(new TeleportBehaviour()); - StartBot(this, behaviours, firstName, lastName, password, loginUri); + StartBot(this, behaviours, firstName, lastName, password, loginUri, wearSetting); } } @@ -226,15 +228,18 @@ namespace pCampBot /// Last name /// Password /// Login URI + /// public void StartBot( BotManager bm, List behaviours, - string firstName, string lastName, string password, string loginUri) + string firstName, string lastName, string password, string loginUri, string wearSetting) { MainConsole.Instance.OutputFormat( "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}", firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri); + pb.wear = wearSetting; + pb.Client.Settings.SEND_AGENT_UPDATES = BotsInitSendAgentUpdates; pb.OnConnected += handlebotEvent; pb.OnDisconnected += handlebotEvent; diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index 2707a49..e43037d 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -26,6 +26,7 @@ */ using System; +using System.IO; using System.Reflection; using System.Threading; using log4net; @@ -50,28 +51,50 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public const string ConfigFileName = "pCampbot.ini"; + [STAThread] public static void Main(string[] args) { XmlConfigurator.Configure(); - IConfig config = ParseConfig(args); - if (config.Get("help") != null || config.Get("loginuri") == null) + IConfig commandLineConfig = ParseConfig(args); + if (commandLineConfig.Get("help") != null || commandLineConfig.Get("loginuri") == null) { Help(); } - else if (config.Get("firstname") == null || config.Get("lastname") == null || config.Get("password") == null) + else if ( + commandLineConfig.Get("firstname") == null + || commandLineConfig.Get("lastname") == null + || commandLineConfig.Get("password") == null) { Console.WriteLine("ERROR: You must supply a firstname, lastname and password for the bots."); } else { - int botcount = config.GetInt("botcount", 1); - BotManager bm = new BotManager(); + string iniFilePath = Path.GetFullPath(Path.Combine(Util.configDir(), ConfigFileName)); + + if (File.Exists(iniFilePath)) + { + m_log.InfoFormat("[PCAMPBOT]: Reading configuration settings from {0}", iniFilePath); + + IConfigSource configSource = new IniConfigSource(iniFilePath); + + IConfig botConfig = configSource.Configs["Bot"]; + + if (botConfig != null) + { + bm.BotsInitSendAgentUpdates + = botConfig.GetBoolean("SendAgentUpdates", bm.BotsInitSendAgentUpdates); + } + } + + int botcount = commandLineConfig.GetInt("botcount", 1); + //startup specified number of bots. 1 is the default - Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, config)); + Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, commandLineConfig)); startBotThread.Name = "Initial start bots thread"; startBotThread.Start(); diff --git a/bin/pCampbot.ini.example b/bin/pCampbot.ini.example new file mode 100644 index 0000000..81cdcf4 --- /dev/null +++ b/bin/pCampbot.ini.example @@ -0,0 +1,9 @@ +; This is the example config file for pCampbot +; To use it, copy this file to pCampbot.ini and change settings if required + +[Bot] + ; Control whether bots should regularly send agent updates + ; Not sending agent updates will reduce CPU requirements for pCampbot but greatly + ; reduce the realism compared to viewers which are constantly sending AgentUpdates UDP packets + ; Defaults to true. + SendAgentUpdates = true -- cgit v1.1 From 0feb5da31e0986d46ea06ffb9804cf30f700e119 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 13 Aug 2013 21:06:24 -0700 Subject: BulletSim: move the creation of the avatar movement actor creating to taint time. Attempt to fix a problem of teleporting within the same region where the remove and addition of the physical avatar occasionally ends up with a non-moving avatar. --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index d584782..502f85f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -89,13 +89,6 @@ public sealed class BSCharacter : BSPhysObject // set _avatarVolume and _mass based on capsule size, _density and Scale ComputeAvatarVolumeAndMass(); - // The avatar's movement is controlled by this motor that speeds up and slows down - // the avatar seeking to reach the motor's target speed. - // This motor runs as a prestep action for the avatar so it will keep the avatar - // standing as well as moving. Destruction of the avatar will destroy the pre-step action. - m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); - PhysicalActors.Add(AvatarMoveActorName, m_moveActor); - DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}", LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos); @@ -106,6 +99,13 @@ public sealed class BSCharacter : BSPhysObject // New body and shape into PhysBody and PhysShape PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); + // The avatar's movement is controlled by this motor that speeds up and slows down + // the avatar seeking to reach the motor's target speed. + // This motor runs as a prestep action for the avatar so it will keep the avatar + // standing as well as moving. Destruction of the avatar will destroy the pre-step action. + m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); + PhysicalActors.Add(AvatarMoveActorName, m_moveActor); + SetPhysicalProperties(); }); return; -- cgit v1.1 From 2146b201694a128764e66680d151b68d83610880 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 16:51:51 +0100 Subject: Add the ability to explicitly specify a login start location to pCampbot via the -start parameter --- OpenSim/Tools/pCampBot/Bot.cs | 7 +++-- OpenSim/Tools/pCampBot/BotManager.cs | 60 +++++++++++++++++++++++++++++++----- OpenSim/Tools/pCampBot/pCampBot.cs | 36 ++++++++++++---------- 3 files changed, 76 insertions(+), 27 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index c56d29b..79344e8 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -97,6 +97,8 @@ namespace pCampBot public string Name { get; private set; } public string Password { get; private set; } public string LoginUri { get; private set; } + public string StartLocation { get; private set; } + public string saveDir; public string wear; @@ -132,7 +134,7 @@ namespace pCampBot /// public Bot( BotManager bm, List behaviours, - string firstName, string lastName, string password, string loginUri) + string firstName, string lastName, string password, string startLocation, string loginUri) { ConnectionState = ConnectionState.Disconnected; @@ -146,6 +148,7 @@ namespace pCampBot Name = string.Format("{0} {1}", FirstName, LastName); Password = password; LoginUri = loginUri; + StartLocation = startLocation; Manager = bm; Behaviours = behaviours; @@ -209,7 +212,7 @@ namespace pCampBot ConnectionState = ConnectionState.Connecting; - if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name")) + if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "Your name")) { ConnectionState = ConnectionState.Connected; diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 16b02b9..57bd737 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -65,7 +65,7 @@ namespace pCampBot /// /// Controls whether bots start out sending agent updates on connection. /// - public bool BotsInitSendAgentUpdates { get; set; } + public bool InitBotSendAgentUpdates { get; set; } /// /// Created bots, whether active or inactive. @@ -92,7 +92,7 @@ namespace pCampBot /// public BotManager() { - BotsInitSendAgentUpdates = true; + InitBotSendAgentUpdates = true; LoginDelay = DefaultLoginDelay; @@ -156,21 +156,25 @@ namespace pCampBot string lastNameStem = startupConfig.GetString("lastname"); string password = startupConfig.GetString("password"); string loginUri = startupConfig.GetString("loginuri"); + string startLocation = startupConfig.GetString("start", "last"); string wearSetting = startupConfig.GetString("wear", "no"); + string startUri = ParseInputStartLocationToUri(startLocation); + HashSet behaviourSwitches = new HashSet(); Array.ForEach( startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); MainConsole.Instance.OutputFormat( - "[BOT MANAGER]: Starting {0} bots connecting to {1}, named {2} {3}_", + "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_", botcount, loginUri, + startUri, firstName, lastNameStem); MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); - MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", BotsInitSendAgentUpdates); + MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates); for (int i = 0; i < botcount; i++) { @@ -195,8 +199,47 @@ namespace pCampBot if (behaviourSwitches.Contains("t")) behaviours.Add(new TeleportBehaviour()); - StartBot(this, behaviours, firstName, lastName, password, loginUri, wearSetting); + StartBot(this, behaviours, firstName, lastName, password, loginUri, startUri, wearSetting); + } + } + + /// + /// Parses the command line start location to a start string/uri that the login mechanism will recognize. + /// + /// + /// The input start location to URI. + /// + /// + /// Start location. + /// + private string ParseInputStartLocationToUri(string startLocation) + { + if (startLocation == "home" || startLocation == "last") + return startLocation; + + string regionName; + + // Just a region name or only one (!) extra component. Like a viewer, we will stick 128/128/0 on the end + Vector3 startPos = new Vector3(128, 128, 0); + + string[] startLocationComponents = startLocation.Split('/'); + + regionName = startLocationComponents[0]; + + if (startLocationComponents.Length >= 2) + { + float.TryParse(startLocationComponents[1], out startPos.X); + + if (startLocationComponents.Length >= 3) + { + float.TryParse(startLocationComponents[2], out startPos.Y); + + if (startLocationComponents.Length >= 4) + float.TryParse(startLocationComponents[3], out startPos.Z); + } } + + return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z); } // /// @@ -228,18 +271,19 @@ namespace pCampBot /// Last name /// Password /// Login URI + /// Location to start the bot. Can be "last", "home" or a specific sim name. /// public void StartBot( BotManager bm, List behaviours, - string firstName, string lastName, string password, string loginUri, string wearSetting) + string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting) { MainConsole.Instance.OutputFormat( "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}", firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); - Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri); + Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri); pb.wear = wearSetting; - pb.Client.Settings.SEND_AGENT_UPDATES = BotsInitSendAgentUpdates; + pb.Client.Settings.SEND_AGENT_UPDATES = InitBotSendAgentUpdates; pb.OnConnected += handlebotEvent; pb.OnDisconnected += handlebotEvent; diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index e43037d..9c9ed3b 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -86,8 +86,8 @@ namespace pCampBot if (botConfig != null) { - bm.BotsInitSendAgentUpdates - = botConfig.GetBoolean("SendAgentUpdates", bm.BotsInitSendAgentUpdates); + bm.InitBotSendAgentUpdates + = botConfig.GetBoolean("SendAgentUpdates", bm.InitBotSendAgentUpdates); } } @@ -119,6 +119,7 @@ namespace pCampBot cs.AddSwitch("Startup", "botcount", "n"); cs.AddSwitch("Startup", "loginuri", "l"); + cs.AddSwitch("Startup", "start", "s"); cs.AddSwitch("Startup", "firstname"); cs.AddSwitch("Startup", "lastname"); cs.AddSwitch("Startup", "password"); @@ -137,22 +138,23 @@ namespace pCampBot // name, to load an specific folder, or save, to save an avatar with some already existing wearables // worn to the folder MyAppearance/FirstName_LastName, and the load it. Console.WriteLine( - "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" + - "Spawns a set of bots to test an OpenSim region\n\n" + - " -l, -loginuri loginuri for sim to log into (required)\n" + - " -n, -botcount number of bots to start (default: 1)\n" + - " -firstname first name for the bots\n" + - " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" + - " -password password for the bots\n" + - " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" + - " current options are:\n" + - " p (physics - bots constantly move and jump around)\n" + - " g (grab - bots randomly click prims whether set clickable or not)\n" + - " n (none - bots do nothing)\n" + - " t (teleport - bots regularly teleport between regions on the grid)\n" + + "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" + + "Spawns a set of bots to test an OpenSim region\n\n" + + " -l, -loginuri loginuri for grid/standalone (required)\n" + + " -s, -start start location for bots. Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" + + " -n, -botcount number of bots to start (default: 1)\n" + + " -firstname first name for the bots\n" + + " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" + + " -password password for the bots\n" + + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" + + " current options are:\n" + + " p (physics - bots constantly move and jump around)\n" + + " g (grab - bots randomly click prims whether set clickable or not)\n" + + " n (none - bots do nothing)\n" + + " t (teleport - bots regularly teleport between regions on the grid)\n" // " c (cross)" + - " -wear set appearance folder to load from (default: no)\n" + - " -h, -help show this message"); + + " -wear set appearance folder to load from (default: no)\n" + + " -h, -help show this message.\n"); } } } -- cgit v1.1 From 3a62f39044403e7bf453c7b5b1fe825a48e908f3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 18:26:11 +0100 Subject: Add a -form switch to pCampbot to allow one to login a sequence of bots starting from numbers other than 0 --- OpenSim/Tools/pCampBot/BotManager.cs | 3 ++- OpenSim/Tools/pCampBot/pCampBot.cs | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 57bd737..0fdfa0e 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -157,6 +157,7 @@ namespace pCampBot string password = startupConfig.GetString("password"); string loginUri = startupConfig.GetString("loginuri"); string startLocation = startupConfig.GetString("start", "last"); + int fromBotNumber = startupConfig.GetInt("from", 0); string wearSetting = startupConfig.GetString("wear", "no"); string startUri = ParseInputStartLocationToUri(startLocation); @@ -178,7 +179,7 @@ namespace pCampBot for (int i = 0; i < botcount; i++) { - string lastName = string.Format("{0}_{1}", lastNameStem, i); + string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber); // We must give each bot its own list of instantiated behaviours since they store state. List behaviours = new List(); diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index 9c9ed3b..c8b6304 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -118,6 +118,7 @@ namespace pCampBot ArgvConfigSource cs = new ArgvConfigSource(args); cs.AddSwitch("Startup", "botcount", "n"); + cs.AddSwitch("Startup", "from", "f"); cs.AddSwitch("Startup", "loginuri", "l"); cs.AddSwitch("Startup", "start", "s"); cs.AddSwitch("Startup", "firstname"); @@ -137,15 +138,17 @@ namespace pCampBot // You can either say no, to not load anything, yes, to load one of the default wearables, a folder // name, to load an specific folder, or save, to save an avatar with some already existing wearables // worn to the folder MyAppearance/FirstName_LastName, and the load it. + Console.WriteLine( "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" + "Spawns a set of bots to test an OpenSim region\n\n" + " -l, -loginuri loginuri for grid/standalone (required)\n" - + " -s, -start start location for bots. Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" - + " -n, -botcount number of bots to start (default: 1)\n" + + " -s, -start optional start location for bots. Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" + " -firstname first name for the bots\n" + " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" + " -password password for the bots\n" + + " -n, -botcount optional number of bots to start (default: 1)\n" + + " -f, -from optional starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0)" + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" + " current options are:\n" + " p (physics - bots constantly move and jump around)\n" @@ -153,7 +156,7 @@ namespace pCampBot + " n (none - bots do nothing)\n" + " t (teleport - bots regularly teleport between regions on the grid)\n" // " c (cross)" + - + " -wear set appearance folder to load from (default: no)\n" + + " -wear optional folder from which to load appearance data, \"no\" if there is no such folder (default: no)\n" + " -h, -help show this message.\n"); } } -- cgit v1.1 From 97c514daa5a3b4e4137bf01b7bee3fffc13a75d7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 19:21:07 +0100 Subject: Shutdown a bot's actions by making it check for disconnecting state rather than aborting the thread. Aborting the thread appears to be causing shutdown issues. --- OpenSim/Tools/pCampBot/Bot.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 79344e8..dac8ccb 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -158,7 +158,7 @@ namespace pCampBot //add additional steps and/or things the bot should do private void Action() { - while (true) + while (ConnectionState != ConnectionState.Disconnecting) lock (Behaviours) Behaviours.ForEach( b => @@ -178,8 +178,8 @@ namespace pCampBot { ConnectionState = ConnectionState.Disconnecting; - if (m_actionThread != null) - m_actionThread.Abort(); +// if (m_actionThread != null) +// m_actionThread.Abort(); Client.Network.Logout(); } -- cgit v1.1 From fd519748e9c828e03468dc61b331115f07b3fadd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 19:35:02 +0100 Subject: Add method doc to Scene.RemoveClient() to ask any callers to use Scene.IncomingCloseAgent() instead. IncomingCloseAgent() now sets the scene presence state machine properly, which is necessary to avoid races between multiple sources of close. Hence, it's also necessary for everyone to consistently call IncomingCloseAgent() Calling RemoveClient() directly is currently generating an attention-grabbing exception though this right now this is harmless. --- OpenSim/Region/Framework/Scenes/Scene.cs | 12 ++++++++++++ OpenSim/Region/Framework/Scenes/SceneBase.cs | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a3bd388..d187377 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3382,6 +3382,18 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// Remove the given client from the scene. + /// + /// + /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead + /// to properly operate the state machine and avoid race conditions with other close requests (such as directly + /// from viewers). + /// + /// ID of agent to close + /// + /// Close the neighbour child agents associated with this client. + /// public override void RemoveClient(UUID agentID, bool closeChildAgents) { AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index d2097ea..5252b96 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -217,6 +217,19 @@ namespace OpenSim.Region.Framework.Scenes #region Add/Remove Agent/Avatar public abstract ISceneAgent AddNewClient(IClientAPI client, PresenceType type); + + /// + /// Remove the given client from the scene. + /// + /// + /// Only clientstack code should call this directly. All other code should call IncomingCloseAgent() instead + /// to properly operate the state machine and avoid race conditions with other close requests (such as directly + /// from viewers). + /// + /// ID of agent to close + /// + /// Close the neighbour child agents associated with this client. + /// public abstract void RemoveClient(UUID agentID, bool closeChildAgents); public bool TryGetScenePresence(UUID agentID, out object scenePresence) -- cgit v1.1 From 225cf0d0102d05721bd01120928b9d1d85c811a7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 19:53:10 +0100 Subject: Add pCampbot RequestObjectTextures ini setting to control whether textures are requested for received objects. --- OpenSim/Tools/pCampBot/BotManager.cs | 7 +++++++ OpenSim/Tools/pCampBot/pCampBot.cs | 2 ++ bin/pCampbot.ini.example | 10 ++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 0fdfa0e..5988584 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -68,6 +68,11 @@ namespace pCampBot public bool InitBotSendAgentUpdates { get; set; } /// + /// Controls whether bots request textures for the object information they receive + /// + public bool InitBotRequestObjectTextures { get; set; } + + /// /// Created bots, whether active or inactive. /// protected List m_lBot; @@ -93,6 +98,7 @@ namespace pCampBot public BotManager() { InitBotSendAgentUpdates = true; + InitBotRequestObjectTextures = true; LoginDelay = DefaultLoginDelay; @@ -176,6 +182,7 @@ namespace pCampBot MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates); + MainConsole.Instance.OutputFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures); for (int i = 0; i < botcount; i++) { diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index c8b6304..b02f917 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -88,6 +88,8 @@ namespace pCampBot { bm.InitBotSendAgentUpdates = botConfig.GetBoolean("SendAgentUpdates", bm.InitBotSendAgentUpdates); + bm.InitBotRequestObjectTextures + = botConfig.GetBoolean("RequestObjectTextures", bm.InitBotRequestObjectTextures); } } diff --git a/bin/pCampbot.ini.example b/bin/pCampbot.ini.example index 81cdcf4..f44feae 100644 --- a/bin/pCampbot.ini.example +++ b/bin/pCampbot.ini.example @@ -3,7 +3,13 @@ [Bot] ; Control whether bots should regularly send agent updates - ; Not sending agent updates will reduce CPU requirements for pCampbot but greatly - ; reduce the realism compared to viewers which are constantly sending AgentUpdates UDP packets + ; Not doing this will reduce CPU requirements for pCampbot but greatly + ; reduce the realism compared to viewers which are constantly sending AgentUpdates UDP packets. ; Defaults to true. SendAgentUpdates = true + + ; Control whether bots will requests textures when receiving object information + ; Not doing this will reduce CPU requirements for pCampbot but greatly + ; reduce the realism compared to viewers which requests such texture data if not already cached. + ; Defaults to true. + RequestObjectTextures = true -- cgit v1.1 From 2c67aa0f41193bf2271b75f060093f44819cdeae Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 21:07:29 +0100 Subject: If pCampbot has been asked to shutdown, don't carry on logging in queued bots --- OpenSim/Tools/pCampBot/BotManager.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 5988584..397a98e 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -52,6 +52,11 @@ namespace pCampBot public const int DefaultLoginDelay = 5000; /// + /// True if pCampbot is in the process of shutting down. + /// + public bool ShuttingDown { get; private set; } + + /// /// Delay between logins of multiple bots. /// /// TODO: This value needs to be configurable by a command line argument. @@ -186,6 +191,9 @@ namespace pCampBot for (int i = 0; i < botcount; i++) { + if (ShuttingDown) + break; + string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber); // We must give each bot its own list of instantiated behaviours since they store state. @@ -363,7 +371,9 @@ namespace pCampBot private void HandleShutdown(string module, string[] cmd) { - m_log.Info("[BOTMANAGER]: Shutting down bots"); + MainConsole.Instance.Output("Shutting down"); + + ShuttingDown = true; doBotShutdown(); } -- cgit v1.1 From 0d5680e9712a5362c23b0ef6e479654d67e99b8b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 22:07:22 +0100 Subject: Count any incoming packet that could not be recognized as an LLUDP packet as a malformed packet. Record this as stat clientstack..IncomingPacketsMalformedCount Used to detect if a simulator is receiving significant junk UDP Decimates the number of packets between which a warning is logged and prints the IP source of the last malformed packet when logging --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 65 +++++++++++++++------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index de2f9d4..553250c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -108,6 +108,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( + "IncomingPacketsMalformedCount", + "Number of inbound UDP packets that could not be recognized as LL protocol packets.", + "", + "", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = m_udpServer.IncomingMalformedPacketCount, + StatVerbosity.Info)); + + StatsManager.RegisterStat( + new Stat( "OutgoingUDPSendsCount", "Number of UDP sends performed", "", @@ -268,7 +281,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP public Socket Server { get { return null; } } - private int m_malformedCount = 0; // Guard against a spamming attack + /// + /// Record how many inbound packets could not be recognized as LLUDP packets. + /// + public int IncomingMalformedPacketCount { get; private set; } /// /// Record current outgoing client for monitoring purposes. @@ -1181,6 +1197,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; } + private void RecordMalformedInboundPacket(IPEndPoint endPoint) + { +// if (m_malformedCount < 100) +// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); + + IncomingMalformedPacketCount++; + + if ((IncomingMalformedPacketCount % 10000) == 0) + m_log.WarnFormat( + "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last malformed was from {1}", + IncomingMalformedPacketCount, endPoint); + } + public override void PacketReceived(UDPPacketBuffer buffer) { // Debugging/Profiling @@ -1202,6 +1231,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", // buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); + RecordMalformedInboundPacket(endPoint); + return; // Drop undersized packet } @@ -1220,6 +1251,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // "[LLUDPSERVER]: Dropping packet with malformed header received from {0} in {1}", // buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); + RecordMalformedInboundPacket(endPoint); + return; // Malformed header } @@ -1235,34 +1268,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Only allocate a buffer for zerodecoding if the packet is zerocoded ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); } - catch (MalformedDataException) - { - } - catch (IndexOutOfRangeException) - { -// m_log.WarnFormat( -// "[LLUDPSERVER]: Dropping short packet received from {0} in {1}", -// buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); - - return; // Drop short packet - } catch (Exception e) { - if (m_malformedCount < 100) + if (IncomingMalformedPacketCount < 100) m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); - - m_malformedCount++; - - if ((m_malformedCount % 100000) == 0) - m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); } // Fail-safe check if (packet == null) { - m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", - buffer.DataLength, buffer.RemoteEndPoint); - m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); + if (IncomingMalformedPacketCount < 100) + { + m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", + buffer.DataLength, buffer.RemoteEndPoint); + m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); + } + + RecordMalformedInboundPacket(endPoint); + return; } -- cgit v1.1 From 93dffe17773ee5af552ac64a7902f66d8acac1b3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 22:33:12 +0100 Subject: Add stat clientstack..IncomingPacketsOrphanedCount to record well-formed packets that were not initial connection packets and could not be associated with a connected viewer. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 33 +++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 553250c..102e581 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -121,6 +121,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP StatsManager.RegisterStat( new Stat( + "IncomingPacketsOrphanedCount", + "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.", + "", + "", + "clientstack", + scene.Name, + StatType.Pull, + MeasuresOfInterest.AverageChangeOverTime, + stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount, + StatVerbosity.Info)); + + StatsManager.RegisterStat( + new Stat( "OutgoingUDPSendsCount", "Number of UDP sends performed", "", @@ -287,6 +300,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP public int IncomingMalformedPacketCount { get; private set; } /// + /// Record how many inbound packets could not be associated with a simulator circuit. + /// + public int IncomingOrphanedPacketCount { get; private set; } + + /// /// Record current outgoing client for monitoring purposes. /// private IClientAPI m_currentOutgoingClient; @@ -1206,7 +1224,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if ((IncomingMalformedPacketCount % 10000) == 0) m_log.WarnFormat( - "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last malformed was from {1}", + "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", IncomingMalformedPacketCount, endPoint); } @@ -1279,9 +1297,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (IncomingMalformedPacketCount < 100) { - m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:", - buffer.DataLength, buffer.RemoteEndPoint); - m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); + m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", + buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); } RecordMalformedInboundPacket(endPoint); @@ -1323,6 +1340,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView)) { //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); + + IncomingOrphanedPacketCount++; + + if ((IncomingOrphanedPacketCount % 10000) == 0) + m_log.WarnFormat( + "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", + IncomingOrphanedPacketCount, endPoint); + return; } -- cgit v1.1 From 7c3b71d294987943058c8b3bcb18a424ca70dea5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 14 Aug 2013 14:13:08 -0700 Subject: BulletSim: add physical object initialized flag so updates and collisions don't happen until the object is completely initialized. This fixes the problem of doing a teleport while the simulator is running. The destruction of the physical object while the engine is running means that the physics parameter update would overwrite the new position of the newly created avatar. --- OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | 4 +++- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 4 ++++ OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 4 ++++ OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 4 ++++ OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 12 ++++++++---- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 5f232a4..c0589cd 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -69,7 +69,9 @@ public class BSActorAvatarMove : BSActor // BSActor.Dispose() public override void Dispose() { - Enabled = false; + base.SetEnabled(false); + // Now that turned off, remove any state we have in the scene. + Refresh(); } // Called when physical parameters (properties set in Bullet) need to be re-applied. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 502f85f..291dfcd 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -107,6 +107,8 @@ public sealed class BSCharacter : BSPhysObject PhysicalActors.Add(AvatarMoveActorName, m_moveActor); SetPhysicalProperties(); + + IsInitialized = true; }); return; } @@ -114,6 +116,8 @@ public sealed class BSCharacter : BSPhysObject // called when this character is being destroyed and the resources should be released public override void Destroy() { + IsInitialized = false; + base.Destroy(); DetailLog("{0},BSCharacter.Destroy", LocalID); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 27caf62..b26fef0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -72,6 +72,8 @@ public abstract class BSPhysObject : PhysicsActor } protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) { + IsInitialized = false; + PhysScene = parentScene; LocalID = localID; PhysObjectName = name; @@ -130,6 +132,8 @@ public abstract class BSPhysObject : PhysicsActor public string PhysObjectName { get; protected set; } public string TypeName { get; protected set; } + // Set to 'true' when the object is completely initialized + public bool IsInitialized { get; protected set; } // Return the object mass without calculating it or having side effects public abstract float RawMass { get; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 6b5dea3..d5b999d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -110,6 +110,8 @@ public class BSPrim : BSPhysObject CreateGeomAndObject(true); CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); + + IsInitialized = true; }); } @@ -117,6 +119,8 @@ public class BSPrim : BSPhysObject public override void Destroy() { // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); + IsInitialized = false; + base.Destroy(); // Undo any vehicle properties diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 79ac5a5..88d50b4 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -639,7 +639,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters BSPhysObject pobj; if (PhysObjects.TryGetValue(entprop.ID, out pobj)) { - pobj.UpdateProperties(entprop); + if (pobj.IsInitialized) + pobj.UpdateProperties(entprop); } } } @@ -766,10 +767,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); - if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) + if (collider.IsInitialized) { - // If a collision was 'good', remember to send it to the simulator - ObjectsWithCollisions.Add(collider); + if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) + { + // If a collision was 'good', remember to send it to the simulator + ObjectsWithCollisions.Add(collider); + } } return; -- cgit v1.1 From e8b1e91a1d4bb3ca65886c367c654a82033f4e03 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 14 Aug 2013 14:36:13 -0700 Subject: BulletSim: include check for volume detect in check for zeroing avatar motion. Normally, avatar motion is zeroed if colliding with a stationary object so they don't slide down hills and such. Without volume detect check this also allowed avatars to stand on volume detect objects and to have some jiggling when they were in the volume detect object. This commit fixes both. --- OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | 2 +- OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index c0589cd..68bc1b9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -183,7 +183,7 @@ public class BSActorAvatarMove : BSActor if (m_controllingPrim.IsColliding) { // If we are colliding with a stationary object, presume we're standing and don't move around - if (!m_controllingPrim.ColliderIsMoving) + if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) { m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); m_controllingPrim.IsStationary = true; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index b26fef0..9dc52d5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -132,7 +132,8 @@ public abstract class BSPhysObject : PhysicsActor public string PhysObjectName { get; protected set; } public string TypeName { get; protected set; } - // Set to 'true' when the object is completely initialized + // Set to 'true' when the object is completely initialized. + // This mostly prevents property updates and collisions until the object is completely here. public bool IsInitialized { get; protected set; } // Return the object mass without calculating it or having side effects @@ -356,6 +357,8 @@ public abstract class BSPhysObject : PhysicsActor // On a collision, check the collider and remember if the last collider was moving // Used to modify the standing of avatars (avatars on stationary things stand still) public bool ColliderIsMoving; + // 'true' if the last collider was a volume detect object + public bool ColliderIsVolumeDetect; // Used by BSCharacter to manage standing (and not slipping) public bool IsStationary; @@ -435,6 +438,7 @@ public abstract class BSPhysObject : PhysicsActor // For movement tests, remember if we are colliding with an object that is moving. ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; + ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; // Make a collection of the collisions that happened the last simulation tick. // This is different than the collection created for sending up to the simulator as it is cleared every tick. -- cgit v1.1 From 60cc9e9a3c87a424fb213597092aa4aad53a6ba5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 23:21:18 +0100 Subject: minor: remove unused entity transfer config in teleport v2 attachments test --- .../CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index f4bf6b3..1fcef20 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -925,7 +925,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests IConfig modulesConfig = config.AddConfig("Modules"); modulesConfig.Set("EntityTransferModule", etmA.Name); modulesConfig.Set("SimulationServices", lscm.Name); - IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); -- cgit v1.1 From 104626d732614a2e0b1988961e61f63447017013 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 23:22:20 +0100 Subject: minor: Comment out AvatarPicketSearch caps log message for now, which is occuring on every login and entity transfer --- OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs index 9f2aed0..10a4753 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs @@ -123,7 +123,7 @@ namespace OpenSim.Region.ClientStack.Linden if (m_URL == "localhost") { - m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); +// m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); caps.RegisterHandler( "AvatarPickerSearch", new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); -- cgit v1.1 From 5011c657b5b8127927c75c4e1db496c15a394b3a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 14 Aug 2013 23:37:07 +0100 Subject: Actually implement the bot request object textures switch started in 225cf0d. Forgot to propogate it down to bot level. --- OpenSim/Tools/pCampBot/Bot.cs | 8 ++++++++ OpenSim/Tools/pCampBot/BotManager.cs | 1 + 2 files changed, 9 insertions(+) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index dac8ccb..32bf32b 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -59,6 +59,11 @@ namespace pCampBot public delegate void AnEvent(Bot callbot, EventType someevent); // event delegate for bot events /// + /// Controls whether bots request textures for the object information they receive + /// + public bool RequestObjectTextures { get; set; } + + /// /// Bot manager. /// public BotManager Manager { get; private set; } @@ -469,6 +474,9 @@ namespace pCampBot public void Objects_NewPrim(object sender, PrimEventArgs args) { + if (!RequestObjectTextures) + return; + Primitive prim = args.Prim; if (prim != null) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 397a98e..dee02c3 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -300,6 +300,7 @@ namespace pCampBot Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri); pb.wear = wearSetting; pb.Client.Settings.SEND_AGENT_UPDATES = InitBotSendAgentUpdates; + pb.RequestObjectTextures = InitBotRequestObjectTextures; pb.OnConnected += handlebotEvent; pb.OnDisconnected += handlebotEvent; -- cgit v1.1 From 2231fcf5b45be9a2f5b6e1a2665ff7223e275b33 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 15 Aug 2013 13:46:46 +0100 Subject: Do not use the SP.DoNotCloseAfterTeleport flag for child agent connections. This approach has problems if a client quits without sending a proper logout but then reconnects before the connection is closed due to inactivity. In this case, the DoNotCloseAfterTeleport was wrongly set. The simplest approach is to close child agents on teleport as quickly as possible so that races are very unlikely to occur Hence, this code now closes child agents as the first action after a sucessful teleport. --- .../EntityTransfer/EntityTransferModule.cs | 24 ++++++++--------- OpenSim/Region/Framework/Scenes/Scene.cs | 31 ++++++++++++++-------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 87f0264..93a089d 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1055,6 +1055,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + // Need to signal neighbours whether child agents may need closing irrespective of whether this + // one needed closing. We also need to close child agents as quickly as possible to avoid complicated + // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back + // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex + // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are + // abandoned without proper close by viewer but then re-used by an incoming connection. + sp.CloseChildAgents(newRegionX, newRegionY); + // May need to logout or other cleanup AgentHasMovedAway(sp, logout); @@ -1064,17 +1072,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Now let's make it officially a child agent sp.MakeChildAgent(); - // May still need to signal neighbours whether child agents may need closing irrespective of whether this - // one needed closing. Neighbour regions also contain logic to prevent a close if a subsequent move or - // teleport re-established the child connection. - // - // It may be possible to also close child agents after a pause but one needs to be very careful about - // race conditions between different regions on rapid teleporting (e.g. from A1 to a non-neighbour B, back - // to a neighbour A2 then off to a non-neighbour C. Also, closing child agents early may be more compatible - // with complicated scenarios where there a mixture of V1 and V2 teleports, though this is conjecture. It's - // easier to close immediately and greatly reduce the scope of race conditions if possible. - sp.CloseChildAgents(newRegionX, newRegionY); - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { @@ -1096,7 +1093,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } else { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Not closing agent {0}, user is back in {1}", sp.Name, Scene.Name); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Connection for {0} in {1} has been re-established after teleport. Not closing.", + sp.Name, Scene.Name); + sp.DoNotCloseAfterTeleport = false; } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d187377..3e5ef10 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3703,21 +3703,30 @@ namespace OpenSim.Region.Framework.Scenes // In the case where, for example, an A B C D region layout, an avatar may // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C // renews the lease on the child agent at B, we must make sure that the close from A does not succeed. - if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) - { - m_log.DebugFormat( - "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", - sp.Name, Name); + // + // XXX: In the end, this should not be necessary if child agents are closed without delay on + // teleport, since realistically, the close request should always be processed before any other + // region tried to re-establish a child agent. This is much simpler since the logic below is + // vulnerable to an issue when a viewer quits a region without sending a proper logout but then + // re-establishes the connection on a relogin. This could wrongly set the DoNotCloseAfterTeleport + // flag when no teleport had taken place (and hence no close was going to come). +// if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) +// { +// m_log.DebugFormat( +// "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", +// sp.Name, Name); +// +// sp.DoNotCloseAfterTeleport = true; +// } +// else if (EntityTransferModule.IsInTransit(sp.UUID)) - sp.DoNotCloseAfterTeleport = true; - } - else if (EntityTransferModule.IsInTransit(sp.UUID)) + if (EntityTransferModule.IsInTransit(sp.UUID)) { + sp.DoNotCloseAfterTeleport = true; + m_log.DebugFormat( - "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.", + "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.", sp.Name, Name); - - sp.DoNotCloseAfterTeleport = true; } } } -- cgit v1.1 From 3f8d79024bc760e4f0c5cbca2126ab725c847078 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 15 Aug 2013 14:07:57 +0100 Subject: Rely on the Scene.IncomingCloseAgent() check as to whether the connection should be kept open after teleport-end rather than doing this in the ET Module This is safer since the close check in IncomingCloseAgent() is done under lock conditions, which prevents a race between ETM and Scene.AddClient() --- .../Framework/EntityTransfer/EntityTransferModule.cs | 20 ++++++-------------- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 93a089d..5f85eb0 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1085,20 +1085,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. Thread.Sleep(15000); - if (!sp.DoNotCloseAfterTeleport) - { - // OK, it got this agent. Let's close everything - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Closing agent {0} in {1}", sp.Name, Scene.Name); - sp.Scene.IncomingCloseAgent(sp.UUID, false); - } - else - { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Connection for {0} in {1} has been re-established after teleport. Not closing.", - sp.Name, Scene.Name); - - sp.DoNotCloseAfterTeleport = false; - } + // OK, it got this agent. Let's close everything + // If we shouldn't close the agent due to some other region renewing the connection + // then this will be handled in IncomingCloseAgent under lock conditions + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); + sp.Scene.IncomingCloseAgent(sp.UUID, false); } else { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 3e5ef10..b58e7c4 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3725,7 +3725,7 @@ namespace OpenSim.Region.Framework.Scenes sp.DoNotCloseAfterTeleport = true; m_log.DebugFormat( - "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.", + "[SCENE]: Set DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt end-of-teleport close from a previous close.", sp.Name, Name); } } -- cgit v1.1 From 3ddb7438d746b3efbe0cbedcb4ba2e18a0db51e2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 15 Aug 2013 14:41:00 +0100 Subject: Move DoNotCloseAfterTeleport flag reset before UpdateAgent in V2 to avoid a low probability where the destination re-establishing the child connection before the flag was reset --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 5f85eb0..4011422 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1029,6 +1029,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.SenderWantsToWaitForRoot = true; //SetCallbackURL(agent, sp.Scene.RegionInfo); + // Reset the do not close flag. This must be done before the destination opens child connections (here + // triggered by UpdateAgent) to avoid race conditions. However, we also want to reset it as late as possible + // to avoid a situation where an unexpectedly early call to Scene.NewUserConnection() wrongly results + // in no close. + sp.DoNotCloseAfterTeleport = false; + // Send the Update. If this returns true, we know the client has contacted the destination // via CompleteMovementIntoRegion, so we can let go. // If it returns false, something went wrong, and we need to abort. @@ -1075,8 +1081,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { - sp.DoNotCloseAfterTeleport = false; - // RED ALERT!!!! // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion -- cgit v1.1 From 7c916ab91ccadb8cb9a84508f29fa64f7e2e9e1e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 15 Aug 2013 14:50:20 +0100 Subject: Try to make "slow down" message that one could receive on rapid teleporting more informative to the user. This message is seen on V2 if one attempts to quickly re-teleport from a source region where one had previously teleported to a non-neighbour and back within 15 secs. The solution here is for the user to wait a short while. This message can also be seen on any teleport protocol if one recieves multiple teleport attempts simultaneously. Probably still useful here to help identify misbehaving scripts. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 4011422..17ebc83 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -317,7 +317,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.", sp.Name, sp.UUID, position, regionHandle); - sp.ControllingClient.SendTeleportFailed("Slow down!"); + sp.ControllingClient.SendTeleportFailed("Previous teleport process incomplete. Please retry shortly."); + return; } -- cgit v1.1 From 7d268912f1ee09b4e146208a4dd84dbf81ba335d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Aug 2013 00:58:25 +0100 Subject: Packet headers are not zero-encoded so don't try to zero-decode these in PacketPool.GetType() Instead adjusts code with that from Packet.BuildHeader(byte[], ref int, ref int):Header in libomv This stops packet decoding failures with agent UUIDs that contain 00 in their earlier parts (e.g. b0b0b0b0-0000-0000-0000-000000000211) Thanks to lkalif for pointing this out. --- .../Region/ClientStack/Linden/UDP/PacketPool.cs | 25 ++++++++-------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs index 1fdc410..5a2bcee 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs @@ -145,39 +145,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP return packet; } - // private byte[] decoded_header = new byte[10]; private static PacketType GetType(byte[] bytes) { - byte[] decoded_header = new byte[10 + 8]; ushort id; PacketFrequency freq; + bool isZeroCoded = (bytes[0] & Helpers.MSG_ZEROCODED) != 0; - if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0) + if (bytes[6] == 0xFF) { - Helpers.ZeroDecode(bytes, 16, decoded_header); - } - else - { - Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10); - } - - if (decoded_header[6] == 0xFF) - { - if (decoded_header[7] == 0xFF) + if (bytes[7] == 0xFF) { - id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]); freq = PacketFrequency.Low; + if (isZeroCoded && bytes[8] == 0) + id = bytes[10]; + else + id = (ushort)((bytes[8] << 8) + bytes[9]); } else { - id = decoded_header[7]; freq = PacketFrequency.Medium; + id = bytes[7]; } } else { - id = decoded_header[6]; freq = PacketFrequency.High; + id = bytes[6]; } return Packet.GetType(id, freq); -- cgit v1.1 From 1624522761b0634cea1089dd02cc9af7d30c356c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Aug 2013 23:45:04 +0100 Subject: refactor: Make AttachmentModulesTests.TestSameSimulatorNeighbouringRegionsTeleportV2 use already available TestClient handle rather than retrieving it via the ScenePresence --- .../CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 1fcef20..bdfef32 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -965,7 +965,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Both these operations will occur on different threads and will wait for each other. // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 // test protocol, where we are trying to avoid unpredictable async operations in regression tests. - ((TestClient)beforeTeleportSp.ControllingClient).OnTestClientSendRegionTeleport + tc.OnTestClientSendRegionTeleport += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); -- cgit v1.1 From fbab898f74186b38cf2dad9aa42f7f9b17a34fe9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Aug 2013 23:52:55 +0100 Subject: Add TestSameSimulatorNeighbouringRegionsV2() regression test for v2 entity transfer protocl --- .../Scenes/Tests/ScenePresenceTeleportTests.cs | 89 +++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index afd2779..936c2c0 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.IO; using System.Net; using System.Text; +using System.Threading; using Nini.Config; using NUnit.Framework; using OpenMetaverse; @@ -107,7 +108,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests } [Test] - public void TestSameSimulatorIsolatedRegions() + public void TestSameSimulatorIsolatedRegionsV1() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -428,7 +429,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests } [Test] - public void TestSameSimulatorNeighbouringRegions() + public void TestSameSimulatorNeighbouringRegionsV1() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); @@ -512,5 +513,89 @@ namespace OpenSim.Region.Framework.Scenes.Tests // TestHelpers.DisableLogging(); } + + [Test] + public void TestSameSimulatorNeighbouringRegionsV2() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + + ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); + + Assert.That(beforeSceneASp, Is.Not.Null); + Assert.That(beforeSceneASp.IsChildAgent, Is.False); + + ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(beforeSceneBSp, Is.Not.Null); + Assert.That(beforeSceneBSp.IsChildAgent, Is.True); + + // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This + // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to + // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt + // Both these operations will occur on different threads and will wait for each other. + // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 + // test protocol, where we are trying to avoid unpredictable async operations in regression tests. + tc.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) + => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); + + sceneA.RequestTeleportLocation( + beforeSceneASp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); + Assert.That(afterSceneASp, Is.Not.Null); + Assert.That(afterSceneASp.IsChildAgent, Is.True); + + ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(afterSceneBSp, Is.Not.Null); + Assert.That(afterSceneBSp.IsChildAgent, Is.False); + Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } } } \ No newline at end of file -- cgit v1.1 From f5d3145bea75fe2c84f49685031443c6826ffae7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 00:24:56 +0100 Subject: Add ScenePresenceTeleportTests.TestSameSimulatorIsolatedRegionsV2() regression test for v2 transfers. Also adjusts names of teleport setup helpers in EntityTransferHelpers --- .../Attachments/Tests/AttachmentsModuleTests.cs | 4 +- .../Scenes/Tests/SceneObjectDeRezTests.cs | 2 +- .../Scenes/Tests/ScenePresenceCrossingTests.cs | 2 +- .../Scenes/Tests/ScenePresenceTeleportTests.cs | 68 +++++++++++++++++++++- .../Tests/Common/Helpers/EntityTransferHelpers.cs | 43 +++++++++++++- 5 files changed, 109 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index bdfef32..fd493fc 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -844,7 +844,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); @@ -943,7 +943,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index d670dad..5b5fb92 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -147,7 +147,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests AgentCircuitData acd = SceneHelpers.GenerateAgentData(uaB); TestClient clientB = new TestClient(acd, sceneB); List childClientsB = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour(clientB, childClientsB); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(clientB, childClientsB); SceneHelpers.AddScenePresence(sceneB, clientB, acd); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 5df9aba..12a778b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -97,7 +97,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); originalSp.AbsolutePosition = new Vector3(128, 32, 10); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 936c2c0..8c25dbc 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -147,7 +147,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests sp.AbsolutePosition = new Vector3(30, 31, 32); List destinationTestClients = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour((TestClient)sp.ControllingClient, destinationTestClients); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate( + (TestClient)sp.ControllingClient, destinationTestClients); sceneA.RequestTeleportLocation( sp.ControllingClient, @@ -180,6 +181,67 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); } + [Test] + public void TestSameSimulatorIsolatedRegionsV2() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + sp.AbsolutePosition = new Vector3(30, 31, 32); + + List destinationTestClients = new List(); + EntityTransferHelpers.SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement( + (TestClient)sp.ControllingClient, destinationTestClients); + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + Assert.That(sceneA.GetScenePresence(userId), Is.Null); + + ScenePresence sceneBSp = sceneB.GetScenePresence(userId); + Assert.That(sceneBSp, Is.Not.Null); + Assert.That(sceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(sceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + } + /// /// Test teleport procedures when the target simulator returns false when queried about access. /// @@ -467,7 +529,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); @@ -545,7 +607,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); TestClient tc = new TestClient(acd, sceneA); List destinationTestClients = new List(); - EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); diff --git a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs index 1b960b1..ff6608d 100644 --- a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs @@ -31,6 +31,7 @@ using System.IO; using System.Net; using System.Reflection; using System.Text; +using System.Threading; using log4net; using Nini.Config; using NUnit.Framework; @@ -59,7 +60,8 @@ namespace OpenSim.Tests.Common /// A list that will be populated with any TestClients set up in response to /// being informed about a destination region. /// - public static void SetUpInformClientOfNeighbour(TestClient tc, List neighbourTcs) + public static void SetupInformClientOfNeighbourTriggersNeighbourClientCreate( + TestClient tc, List neighbourTcs) { // XXX: Confusingly, this is also used for non-neighbour notification (as in teleports that do not use the // event queue). @@ -75,8 +77,6 @@ namespace OpenSim.Tests.Common "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}", x, y, neighbourExternalEndPoint); - // In response to this message, we are going to make a teleport to the scene we've previous been told - // about by test code (this needs to be improved). AgentCircuitData newAgent = tc.RequestClientInfo(); Scene neighbourScene; @@ -87,5 +87,42 @@ namespace OpenSim.Tests.Common neighbourScene.AddNewClient(neighbourTc, PresenceType.User); }; } + + /// + /// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the + /// viewer to setup a connection with the destination region. + /// + /// + /// + /// A list that will be populated with any TestClients set up in response to + /// being informed about a destination region. + /// + public static void SetupSendRegionTeleportTriggersDestinationClientCreateAndCompleteMovement( + TestClient client, List destinationClients) + { + client.OnTestClientSendRegionTeleport + += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => + { + uint x, y; + Utils.LongToUInts(regionHandle, out x, out y); + x /= Constants.RegionSize; + y /= Constants.RegionSize; + + m_log.DebugFormat( + "[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}", + x, y, regionExternalEndPoint); + + AgentCircuitData newAgent = client.RequestClientInfo(); + + Scene destinationScene; + SceneManager.Instance.TryGetScene(x, y, out destinationScene); + + TestClient destinationClient = new TestClient(newAgent, destinationScene); + destinationClients.Add(destinationClient); + destinationScene.AddNewClient(destinationClient, PresenceType.User); + + ThreadPool.UnsafeQueueUserWorkItem(o => destinationClient.CompleteMovement(), null); + }; + } } } \ No newline at end of file -- cgit v1.1 From 14ae89dbe7e06d838fc1bc01cf377d8f0d3eb035 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 00:39:41 +0100 Subject: Fix issues with RemoteAdmin admin_save_heightmap and admin_load_heightmap not working. This is because they were wrongly looking for both regionid and region_id parameters in the same request. Now only region_id is required (and recognized), regionid having been already deprecated for some time. This is essentially Michelle Argus' patch from http://opensimulator.org/mantis/view.php?id=6737 but with tabs replaced with spaces. Thanks! --- .../RemoteController/RemoteAdminPlugin.cs | 45 ++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 3abf40b..c78cf3b 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -327,18 +327,26 @@ namespace OpenSim.ApplicationPlugins.RemoteController // k, (string)requestData[k], ((string)requestData[k]).Length); // } - CheckStringParameters(requestData, responseData, new string[] {"filename", "regionid"}); + CheckStringParameters(requestData, responseData, new string[] { "filename" }); CheckRegionParams(requestData, responseData); Scene scene = null; GetSceneFromRegionParams(requestData, responseData, out scene); - string file = (string)requestData["filename"]; - responseData["accepted"] = true; + if (scene != null) + { + string file = (string)requestData["filename"]; - LoadHeightmap(file, scene.RegionInfo.RegionID); + responseData["accepted"] = true; - responseData["success"] = true; + LoadHeightmap(file, scene.RegionInfo.RegionID); + + responseData["success"] = true; + } + else + { + responseData["success"] = false; + } m_log.Info("[RADMIN]: Load height maps request complete"); } @@ -352,23 +360,30 @@ namespace OpenSim.ApplicationPlugins.RemoteController // m_log.DebugFormat("[RADMIN]: Save Terrain: XmlRpc {0}", request.ToString()); - CheckStringParameters(requestData, responseData, new string[] { "filename", "regionid" }); + CheckStringParameters(requestData, responseData, new string[] { "filename" }); CheckRegionParams(requestData, responseData); - Scene region = null; - GetSceneFromRegionParams(requestData, responseData, out region); + Scene scene = null; + GetSceneFromRegionParams(requestData, responseData, out scene); - string file = (string)requestData["filename"]; - m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file); + if (scene != null) + { + string file = (string)requestData["filename"]; + m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file); - responseData["accepted"] = true; + responseData["accepted"] = true; - ITerrainModule terrainModule = region.RequestModuleInterface(); - if (null == terrainModule) throw new Exception("terrain module not available"); + ITerrainModule terrainModule = scene.RequestModuleInterface(); + if (null == terrainModule) throw new Exception("terrain module not available"); - terrainModule.SaveToFile(file); + terrainModule.SaveToFile(file); - responseData["success"] = true; + responseData["success"] = true; + } + else + { + responseData["success"] = false; + } m_log.Info("[RADMIN]: Save height maps request complete"); } -- cgit v1.1 From 1f1736a79f925c3e19dee634f8cf74fd0f446073 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 00:46:18 +0100 Subject: minor: Make log messages consistent in NeighbourServicesConnector --- .../Connectors/Neighbour/NeighbourServicesConnector.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs index 5948380..774fe2a 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs @@ -98,7 +98,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Unable to parse uri {0} to send HelloNeighbour from {1} to {2}. Exception {3}{4}", + "[NEIGHBOUR SERVICES CONNECTOR]: Unable to parse uri {0} to send HelloNeighbour from {1} to {2}. Exception {3}{4}", uri, thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); return false; @@ -117,7 +117,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: PackRegionInfoData failed for HelloNeighbour from {0} to {1}. Exception {2}{3}", + "[NEIGHBOUR SERVICES CONNECTOR]: PackRegionInfoData failed for HelloNeighbour from {0} to {1}. Exception {2}{3}", thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); return false; @@ -137,7 +137,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Exception thrown on serialization of HelloNeighbour from {0} to {1}. Exception {2}{3}", + "[NEIGHBOUR SERVICES CONNECTOR]: Exception thrown on serialization of HelloNeighbour from {0} to {1}. Exception {2}{3}", thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); return false; @@ -154,7 +154,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Unable to send HelloNeighbour from {0} to {1}. Exception {2}{3}", + "[NEIGHBOUR SERVICES CONNECTOR]: Unable to send HelloNeighbour from {0} to {1}. Exception {2}{3}", thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); return false; @@ -175,7 +175,7 @@ namespace OpenSim.Services.Connectors if (webResponse == null) { m_log.DebugFormat( - "[REST COMMS]: Null reply on DoHelloNeighbourCall post from {0} to {1}", + "[NEIGHBOUR SERVICES CONNECTOR]: Null reply on DoHelloNeighbourCall post from {0} to {1}", thisRegion.RegionName, region.RegionName); } @@ -193,7 +193,7 @@ namespace OpenSim.Services.Connectors catch (Exception e) { m_log.WarnFormat( - "[NEIGHBOUR SERVICE CONNCTOR]: Exception on reply of DoHelloNeighbourCall from {0} back to {1}. Exception {2}{3}", + "[NEIGHBOUR SERVICES CONNECTOR]: Exception on reply of DoHelloNeighbourCall from {0} back to {1}. Exception {2}{3}", region.RegionName, thisRegion.RegionName, e.Message, e.StackTrace); return false; -- cgit v1.1 From 217c8deae5fab5aa025932b027dfc4a4b629cc58 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 00:51:21 +0100 Subject: minor: remove mono compiler warning in StatsManager --- OpenSim/Framework/Monitoring/StatsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 7cf1fa7..05ee4c5 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -267,7 +267,7 @@ namespace OpenSim.Framework.Monitoring public static Hashtable HandleStatsRequest(Hashtable request) { Hashtable responsedata = new Hashtable(); - string regpath = request["uri"].ToString(); +// string regpath = request["uri"].ToString(); int response_code = 200; string contenttype = "text/json"; -- cgit v1.1 From 77d418a36d532e9aaf756858ff97c15edf04759a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 00:56:19 +0100 Subject: remove mono compiler warnings from PollServiceRequestManager --- OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 6ab05d0..6aa5907 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -51,10 +51,8 @@ namespace OpenSim.Framework.Servers.HttpServer private uint m_WorkerThreadCount = 0; private Thread[] m_workerThreads; - private Thread m_longPollThread; private bool m_running = true; - private int slowCount = 0; private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); @@ -83,7 +81,7 @@ namespace OpenSim.Framework.Servers.HttpServer int.MaxValue); } - m_longPollThread = Watchdog.StartThread( + Watchdog.StartThread( this.CheckLongPollThreads, string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), ThreadPriority.Normal, @@ -136,7 +134,7 @@ namespace OpenSim.Framework.Servers.HttpServer Thread.Sleep(500); Watchdog.UpdateThread(); - List not_ready = new List(); +// List not_ready = new List(); lock (m_longPollRequests) { if (m_longPollRequests.Count > 0 && m_running) -- cgit v1.1 From d38d5ecbac5777c2bea1f9858410d7d2ff13935b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 01:00:20 +0100 Subject: minor: remove mono compiler warnings from ScenePresence --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 69339b7..37e5286 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -219,7 +219,7 @@ namespace OpenSim.Region.Framework.Scenes private float m_sitAvatarHeight = 2.0f; private Vector3 m_lastChildAgentUpdatePosition; - private Vector3 m_lastChildAgentUpdateCamPosition; +// private Vector3 m_lastChildAgentUpdateCamPosition; private const int LAND_VELOCITYMAG_MAX = 12; @@ -1847,8 +1847,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_movementUpdateCount < 1) m_movementUpdateCount = 1; - - AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; +// AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; // Camera location in world. We'll need to raytrace // from this location from time to time. @@ -3025,7 +3024,7 @@ namespace OpenSim.Region.Framework.Scenes if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance) { m_lastChildAgentUpdatePosition = AbsolutePosition; - m_lastChildAgentUpdateCamPosition = CameraPosition; +// m_lastChildAgentUpdateCamPosition = CameraPosition; ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); cadu.ActiveGroupID = UUID.Zero.Guid; -- cgit v1.1 From f5dbfe99b10085a6d954105ce473daeb9235686c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 01:06:48 +0100 Subject: minor: remove mono compiler warnings from OpenSim/Services/Connectors/SimianGrid --- .../Services/Connectors/SimianGrid/SimianExternalCapsModule.cs | 3 --- OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs | 8 ++------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs index e85b0b7..764e71f 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianExternalCapsModule.cs @@ -56,11 +56,8 @@ namespace OpenSim.Services.Connectors.SimianGrid private Scene m_scene; private String m_simianURL; - private IGridUserService m_GridUserService; - #region IRegionModule Members - public string Name { get { return this.GetType().Name; } diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs index e7d2f86..9898da9 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs @@ -29,11 +29,9 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Reflection; - using log4net; using Mono.Addins; using Nini.Config; - using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -52,7 +50,6 @@ namespace OpenSim.Services.Connectors.SimianGrid private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IConfig m_config = null; - private bool m_enabled = true; private String m_simianURL; @@ -62,7 +59,6 @@ namespace OpenSim.Services.Connectors.SimianGrid { get { return this.GetType().Name; } } - public void Initialise(IConfigSource config) { @@ -76,7 +72,6 @@ namespace OpenSim.Services.Connectors.SimianGrid if (String.IsNullOrEmpty(m_simianURL)) { // m_log.DebugFormat("[SimianGrid] service URL is not defined"); - m_enabled = false; return; } @@ -141,6 +136,7 @@ namespace OpenSim.Services.Connectors.SimianGrid } #endregion + public static String SimulatorCapability = UUID.Zero.ToString(); public static OSDMap PostToService(string url, NameValueCollection data) { @@ -148,4 +144,4 @@ namespace OpenSim.Services.Connectors.SimianGrid return WebUtil.PostToService(url, data); } } -} +} \ No newline at end of file -- cgit v1.1 From b3052c425effe7eed6f4a8ab8e25fd4de907bc86 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 01:08:19 +0100 Subject: Remove some mono compiler warnings from OpenSim/Server/Handlers --- OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs | 2 +- OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs | 6 +----- OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs | 6 ++---- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs index f37f2f1..04bb9e8 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HomeAgentHandlers.cs @@ -85,7 +85,7 @@ namespace OpenSim.Server.Handlers.Hypergrid data.destinationServerURI = args["destination_serveruri"]; } - catch (InvalidCastException e) + catch (InvalidCastException) { m_log.ErrorFormat("[HOME AGENT HANDLER]: Bad cast in UnpackData"); } diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index d9c1bd3..7137836 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs @@ -453,7 +453,6 @@ namespace OpenSim.Server.Handlers.Hypergrid XmlRpcResponse response = new XmlRpcResponse(); response.Value = hash; return response; - } /// @@ -471,9 +470,7 @@ namespace OpenSim.Server.Handlers.Hypergrid //string portstr = (string)requestData["port"]; if (requestData.ContainsKey("first") && requestData.ContainsKey("last")) { - UUID userID = UUID.Zero; string first = (string)requestData["first"]; - string last = (string)requestData["last"]; UUID uuid = m_HomeUsersService.GetUUID(first, last); hash["UUID"] = uuid.ToString(); @@ -482,7 +479,6 @@ namespace OpenSim.Server.Handlers.Hypergrid XmlRpcResponse response = new XmlRpcResponse(); response.Value = hash; return response; - } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs index f9a520a..28dbbc2 100644 --- a/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs +++ b/OpenSim/Server/Handlers/Profiles/UserProfilesConnector.cs @@ -39,8 +39,7 @@ namespace OpenSim.Server.Handlers.Profiles { public class UserProfilesConnector: ServiceConnector { - static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - +// static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // Our Local Module public IUserProfilesService ServiceModule @@ -110,5 +109,4 @@ namespace OpenSim.Server.Handlers.Profiles Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); } } -} - +} \ No newline at end of file -- cgit v1.1 From d75f00cc2d0d601c6b9b4f2ea7a983c2ea85c62d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 01:09:31 +0100 Subject: minor: remove mono compiler warning from AttachmentsModule --- OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 675fccc..2818712 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -316,8 +316,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { // If we're an NPC then skip all the item checks and manipulations since we don't have an // inventory right now. - SceneObjectGroup objatt - = RezSingleAttachmentFromInventoryInternal( + RezSingleAttachmentFromInventoryInternal( sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true); } catch (Exception e) -- cgit v1.1 From 85a9cb260a5f06df495e29dd8a3ae590970efe57 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 17 Aug 2013 01:10:58 +0100 Subject: Remove mono compiler warnings from UserProfilesModule --- .../Avatar/UserProfiles/UserProfileModule.cs | 35 ++++++++++------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index c04098c..966a05c 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -307,7 +307,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(targetID, out serverURI); + GetUserProfileServerURI(targetID, out serverURI); UUID creatorId = UUID.Zero; OSDMap parameters= new OSDMap(); @@ -372,7 +372,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(target, out serverURI); + GetUserProfileServerURI(target, out serverURI); object Ad = (object)ad; if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) @@ -441,10 +441,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); ScenePresence p = FindPresence(remoteClient.AgentId); - Vector3 avaPos = p.AbsolutePosition; +// Vector3 avaPos = p.AbsolutePosition; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); if (land == null) { @@ -470,7 +470,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles object Ad = ad; - OSD X = OSD.SerializeMembers(Ad); + OSD.SerializeMembers(Ad); if(!JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString())) { @@ -491,7 +491,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) { string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); UUID classifiedId; OSDMap parameters= new OSDMap(); @@ -541,7 +541,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(targetId, out serverURI); + GetUserProfileServerURI(targetId, out serverURI); OSDMap parameters= new OSDMap(); parameters.Add("creatorId", OSD.FromUUID(targetId)); @@ -592,7 +592,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles UUID targetID; UUID.TryParse(args[0], out targetID); string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(targetID, out serverURI); + GetUserProfileServerURI(targetID, out serverURI); IClientAPI remoteClient = (IClientAPI)sender; UserProfilePick pick = new UserProfilePick(); @@ -660,7 +660,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); UserProfilePick pick = new UserProfilePick(); string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); ScenePresence p = FindPresence(remoteClient.AgentId); Vector3 avaPos = p.AbsolutePosition; @@ -720,7 +720,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles public void PickDelete(IClientAPI remoteClient, UUID queryPickID) { string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); OSDMap parameters= new OSDMap(); parameters.Add("pickId", OSD.FromUUID(queryPickID)); @@ -755,7 +755,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles IClientAPI remoteClient = (IClientAPI)sender; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); note.TargetId = remoteClient.AgentId; UUID.TryParse(args[0], out note.UserId); @@ -791,7 +791,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles note.Notes = queryNotes; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Note = note; if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) @@ -836,7 +836,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles prop.Language = languages; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Param = prop; if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) @@ -958,7 +958,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles prop.FirstLifeText = newProfile.FirstLifeAboutText; string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + GetUserProfileServerURI(remoteClient.AgentId, out serverURI); object Prop = prop; @@ -972,7 +972,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } } - /// /// Gets the profile data. /// @@ -997,7 +996,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } string serverURI = string.Empty; - bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); + GetUserProfileServerURI(properties.UserId, out serverURI); // This is checking a friend on the home grid // Not HG friend @@ -1245,11 +1244,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles return false; } - byte[] buf = new byte[8192]; Stream rstream = webResponse.GetResponseStream(); OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); - if(mret.ContainsKey("error")) + if (mret.ContainsKey("error")) return false; // get params... @@ -1311,7 +1309,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles return false; } - byte[] buf = new byte[8192]; Stream rstream = webResponse.GetResponseStream(); OSDMap response = new OSDMap(); -- cgit v1.1 From 3585b0a1392b7f9e93c4156d1d9fad224b4f187a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 18 Aug 2013 02:59:10 +0100 Subject: Allow updating the wearable type of wearables that have a type of 0. This will allow viewers to fix broken wearables as they detect them. --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 8e4e307..c4b07a5 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -416,6 +416,8 @@ namespace OpenSim.Region.Framework.Scenes // itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags, // item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions); + bool sendUpdate = false; + if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid { // Create a set of base permissions that will not include export if the user @@ -489,11 +491,13 @@ namespace OpenSim.Region.Framework.Scenes item.SalePrice = itemUpd.SalePrice; item.SaleType = itemUpd.SaleType; - InventoryService.UpdateItem(item); + if (item.InvType == (int)InventoryType.Wearable && (item.Flags & 0xf) == 0 && (itemUpd.Flags & 0xf) != 0) + { + item.Flags = (uint)(item.Flags & 0xfffffff0) | (itemUpd.Flags & 0xf); + sendUpdate = true; + } - // We cannot send out a bulk update here, since this will cause editing of clothing to start - // failing frequently. Possibly this is a race with a separate transaction that uploads the asset. -// remoteClient.SendBulkUpdateInventory(item); + InventoryService.UpdateItem(item); } if (UUID.Zero != transactionID) @@ -503,6 +507,14 @@ namespace OpenSim.Region.Framework.Scenes AgentTransactionsModule.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); } } + else + { + // This MAY be problematic, if it is, another solution + // needs to be found. If inventory item flags are updated + // the viewer's notion of the item needs to be refreshed. + if (sendUpdate) + remoteClient.SendBulkUpdateInventory(item); + } } else { -- cgit v1.1 From a90a5f52dd5f053a83a09fdd70ca08148ef641ce Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 19 Aug 2013 19:38:20 +0100 Subject: Show number of connections each bot has established in "show bots" command. --- OpenSim/Tools/pCampBot/Bot.cs | 15 ++++++++++++++- OpenSim/Tools/pCampBot/BotManager.cs | 17 ++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 32bf32b..be7a5a1 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -97,6 +97,19 @@ namespace pCampBot /// public ConnectionState ConnectionState { get; private set; } + /// + /// The number of connections that this bot has to different simulators. + /// + /// Includes both root and child connections. + public int ConnectionsCount + { + get + { + lock (Client.Network.Simulators) + return Client.Network.Simulators.Count; + } + } + public string FirstName { get; private set; } public string LastName { get; private set; } public string Name { get; private set; } @@ -144,7 +157,7 @@ namespace pCampBot ConnectionState = ConnectionState.Disconnected; behaviours.ForEach(b => b.Initialize(this)); - + Client = new GridClient(); Random = new Random(Environment.TickCount);// We do stuff randomly here diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index dee02c3..8f31bdf 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -395,8 +395,11 @@ namespace pCampBot private void HandleShowStatus(string module, string[] cmd) { - string outputFormat = "{0,-30} {1, -30} {2,-14}"; - MainConsole.Instance.OutputFormat(outputFormat, "Name", "Region", "Status"); + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Name", 30); + cdt.AddColumn("Region", 30); + cdt.AddColumn("Status", 14); + cdt.AddColumn("Connections", 11); Dictionary totals = new Dictionary(); foreach (object o in Enum.GetValues(typeof(ConnectionState))) @@ -409,19 +412,19 @@ namespace pCampBot Simulator currentSim = pb.Client.Network.CurrentSim; totals[pb.ConnectionState]++; - MainConsole.Instance.OutputFormat( - outputFormat, - pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState); + cdt.AddRow( + pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState, pb.ConnectionsCount); } } + MainConsole.Instance.Output(cdt.ToString()); + ConsoleDisplayList cdl = new ConsoleDisplayList(); foreach (KeyValuePair kvp in totals) cdl.AddRow(kvp.Key, kvp.Value); - - MainConsole.Instance.OutputFormat("\n{0}", cdl.ToString()); + MainConsole.Instance.Output(cdl.ToString()); } /* -- cgit v1.1 From 49b7cbda72cdaae8b5a7a89c94915851997b0b13 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 19 Aug 2013 20:29:17 +0100 Subject: Create a separate pCampbot "disconnect" console command which disconnects connected bots. "quit" console command now requires bots to be separate disconnected first before quitting. This is to prepare the way for disconnecting/reconnecting different numbers of bots in a pCampbot session. And hopefully resolves bug where console appears not to be reset if Environment.Exit(0) is called on a different thread --- OpenSim/Tools/pCampBot/BotManager.cs | 110 +++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 8f31bdf..5c0dc81 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -52,9 +52,9 @@ namespace pCampBot public const int DefaultLoginDelay = 5000; /// - /// True if pCampbot is in the process of shutting down. + /// Is pCampbot in the process of disconnecting bots? /// - public bool ShuttingDown { get; private set; } + public bool DisconnectingBots { get; private set; } /// /// Delay between logins of multiple bots. @@ -139,6 +139,11 @@ namespace pCampBot "Shutdown bots and exit", HandleShutdown); + m_console.Commands.AddCommand("bot", false, "disconnect", + "disconnect", + "Disconnect all bots", + HandleDisconnect); + m_console.Commands.AddCommand("bot", false, "show regions", "show regions", "Show regions known to bots", @@ -191,31 +196,37 @@ namespace pCampBot for (int i = 0; i < botcount; i++) { - if (ShuttingDown) - break; + lock (m_lBot) + { + if (DisconnectingBots) + break; + + string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber); - string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber); + // We must give each bot its own list of instantiated behaviours since they store state. + List behaviours = new List(); + + // Hard-coded for now + if (behaviourSwitches.Contains("c")) + behaviours.Add(new CrossBehaviour()); - // We must give each bot its own list of instantiated behaviours since they store state. - List behaviours = new List(); - - // Hard-coded for now - if (behaviourSwitches.Contains("c")) - behaviours.Add(new CrossBehaviour()); + if (behaviourSwitches.Contains("g")) + behaviours.Add(new GrabbingBehaviour()); - if (behaviourSwitches.Contains("g")) - behaviours.Add(new GrabbingBehaviour()); + if (behaviourSwitches.Contains("n")) + behaviours.Add(new NoneBehaviour()); - if (behaviourSwitches.Contains("n")) - behaviours.Add(new NoneBehaviour()); + if (behaviourSwitches.Contains("p")) + behaviours.Add(new PhysicsBehaviour()); + + if (behaviourSwitches.Contains("t")) + behaviours.Add(new TeleportBehaviour()); - if (behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - - if (behaviourSwitches.Contains("t")) - behaviours.Add(new TeleportBehaviour()); + StartBot(this, behaviours, firstName, lastName, password, loginUri, startUri, wearSetting); + } - StartBot(this, behaviours, firstName, lastName, password, loginUri, startUri, wearSetting); + // Stagger logins + Thread.Sleep(LoginDelay); } } @@ -305,17 +316,13 @@ namespace pCampBot pb.OnConnected += handlebotEvent; pb.OnDisconnected += handlebotEvent; - lock (m_lBot) - m_lBot.Add(pb); + m_lBot.Add(pb); Thread pbThread = new Thread(pb.startup); pbThread.Name = pb.Name; pbThread.IsBackground = true; pbThread.Start(); - - // Stagger logins - Thread.Sleep(LoginDelay); } /// @@ -328,18 +335,16 @@ namespace pCampBot switch (eventt) { case EventType.CONNECTED: + { m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Connected"); break; + } + case EventType.DISCONNECTED: + { m_log.Info("[" + callbot.FirstName + " " + callbot.LastName + "]: Disconnected"); - - lock (m_lBot) - { - if (m_lBot.TrueForAll(b => b.ConnectionState == ConnectionState.Disconnected)) - Environment.Exit(0); - - break; - } + break; + } } } @@ -349,15 +354,12 @@ namespace pCampBot /// /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others. /// - public void doBotShutdown() + private void ShutdownBots() { - lock (m_lBot) + foreach (Bot bot in m_lBot) { - foreach (Bot bot in m_lBot) - { - Bot thisBot = bot; - Util.FireAndForget(o => thisBot.shutdown()); - } + Bot thisBot = bot; + Util.FireAndForget(o => thisBot.shutdown()); } } @@ -370,12 +372,34 @@ namespace pCampBot return new LocalConsole("pCampbot"); } + private void HandleDisconnect(string module, string[] cmd) + { + MainConsole.Instance.Output("Disconnecting bots"); + + lock (m_lBot) + { + DisconnectingBots = true; + + ShutdownBots(); + } + } + private void HandleShutdown(string module, string[] cmd) { + lock (m_lBot) + { + int connectedBots = m_lBot.Count(b => b.ConnectionState == ConnectionState.Connected); + + if (connectedBots > 0) + { + MainConsole.Instance.OutputFormat("Please disconnect {0} connected bots first", connectedBots); + return; + } + } + MainConsole.Instance.Output("Shutting down"); - ShuttingDown = true; - doBotShutdown(); + Environment.Exit(0); } private void HandleShowRegions(string module, string[] cmd) -- cgit v1.1 From 2fa42f24fd0e80adc16320a404e3e85ca6d1baa1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 19 Aug 2013 21:00:31 +0100 Subject: Make it possible to disconnected a specified number of bots via the pCampbot console command "disconnect []" Bots disconnected are ascending from last in numeric order. Temporarily no way to reconnect bots. --- OpenSim/Framework/Console/ConsoleUtil.cs | 29 ++++++++- OpenSim/Tools/pCampBot/BotManager.cs | 101 +++++++++++++++++-------------- 2 files changed, 82 insertions(+), 48 deletions(-) diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs index c0ff454..794bfaf 100644 --- a/OpenSim/Framework/Console/ConsoleUtil.cs +++ b/OpenSim/Framework/Console/ConsoleUtil.cs @@ -179,8 +179,8 @@ namespace OpenSim.Framework.Console /// Convert a console integer to an int, automatically complaining if a console is given. /// /// Can be null if no console is available. - /// /param> - /// + /// /param> + /// /// public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i) { @@ -194,6 +194,31 @@ namespace OpenSim.Framework.Console return true; } + + /// + /// Convert a console integer to a natural int, automatically complaining if a console is given. + /// + /// Can be null if no console is available. + /// /param> + /// + /// + public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i) + { + if (TryParseConsoleInt(console, rawConsoleInt, out i)) + { + if (i < 0) + { + if (console != null) + console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt); + + return false; + } + + return true; + } + + return false; + } /// /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 5c0dc81..157c69c 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -80,7 +80,7 @@ namespace pCampBot /// /// Created bots, whether active or inactive. /// - protected List m_lBot; + protected List m_bots; /// /// Random number generator. @@ -130,35 +130,30 @@ namespace pCampBot } } - m_console.Commands.AddCommand("bot", false, "shutdown", - "shutdown", - "Shutdown bots and exit", HandleShutdown); + m_console.Commands.AddCommand( + "bot", false, "shutdown", "shutdown", "Shutdown bots and exit", HandleShutdown); - m_console.Commands.AddCommand("bot", false, "quit", - "quit", - "Shutdown bots and exit", - HandleShutdown); + m_console.Commands.AddCommand( + "bot", false, "quit", "quit", "Shutdown bots and exit", HandleShutdown); - m_console.Commands.AddCommand("bot", false, "disconnect", - "disconnect", - "Disconnect all bots", - HandleDisconnect); + m_console.Commands.AddCommand( + "bot", false, "disconnect", "disconnect []", "Disconnect bots", + "Disconnecting bots will interupt any bot connection process, including connection on startup.\n" + + "If an is given, then the last connected bots by postfix number are disconnected.\n" + + "If no is given, then all currently connected bots are disconnected.", + HandleDisconnect); - m_console.Commands.AddCommand("bot", false, "show regions", - "show regions", - "Show regions known to bots", - HandleShowRegions); + m_console.Commands.AddCommand( + "bot", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions); - m_console.Commands.AddCommand("bot", false, "show bots", - "show bots", - "Shows the status of all bots", - HandleShowStatus); + m_console.Commands.AddCommand( + "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowStatus); // m_console.Commands.AddCommand("bot", false, "add bots", // "add bots ", // "Add more bots", HandleAddBots); - m_lBot = new List(); + m_bots = new List(); } /// @@ -196,7 +191,7 @@ namespace pCampBot for (int i = 0; i < botcount; i++) { - lock (m_lBot) + lock (m_bots) { if (DisconnectingBots) break; @@ -316,7 +311,7 @@ namespace pCampBot pb.OnConnected += handlebotEvent; pb.OnDisconnected += handlebotEvent; - m_lBot.Add(pb); + m_bots.Add(pb); Thread pbThread = new Thread(pb.startup); pbThread.Name = pb.Name; @@ -349,21 +344,6 @@ namespace pCampBot } /// - /// Shut down all bots - /// - /// - /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others. - /// - private void ShutdownBots() - { - foreach (Bot bot in m_lBot) - { - Bot thisBot = bot; - Util.FireAndForget(o => thisBot.shutdown()); - } - } - - /// /// Standard CreateConsole routine /// /// @@ -374,21 +354,50 @@ namespace pCampBot private void HandleDisconnect(string module, string[] cmd) { - MainConsole.Instance.Output("Disconnecting bots"); - - lock (m_lBot) + lock (m_bots) { + int botsToDisconnect; + int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected); + + if (cmd.Length == 1) + { + botsToDisconnect = connectedBots; + } + else + { + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToDisconnect)) + return; + + botsToDisconnect = Math.Min(botsToDisconnect, connectedBots); + } + DisconnectingBots = true; - ShutdownBots(); + MainConsole.Instance.OutputFormat("Disconnecting {0} bots", botsToDisconnect); + + int disconnectedBots = 0; + + for (int i = m_bots.Count - 1; i >= 0; i--) + { + if (disconnectedBots >= botsToDisconnect) + break; + + Bot thisBot = m_bots[i]; + + if (thisBot.ConnectionState == ConnectionState.Connected) + { + Util.FireAndForget(o => thisBot.shutdown()); + disconnectedBots++; + } + } } } private void HandleShutdown(string module, string[] cmd) { - lock (m_lBot) + lock (m_bots) { - int connectedBots = m_lBot.Count(b => b.ConnectionState == ConnectionState.Connected); + int connectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Connected); if (connectedBots > 0) { @@ -429,9 +438,9 @@ namespace pCampBot foreach (object o in Enum.GetValues(typeof(ConnectionState))) totals[(ConnectionState)o] = 0; - lock (m_lBot) + lock (m_bots) { - foreach (Bot pb in m_lBot) + foreach (Bot pb in m_bots) { Simulator currentSim = pb.Client.Network.CurrentSim; totals[pb.ConnectionState]++; -- cgit v1.1 From 079cd4e94f820bad83fcbf8373ef268ecb82d9a6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 19 Aug 2013 21:17:59 +0100 Subject: refactor: restructure pCampbot multi-bot connection code. --- OpenSim/Tools/pCampBot/BotManager.cs | 70 ++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 157c69c..2cbadef 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -98,6 +98,46 @@ namespace pCampBot public Dictionary RegionsKnown { get; private set; } /// + /// First name for bots + /// + private string m_firstName; + + /// + /// Last name stem for bots + /// + private string m_lastNameStem; + + /// + /// Password for bots + /// + private string m_password; + + /// + /// Login URI for bots. + /// + private string m_loginUri; + + /// + /// Start location for bots. + /// + private string m_startUri; + + /// + /// Postfix bot number at which bot sequence starts. + /// + private int m_fromBotNumber; + + /// + /// Wear setting for bots. + /// + private string m_wearSetting; + + /// + /// Behaviour switches for bots. + /// + private HashSet m_behaviourSwitches = new HashSet(); + + /// /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data /// public BotManager() @@ -163,20 +203,26 @@ namespace pCampBot /// The configuration for the bots to use public void dobotStartup(int botcount, IConfig startupConfig) { - string firstName = startupConfig.GetString("firstname"); - string lastNameStem = startupConfig.GetString("lastname"); - string password = startupConfig.GetString("password"); - string loginUri = startupConfig.GetString("loginuri"); - string startLocation = startupConfig.GetString("start", "last"); - int fromBotNumber = startupConfig.GetInt("from", 0); - string wearSetting = startupConfig.GetString("wear", "no"); + m_firstName = startupConfig.GetString("firstname"); + m_lastNameStem = startupConfig.GetString("lastname"); + m_password = startupConfig.GetString("password"); + m_loginUri = startupConfig.GetString("loginuri"); + m_fromBotNumber = startupConfig.GetInt("from", 0); + m_wearSetting = startupConfig.GetString("wear", "no"); - string startUri = ParseInputStartLocationToUri(startLocation); + m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last")); - HashSet behaviourSwitches = new HashSet(); Array.ForEach( - startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); + startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_behaviourSwitches.Add(b)); + + ConnectBots( + botcount, m_firstName, m_lastNameStem, m_password, m_loginUri, m_startUri, m_fromBotNumber, m_wearSetting, m_behaviourSwitches); + } + private void ConnectBots( + int botcount, string firstName, string lastNameStem, string password, string loginUri, string startUri, int fromBotNumber, string wearSetting, + HashSet behaviourSwitches) + { MainConsole.Instance.OutputFormat( "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_", botcount, @@ -194,7 +240,11 @@ namespace pCampBot lock (m_bots) { if (DisconnectingBots) + { + MainConsole.Instance.Output( + "[BOT MANAGER]: Aborting bot connection due to user-initiated disconnection"); break; + } string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber); -- cgit v1.1 From ea3f024b8a546608fce825d4aa9f165eaecfeed5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 19 Aug 2013 21:25:17 +0100 Subject: refactor: start bot connection thread within BotManager rather than externally --- OpenSim/Tools/pCampBot/BotManager.cs | 27 ++++++++++++++++++++++++++- OpenSim/Tools/pCampBot/pCampBot.cs | 5 +---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 2cbadef..fe6048a 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -52,6 +52,11 @@ namespace pCampBot public const int DefaultLoginDelay = 5000; /// + /// Is pCampbot in the process of connecting bots? + /// + public bool ConnectingBots { get; private set; } + + /// /// Is pCampbot in the process of disconnecting bots? /// public bool DisconnectingBots { get; private set; } @@ -219,7 +224,25 @@ namespace pCampBot botcount, m_firstName, m_lastNameStem, m_password, m_loginUri, m_startUri, m_fromBotNumber, m_wearSetting, m_behaviourSwitches); } - private void ConnectBots( + private bool ConnectBots( + int botcount, string firstName, string lastNameStem, string password, string loginUri, string startUri, int fromBotNumber, string wearSetting, + HashSet behaviourSwitches) + { + ConnectingBots = true; + + Thread startBotThread + = new Thread( + o => ConnectBotsInternal( + botcount, firstName, lastNameStem, password, loginUri, startUri, fromBotNumber, wearSetting, + behaviourSwitches)); + + startBotThread.Name = "Bots connection thread"; + startBotThread.Start(); + + return true; + } + + private void ConnectBotsInternal( int botcount, string firstName, string lastNameStem, string password, string loginUri, string startUri, int fromBotNumber, string wearSetting, HashSet behaviourSwitches) { @@ -273,6 +296,8 @@ namespace pCampBot // Stagger logins Thread.Sleep(LoginDelay); } + + ConnectingBots = false; } /// diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index b02f917..e58b130 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -95,10 +95,7 @@ namespace pCampBot int botcount = commandLineConfig.GetInt("botcount", 1); - //startup specified number of bots. 1 is the default - Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, commandLineConfig)); - startBotThread.Name = "Initial start bots thread"; - startBotThread.Start(); + bm.dobotStartup(botcount, commandLineConfig); while (true) { -- cgit v1.1 From 589b1a2eaf9058c3577b17ae76580a79ba855978 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 19 Aug 2013 23:50:18 +0100 Subject: Make it possible to reconnect pCampbots with the console command "connect []". If no n is given then all available bots are connected --- OpenSim/Tools/pCampBot/Bot.cs | 96 ++++++++++++++++++------- OpenSim/Tools/pCampBot/BotManager.cs | 136 +++++++++++++++++++++-------------- OpenSim/Tools/pCampBot/pCampBot.cs | 3 +- 3 files changed, 155 insertions(+), 80 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index be7a5a1..f7af26e 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -158,8 +158,6 @@ namespace pCampBot behaviours.ForEach(b => b.Initialize(this)); - Client = new GridClient(); - Random = new Random(Environment.TickCount);// We do stuff randomly here FirstName = firstName; LastName = lastName; @@ -170,6 +168,59 @@ namespace pCampBot Manager = bm; Behaviours = behaviours; + + // Only calling for use as a template. + CreateLibOmvClient(); + } + + private void CreateLibOmvClient() + { + GridClient newClient = new GridClient(); + + if (Client != null) + { + newClient.Settings.LOGIN_SERVER = Client.Settings.LOGIN_SERVER; + newClient.Settings.ALWAYS_DECODE_OBJECTS = Client.Settings.ALWAYS_DECODE_OBJECTS; + newClient.Settings.AVATAR_TRACKING = Client.Settings.AVATAR_TRACKING; + newClient.Settings.OBJECT_TRACKING = Client.Settings.OBJECT_TRACKING; + newClient.Settings.SEND_AGENT_THROTTLE = Client.Settings.SEND_AGENT_THROTTLE; + newClient.Settings.SEND_AGENT_UPDATES = Client.Settings.SEND_AGENT_UPDATES; + newClient.Settings.SEND_PINGS = Client.Settings.SEND_PINGS; + newClient.Settings.STORE_LAND_PATCHES = Client.Settings.STORE_LAND_PATCHES; + newClient.Settings.USE_ASSET_CACHE = Client.Settings.USE_ASSET_CACHE; + newClient.Settings.MULTIPLE_SIMS = Client.Settings.MULTIPLE_SIMS; + newClient.Throttle.Asset = Client.Throttle.Asset; + newClient.Throttle.Land = Client.Throttle.Land; + newClient.Throttle.Task = Client.Throttle.Task; + newClient.Throttle.Texture = Client.Throttle.Texture; + newClient.Throttle.Wind = Client.Throttle.Wind; + newClient.Throttle.Total = Client.Throttle.Total; + } + else + { + newClient.Settings.LOGIN_SERVER = LoginUri; + newClient.Settings.ALWAYS_DECODE_OBJECTS = false; + newClient.Settings.AVATAR_TRACKING = false; + newClient.Settings.OBJECT_TRACKING = false; + newClient.Settings.SEND_AGENT_THROTTLE = true; + newClient.Settings.SEND_PINGS = true; + newClient.Settings.STORE_LAND_PATCHES = false; + newClient.Settings.USE_ASSET_CACHE = false; + newClient.Settings.MULTIPLE_SIMS = true; + newClient.Throttle.Asset = 100000; + newClient.Throttle.Land = 100000; + newClient.Throttle.Task = 100000; + newClient.Throttle.Texture = 100000; + newClient.Throttle.Wind = 100000; + newClient.Throttle.Total = 400000; + } + + newClient.Network.LoginProgress += this.Network_LoginProgress; + newClient.Network.SimConnected += this.Network_SimConnected; + newClient.Network.Disconnected += this.Network_OnDisconnected; + newClient.Objects.ObjectUpdate += Objects_NewPrim; + + Client = newClient; } //We do our actions here. This is where one would @@ -192,7 +243,7 @@ namespace pCampBot /// /// Tells LibSecondLife to logout and disconnect. Raises the disconnect events once it finishes. /// - public void shutdown() + public void Disconnect() { ConnectionState = ConnectionState.Disconnecting; @@ -202,34 +253,27 @@ namespace pCampBot Client.Network.Logout(); } + public void Connect() + { + Thread connectThread = new Thread(ConnectInternal); + connectThread.Name = Name; + connectThread.IsBackground = true; + + connectThread.Start(); + } + /// /// This is the bot startup loop. /// - public void startup() + private void ConnectInternal() { - Client.Settings.LOGIN_SERVER = LoginUri; - Client.Settings.ALWAYS_DECODE_OBJECTS = false; - Client.Settings.AVATAR_TRACKING = false; - Client.Settings.OBJECT_TRACKING = false; - Client.Settings.SEND_AGENT_THROTTLE = true; - Client.Settings.SEND_AGENT_UPDATES = false; - Client.Settings.SEND_PINGS = true; - Client.Settings.STORE_LAND_PATCHES = false; - Client.Settings.USE_ASSET_CACHE = false; - Client.Settings.MULTIPLE_SIMS = true; - Client.Throttle.Asset = 100000; - Client.Throttle.Land = 100000; - Client.Throttle.Task = 100000; - Client.Throttle.Texture = 100000; - Client.Throttle.Wind = 100000; - Client.Throttle.Total = 400000; - Client.Network.LoginProgress += this.Network_LoginProgress; - Client.Network.SimConnected += this.Network_SimConnected; - Client.Network.Disconnected += this.Network_OnDisconnected; - Client.Objects.ObjectUpdate += Objects_NewPrim; - ConnectionState = ConnectionState.Connecting; + // Current create a new client on each connect. libomv doesn't seem to process new sim + // information (e.g. EstablishAgentCommunication events) if connecting after a disceonnect with the same + // client + CreateLibOmvClient(); + if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", StartLocation, "Your name")) { ConnectionState = ConnectionState.Connected; @@ -474,6 +518,8 @@ namespace pCampBot // || args.Reason == NetworkManager.DisconnectType.NetworkTimeout) // && OnDisconnected != null) + + if ( (args.Reason == NetworkManager.DisconnectType.ClientInitiated || args.Reason == NetworkManager.DisconnectType.ServerInitiated diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index fe6048a..f40a84d 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -182,6 +182,12 @@ namespace pCampBot "bot", false, "quit", "quit", "Shutdown bots and exit", HandleShutdown); m_console.Commands.AddCommand( + "bot", false, "connect", "connect []", "Connect bots", + "If an is given, then the first disconnected bots by postfix number are connected.\n" + + "If no is given, then all currently disconnected bots are connected.", + HandleConnect); + + m_console.Commands.AddCommand( "bot", false, "disconnect", "disconnect []", "Disconnect bots", "Disconnecting bots will interupt any bot connection process, including connection on startup.\n" + "If an is given, then the last connected bots by postfix number are disconnected.\n" @@ -206,7 +212,7 @@ namespace pCampBot /// /// How many bots to start up /// The configuration for the bots to use - public void dobotStartup(int botcount, IConfig startupConfig) + public void CreateBots(int botcount, IConfig startupConfig) { m_firstName = startupConfig.GetString("firstname"); m_lastNameStem = startupConfig.GetString("lastname"); @@ -220,39 +226,55 @@ namespace pCampBot Array.ForEach( startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_behaviourSwitches.Add(b)); - ConnectBots( - botcount, m_firstName, m_lastNameStem, m_password, m_loginUri, m_startUri, m_fromBotNumber, m_wearSetting, m_behaviourSwitches); + for (int i = 0; i < botcount; i++) + { + lock (m_bots) + { + string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber); + + // We must give each bot its own list of instantiated behaviours since they store state. + List behaviours = new List(); + + // Hard-coded for now + if (m_behaviourSwitches.Contains("c")) + behaviours.Add(new CrossBehaviour()); + + if (m_behaviourSwitches.Contains("g")) + behaviours.Add(new GrabbingBehaviour()); + + if (m_behaviourSwitches.Contains("n")) + behaviours.Add(new NoneBehaviour()); + + if (m_behaviourSwitches.Contains("p")) + behaviours.Add(new PhysicsBehaviour()); + + if (m_behaviourSwitches.Contains("t")) + behaviours.Add(new TeleportBehaviour()); + + CreateBot(this, behaviours, m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); + } + } } - private bool ConnectBots( - int botcount, string firstName, string lastNameStem, string password, string loginUri, string startUri, int fromBotNumber, string wearSetting, - HashSet behaviourSwitches) + public void ConnectBots(int botcount) { ConnectingBots = true; - Thread startBotThread - = new Thread( - o => ConnectBotsInternal( - botcount, firstName, lastNameStem, password, loginUri, startUri, fromBotNumber, wearSetting, - behaviourSwitches)); - - startBotThread.Name = "Bots connection thread"; - startBotThread.Start(); + Thread connectBotThread = new Thread(o => ConnectBotsInternal(botcount)); - return true; + connectBotThread.Name = "Bots connection thread"; + connectBotThread.Start(); } - private void ConnectBotsInternal( - int botcount, string firstName, string lastNameStem, string password, string loginUri, string startUri, int fromBotNumber, string wearSetting, - HashSet behaviourSwitches) + private void ConnectBotsInternal(int botcount) { MainConsole.Instance.OutputFormat( "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_", botcount, - loginUri, - startUri, - firstName, - lastNameStem); + m_loginUri, + m_startUri, + m_firstName, + m_lastNameStem); MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates); @@ -269,28 +291,7 @@ namespace pCampBot break; } - string lastName = string.Format("{0}_{1}", lastNameStem, i + fromBotNumber); - - // We must give each bot its own list of instantiated behaviours since they store state. - List behaviours = new List(); - - // Hard-coded for now - if (behaviourSwitches.Contains("c")) - behaviours.Add(new CrossBehaviour()); - - if (behaviourSwitches.Contains("g")) - behaviours.Add(new GrabbingBehaviour()); - - if (behaviourSwitches.Contains("n")) - behaviours.Add(new NoneBehaviour()); - - if (behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - - if (behaviourSwitches.Contains("t")) - behaviours.Add(new TeleportBehaviour()); - - StartBot(this, behaviours, firstName, lastName, password, loginUri, startUri, wearSetting); + m_bots[i].Connect(); } // Stagger logins @@ -360,7 +361,7 @@ namespace pCampBot // } /// - /// This starts up the bot and stores the thread for the bot in the thread array + /// This creates a bot but does not start it. /// /// /// Behaviours for this bot to perform. @@ -370,12 +371,12 @@ namespace pCampBot /// Login URI /// Location to start the bot. Can be "last", "home" or a specific sim name. /// - public void StartBot( + public void CreateBot( BotManager bm, List behaviours, string firstName, string lastName, string password, string loginUri, string startLocation, string wearSetting) { MainConsole.Instance.OutputFormat( - "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}", + "[BOT MANAGER]: Creating bot {0} {1}, behaviours are {2}", firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); Bot pb = new Bot(bm, behaviours, firstName, lastName, password, startLocation, loginUri); @@ -387,12 +388,6 @@ namespace pCampBot pb.OnDisconnected += handlebotEvent; m_bots.Add(pb); - - Thread pbThread = new Thread(pb.startup); - pbThread.Name = pb.Name; - pbThread.IsBackground = true; - - pbThread.Start(); } /// @@ -427,6 +422,37 @@ namespace pCampBot return new LocalConsole("pCampbot"); } + private void HandleConnect(string module, string[] cmd) + { + if (ConnectingBots) + { + MainConsole.Instance.Output("Still connecting bots. Please wait for previous process to complete."); + return; + } + + lock (m_bots) + { + int botsToConnect; + int disconnectedBots = m_bots.Count(b => b.ConnectionState == ConnectionState.Disconnected); + + if (cmd.Length == 1) + { + botsToConnect = disconnectedBots; + } + else + { + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[1], out botsToConnect)) + return; + + botsToConnect = Math.Min(botsToConnect, disconnectedBots); + } + + MainConsole.Instance.OutputFormat("Connecting {0} bots", botsToConnect); + + ConnectBots(botsToConnect); + } + } + private void HandleDisconnect(string module, string[] cmd) { lock (m_bots) @@ -461,10 +487,12 @@ namespace pCampBot if (thisBot.ConnectionState == ConnectionState.Connected) { - Util.FireAndForget(o => thisBot.shutdown()); + Util.FireAndForget(o => thisBot.Disconnect()); disconnectedBots++; } } + + DisconnectingBots = false; } } diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index e58b130..ada39ee 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -95,7 +95,8 @@ namespace pCampBot int botcount = commandLineConfig.GetInt("botcount", 1); - bm.dobotStartup(botcount, commandLineConfig); + bm.CreateBots(botcount, commandLineConfig); + bm.ConnectBots(botcount); while (true) { -- cgit v1.1 From a3dd7db4a341f34e0df5b7fa4bddda4049e50acd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Aug 2013 00:08:47 +0100 Subject: Add -connect (-c) switch to pCampbot command line options. Now, bots will only connect at startup if this switch is specified. If it is not specified, then a separate "connect" command is required on the pCampbot command line --- OpenSim/Tools/pCampBot/pCampBot.cs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index ada39ee..fc67398 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -94,9 +94,12 @@ namespace pCampBot } int botcount = commandLineConfig.GetInt("botcount", 1); + bool startConnected = commandLineConfig.Get("connect") != null; bm.CreateBots(botcount, commandLineConfig); - bm.ConnectBots(botcount); + + if (startConnected) + bm.ConnectBots(botcount); while (true) { @@ -117,6 +120,7 @@ namespace pCampBot //Set up our nifty config.. thanks to nini ArgvConfigSource cs = new ArgvConfigSource(args); + cs.AddSwitch("Startup", "connect", "c"); cs.AddSwitch("Startup", "botcount", "n"); cs.AddSwitch("Startup", "from", "f"); cs.AddSwitch("Startup", "loginuri", "l"); @@ -143,20 +147,21 @@ namespace pCampBot "usage: pCampBot <-loginuri loginuri> [OPTIONS]\n" + "Spawns a set of bots to test an OpenSim region\n\n" + " -l, -loginuri loginuri for grid/standalone (required)\n" - + " -s, -start optional start location for bots. Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" - + " -firstname first name for the bots\n" - + " -lastname lastname for the bots. Each lastname will have _ appended, e.g. Ima Bot_0\n" - + " -password password for the bots\n" - + " -n, -botcount optional number of bots to start (default: 1)\n" - + " -f, -from optional starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0)" - + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p\n" + + " -s, -start start location for bots (optional). Can be \"last\", \"home\" or a specific location with or without co-ords (e.g. \"region1\" or \"region2/50/30/90\"\n" + + " -firstname first name for the bots (required)\n" + + " -lastname lastname for the bots (required). Each lastname will have _ appended, e.g. Ima Bot_0\n" + + " -password password for the bots (required)\n" + + " -n, -botcount number of bots to start (default: 1) (optional)\n" + + " -f, -from starting number for login bot names, e.g. 25 will login Ima Bot_25, Ima Bot_26, etc. (default: 0) (optional)\n" + + " -c, -connect connect all bots at startup (optional)\n" + + " -b, behaviours behaviours for bots. Comma separated, e.g. p,g. Default is p (required)\n" + " current options are:\n" + " p (physics - bots constantly move and jump around)\n" + " g (grab - bots randomly click prims whether set clickable or not)\n" + " n (none - bots do nothing)\n" + " t (teleport - bots regularly teleport between regions on the grid)\n" -// " c (cross)" + - + " -wear optional folder from which to load appearance data, \"no\" if there is no such folder (default: no)\n" +// " c (cross)\n" + + + " -wear folder from which to load appearance data, \"no\" if there is no such folder (default: no) (optional)\n" + " -h, -help show this message.\n"); } } -- cgit v1.1 From 56d1d67a34bbd3e597168ab9bfa43be6a34e580a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Aug 2013 17:01:12 +0100 Subject: Add pCampbot console commands to sit all bots on ground and stand all bots --- OpenSim/Tools/pCampBot/Bot.cs | 24 ++++++++++++ OpenSim/Tools/pCampBot/BotManager.cs | 74 +++++++++++++----------------------- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index f7af26e..27c086e 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -318,6 +318,30 @@ namespace pCampBot } } + /// + /// Sit this bot on the ground. + /// + public void SitOnGround() + { + if (ConnectionState == ConnectionState.Connected) + Client.Self.SitOnGround(); + } + + /// + /// Stand this bot + /// + public void Stand() + { + if (ConnectionState == ConnectionState.Connected) + { + // Unlike sit on ground, here libomv checks whether we have SEND_AGENT_UPDATES enabled. + bool prevUpdatesSetting = Client.Settings.SEND_AGENT_UPDATES; + Client.Settings.SEND_AGENT_UPDATES = true; + Client.Self.Stand(); + Client.Settings.SEND_AGENT_UPDATES = prevUpdatesSetting; + } + } + public void SaveDefaultAppearance() { saveDir = "MyAppearance/" + FirstName + "_" + LastName; diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index f40a84d..f5b5256 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -195,14 +195,18 @@ namespace pCampBot HandleDisconnect); m_console.Commands.AddCommand( - "bot", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions); + "bot", false, "sit", "sit", "Sit all bots on the ground.", + HandleSit); + + m_console.Commands.AddCommand( + "bot", false, "stand", "stand", "Stand all bots.", + HandleStand); m_console.Commands.AddCommand( - "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowStatus); + "bot", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions); -// m_console.Commands.AddCommand("bot", false, "add bots", -// "add bots ", -// "Add more bots", HandleAddBots); + m_console.Commands.AddCommand( + "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus); m_bots = new List(); } @@ -340,26 +344,6 @@ namespace pCampBot return string.Format("uri:{0}&{1}&{2}&{3}", regionName, startPos.X, startPos.Y, startPos.Z); } -// /// -// /// Add additional bots (and threads) to our bot pool -// /// -// /// How Many of them to add -// public void addbots(int botcount) -// { -// int len = m_td.Length; -// Thread[] m_td2 = new Thread[len + botcount]; -// for (int i = 0; i < len; i++) -// { -// m_td2[i] = m_td[i]; -// } -// m_td = m_td2; -// int newlen = len + botcount; -// for (int i = len; i < newlen; i++) -// { -// startupBot(Config); -// } -// } - /// /// This creates a bot but does not start it. /// @@ -496,6 +480,22 @@ namespace pCampBot } } + private void HandleSit(string module, string[] cmd) + { + lock (m_bots) + { + m_bots.ForEach(b => b.SitOnGround()); + } + } + + private void HandleStand(string module, string[] cmd) + { + lock (m_bots) + { + m_bots.ForEach(b => b.Stand()); + } + } + private void HandleShutdown(string module, string[] cmd) { lock (m_bots) @@ -529,7 +529,7 @@ namespace pCampBot } } - private void HandleShowStatus(string module, string[] cmd) + private void HandleShowBotsStatus(string module, string[] cmd) { ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("Name", 30); @@ -563,26 +563,6 @@ namespace pCampBot MainConsole.Instance.Output(cdl.ToString()); } - /* - private void HandleQuit(string module, string[] cmd) - { - m_console.Warn("DANGER", "This should only be used to quit the program if you've already used the shutdown command and the program hasn't quit"); - Environment.Exit(0); - } - */ -// -// private void HandleAddBots(string module, string[] cmd) -// { -// int newbots = 0; -// -// if (cmd.Length > 2) -// { -// Int32.TryParse(cmd[2], out newbots); -// } -// if (newbots > 0) -// addbots(newbots); -// } - internal void Grid_GridRegion(object o, GridRegionEventArgs args) { lock (RegionsKnown) @@ -602,4 +582,4 @@ namespace pCampBot } } } -} +} \ No newline at end of file -- cgit v1.1 From e384ff604e081970ae9351431115a87e82345b18 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Aug 2013 17:43:02 +0100 Subject: Add experimental "sit user name" and "stand user name" console commands in SitStandCommandsModule. "sit user name" will currently only sit the given avatar on prims which have a sit target set and are not already sat upon. Chiefly for debug purposes. --- .../Avatar/SitStand/SitStandCommandsModule.cs | 180 +++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs diff --git a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs new file mode 100644 index 0000000..874723c --- /dev/null +++ b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs @@ -0,0 +1,180 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Monitoring; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Animation; +using OpenSim.Services.Interfaces; + +namespace OpenSim.Region.OptionalModules.Avatar.SitStand +{ + /// + /// A module that just holds commands for changing avatar sitting and standing states. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")] + public class SitStandCommandModule : INonSharedRegionModule + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + + public string Name { get { return "SitStand Command Module"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE"); + } + + public void PostInitialise() + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE"); + } + + public void Close() + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); + + m_scene = scene; + + scene.AddCommand( + "Users", this, "sit user name", + "sit user name ", + "Sit the named user on an unoccupied object with a sit target.\n" + + "If there are no such objects then nothing happens", + HandleSitUserNameCommand); + + scene.AddCommand( + "Users", this, "stand user name", + "stand user name ", + "Stand the named user.", + HandleStandUserNameCommand); + } + + protected void HandleSitUserNameCommand(string module, string[] cmd) + { + if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) + return; + + if (cmd.Length != 5) + { + MainConsole.Instance.Output("Usage: sit user name "); + return; + } + + string firstName = cmd[3]; + string lastName = cmd[4]; + + ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); + + if (sp == null || sp.IsChildAgent) + return; + + SceneObjectPart sitPart = null; + List sceneObjects = m_scene.GetSceneObjectGroups(); + + foreach (SceneObjectGroup sceneObject in sceneObjects) + { + foreach (SceneObjectPart part in sceneObject.Parts) + { + if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) + { + sitPart = part; + break; + } + } + } + + if (sitPart != null) + { + MainConsole.Instance.OutputFormat( + "Sitting {0} on {1} {2} in {3}", + sp.Name, sitPart.ParentGroup.Name, sitPart.ParentGroup.UUID, m_scene.Name); + + sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, sitPart.UUID, Vector3.Zero); + sp.HandleAgentSit(sp.ControllingClient, sp.UUID); + } + else + { + MainConsole.Instance.OutputFormat( + "Could not find any unoccupied set seat on which to sit {0} in {1}", + sp.Name, m_scene.Name); + } + } + + protected void HandleStandUserNameCommand(string module, string[] cmd) + { + if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) + return; + + if (cmd.Length != 5) + { + MainConsole.Instance.Output("Usage: stand user name "); + return; + } + + string firstName = cmd[3]; + string lastName = cmd[4]; + + ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); + + if (sp == null || sp.IsChildAgent) + return; + + sp.StandUp(); + } + } +} \ No newline at end of file -- cgit v1.1 From 43940f656210d5e572ef05bd223b3959513ee687 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Aug 2013 18:13:40 +0100 Subject: Add --regex options to "sit user name" and "stand user name" console commands to sit/stand many avatars at once. Currently, first name and last name are input separate but are concatenated with a space in the middle to form a regex. So to sit all bots with the first name "ima", for instance, the command is "sit user name --regex ima .*" --- .../Avatar/SitStand/SitStandCommandsModule.cs | 131 +++++++++++++-------- 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs index 874723c..e9cb213 100644 --- a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs @@ -30,18 +30,16 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using log4net; using Mono.Addins; +using NDesk.Options; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Console; -using OpenSim.Framework.Monitoring; -using OpenSim.Region.ClientStack.LindenUDP; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; -using OpenSim.Region.Framework.Scenes.Animation; -using OpenSim.Services.Interfaces; namespace OpenSim.Region.OptionalModules.Avatar.SitStand { @@ -92,89 +90,122 @@ namespace OpenSim.Region.OptionalModules.Avatar.SitStand scene.AddCommand( "Users", this, "sit user name", - "sit user name ", - "Sit the named user on an unoccupied object with a sit target.\n" - + "If there are no such objects then nothing happens", + "sit user name [--regex] ", + "Sit the named user on an unoccupied object with a sit target.", + "If there are no such objects then nothing happens.\n" + + "If --regex is specified then the names are treated as regular expressions.", HandleSitUserNameCommand); scene.AddCommand( "Users", this, "stand user name", - "stand user name ", + "stand user name [--regex] ", "Stand the named user.", + "If --regex is specified then the names are treated as regular expressions.", HandleStandUserNameCommand); } - protected void HandleSitUserNameCommand(string module, string[] cmd) + private void HandleSitUserNameCommand(string module, string[] cmd) { if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) return; - if (cmd.Length != 5) + if (cmd.Length < 5) { - MainConsole.Instance.Output("Usage: sit user name "); + MainConsole.Instance.Output("Usage: sit user name [--regex] "); return; } - string firstName = cmd[3]; - string lastName = cmd[4]; + List scenePresences = GetScenePresences(cmd); - ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); - - if (sp == null || sp.IsChildAgent) - return; - - SceneObjectPart sitPart = null; - List sceneObjects = m_scene.GetSceneObjectGroups(); - - foreach (SceneObjectGroup sceneObject in sceneObjects) + foreach (ScenePresence sp in scenePresences) { - foreach (SceneObjectPart part in sceneObject.Parts) + SceneObjectPart sitPart = null; + List sceneObjects = m_scene.GetSceneObjectGroups(); + + foreach (SceneObjectGroup sceneObject in sceneObjects) { - if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) + foreach (SceneObjectPart part in sceneObject.Parts) { - sitPart = part; - break; + if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) + { + sitPart = part; + break; + } } } - } - if (sitPart != null) - { - MainConsole.Instance.OutputFormat( - "Sitting {0} on {1} {2} in {3}", - sp.Name, sitPart.ParentGroup.Name, sitPart.ParentGroup.UUID, m_scene.Name); + if (sitPart != null) + { + MainConsole.Instance.OutputFormat( + "Sitting {0} on {1} {2} in {3}", + sp.Name, sitPart.ParentGroup.Name, sitPart.ParentGroup.UUID, m_scene.Name); - sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, sitPart.UUID, Vector3.Zero); - sp.HandleAgentSit(sp.ControllingClient, sp.UUID); - } - else - { - MainConsole.Instance.OutputFormat( - "Could not find any unoccupied set seat on which to sit {0} in {1}", - sp.Name, m_scene.Name); + sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, sitPart.UUID, Vector3.Zero); + sp.HandleAgentSit(sp.ControllingClient, sp.UUID); + } + else + { + MainConsole.Instance.OutputFormat( + "Could not find any unoccupied set seat on which to sit {0} in {1}. Aborting", + sp.Name, m_scene.Name); + + break; + } } } - protected void HandleStandUserNameCommand(string module, string[] cmd) + private void HandleStandUserNameCommand(string module, string[] cmd) { if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) return; - if (cmd.Length != 5) + if (cmd.Length < 5) { - MainConsole.Instance.Output("Usage: stand user name "); + MainConsole.Instance.Output("Usage: stand user name [--regex] "); return; } - string firstName = cmd[3]; - string lastName = cmd[4]; + List scenePresences = GetScenePresences(cmd); - ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); - - if (sp == null || sp.IsChildAgent) - return; + foreach (ScenePresence sp in scenePresences) + { + MainConsole.Instance.OutputFormat("Standing {0} in {1}", sp.Name, m_scene.Name); + sp.StandUp(); + } + } + + private List GetScenePresences(string[] cmdParams) + { + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdParams); + + string firstName = mainParams[3]; + string lastName = mainParams[4]; + + List scenePresencesMatched = new List(); + + if (useRegex) + { + Regex nameRegex = new Regex(string.Format("{0} {1}", firstName, lastName)); + List scenePresences = m_scene.GetScenePresences(); + + foreach (ScenePresence sp in scenePresences) + { + if (!sp.IsChildAgent && nameRegex.IsMatch(sp.Name)) + scenePresencesMatched.Add(sp); + } + } + else + { + ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); + + if (sp != null && !sp.IsChildAgent) + scenePresencesMatched.Add(sp); + } - sp.StandUp(); + return scenePresencesMatched; } } } \ No newline at end of file -- cgit v1.1 From a3e1b278a1d82e231f85bf0bf181ed79bbdaa7f2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Aug 2013 18:41:09 +0100 Subject: Add pCampbot "show bot" console command to show more detailed information on a particular bot (e.g. what sims they are connected to) --- OpenSim/Tools/pCampBot/Bot.cs | 11 +++++++- OpenSim/Tools/pCampBot/BotManager.cs | 49 +++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 27c086e..d418288 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -97,11 +97,20 @@ namespace pCampBot /// public ConnectionState ConnectionState { get; private set; } + public List Simulators + { + get + { + lock (Client.Network.Simulators) + return new List(Client.Network.Simulators); + } + } + /// /// The number of connections that this bot has to different simulators. /// /// Includes both root and child connections. - public int ConnectionsCount + public int SimulatorsCount { get { diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index f5b5256..303c8dd 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -208,6 +208,10 @@ namespace pCampBot m_console.Commands.AddCommand( "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus); + m_console.Commands.AddCommand( + "bot", false, "show bot", "show bot ", + "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus); + m_bots = new List(); } @@ -549,7 +553,7 @@ namespace pCampBot totals[pb.ConnectionState]++; cdt.AddRow( - pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState, pb.ConnectionsCount); + pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState, pb.SimulatorsCount); } } @@ -563,6 +567,49 @@ namespace pCampBot MainConsole.Instance.Output(cdl.ToString()); } + private void HandleShowBotStatus(string module, string[] cmd) + { + if (cmd.Length != 4) + { + MainConsole.Instance.Output("Usage: show bot "); + return; + } + + string name = string.Format("{0} {1}", cmd[2], cmd[3]); + + Bot bot; + + lock (m_bots) + bot = m_bots.Find(b => b.Name == name); + + if (bot == null) + { + MainConsole.Instance.Output("No bot found with name {0}", name); + return; + } + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + cdl.AddRow("Name", bot.Name); + cdl.AddRow("Status", bot.ConnectionState); + + Simulator currentSim = bot.Client.Network.CurrentSim; + cdl.AddRow("Region", currentSim != null ? currentSim.Name : "(none)"); + + List connectedSimulators = bot.Simulators; + List simulatorNames = connectedSimulators.ConvertAll(cs => cs.Name); + cdl.AddRow("Connections", string.Join(", ", simulatorNames)); + + MainConsole.Instance.Output(cdl.ToString()); + + MainConsole.Instance.Output("Settings"); + + ConsoleDisplayList statusCdl = new ConsoleDisplayList(); + GridClient botClient = bot.Client; + statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES); + + MainConsole.Instance.Output(statusCdl.ToString()); + } + internal void Grid_GridRegion(object o, GridRegionEventArgs args) { lock (RegionsKnown) -- cgit v1.1 From 4a81465b91b6506200157f8679ae9192cd43b45f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Aug 2013 18:47:52 +0100 Subject: Fix build break from last commit a3e1b27 on mono 2.4.3 Looks like this level of mono doesn't have a string.Join() which will take a list rather than an array (or some implicit conversion isn't happening) --- OpenSim/Tools/pCampBot/BotManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 303c8dd..13912ae 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -597,7 +597,7 @@ namespace pCampBot List connectedSimulators = bot.Simulators; List simulatorNames = connectedSimulators.ConvertAll(cs => cs.Name); - cdl.AddRow("Connections", string.Join(", ", simulatorNames)); + cdl.AddRow("Connections", string.Join(", ", simulatorNames.ToArray())); MainConsole.Instance.Output(cdl.ToString()); -- cgit v1.1 From a6af561660759ef7625d88213b7d43b76e687280 Mon Sep 17 00:00:00 2001 From: teravus Date: Tue, 20 Aug 2013 21:09:17 -0500 Subject: * Fix some threading issues in BulletXNA (the managed bullet library), this should better allow you to run it in multiple region scenarios (but why would you really want to do that?) Source in OpenSimLibs. * Fixed a null ref during shutdown. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 5 ++- OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 46 ++++++++++++++++++++- bin/BulletXNA.dll | Bin 610304 -> 618496 bytes bin/BulletXNA.pdb | Bin 1963520 -> 1889792 bytes 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index eb3af42..c9ff4f3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4089,7 +4089,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { return IsHingeJoint() || IsBallJoint(); } @@ -4413,7 +4413,8 @@ namespace OpenSim.Region.Framework.Scenes public void RemoveFromPhysics() { ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this); - ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); + if (ParentGroup.Scene.PhysicsScene != null) + ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); PhysActor = null; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 6db5f5e..2a820be 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -1221,6 +1221,50 @@ private sealed class BulletConstraintXNA : BulletConstraint //BSParam.TerrainImplementation = 0; world.SetGravity(new IndexedVector3(0,0,p.gravity)); + // Turn off Pooling since globals and pooling are bad for threading. + BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false); + BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false); + BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false); + BulletGlobals.CastResultPool.SetPoolingEnabled(false); + BulletGlobals.SphereShapePool.SetPoolingEnabled(false); + BulletGlobals.DbvtNodePool.SetPoolingEnabled(false); + BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false); + BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false); + BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false); + BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false); + BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false); + BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false); + BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false); + BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false); + BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false); + + BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false); + BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false); + BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false); + BulletGlobals.GJKPool.SetPoolingEnabled(false); + BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false); + BulletGlobals.TriangleShapePool.SetPoolingEnabled(false); + BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false); + BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false); + BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false); + BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false); + BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false); + BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false); + return world; } //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL @@ -1914,7 +1958,7 @@ private sealed class BulletConstraintXNA : BulletConstraint heightMap, scaleFactor, minHeight, maxHeight, upAxis, false); - terrainShape.SetMargin(collisionMargin + 0.5f); + terrainShape.SetMargin(collisionMargin); terrainShape.SetUseDiamondSubdivision(true); terrainShape.SetUserPointer(id); return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); diff --git a/bin/BulletXNA.dll b/bin/BulletXNA.dll index bfaac4f..b3ddc32 100644 Binary files a/bin/BulletXNA.dll and b/bin/BulletXNA.dll differ diff --git a/bin/BulletXNA.pdb b/bin/BulletXNA.pdb index ecab22f..ed3baad 100644 Binary files a/bin/BulletXNA.pdb and b/bin/BulletXNA.pdb differ -- cgit v1.1 From 1f39a763a5186c7c51e10b5b055394672cc6c54e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 21 Aug 2013 21:35:03 +0100 Subject: Don't allow users to attempt to sit on objects in a child region without going to that region first. If this is attempted, they get a "Try moving closer. Can't sit on object because it is not in the same region as you." message instead, which is the same as current ll grid. Sitting on ground is okay, since viewer navigates avatar to required region first before sitting. --- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 20 ++++++++++++++++++++ OpenSim/Region/Framework/Scenes/ScenePresence.cs | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index f0d8181..8c51077 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -6651,6 +6651,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion + if (SceneAgent.IsChildAgent) + { + SendCantSitBecauseChildAgentResponse(); + return true; + } + AgentRequestSit handlerAgentRequestSit = OnAgentRequestSit; if (handlerAgentRequestSit != null) @@ -6675,6 +6681,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion + if (SceneAgent.IsChildAgent) + { + SendCantSitBecauseChildAgentResponse(); + return true; + } + AgentSit handlerAgentSit = OnAgentSit; if (handlerAgentSit != null) { @@ -6684,6 +6696,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } + /// + /// Used when a child agent gets a sit response which should not be fulfilled. + /// + private void SendCantSitBecauseChildAgentResponse() + { + SendAlertMessage("Try moving closer. Can't sit on object because it is not in the same region as you."); + } + private bool HandleSoundTrigger(IClientAPI sender, Packet Pack) { SoundTriggerPacket soundTriggerPacket = (SoundTriggerPacket)Pack; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 37e5286..4fc207a 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2297,6 +2297,9 @@ namespace OpenSim.Region.Framework.Scenes public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) { + if (IsChildAgent) + return; + if (ParentID != 0) { if (ParentPart.UUID == targetID) @@ -2523,6 +2526,9 @@ namespace OpenSim.Region.Framework.Scenes public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) { + if (IsChildAgent) + return; + SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); if (part != null) @@ -2583,6 +2589,9 @@ namespace OpenSim.Region.Framework.Scenes public void HandleAgentSitOnGround() { + if (IsChildAgent) + return; + // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. m_AngularVelocity = Vector3.Zero; Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); -- cgit v1.1 From 3d9b73c47a15cf00150ac80570fea88de8cecbdf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 21 Aug 2013 23:19:31 +0100 Subject: Implement ability for hg logins to try fallback regions just like local logins. These would be specified in the [GridService] section of Robust.HG.ini, which already lists these in the example text. Untested patch so that Neb can easily pull in for testing, though shouldn't disrupt existing hg logins since fallback processing is a bit of code stuck on the end of the login sequence. --- .../Services/HypergridService/GatekeeperService.cs | 44 +++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 0a3e70b..cbe1af0 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -326,7 +326,7 @@ namespace OpenSim.Services.HypergridService return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: User is OK"); + m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name); bool isFirstLogin = false; // @@ -345,7 +345,7 @@ namespace OpenSim.Services.HypergridService aCircuit.firstname, aCircuit.lastname); return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); + m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name); // Also login foreigners with GridUser service if (m_GridUserService != null && account == null) @@ -376,7 +376,8 @@ namespace OpenSim.Services.HypergridService reason = "Destination region not found"; return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: destination ok: {0}", destination.RegionName); + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name); // // Adjust the visible name @@ -410,8 +411,41 @@ namespace OpenSim.Services.HypergridService // Preserve our TeleportFlags we have gathered so-far loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags; - m_log.DebugFormat("[GATEKEEPER SERVICE]: launching agent {0}", loginFlag); - return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); + m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0} {1}", aCircuit.Name, loginFlag); + + bool success = m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); + + if (!success) + { + List fallbackRegions = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY); + if (fallbackRegions != null) + { + // Try the fallback regions + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Could not successfully log agent {0} into {1}. Trying fallback regions.", + aCircuit.Name, destination.RegionName); + + foreach (GridRegion fallbackRegion in fallbackRegions) + { + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Trying fallback region {0} for {1}", + fallbackRegion.RegionName, aCircuit.Name); + + success = m_SimulationService.CreateAgent(fallbackRegion, aCircuit, (uint)loginFlag, out reason); + + if (success) + break; + } + } + else + { + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Could not successfully log agent {0} into {1} and no fallback regions to try.", + aCircuit.Name, destination.RegionName); + } + } + + return success; } protected bool Authenticate(AgentCircuitData aCircuit) -- cgit v1.1 From bcb8605f8428a9009a2badf9c9eed06d9f59962c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 01:20:01 +0100 Subject: Revert "Implement ability for hg logins to try fallback regions just like local logins." This approach does not work - it is taking place too far down the login process where really the region checking could only be done when the hg map tiles are linked on the main map (messy and probably impossible) or possibly when the final destination is fetched at the very first stage of teleport (which couldn't be done without a protocol change to pass the agentID as well as the requested regionID) This reverts commit 3d9b73c47a15cf00150ac80570fea88de8cecbdf. --- .../Services/HypergridService/GatekeeperService.cs | 44 +++------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index cbe1af0..0a3e70b 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -326,7 +326,7 @@ namespace OpenSim.Services.HypergridService return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name); + m_log.DebugFormat("[GATEKEEPER SERVICE]: User is OK"); bool isFirstLogin = false; // @@ -345,7 +345,7 @@ namespace OpenSim.Services.HypergridService aCircuit.firstname, aCircuit.lastname); return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name); + m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); // Also login foreigners with GridUser service if (m_GridUserService != null && account == null) @@ -376,8 +376,7 @@ namespace OpenSim.Services.HypergridService reason = "Destination region not found"; return false; } - m_log.DebugFormat( - "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name); + m_log.DebugFormat("[GATEKEEPER SERVICE]: destination ok: {0}", destination.RegionName); // // Adjust the visible name @@ -411,41 +410,8 @@ namespace OpenSim.Services.HypergridService // Preserve our TeleportFlags we have gathered so-far loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags; - m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0} {1}", aCircuit.Name, loginFlag); - - bool success = m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); - - if (!success) - { - List fallbackRegions = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY); - if (fallbackRegions != null) - { - // Try the fallback regions - m_log.DebugFormat( - "[GATEKEEPER SERVICE]: Could not successfully log agent {0} into {1}. Trying fallback regions.", - aCircuit.Name, destination.RegionName); - - foreach (GridRegion fallbackRegion in fallbackRegions) - { - m_log.DebugFormat( - "[GATEKEEPER SERVICE]: Trying fallback region {0} for {1}", - fallbackRegion.RegionName, aCircuit.Name); - - success = m_SimulationService.CreateAgent(fallbackRegion, aCircuit, (uint)loginFlag, out reason); - - if (success) - break; - } - } - else - { - m_log.DebugFormat( - "[GATEKEEPER SERVICE]: Could not successfully log agent {0} into {1} and no fallback regions to try.", - aCircuit.Name, destination.RegionName); - } - } - - return success; + m_log.DebugFormat("[GATEKEEPER SERVICE]: launching agent {0}", loginFlag); + return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); } protected bool Authenticate(AgentCircuitData aCircuit) -- cgit v1.1 From 689cf2d3670ab4f9493acd5ef5adec4f446a4a47 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 01:24:55 +0100 Subject: minor: Make logging in GatekeeperService.LoginAgent() a bit more detailed so that we can distinguish between simultaneous logins --- OpenSim/Services/HypergridService/GatekeeperService.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 0a3e70b..e10c4cb 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -326,7 +326,7 @@ namespace OpenSim.Services.HypergridService return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: User is OK"); + m_log.DebugFormat("[GATEKEEPER SERVICE]: User {0} is ok", aCircuit.Name); bool isFirstLogin = false; // @@ -345,7 +345,8 @@ namespace OpenSim.Services.HypergridService aCircuit.firstname, aCircuit.lastname); return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); + + m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence {0} is ok", aCircuit.Name); // Also login foreigners with GridUser service if (m_GridUserService != null && account == null) @@ -376,7 +377,9 @@ namespace OpenSim.Services.HypergridService reason = "Destination region not found"; return false; } - m_log.DebugFormat("[GATEKEEPER SERVICE]: destination ok: {0}", destination.RegionName); + + m_log.DebugFormat( + "[GATEKEEPER SERVICE]: Destination {0} is ok for {1}", destination.RegionName, aCircuit.Name); // // Adjust the visible name @@ -410,7 +413,8 @@ namespace OpenSim.Services.HypergridService // Preserve our TeleportFlags we have gathered so-far loginFlag |= (Constants.TeleportFlags) aCircuit.teleportFlags; - m_log.DebugFormat("[GATEKEEPER SERVICE]: launching agent {0}", loginFlag); + m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0} {1}", aCircuit.Name, loginFlag); + return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); } -- cgit v1.1 From 832c35d4d5288de0f976e40ede1c8f2ad7df4bcf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 20:05:57 +0100 Subject: Stop "sit user name" and "stand user name" console commands from trying to sit/stand avatars already sitting/standing --- .../OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs index e9cb213..4a591cf 100644 --- a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs @@ -119,6 +119,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.SitStand foreach (ScenePresence sp in scenePresences) { + if (sp.SitGround || sp.IsSatOnObject) + continue; + SceneObjectPart sitPart = null; List sceneObjects = m_scene.GetSceneObjectGroups(); @@ -169,8 +172,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.SitStand foreach (ScenePresence sp in scenePresences) { - MainConsole.Instance.OutputFormat("Standing {0} in {1}", sp.Name, m_scene.Name); - sp.StandUp(); + if (sp.SitGround || sp.IsSatOnObject) + { + MainConsole.Instance.OutputFormat("Standing {0} in {1}", sp.Name, m_scene.Name); + sp.StandUp(); + } } } -- cgit v1.1 From 66a7dc3a0de599068ea257cc2cefbbe4b95599c7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 20:12:14 +0100 Subject: In pCampbot, don't try and reconnect bots that are already connected on console "connect" command --- OpenSim/Tools/pCampBot/BotManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 13912ae..245c460 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -299,7 +299,8 @@ namespace pCampBot break; } - m_bots[i].Connect(); + if (m_bots[i].ConnectionState == ConnectionState.Disconnected) + m_bots[i].Connect(); } // Stagger logins -- cgit v1.1 From 416bbe9583c77e2b1087b375d29ce1ace9c4b050 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 22:44:43 +0100 Subject: Stop error messages being misleadingly generated when on client connection activity timeout, a root connection triggers a CloseAgent to a neighbour region which has already closed the agent due to inactivity. Also separates out log messages to distinguish between close not finding an agent and wrong auth token, and downgrades former to debug and latter to warn --- OpenSim/Region/Framework/Scenes/Scene.cs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index b58e7c4..cb12d65 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4416,10 +4416,27 @@ namespace OpenSim.Region.Framework.Scenes // Check that the auth_token is valid AgentCircuitData acd = AuthenticateHandler.GetAgentCircuitData(agentID); - if (acd != null && acd.SessionID.ToString() == auth_token) + + if (acd == null) + { + m_log.DebugFormat( + "[SCENE]: Request to close agent {0} but no such agent in scene {1}. May have been closed previously.", + agentID, Name); + + return false; + } + + if (acd.SessionID.ToString() == auth_token) + { return IncomingCloseAgent(agentID, force); + } else - m_log.ErrorFormat("[SCENE]: Request to close agent {0} with invalid authorization token {1}", agentID, auth_token); + { + m_log.WarnFormat( + "[SCENE]: Request to close agent {0} with invalid authorization token {1} in {2}", + agentID, auth_token, Name); + } + return false; } -- cgit v1.1 From beb9d966f9efb571b3d6635ba2500b6b0e685fc0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 22:49:23 +0100 Subject: Stop "handle sit user name" command from trying to sit avatars on objects which have sit positions but are attachments --- .../Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs index 4a591cf..5a6b284 100644 --- a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs @@ -127,6 +127,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.SitStand foreach (SceneObjectGroup sceneObject in sceneObjects) { + if (sceneObject.IsAttachment) + continue; + foreach (SceneObjectPart part in sceneObject.Parts) { if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) -- cgit v1.1 From 51c7fb1969f4850750de4b37827e5e2e9d85f3e0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 23:11:05 +0100 Subject: Add "set bots" command to make it possible to set SEND_AGENT_UPDATES on all bots whilst pCampbot is running --- OpenSim/Tools/pCampBot/BotManager.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 245c460..c335a6e 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -203,6 +203,9 @@ namespace pCampBot HandleStand); m_console.Commands.AddCommand( + "bot", false, "set bots", "set bots ", "Set a setting for all bots.", HandleSetBots); + + m_console.Commands.AddCommand( "bot", false, "show regions", "show regions", "Show regions known to bots", HandleShowRegions); m_console.Commands.AddCommand( @@ -519,6 +522,30 @@ namespace pCampBot Environment.Exit(0); } + private void HandleSetBots(string module, string[] cmd) + { + string key = cmd[2]; + string rawValue = cmd[3]; + + if (key == "SEND_AGENT_UPDATES") + { + bool newSendAgentUpdatesSetting; + + if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newSendAgentUpdatesSetting)) + return; + + MainConsole.Instance.OutputFormat( + "Setting SEND_AGENT_UPDATES to {0} for all bots", newSendAgentUpdatesSetting); + + lock (m_bots) + m_bots.ForEach(b => b.Client.Settings.SEND_AGENT_UPDATES = newSendAgentUpdatesSetting); + } + else + { + MainConsole.Instance.Output("Error: Only setting currently available is SEND_AGENT_UPDATES"); + } + } + private void HandleShowRegions(string module, string[] cmd) { string outputFormat = "{0,-30} {1, -20} {2, -5} {3, -5}"; -- cgit v1.1 From 70f89ae65b09e9c2f0dc63cb416fea4cceb7dd13 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 23:43:33 +0100 Subject: Make it possible to adjust the pCampbot login delay via the [BotManager] LoginDelay parameter of pCampbot.ini --- OpenSim/Tools/pCampBot/pCampBot.cs | 7 +++++++ bin/pCampbot.ini.example | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index fc67398..aee5864 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -82,6 +82,13 @@ namespace pCampBot IConfigSource configSource = new IniConfigSource(iniFilePath); + IConfig botManagerConfig = configSource.Configs["BotManager"]; + + if (botManagerConfig != null) + { + bm.LoginDelay = botManagerConfig.GetInt("LoginDelay", bm.LoginDelay); + } + IConfig botConfig = configSource.Configs["Bot"]; if (botConfig != null) diff --git a/bin/pCampbot.ini.example b/bin/pCampbot.ini.example index f44feae..2952bb0 100644 --- a/bin/pCampbot.ini.example +++ b/bin/pCampbot.ini.example @@ -1,6 +1,10 @@ ; This is the example config file for pCampbot ; To use it, copy this file to pCampbot.ini and change settings if required +[BotManager] + ; Number of milliseconds to wait between bot logins + LoginDelay = 5000 + [Bot] ; Control whether bots should regularly send agent updates ; Not doing this will reduce CPU requirements for pCampbot but greatly -- cgit v1.1 From 13556cf1296d3c928d6eb286a6a1c9058c9ab5e7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 22 Aug 2013 23:49:19 +0100 Subject: Fix a further bug in pCampbot connect where ignoring already connected bots was wrongly counted as a connect Also, only sleep when we actually perform a connection --- OpenSim/Tools/pCampBot/BotManager.cs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index c335a6e..50a77ed 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -277,11 +277,11 @@ namespace pCampBot connectBotThread.Start(); } - private void ConnectBotsInternal(int botcount) + private void ConnectBotsInternal(int botCount) { MainConsole.Instance.OutputFormat( "[BOT MANAGER]: Starting {0} bots connecting to {1}, location {2}, named {3} {4}_", - botcount, + botCount, m_loginUri, m_startUri, m_firstName, @@ -291,7 +291,9 @@ namespace pCampBot MainConsole.Instance.OutputFormat("[BOT MANAGER]: BotsSendAgentUpdates is {0}", InitBotSendAgentUpdates); MainConsole.Instance.OutputFormat("[BOT MANAGER]: InitBotRequestObjectTextures is {0}", InitBotRequestObjectTextures); - for (int i = 0; i < botcount; i++) + int connectedBots = 0; + + for (int i = 0; i < m_bots.Count; i++) { lock (m_bots) { @@ -303,11 +305,17 @@ namespace pCampBot } if (m_bots[i].ConnectionState == ConnectionState.Disconnected) + { m_bots[i].Connect(); - } + connectedBots++; - // Stagger logins - Thread.Sleep(LoginDelay); + if (connectedBots >= botCount) + break; + + // Stagger logins + Thread.Sleep(LoginDelay); + } + } } ConnectingBots = false; -- cgit v1.1 From a0c99a7dccbc625fc2c721da480521019260fc7b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 00:03:47 +0100 Subject: minor: remove mono compiler warning from LLClientView --- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 8c51077..1b091bf 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -12602,7 +12602,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (p is ScenePresence) { - ScenePresence presence = p as ScenePresence; // It turns out to get the agent to stop flying, you have to feed it stop flying velocities // There's no explicit message to send the client to tell it to stop flying.. it relies on the // velocity, collision plane and avatar height @@ -12610,15 +12609,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air // when the avatar stands up - Vector3 pos = presence.AbsolutePosition; - ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = CreateImprovedTerseBlock(p, false); const float TIME_DILATION = 1.0f; ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f); - ImprovedTerseObjectUpdatePacket packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( PacketType.ImprovedTerseObjectUpdate); -- cgit v1.1 From a9f9b0da9d6c42aaa0c28c78c27f078f1a80c874 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 00:13:31 +0100 Subject: minor: Correct typo on "debug stats record start" message --- OpenSim/Framework/Monitoring/StatsLogger.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs index fa2e1b6..1e4fa11 100644 --- a/OpenSim/Framework/Monitoring/StatsLogger.cs +++ b/OpenSim/Framework/Monitoring/StatsLogger.cs @@ -67,7 +67,7 @@ namespace OpenSim.Framework.Monitoring if (cmd[3] == "start") { Start(); - con.OutputFormat("Now recording all stats very {0}ms to file", m_statsLogIntervalMs); + con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs); } else if (cmd[3] == "stop") { -- cgit v1.1 From 065c5839b5fb8ddf8a839026934b93cea8aba068 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 00:49:13 +0100 Subject: Refactor: merge SceneGraph.AddScenePresence() into CreateAndAddChildScenePresence() since the former was only ever called from the latter This allows us to remove dead code relating to adding root agents directly to the scenegraph, which never happens. --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 34 +++++---------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index bb7ae7f..0a5bfd2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -561,39 +561,15 @@ namespace OpenSim.Region.Framework.Scenes protected internal ScenePresence CreateAndAddChildScenePresence( IClientAPI client, AvatarAppearance appearance, PresenceType type) { - ScenePresence newAvatar = null; - // ScenePresence always defaults to child agent - newAvatar = new ScenePresence(client, m_parentScene, appearance, type); - - AddScenePresence(newAvatar); - - return newAvatar; - } - - /// - /// Add a presence to the scene - /// - /// - protected internal void AddScenePresence(ScenePresence presence) - { - // Always a child when added to the scene - bool child = presence.IsChildAgent; - - if (child) - { - m_numChildAgents++; - } - else - { - m_numRootAgents++; - presence.AddToPhysicalScene(false); - } + ScenePresence presence = new ScenePresence(client, m_parentScene, appearance, type); Entities[presence.UUID] = presence; lock (m_presenceLock) { + m_numChildAgents++; + Dictionary newmap = new Dictionary(m_scenePresenceMap); List newlist = new List(m_scenePresenceArray); @@ -604,7 +580,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - // Remember the old presene reference from the dictionary + // Remember the old presence reference from the dictionary ScenePresence oldref = newmap[presence.UUID]; // Replace the presence reference in the dictionary with the new value newmap[presence.UUID] = presence; @@ -616,6 +592,8 @@ namespace OpenSim.Region.Framework.Scenes m_scenePresenceMap = newmap; m_scenePresenceArray = newlist; } + + return presence; } /// -- cgit v1.1 From 61c20bd06a37bc4a8a264cdd66afc13ea3a43b79 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 00:53:42 +0100 Subject: Remove old and unused ScenePresence.RestoreInCurrentScene() --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4fc207a..b4e8f09 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3243,11 +3243,6 @@ namespace OpenSim.Region.Framework.Scenes } } - public void RestoreInCurrentScene() - { - AddToPhysicalScene(false); // not exactly false - } - public void Reset() { // m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); -- cgit v1.1 From 2be786709badc9913f348932e75d3481d445caf8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 01:03:27 +0100 Subject: Make it possible for the "deregister region id" command to accept more than one id --- OpenSim/Services/GridService/GridService.cs | 51 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index daebf8b..59b150b 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -86,7 +86,7 @@ namespace OpenSim.Services.GridService { MainConsole.Instance.Commands.AddCommand("Regions", true, "deregister region id", - "deregister region id ", + "deregister region id +", "Deregister a region manually.", String.Empty, HandleDeregisterRegion); @@ -526,37 +526,40 @@ namespace OpenSim.Services.GridService private void HandleDeregisterRegion(string module, string[] cmd) { - if (cmd.Length != 4) + if (cmd.Length < 4) { - MainConsole.Instance.Output("Syntax: degregister region id "); + MainConsole.Instance.Output("Usage: degregister region id +"); return; } - string rawRegionUuid = cmd[3]; - UUID regionUuid; - - if (!UUID.TryParse(rawRegionUuid, out regionUuid)) + for (int i = 3; i < cmd.Length; i++) { - MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid); - return; - } + string rawRegionUuid = cmd[i]; + UUID regionUuid; - GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid); + if (!UUID.TryParse(rawRegionUuid, out regionUuid)) + { + MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid); + return; + } - if (region == null) - { - MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid); - return; - } + GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid); - if (DeregisterRegion(regionUuid)) - { - MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid); - } - else - { - // I don't think this can ever occur if we know that the region exists. - MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid); + if (region == null) + { + MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid); + return; + } + + if (DeregisterRegion(regionUuid)) + { + MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid); + } + else + { + // I don't think this can ever occur if we know that the region exists. + MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid); + } } return; -- cgit v1.1 From 04f4dd3dc7da5657ce3f792ef6d5f9191a7281f7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 01:04:03 +0100 Subject: remove redundant return at end of HandleDeregisterRegion() --- OpenSim/Services/GridService/GridService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 59b150b..a1485c8 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -561,8 +561,6 @@ namespace OpenSim.Services.GridService MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid); } } - - return; } private void HandleShowRegions(string module, string[] cmd) -- cgit v1.1 From 050617ae0ec13075db36449e8e5a4616c8bcd96e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 01:13:19 +0100 Subject: Make pCampbot "show bot" command take the bot number instead of the full bot name Shorter and can do this because bot names are uniform --- OpenSim/Tools/pCampBot/BotManager.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 50a77ed..5c3835b 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -212,7 +212,7 @@ namespace pCampBot "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus); m_console.Commands.AddCommand( - "bot", false, "show bot", "show bot ", + "bot", false, "show bot", "show bot ", "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus); m_bots = new List(); @@ -605,13 +605,18 @@ namespace pCampBot private void HandleShowBotStatus(string module, string[] cmd) { - if (cmd.Length != 4) + if (cmd.Length != 3) { - MainConsole.Instance.Output("Usage: show bot "); + MainConsole.Instance.Output("Usage: show bot "); return; } - string name = string.Format("{0} {1}", cmd[2], cmd[3]); + int botNumber; + + if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber)) + return; + + string name = string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber); Bot bot; -- cgit v1.1 From 0fbfef964928300df3cf4144d39dff2490b6a4e4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 01:21:03 +0100 Subject: minor: shortern warning messages in EntityTransferModule when UpdateAgent() fails --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 17ebc83..8950516 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -832,8 +832,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", - sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", + sp.Name, finalDestination.RegionName, sp.Scene.Name); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); return; @@ -1053,8 +1053,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", - sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", + sp.Name, finalDestination.RegionName, sp.Scene.Name); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); return; -- cgit v1.1 From 1a623bb266e78c9dc2648038de7b67d81b5a417e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Aug 2013 20:58:22 +0100 Subject: Rename pCampbot.ini -> pCampBot.ini (and example file) to be consistent with other capitalizations of pCampBot --- OpenSim/Tools/pCampBot/pCampBot.cs | 2 +- bin/pCampBot.ini.example | 19 +++++++++++++++++++ bin/pCampbot.ini.example | 19 ------------------- 3 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 bin/pCampBot.ini.example delete mode 100644 bin/pCampbot.ini.example diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index aee5864..781bb00 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -51,7 +51,7 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public const string ConfigFileName = "pCampbot.ini"; + public const string ConfigFileName = "pCampBot.ini"; [STAThread] public static void Main(string[] args) diff --git a/bin/pCampBot.ini.example b/bin/pCampBot.ini.example new file mode 100644 index 0000000..2952bb0 --- /dev/null +++ b/bin/pCampBot.ini.example @@ -0,0 +1,19 @@ +; This is the example config file for pCampbot +; To use it, copy this file to pCampbot.ini and change settings if required + +[BotManager] + ; Number of milliseconds to wait between bot logins + LoginDelay = 5000 + +[Bot] + ; Control whether bots should regularly send agent updates + ; Not doing this will reduce CPU requirements for pCampbot but greatly + ; reduce the realism compared to viewers which are constantly sending AgentUpdates UDP packets. + ; Defaults to true. + SendAgentUpdates = true + + ; Control whether bots will requests textures when receiving object information + ; Not doing this will reduce CPU requirements for pCampbot but greatly + ; reduce the realism compared to viewers which requests such texture data if not already cached. + ; Defaults to true. + RequestObjectTextures = true diff --git a/bin/pCampbot.ini.example b/bin/pCampbot.ini.example deleted file mode 100644 index 2952bb0..0000000 --- a/bin/pCampbot.ini.example +++ /dev/null @@ -1,19 +0,0 @@ -; This is the example config file for pCampbot -; To use it, copy this file to pCampbot.ini and change settings if required - -[BotManager] - ; Number of milliseconds to wait between bot logins - LoginDelay = 5000 - -[Bot] - ; Control whether bots should regularly send agent updates - ; Not doing this will reduce CPU requirements for pCampbot but greatly - ; reduce the realism compared to viewers which are constantly sending AgentUpdates UDP packets. - ; Defaults to true. - SendAgentUpdates = true - - ; Control whether bots will requests textures when receiving object information - ; Not doing this will reduce CPU requirements for pCampbot but greatly - ; reduce the realism compared to viewers which requests such texture data if not already cached. - ; Defaults to true. - RequestObjectTextures = true -- cgit v1.1 From c34e6f25b1c8df14d62c102283efbf8ea263805c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 23 Aug 2013 13:53:47 -0700 Subject: Fix a printing of exception error in InventoryArchiveModule that only printed the error message and not the call stack. --- .../CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index 797097f..5854428 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs @@ -536,7 +536,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } catch (Exception e) { - m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e.Message); + m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e); return null; } } -- cgit v1.1 From 6a24515269bf4f478c78e2b93f1c09aa5b598775 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 24 Aug 2013 03:40:44 -0700 Subject: Whitespace fubar. --- bin/data/LICENSE-README-IMPORTANT.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/data/LICENSE-README-IMPORTANT.txt b/bin/data/LICENSE-README-IMPORTANT.txt index a1ac20c..dd8671d 100644 --- a/bin/data/LICENSE-README-IMPORTANT.txt +++ b/bin/data/LICENSE-README-IMPORTANT.txt @@ -2,4 +2,4 @@ Not all of the files in this directory are licensed under the BSD license. Some These files are: -- avataranimations.xml (Derivative work of viewerart.ini, Creative Commons Attribution+Share-Alike v2.5 License) +- avataranimations.xml (Derivative work of viewerart.ini, Creative Commons Attribution+Share-Alike v2.5 License) -- cgit v1.1 From c7a8afbb8da40e09252d58d95c89b8a99a684157 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 24 Aug 2013 03:41:56 -0700 Subject: Make HG logins fall back to fallback regions if the desired region fails. --- .../Services/HypergridService/GatekeeperService.cs | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index e10c4cb..4a6b079 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -72,11 +72,14 @@ namespace OpenSim.Services.HypergridService private static Uri m_Uri; private static GridRegion m_DefaultGatewayRegion; + private static Random m_Random; + public GatekeeperService(IConfigSource config, ISimulationService simService) { if (!m_Initialized) { m_Initialized = true; + m_Random = new Random(); IConfig serverConfig = config.Configs["GatekeeperService"]; if (serverConfig == null) @@ -220,6 +223,8 @@ namespace OpenSim.Services.HypergridService public bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason) { reason = string.Empty; + List defaultRegions; + List fallbackRegions; string authURL = string.Empty; if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) @@ -374,8 +379,14 @@ namespace OpenSim.Services.HypergridService destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID); if (destination == null) { - reason = "Destination region not found"; - return false; + defaultRegions = m_GridService.GetDefaultRegions(UUID.Zero); + if (defaultRegions == null || (defaultRegions != null && defaultRegions.Count == 0)) + { + reason = "Destination region not found"; + return false; + } + int index = m_Random.Next(0, defaultRegions.Count - 1); + destination = defaultRegions[index]; } m_log.DebugFormat( @@ -415,7 +426,17 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0} {1}", aCircuit.Name, loginFlag); - return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); + // try login to the desired region + if (m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason)) + return true; + + // if that failed, try the fallbacks + fallbackRegions = m_GridService.GetFallbackRegions(UUID.Zero, destination.RegionLocX, destination.RegionLocY); + foreach (GridRegion r in fallbackRegions) + if (m_SimulationService.CreateAgent(r, aCircuit, (uint)loginFlag, out reason)) + return true; + + return false; } protected bool Authenticate(AgentCircuitData aCircuit) -- cgit v1.1 From f0c0376660d767f232a1370f02e70d81728c9326 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 24 Aug 2013 08:42:41 -0700 Subject: Potential fix for access control bug on login introduced with SeeIntoRegion commit. --- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index cb12d65..d547323 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3824,7 +3824,7 @@ namespace OpenSim.Region.Framework.Scenes try { - if (!AuthorizeUser(acd, SeeIntoRegion, out reason)) + if (!AuthorizeUser(acd, (vialogin ? false : SeeIntoRegion), out reason)) { m_authenticateHandler.RemoveCircuit(acd.circuitcode); return false; -- cgit v1.1 From ec32c1d4b69e4219fe44a38bcbc411e7996641f1 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 24 Aug 2013 09:59:05 -0700 Subject: Added some more debug messages. --- OpenSim/Services/HypergridService/GatekeeperService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 4a6b079..00502b1 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -431,11 +431,14 @@ namespace OpenSim.Services.HypergridService return true; // if that failed, try the fallbacks + m_log.DebugFormat("[GATEKEEPER SERVICE]: Region {0} did not accept agent {1}", destination.RegionName, aCircuit.Name); fallbackRegions = m_GridService.GetFallbackRegions(UUID.Zero, destination.RegionLocX, destination.RegionLocY); foreach (GridRegion r in fallbackRegions) + { + m_log.DebugFormat("[GATEKEEPER SERVICE]: Trying region {0}...", r.RegionName); if (m_SimulationService.CreateAgent(r, aCircuit, (uint)loginFlag, out reason)) return true; - + } return false; } -- cgit v1.1 From 60e4ce20b86e0594f4ed457b6a7329560dbaa121 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sun, 25 Aug 2013 20:17:04 +0100 Subject: Fix exception thrown after a region has been restarted through scheduling. This exception was very likely harmless since it occurred after the restart had taken place, but still misleading. Thanks to SCGreyWolf for the code change suggestion in http://opensimulator.org/mantis/view.php?id=6747, though I did this in a slightly different way. --- .../CoreModules/World/Region/RestartModule.cs | 32 +++++++++++++++------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs index 249a40d..75a8295 100644 --- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs +++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs @@ -46,8 +46,8 @@ namespace OpenSim.Region.CoreModules.World.Region [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RestartModule")] public class RestartModule : INonSharedRegionModule, IRestartModule { -// private static readonly ILog m_log = -// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected Scene m_Scene; protected Timer m_CountdownTimer = null; @@ -203,18 +203,30 @@ namespace OpenSim.Region.CoreModules.World.Region public void SetTimer(int intervalSeconds) { - m_CountdownTimer = new Timer(); - m_CountdownTimer.AutoReset = false; - m_CountdownTimer.Interval = intervalSeconds * 1000; - m_CountdownTimer.Elapsed += OnTimer; - m_CountdownTimer.Start(); + if (intervalSeconds > 0) + { + m_CountdownTimer = new Timer(); + m_CountdownTimer.AutoReset = false; + m_CountdownTimer.Interval = intervalSeconds * 1000; + m_CountdownTimer.Elapsed += OnTimer; + m_CountdownTimer.Start(); + } + else if (m_CountdownTimer != null) + { + m_CountdownTimer.Stop(); + m_CountdownTimer = null; + } + else + { + m_log.WarnFormat( + "[RESTART MODULE]: Tried to set restart timer to {0} in {1}, which is not a valid interval", + intervalSeconds, m_Scene.Name); + } } private void OnTimer(object source, ElapsedEventArgs e) { - int nextInterval = DoOneNotice(); - - SetTimer(nextInterval); + SetTimer(DoOneNotice()); } public void AbortRestart(string message) -- cgit v1.1 From 1b2830b929640544b6b19ee56b436a5a54d8d0d5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 26 Aug 2013 21:05:55 +0100 Subject: Revert "Added some more debug messages." Fallback doesn't work at this level as the change of destination isn't communicated to the source region/viewer Reverting because this introduces a bug when access does fail. More detail in revert of main commit. This reverts commit ec32c1d4b69e4219fe44a38bcbc411e7996641f1. --- OpenSim/Services/HypergridService/GatekeeperService.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 00502b1..4a6b079 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -431,14 +431,11 @@ namespace OpenSim.Services.HypergridService return true; // if that failed, try the fallbacks - m_log.DebugFormat("[GATEKEEPER SERVICE]: Region {0} did not accept agent {1}", destination.RegionName, aCircuit.Name); fallbackRegions = m_GridService.GetFallbackRegions(UUID.Zero, destination.RegionLocX, destination.RegionLocY); foreach (GridRegion r in fallbackRegions) - { - m_log.DebugFormat("[GATEKEEPER SERVICE]: Trying region {0}...", r.RegionName); if (m_SimulationService.CreateAgent(r, aCircuit, (uint)loginFlag, out reason)) return true; - } + return false; } -- cgit v1.1 From 0dd9a68eb74a7374f72cbed14c6e0eacdb642b60 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 26 Aug 2013 21:07:49 +0100 Subject: Revert "Make HG logins fall back to fallback regions if the desired region fails." This is very similar to my earlier revert in bcb8605f8428a9009a2badf9c9eed06d9f59962c and fails for the same reasons. Reverting this change because it causes a problem if access is denied to the user. This reverts commit c7a8afbb8da40e09252d58d95c89b8a99a684157. --- .../Services/HypergridService/GatekeeperService.cs | 27 +++------------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 4a6b079..e10c4cb 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -72,14 +72,11 @@ namespace OpenSim.Services.HypergridService private static Uri m_Uri; private static GridRegion m_DefaultGatewayRegion; - private static Random m_Random; - public GatekeeperService(IConfigSource config, ISimulationService simService) { if (!m_Initialized) { m_Initialized = true; - m_Random = new Random(); IConfig serverConfig = config.Configs["GatekeeperService"]; if (serverConfig == null) @@ -223,8 +220,6 @@ namespace OpenSim.Services.HypergridService public bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason) { reason = string.Empty; - List defaultRegions; - List fallbackRegions; string authURL = string.Empty; if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) @@ -379,14 +374,8 @@ namespace OpenSim.Services.HypergridService destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID); if (destination == null) { - defaultRegions = m_GridService.GetDefaultRegions(UUID.Zero); - if (defaultRegions == null || (defaultRegions != null && defaultRegions.Count == 0)) - { - reason = "Destination region not found"; - return false; - } - int index = m_Random.Next(0, defaultRegions.Count - 1); - destination = defaultRegions[index]; + reason = "Destination region not found"; + return false; } m_log.DebugFormat( @@ -426,17 +415,7 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[GATEKEEPER SERVICE]: Launching {0} {1}", aCircuit.Name, loginFlag); - // try login to the desired region - if (m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason)) - return true; - - // if that failed, try the fallbacks - fallbackRegions = m_GridService.GetFallbackRegions(UUID.Zero, destination.RegionLocX, destination.RegionLocY); - foreach (GridRegion r in fallbackRegions) - if (m_SimulationService.CreateAgent(r, aCircuit, (uint)loginFlag, out reason)) - return true; - - return false; + return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); } protected bool Authenticate(AgentCircuitData aCircuit) -- cgit v1.1 From 0882cf0fc32dac05d0e762abf68d6956305543bc Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 27 Aug 2013 09:55:50 -0700 Subject: BulletSim: add some protections for processing when shutting down. Attempt to fix Mantis 6740 (http://opensimulator.org/mantis/view.php?id=6740). --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 88d50b4..c92c9b9 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -946,7 +946,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters private void ProcessRegularTaints() { - if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process + if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process { // swizzle a new list into the list location so we can process what's there List oldList; @@ -989,7 +989,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // Taints that happen after the normal taint processing but before the simulation step. private void ProcessPostTaintTaints() { - if (_postTaintOperations.Count > 0) + if (m_initialized && _postTaintOperations.Count > 0) { Dictionary oldList; lock (_taintLock) -- cgit v1.1 From aa521fb385c055980c8af1ddf44d839c643fd22e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 28 Aug 2013 16:33:01 -0700 Subject: Do not add a port zero to end of the hypergrid gateway host name. If the port is specified it is added but a ":0" is not added if the port is zero. This enables the hypergrid address short form "hypergridGateway:regionName" which is handled by the parser but failed because of this zero port addition. --- OpenSim/Services/Interfaces/IGridService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs index d7da056..6ed681f 100644 --- a/OpenSim/Services/Interfaces/IGridService.cs +++ b/OpenSim/Services/Interfaces/IGridService.cs @@ -137,7 +137,10 @@ namespace OpenSim.Services.Interfaces if ( m_serverURI != string.Empty ) { return m_serverURI; } else { - return "http://" + m_externalHostName + ":" + m_httpPort + "/"; + if (m_httpPort == 0) + return "http://" + m_externalHostName + "/"; + else + return "http://" + m_externalHostName + ":" + m_httpPort + "/"; } } set { -- cgit v1.1 From a8c0e16e474e5857ca83791d6bd1a484e2cfc9c9 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 29 Aug 2013 14:35:56 -0400 Subject: Initialization: move key expansion out to operate on all sources and not just environment variables --- OpenSim/Region/Application/ConfigurationLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index 3e93638..bc7ecb7 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -201,11 +201,11 @@ namespace OpenSim envConfigSource.LoadEnv(); m_config.Source.Merge(envConfigSource); - m_config.Source.ExpandKeyValues(); } - ReadConfigSettings(); + + m_config.Source.ExpandKeyValues(); return m_config; } -- cgit v1.1 From 56f565b601c527a1b6fd345813972ee32e2e103d Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 29 Aug 2013 16:54:13 -0400 Subject: Profiles: Clean up some log entries caused when visiting HG avatar is using legacy profiles --- .../Avatar/UserProfiles/UserProfileModule.cs | 42 +++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index 966a05c..bf1cffb 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -309,6 +309,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(targetID, out serverURI); UUID creatorId = UUID.Zero; + Dictionary classifieds = new Dictionary(); OSDMap parameters= new OSDMap(); UUID.TryParse(args[0], out creatorId); @@ -316,15 +317,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles OSD Params = (OSD)parameters; if(!JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) { - // Error Handling here! - // if(parameters.ContainsKey("message") + remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); + return; } parameters = (OSDMap)Params; OSDArray list = (OSDArray)parameters["result"]; - Dictionary classifieds = new Dictionary(); foreach(OSD map in list) { @@ -441,7 +441,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); ScenePresence p = FindPresence(remoteClient.AgentId); -// Vector3 avaPos = p.AbsolutePosition; string serverURI = string.Empty; GetUserProfileServerURI(remoteClient.AgentId, out serverURI); @@ -542,14 +541,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles string serverURI = string.Empty; GetUserProfileServerURI(targetId, out serverURI); + + Dictionary picks = new Dictionary(); OSDMap parameters= new OSDMap(); parameters.Add("creatorId", OSD.FromUUID(targetId)); OSD Params = (OSD)parameters; if(!JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString())) { - remoteClient.SendAgentAlertMessage( - "Error requesting picks", false); + remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); return; } @@ -557,8 +557,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles OSDArray list = (OSDArray)parameters["result"]; - Dictionary picks = new Dictionary(); - foreach(OSD map in list) { OSDMap m = (OSDMap)map; @@ -762,8 +760,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles object Note = (object)note; if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) { - remoteClient.SendAgentAlertMessage( - "Error requesting note", false); + remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); + return; } note = (UserProfileNotes) Note; @@ -796,8 +794,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles object Note = note; if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) { - remoteClient.SendAgentAlertMessage( - "Error updating note", false); + return; } } #endregion Notes @@ -1033,8 +1030,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles OSD Params = (OSD)parameters; if(!JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString())) { - // Error Handling here! - // if(parameters.ContainsKey("message") return false; } @@ -1224,7 +1219,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); - // webRequest.Credentials = new NetworkCredential(rpcUser, rpcPass); + webRequest.ContentType = "application/json-rpc"; webRequest.Method = "POST"; @@ -1245,7 +1240,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } Stream rstream = webResponse.GetResponseStream(); - OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); + if (rstream.Length < 1) + return false; + + OSDMap mret = new OSDMap(); + try + { + mret = (OSDMap)OSDParser.DeserializeJson(rstream); + } + catch (Exception e) + { + m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message); + return false; + } + if (mret.ContainsKey("error")) return false; @@ -1310,6 +1318,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } Stream rstream = webResponse.GetResponseStream(); + if (rstream.Length < 1) + return false; OSDMap response = new OSDMap(); try -- cgit v1.1 From 4cbadc3c4984b8bebc7098a720846309f645ad7b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 2 Sep 2013 17:27:45 +0100 Subject: Allow one to specify a DefaultHGRegion flag in [GridService] in order to allow different default regions for HG and direct grid logins. This requires a new GridService.GetDefaultHypergridRegions() so ROBUST services require updating but not simulators. This method still returns regions flagged with just DefaultRegion after any DefaultHGRegions, so if no DefaultHGRegions are specified then existing configured defaults will still work. Immediate use is for conference where we need to be able to specify different defaults However, this is also generally useful to send experienced HG users to one default location and local users whose specified region fails (e.g. no "home" or "last") to another. --- OpenSim/Data/IRegionData.cs | 1 + OpenSim/Data/MSSQL/MSSQLRegionData.cs | 5 +++ OpenSim/Data/MySQL/MySQLRegionData.cs | 5 +++ OpenSim/Data/Null/NullRegionData.cs | 5 +++ OpenSim/Framework/RegionFlags.cs | 3 +- .../Grid/LocalGridServiceConnector.cs | 5 +++ .../Grid/RemoteGridServiceConnector.cs | 20 +++++++++ .../Server/Handlers/Grid/GridServerPostHandler.cs | 33 ++++++++++++++ .../Connectors/Grid/GridServicesConnector.cs | 51 ++++++++++++++++++++++ .../SimianGrid/SimianGridServiceConnector.cs | 6 +++ OpenSim/Services/GridService/GridService.cs | 32 +++++++++++++- OpenSim/Services/GridService/HypergridLinker.cs | 2 +- .../Services/HypergridService/GatekeeperService.cs | 2 +- OpenSim/Services/Interfaces/IGridService.cs | 1 + bin/Robust.HG.ini.example | 11 ++--- 15 files changed, 172 insertions(+), 10 deletions(-) diff --git a/OpenSim/Data/IRegionData.cs b/OpenSim/Data/IRegionData.cs index 70e1065..463c621 100644 --- a/OpenSim/Data/IRegionData.cs +++ b/OpenSim/Data/IRegionData.cs @@ -81,6 +81,7 @@ namespace OpenSim.Data bool Delete(UUID regionID); List GetDefaultRegions(UUID scopeID); + List GetDefaultHypergridRegions(UUID scopeID); List GetFallbackRegions(UUID scopeID, int x, int y); List GetHyperlinks(UUID scopeID); } diff --git a/OpenSim/Data/MSSQL/MSSQLRegionData.cs b/OpenSim/Data/MSSQL/MSSQLRegionData.cs index 0d89706..c0589df 100644 --- a/OpenSim/Data/MSSQL/MSSQLRegionData.cs +++ b/OpenSim/Data/MSSQL/MSSQLRegionData.cs @@ -315,6 +315,11 @@ namespace OpenSim.Data.MSSQL return Get((int)RegionFlags.DefaultRegion, scopeID); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultHGRegion, scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List regions = Get((int)RegionFlags.FallbackRegion, scopeID); diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index a2d4ae4..2ad7590 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -310,6 +310,11 @@ namespace OpenSim.Data.MySQL return Get((int)RegionFlags.DefaultRegion, scopeID); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultHGRegion, scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List regions = Get((int)RegionFlags.FallbackRegion, scopeID); diff --git a/OpenSim/Data/Null/NullRegionData.cs b/OpenSim/Data/Null/NullRegionData.cs index f707d98..d28cd99 100644 --- a/OpenSim/Data/Null/NullRegionData.cs +++ b/OpenSim/Data/Null/NullRegionData.cs @@ -239,6 +239,11 @@ namespace OpenSim.Data.Null return Get((int)RegionFlags.DefaultRegion, scopeID); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + return Get((int)RegionFlags.DefaultHGRegion, scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List regions = Get((int)RegionFlags.FallbackRegion, scopeID); diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs index a3089b0..7c6569e 100644 --- a/OpenSim/Framework/RegionFlags.cs +++ b/OpenSim/Framework/RegionFlags.cs @@ -48,6 +48,7 @@ namespace OpenSim.Framework NoMove = 64, // Don't allow moving this region Reservation = 128, // This is an inactive reservation Authenticate = 256, // Require authentication - Hyperlink = 512 // Record represents a HG link + Hyperlink = 512, // Record represents a HG link + DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only. } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index 3849a3f..31ef79b 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs @@ -235,6 +235,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid return m_GridService.GetDefaultRegions(scopeID); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + return m_GridService.GetDefaultHypergridRegions(scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { return m_GridService.GetFallbackRegions(scopeID, x, y); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs index b2646ba..6a57d1f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RemoteGridServiceConnector.cs @@ -277,6 +277,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid return rinfo; } + public List GetDefaultHypergridRegions(UUID scopeID) + { + List rinfo = m_LocalGridService.GetDefaultHypergridRegions(scopeID); + //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Local GetDefaultHypergridRegions {0} found {1} regions", name, rinfo.Count); + List grinfo = m_RemoteGridService.GetDefaultHypergridRegions(scopeID); + + if (grinfo != null) + { + //m_log.DebugFormat("[REMOTE GRID CONNECTOR]: Remote GetDefaultHypergridRegions {0} found {1} regions", name, grinfo.Count); + foreach (GridRegion r in grinfo) + { + m_RegionInfoCache.Cache(r); + if (rinfo.Find(delegate(GridRegion gr) { return gr.RegionID == r.RegionID; }) == null) + rinfo.Add(r); + } + } + + return rinfo; + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List rinfo = m_LocalGridService.GetFallbackRegions(scopeID, x, y); diff --git a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs index 89cba8a..c63b409 100644 --- a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs @@ -106,6 +106,9 @@ namespace OpenSim.Server.Handlers.Grid case "get_default_regions": return GetDefaultRegions(request); + case "get_default_hypergrid_regions": + return GetDefaultHypergridRegions(request); + case "get_fallback_regions": return GetFallbackRegions(request); @@ -444,6 +447,36 @@ namespace OpenSim.Server.Handlers.Grid return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + byte[] GetDefaultHypergridRegions(Dictionary request) + { + //m_log.DebugFormat("[GRID HANDLER]: GetDefaultRegions"); + UUID scopeID = UUID.Zero; + if (request.ContainsKey("SCOPEID")) + UUID.TryParse(request["SCOPEID"].ToString(), out scopeID); + else + m_log.WarnFormat("[GRID HANDLER]: no scopeID in request to get region range"); + + List rinfos = m_GridService.GetDefaultHypergridRegions(scopeID); + + Dictionary result = new Dictionary(); + if ((rinfos == null) || ((rinfos != null) && (rinfos.Count == 0))) + result["result"] = "null"; + else + { + int i = 0; + foreach (GridRegion rinfo in rinfos) + { + Dictionary rinfoDict = rinfo.ToKeyValuePairs(); + result["region" + i] = rinfoDict; + i++; + } + } + string xmlString = ServerUtils.BuildXmlResponse(result); + + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } + byte[] GetFallbackRegions(Dictionary request) { //m_log.DebugFormat("[GRID HANDLER]: GetRegionRange"); diff --git a/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs b/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs index 34ed0d7..0f5a613 100644 --- a/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs +++ b/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs @@ -515,6 +515,57 @@ namespace OpenSim.Services.Connectors return rinfos; } + public List GetDefaultHypergridRegions(UUID scopeID) + { + Dictionary sendData = new Dictionary(); + + sendData["SCOPEID"] = scopeID.ToString(); + + sendData["METHOD"] = "get_default_hypergrid_regions"; + + List rinfos = new List(); + string reply = string.Empty; + string uri = m_ServerURI + "/grid"; + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", + uri, + ServerUtils.BuildQueryString(sendData)); + + //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); + } + catch (Exception e) + { + m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server at {0}: {1}", uri, e.Message); + return rinfos; + } + + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if (replyData != null) + { + Dictionary.ValueCollection rinfosList = replyData.Values; + foreach (object r in rinfosList) + { + if (r is Dictionary) + { + GridRegion rinfo = new GridRegion((Dictionary)r); + rinfos.Add(rinfo); + } + } + } + else + m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultHypergridRegions {0} received null response", + scopeID); + } + else + m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultHypergridRegions received null reply"); + + return rinfos; + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { Dictionary sendData = new Dictionary(); diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs index bcc1e4a..816591b 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs @@ -330,6 +330,12 @@ namespace OpenSim.Services.Connectors.SimianGrid return new List(0); } + public List GetDefaultHypergridRegions(UUID scopeID) + { + // TODO: Allow specifying the default grid location + return GetDefaultRegions(scopeID); + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true); diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index a1485c8..e72b7f9 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -265,8 +265,9 @@ namespace OpenSim.Services.GridService m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e); } - m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}", - regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY); + m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3} with flags {4}", + regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY, + (OpenSim.Framework.RegionFlags)flags); return String.Empty; } @@ -478,6 +479,33 @@ namespace OpenSim.Services.GridService return ret; } + public List GetDefaultHypergridRegions(UUID scopeID) + { + List ret = new List(); + + List regions = m_Database.GetDefaultHypergridRegions(scopeID); + + foreach (RegionData r in regions) + { + if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Framework.RegionFlags.RegionOnline) != 0) + ret.Add(RegionData2RegionInfo(r)); + } + + int hgDefaultRegionsFoundOnline = regions.Count; + + // For now, hypergrid default regions will always be given precedence but we will also return simple default + // regions in case no specific hypergrid regions are specified. + ret.AddRange(GetDefaultRegions(scopeID)); + + int normalDefaultRegionsFoundOnline = ret.Count - hgDefaultRegionsFoundOnline; + + m_log.DebugFormat( + "[GRID SERVICE]: GetDefaultHypergridRegions returning {0} hypergrid default and {1} normal default regions", + hgDefaultRegionsFoundOnline, normalDefaultRegionsFoundOnline); + + return ret; + } + public List GetFallbackRegions(UUID scopeID, int x, int y) { List ret = new List(); diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index 8335724..4024295 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs @@ -79,7 +79,7 @@ namespace OpenSim.Services.GridService { if (m_DefaultRegion == null) { - List defs = m_GridService.GetDefaultRegions(m_ScopeID); + List defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID); if (defs != null && defs.Count > 0) m_DefaultRegion = defs[0]; else diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index e10c4cb..f6136b5 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -171,7 +171,7 @@ namespace OpenSim.Services.HypergridService m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName); if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty) { - List defs = m_GridService.GetDefaultRegions(m_ScopeID); + List defs = m_GridService.GetDefaultHypergridRegions(m_ScopeID); if (defs != null && defs.Count > 0) { region = defs[0]; diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs index 6ed681f..88ac5b3 100644 --- a/OpenSim/Services/Interfaces/IGridService.cs +++ b/OpenSim/Services/Interfaces/IGridService.cs @@ -97,6 +97,7 @@ namespace OpenSim.Services.Interfaces List GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax); List GetDefaultRegions(UUID scopeID); + List GetDefaultHypergridRegions(UUID scopeID); List GetFallbackRegions(UUID scopeID, int x, int y); List GetHyperlinks(UUID scopeID); diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 466aed2..0fbdf4e 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -151,7 +151,8 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ; * [GridService] LocalServiceModule = "OpenSim.Services.GridService.dll:GridService" - HypergridLinker = true + + HypergridLinker = true ; Realm = "regions" ; AllowDuplicateNames = "True" @@ -168,16 +169,16 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ;; Next, we can specify properties of regions, including default and fallback regions ;; The syntax is: Region_ = "" ;; or: Region_ = "" - ;; where can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut,Reservation,NoMove,Authenticate + ;; where can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate ;; For example: ; Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; (replace spaces with underscore) - ;; Allow Hyperlinks to be created at the console + ;; Allow Hyperlinks to be created at the console HypergridLinker = true - ;; If you have this set under [Hypergrid], no need to set it here, leave it commented - ; GatekeeperURI = "http://127.0.0.1:8002" + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented + ; GatekeeperURI = "http://127.0.0.1:8002" ; * This is the configuration for the freeswitch server in grid mode -- cgit v1.1 From 5ce5ce6edb2217639cdcc375bf375452b81bb868 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 2 Sep 2013 17:45:38 +0100 Subject: Comment out warning about agent updating without valid session ID for now. This causes extreme console spam if a simulator running latest master and one running 0.7.5 have adjacent regions occupied by avatars. --- OpenSim/Region/Framework/Scenes/Scene.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d547323..005c9b9 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4346,10 +4346,10 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); if (childAgentUpdate != null) { - if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) - // Only warn for now - m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", - childAgentUpdate.UUID, cAgentData.SessionID); +// if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID) +// // Only warn for now +// m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?", +// childAgentUpdate.UUID, cAgentData.SessionID); // I can't imagine *yet* why we would get an update if the agent is a root agent.. // however to avoid a race condition crossing borders.. -- cgit v1.1 From 857f24a5e2b59072ad4d987d5e64318f5249c7e7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 2 Sep 2013 19:15:10 +0100 Subject: Fix bug where users teleporting to non-neighbour regions could continue to hear chat from their source region for some time after teleport completion. This occurs on v2 teleport since the source region now waits 15 secs before closing the old child agent, which could still receive chat. This commit introduces a ScenePresenceState.PreClose which is set before the wait, so that ChatModule can check for ScenePresenceState.Running. This was theoretically also an issue on v1 teleport but since the pause before close was only 2 secs there, it was not noticed. --- .../Caps/EventQueue/Tests/EventQueueTests.cs | 4 +- .../Region/CoreModules/Avatar/Chat/ChatModule.cs | 15 +++--- .../EntityTransfer/EntityTransferModule.cs | 7 +++ OpenSim/Region/Framework/Scenes/Scene.cs | 59 ++++++++++++++++++++-- .../Framework/Scenes/ScenePresenceStateMachine.cs | 15 +++++- 5 files changed, 85 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index 626932f..b3b0b8a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests } [Test] - public void AddForClient() + public void TestAddForClient() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); @@ -88,7 +88,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests } [Test] - public void RemoveForClient() + public void TestRemoveForClient() { TestHelpers.InMethod(); // TestHelpers.EnableLogging(); diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 58f747b..5229c08 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -326,15 +326,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat UUID fromAgentID, UUID ownerID, string fromName, ChatTypeEnum type, string message, ChatSourceType src, bool ignoreDistance) { - Vector3 fromRegionPos = fromPos + regionPos; - Vector3 toRegionPos = presence.AbsolutePosition + - new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, - presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); - - int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); + if (presence.LifecycleState != ScenePresenceState.Running) + return false; if (!ignoreDistance) { + Vector3 fromRegionPos = fromPos + regionPos; + Vector3 toRegionPos = presence.AbsolutePosition + + new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, + presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0); + + int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); + if (type == ChatTypeEnum.Whisper && dis > m_whisperdistance || type == ChatTypeEnum.Say && dis > m_saydistance || type == ChatTypeEnum.Shout && dis > m_shoutdistance) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 8950516..4219254 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -920,6 +920,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { + if (!sp.Scene.IncomingPreCloseAgent(sp)) + return; + // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before // they regard the new region as the current region after receiving the AgentMovementComplete // response. If close is sent before then, it will cause the viewer to quit instead. @@ -1082,6 +1085,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { + if (!sp.Scene.IncomingPreCloseAgent(sp)) + return; + // RED ALERT!!!! // PLEASE DO NOT DECREASE THIS WAIT TIME UNDER ANY CIRCUMSTANCES. // THE VIEWERS SEEM TO NEED SOME TIME AFTER RECEIVING MoveAgentIntoRegion @@ -1095,6 +1101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // then this will be handled in IncomingCloseAgent under lock conditions m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); + sp.Scene.IncomingCloseAgent(sp.UUID, false); } else diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 005c9b9..2a21a4c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3695,10 +3695,13 @@ namespace OpenSim.Region.Framework.Scenes // We need to ensure that we are not already removing the scene presence before we ask it not to be // closed. - if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running) + if (sp != null && sp.IsChildAgent + && (sp.LifecycleState == ScenePresenceState.Running + || sp.LifecycleState == ScenePresenceState.PreRemove)) { m_log.DebugFormat( - "[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name); + "[SCENE]: Reusing existing child scene presence for {0}, state {1} in {2}", + sp.Name, sp.LifecycleState, Name); // In the case where, for example, an A B C D region layout, an avatar may // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C @@ -3720,6 +3723,8 @@ namespace OpenSim.Region.Framework.Scenes // } // else if (EntityTransferModule.IsInTransit(sp.UUID)) + sp.LifecycleState = ScenePresenceState.Running; + if (EntityTransferModule.IsInTransit(sp.UUID)) { sp.DoNotCloseAfterTeleport = true; @@ -4441,6 +4446,50 @@ namespace OpenSim.Region.Framework.Scenes } /// + /// Tell a single agent to prepare to close. + /// + /// + /// This should only be called if we may close the agent but there will be some delay in so doing. Meant for + /// internal use - other callers should almost certainly called IncomingCloseAgent(). + /// + /// + /// true if pre-close state notification was successful. false if the agent + /// was not in a state where it could transition to pre-close. + public bool IncomingPreCloseAgent(ScenePresence sp) + { + lock (m_removeClientLock) + { + // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may + // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not + // want to obey this close since C may have renewed the child agent lease on B. + if (sp.DoNotCloseAfterTeleport) + { + m_log.DebugFormat( + "[SCENE]: Not pre-closing {0} agent {1} in {2} since another simulator has re-established the child connection", + sp.IsChildAgent ? "child" : "root", sp.Name, Name); + + // Need to reset the flag so that a subsequent close after another teleport can succeed. + sp.DoNotCloseAfterTeleport = false; + + return false; + } + + if (sp.LifecycleState != ScenePresenceState.Running) + { + m_log.DebugFormat( + "[SCENE]: Called IncomingPreCloseAgent() for {0} in {1} but presence is already in state {2}", + sp.Name, Name, sp.LifecycleState); + + return false; + } + + sp.LifecycleState = ScenePresenceState.PreRemove; + + return true; + } + } + + /// /// Tell a single agent to disconnect from the region. /// /// @@ -4459,16 +4508,16 @@ namespace OpenSim.Region.Framework.Scenes if (sp == null) { m_log.DebugFormat( - "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}", + "[SCENE]: Called IncomingCloseAgent() with agent ID {0} but no such presence is in {1}", agentID, Name); return false; } - if (sp.LifecycleState != ScenePresenceState.Running) + if (sp.LifecycleState != ScenePresenceState.Running && sp.LifecycleState != ScenePresenceState.PreRemove) { m_log.DebugFormat( - "[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}", + "[SCENE]: Called IncomingCloseAgent() for {0} in {1} but presence is already in state {2}", sp.Name, Name, sp.LifecycleState); return false; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs index dc3a212..cae7fe5 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs @@ -37,7 +37,8 @@ namespace OpenSim.Region.Framework.Scenes /// This is a state machine. /// /// [Entry] => Running - /// Running => Removing + /// Running => PreRemove, Removing + /// PreRemove => Running, Removing /// Removing => Removed /// /// All other methods should only see the scene presence in running state - this is the normal operational state @@ -46,6 +47,7 @@ namespace OpenSim.Region.Framework.Scenes public enum ScenePresenceState { Running, // Normal operation state. The scene presence is available. + PreRemove, // The presence is due to be removed but can still be returning to running. Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient. Removed, // The presence has been removed from the scene and is effectively dead. // There is no exit from this state. @@ -80,8 +82,17 @@ namespace OpenSim.Region.Framework.Scenes lock (this) { - if (newState == ScenePresenceState.Removing && m_state == ScenePresenceState.Running) + if (newState == m_state) + return; + else if (newState == ScenePresenceState.Running && m_state == ScenePresenceState.PreRemove) transitionOkay = true; + else if (newState == ScenePresenceState.PreRemove && m_state == ScenePresenceState.Running) + transitionOkay = true; + else if (newState == ScenePresenceState.Removing) + { + if (m_state == ScenePresenceState.Running || m_state == ScenePresenceState.PreRemove) + transitionOkay = true; + } else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing) transitionOkay = true; } -- cgit v1.1 From 9643915093aad385163551655676adc943855330 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Mon, 2 Sep 2013 16:28:40 -0400 Subject: Remove test that gives issue on Windows, just let the try/catch do the work. --- OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index bf1cffb..56ff2bd 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -1212,7 +1212,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles json.Add("jsonrpc", OSD.FromString("2.0")); json.Add("id", OSD.FromString(jsonId)); json.Add("method", OSD.FromString(method)); - // Experiment + json.Add("params", OSD.SerializeMembers(parameters)); string jsonRequestData = OSDParser.SerializeJsonString(json); @@ -1240,8 +1240,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } Stream rstream = webResponse.GetResponseStream(); - if (rstream.Length < 1) - return false; OSDMap mret = new OSDMap(); try @@ -1318,8 +1316,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles } Stream rstream = webResponse.GetResponseStream(); - if (rstream.Length < 1) - return false; OSDMap response = new OSDMap(); try -- cgit v1.1 From 4035badd20c00c766a1262afd7fa730ea6c53e98 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 00:04:12 +0100 Subject: Add experimental "show grid users online" console command to show grid users online from a standalone/robust instance. This is not guaranteed to be accurate since users may be left "online" in certain situations. For example, if a simulator crashes and they never login/logout again. To counter this somewhat, only users continuously online for less than 5 days are shown. --- OpenSim/Framework/Util.cs | 8 ++--- .../Services/UserAccountService/GridUserService.cs | 39 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f0e5bc1..52f5432 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -130,7 +130,7 @@ namespace OpenSim.Framework private static SmartThreadPool m_ThreadPool; // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. - private static readonly DateTime unixEpoch = + public static readonly DateTime UnixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); private static readonly string rawUUIDPattern @@ -521,19 +521,19 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { - TimeSpan t = stamp.ToUniversalTime() - unixEpoch; + TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; return (int) t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) { - DateTime epoch = unixEpoch; + DateTime epoch = UnixEpoch; return epoch.AddSeconds(seconds); } public static DateTime ToDateTime(int seconds) { - DateTime epoch = unixEpoch; + DateTime epoch = UnixEpoch; return epoch.AddSeconds(seconds); } diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index b1cdd45..f9cfa12 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -47,6 +47,45 @@ namespace OpenSim.Services.UserAccountService public GridUserService(IConfigSource config) : base(config) { m_log.Debug("[GRID USER SERVICE]: Starting user grid service"); + + MainConsole.Instance.Commands.AddCommand( + "Users", false, + "show grid users online", + "show grid users online", + "Show number of grid users registered as online.", + "This number may not be accurate as a region may crash or not be cleanly shutdown and leave grid users shown as online\n." + + "For this reason, users online for more than 5 days are not currently counted", + HandleShowGridUsersOnline); + } + + protected void HandleShowGridUsersOnline(string module, string[] cmdparams) + { +// if (cmdparams.Length != 4) +// { +// MainConsole.Instance.Output("Usage: show grid users online"); +// return; +// } + +// int onlineCount; + int onlineRecentlyCount = 0; + + DateTime now = DateTime.UtcNow; + + foreach (GridUserData gu in m_Database.GetAll("")) + { + if (bool.Parse(gu.Data["Online"])) + { +// onlineCount++; + + int unixLoginTime = int.Parse(gu.Data["Login"]); + DateTime loginDateTime = Util.UnixEpoch.AddSeconds(unixLoginTime); + + if ((loginDateTime - now).Days < 5) + onlineRecentlyCount++; + } + } + + MainConsole.Instance.OutputFormat("Users online within last 5 days: {0}", onlineRecentlyCount); } public virtual GridUserInfo GetGridUserInfo(string userID) -- cgit v1.1 From 5f15ee95dc140ba775c4db801a72f6623e408b0f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 00:16:43 +0100 Subject: Fix logic errors in "show grid users online" console command which didn't actually filter out users shown continuously online for more than 5 days Remove confusion in command output. --- OpenSim/Services/UserAccountService/GridUserService.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index f9cfa12..944411f 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs @@ -78,14 +78,13 @@ namespace OpenSim.Services.UserAccountService // onlineCount++; int unixLoginTime = int.Parse(gu.Data["Login"]); - DateTime loginDateTime = Util.UnixEpoch.AddSeconds(unixLoginTime); - if ((loginDateTime - now).Days < 5) + if ((now - Util.ToDateTime(unixLoginTime)).Days < 5) onlineRecentlyCount++; } } - MainConsole.Instance.OutputFormat("Users online within last 5 days: {0}", onlineRecentlyCount); + MainConsole.Instance.OutputFormat("Users online: {0}", onlineRecentlyCount); } public virtual GridUserInfo GetGridUserInfo(string userID) -- cgit v1.1 From 431156f6c48944c79e3f56c54d64e7f3bc748f7b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 00:17:50 +0100 Subject: minor simplification of some unix date functions in Util. No functional change. --- OpenSim/Framework/Util.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 52f5432..e8dfec1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -522,19 +522,17 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; - return (int) t.TotalSeconds; + return (int)t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) { - DateTime epoch = UnixEpoch; - return epoch.AddSeconds(seconds); + return UnixEpoch.AddSeconds(seconds); } public static DateTime ToDateTime(int seconds) { - DateTime epoch = UnixEpoch; - return epoch.AddSeconds(seconds); + return UnixEpoch.AddSeconds(seconds); } /// -- cgit v1.1 From 9c652079361f496c46640ed67e964ee6164ce06e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 17:07:57 +0100 Subject: Show behaviours of pCampbot bots in "show bots" and "show bot" console commands --- .../Tools/pCampBot/Behaviours/AbstractBehaviour.cs | 5 +++++ .../Tools/pCampBot/Behaviours/CrossBehaviour.cs | 6 +++++- .../Tools/pCampBot/Behaviours/GrabbingBehaviour.cs | 6 +++++- OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs | 6 +++++- .../Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | 1 + .../Tools/pCampBot/Behaviours/TeleportBehaviour.cs | 6 +++++- OpenSim/Tools/pCampBot/BotManager.cs | 22 ++++++++++++++-------- OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs | 5 +++++ 8 files changed, 45 insertions(+), 12 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs index 9a9371d..66d5542 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs @@ -35,6 +35,11 @@ namespace pCampBot { public class AbstractBehaviour : IBehaviour { + /// + /// Abbreviated name of this behaviour. + /// + public string AbbreviatedName { get; protected set; } + public string Name { get; protected set; } public Bot Bot { get; protected set; } diff --git a/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs index 1e01c64..4d806fc 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/CrossBehaviour.cs @@ -47,7 +47,11 @@ namespace pCampBot public const int m_regionCrossingTimeout = 1000 * 60; - public CrossBehaviour() { Name = "Cross"; } + public CrossBehaviour() + { + AbbreviatedName = "c"; + Name = "Cross"; + } public override void Action() { diff --git a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs index 66a336a..6acc27d 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs @@ -41,7 +41,11 @@ namespace pCampBot /// public class GrabbingBehaviour : AbstractBehaviour { - public GrabbingBehaviour() { Name = "Grabbing"; } + public GrabbingBehaviour() + { + AbbreviatedName = "g"; + Name = "Grabbing"; + } public override void Action() { diff --git a/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs index 9cf8a54..9a3075c 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/NoneBehaviour.cs @@ -38,6 +38,10 @@ namespace pCampBot /// public class NoneBehaviour : AbstractBehaviour { - public NoneBehaviour() { Name = "None"; } + public NoneBehaviour() + { + AbbreviatedName = "n"; + Name = "None"; + } } } \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs index daa7485..47b4d46 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs @@ -46,6 +46,7 @@ namespace pCampBot public PhysicsBehaviour() { + AbbreviatedName = "p"; Name = "Physics"; talkarray = readexcuses(); } diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs index fbb4e96..5f7edda 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs @@ -42,7 +42,11 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public TeleportBehaviour() { Name = "Teleport"; } + public TeleportBehaviour() + { + AbbreviatedName = "t"; + Name = "Teleport"; + } public override void Action() { diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 5c3835b..35a24d1 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -572,10 +572,11 @@ namespace pCampBot private void HandleShowBotsStatus(string module, string[] cmd) { ConsoleDisplayTable cdt = new ConsoleDisplayTable(); - cdt.AddColumn("Name", 30); - cdt.AddColumn("Region", 30); - cdt.AddColumn("Status", 14); - cdt.AddColumn("Connections", 11); + cdt.AddColumn("Name", 24); + cdt.AddColumn("Region", 24); + cdt.AddColumn("Status", 13); + cdt.AddColumn("Conns", 5); + cdt.AddColumn("Behaviours", 20); Dictionary totals = new Dictionary(); foreach (object o in Enum.GetValues(typeof(ConnectionState))) @@ -583,13 +584,17 @@ namespace pCampBot lock (m_bots) { - foreach (Bot pb in m_bots) + foreach (Bot bot in m_bots) { - Simulator currentSim = pb.Client.Network.CurrentSim; - totals[pb.ConnectionState]++; + Simulator currentSim = bot.Client.Network.CurrentSim; + totals[bot.ConnectionState]++; cdt.AddRow( - pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState, pb.SimulatorsCount); + bot.Name, + currentSim != null ? currentSim.Name : "(none)", + bot.ConnectionState, + bot.SimulatorsCount, + string.Join(",", bot.Behaviours.ConvertAll(behaviour => behaviour.AbbreviatedName))); } } @@ -645,6 +650,7 @@ namespace pCampBot MainConsole.Instance.Output("Settings"); ConsoleDisplayList statusCdl = new ConsoleDisplayList(); + statusCdl.AddRow("Behaviours", string.Join(", ", bot.Behaviours.ConvertAll(b => b.Name))); GridClient botClient = bot.Client; statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES); diff --git a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs index 9c984be..f8a661b 100644 --- a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs @@ -32,6 +32,11 @@ namespace pCampBot.Interfaces public interface IBehaviour { /// + /// Abbreviated name of this behaviour. + /// + string AbbreviatedName { get; } + + /// /// Name of this behaviour. /// string Name { get; } -- cgit v1.1 From a89c56dcf1e2645554f8b81b6f1e517b829cc3a4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 17:53:29 +0100 Subject: Fix build break from last commit 9c65207. Mono 2.4 lacks string.join(string, List), or some auto casting is missing --- OpenSim/Tools/pCampBot/BotManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 35a24d1..7d4af13 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -594,7 +594,7 @@ namespace pCampBot currentSim != null ? currentSim.Name : "(none)", bot.ConnectionState, bot.SimulatorsCount, - string.Join(",", bot.Behaviours.ConvertAll(behaviour => behaviour.AbbreviatedName))); + string.Join(",", bot.Behaviours.ConvertAll(behaviour => behaviour.AbbreviatedName).ToArray())); } } -- cgit v1.1 From 01cb8033a42514728835a18a38f2a18349e83638 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 17:55:20 +0100 Subject: And fix break in "show bot" from commit 9c65207 --- OpenSim/Tools/pCampBot/BotManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 7d4af13..3e446af 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -650,7 +650,7 @@ namespace pCampBot MainConsole.Instance.Output("Settings"); ConsoleDisplayList statusCdl = new ConsoleDisplayList(); - statusCdl.AddRow("Behaviours", string.Join(", ", bot.Behaviours.ConvertAll(b => b.Name))); + statusCdl.AddRow("Behaviours", string.Join(", ", bot.Behaviours.ConvertAll(b => b.Name).ToArray())); GridClient botClient = bot.Client; statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES); -- cgit v1.1 From 9bd62715704685738c55c6de8127b16cc6695bdb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 18:51:55 +0100 Subject: Add ability to adjust pCampbot bot behaviours whilst running with "add behaviour " console commad --- OpenSim/Tools/pCampBot/Bot.cs | 51 ++++++++---- OpenSim/Tools/pCampBot/BotManager.cs | 147 ++++++++++++++++++++++++++++------- 2 files changed, 157 insertions(+), 41 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index d418288..6037516 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -72,9 +72,10 @@ namespace pCampBot /// Behaviours implemented by this bot. /// /// - /// Lock this list before manipulating it. + /// Indexed by abbreviated name. There can only be one instance of a particular behaviour. + /// Lock this structure before manipulating it. /// - public List Behaviours { get; private set; } + public Dictionary Behaviours { get; private set; } /// /// Objects that the bot has discovered. @@ -165,8 +166,6 @@ namespace pCampBot { ConnectionState = ConnectionState.Disconnected; - behaviours.ForEach(b => b.Initialize(this)); - Random = new Random(Environment.TickCount);// We do stuff randomly here FirstName = firstName; LastName = lastName; @@ -176,12 +175,31 @@ namespace pCampBot StartLocation = startLocation; Manager = bm; - Behaviours = behaviours; + + Behaviours = new Dictionary(); + foreach (IBehaviour behaviour in behaviours) + AddBehaviour(behaviour); // Only calling for use as a template. CreateLibOmvClient(); } + public bool AddBehaviour(IBehaviour behaviour) + { + lock (Behaviours) + { + if (!Behaviours.ContainsKey(behaviour.AbbreviatedName)) + { + behaviour.Initialize(this); + Behaviours.Add(behaviour.AbbreviatedName, behaviour); + + return true; + } + } + + return false; + } + private void CreateLibOmvClient() { GridClient newClient = new GridClient(); @@ -237,16 +255,21 @@ namespace pCampBot private void Action() { while (ConnectionState != ConnectionState.Disconnecting) + { lock (Behaviours) - Behaviours.ForEach( - b => - { - Thread.Sleep(Random.Next(3000, 10000)); - - // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); - b.Action(); - } - ); + { + foreach (IBehaviour behaviour in Behaviours.Values) + { + Thread.Sleep(Random.Next(3000, 10000)); + + // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); + behaviour.Action(); + } + } + + // XXX: This is a really shitty way of yielding so that behaviours can be added/removed + Thread.Sleep(100); + } } /// diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 3e446af..51c5ff4 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -140,7 +140,7 @@ namespace pCampBot /// /// Behaviour switches for bots. /// - private HashSet m_behaviourSwitches = new HashSet(); + private HashSet m_defaultBehaviourSwitches = new HashSet(); /// /// Constructor Creates MainConsole.Instance to take commands and provide the place to write data @@ -195,6 +195,18 @@ namespace pCampBot HandleDisconnect); m_console.Commands.AddCommand( + "bot", false, "add behaviour", "add behaviour ", + "Add a behaviour to a bot", + "Can be performed on connected or disconnected bots.", + HandleAddBehaviour); + +// m_console.Commands.AddCommand( +// "bot", false, "remove behaviour", "remove behaviour ", +// "Remove a behaviour from a bot", +// "Can be performed on connected or disconnected bots.", +// HandleRemoveBehaviour); + + m_console.Commands.AddCommand( "bot", false, "sit", "sit", "Sit all bots on the ground.", HandleSit); @@ -235,7 +247,7 @@ namespace pCampBot m_startUri = ParseInputStartLocationToUri(startupConfig.GetString("start", "last")); Array.ForEach( - startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_behaviourSwitches.Add(b)); + startupConfig.GetString("behaviours", "p").Split(new char[] { ',' }), b => m_defaultBehaviourSwitches.Add(b)); for (int i = 0; i < botcount; i++) { @@ -243,28 +255,50 @@ namespace pCampBot { string lastName = string.Format("{0}_{1}", m_lastNameStem, i + m_fromBotNumber); - // We must give each bot its own list of instantiated behaviours since they store state. - List behaviours = new List(); - - // Hard-coded for now - if (m_behaviourSwitches.Contains("c")) - behaviours.Add(new CrossBehaviour()); + CreateBot( + this, + CreateBehavioursFromAbbreviatedNames(m_defaultBehaviourSwitches), + m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); + } + } + } + + private List CreateBehavioursFromAbbreviatedNames(HashSet abbreviatedNames) + { + // We must give each bot its own list of instantiated behaviours since they store state. + List behaviours = new List(); + + // Hard-coded for now + foreach (string abName in abbreviatedNames) + { + IBehaviour newBehaviour = null; + + if (abName == "c") + newBehaviour = new CrossBehaviour(); + + if (abName == "g") + newBehaviour = new GrabbingBehaviour(); - if (m_behaviourSwitches.Contains("g")) - behaviours.Add(new GrabbingBehaviour()); + if (abName == "n") + newBehaviour = new NoneBehaviour(); - if (m_behaviourSwitches.Contains("n")) - behaviours.Add(new NoneBehaviour()); + if (abName == "p") + newBehaviour = new PhysicsBehaviour(); - if (m_behaviourSwitches.Contains("p")) - behaviours.Add(new PhysicsBehaviour()); - - if (m_behaviourSwitches.Contains("t")) - behaviours.Add(new TeleportBehaviour()); + if (abName == "t") + newBehaviour = new TeleportBehaviour(); - CreateBot(this, behaviours, m_firstName, lastName, m_password, m_loginUri, m_startUri, m_wearSetting); + if (newBehaviour != null) + { + behaviours.Add(newBehaviour); + } + else + { + MainConsole.Instance.OutputFormat("No behaviour with abbreviated name {0} found", abName); } } + + return behaviours; } public void ConnectBots(int botcount) @@ -453,6 +487,44 @@ namespace pCampBot } } + private void HandleAddBehaviour(string module, string[] cmd) + { + if (cmd.Length != 4) + { + MainConsole.Instance.OutputFormat("Usage: add behaviour "); + return; + } + + string rawBehaviours = cmd[2]; + int botNumber; + + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) + return; + + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + + HashSet rawAbbreviatedSwitchesToAdd = new HashSet(); + Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b)); + + List behavioursAdded = new List(); + + foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd)) + { + if (bot.AddBehaviour(behaviour)) + behavioursAdded.Add(behaviour); + } + + MainConsole.Instance.OutputFormat( + "Added behaviours {0} to bot {1}", + string.Join(", ", behavioursAdded.ConvertAll(b => b.Name).ToArray()), bot.Name); + } + private void HandleDisconnect(string module, string[] cmd) { lock (m_bots) @@ -594,7 +666,7 @@ namespace pCampBot currentSim != null ? currentSim.Name : "(none)", bot.ConnectionState, bot.SimulatorsCount, - string.Join(",", bot.Behaviours.ConvertAll(behaviour => behaviour.AbbreviatedName).ToArray())); + string.Join(",", bot.Behaviours.Keys.ToArray())); } } @@ -621,16 +693,11 @@ namespace pCampBot if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, cmd[2], out botNumber)) return; - string name = string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber); - - Bot bot; - - lock (m_bots) - bot = m_bots.Find(b => b.Name == name); + Bot bot = GetBotFromNumber(botNumber); if (bot == null) { - MainConsole.Instance.Output("No bot found with name {0}", name); + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); return; } @@ -650,13 +717,39 @@ namespace pCampBot MainConsole.Instance.Output("Settings"); ConsoleDisplayList statusCdl = new ConsoleDisplayList(); - statusCdl.AddRow("Behaviours", string.Join(", ", bot.Behaviours.ConvertAll(b => b.Name).ToArray())); + + statusCdl.AddRow( + "Behaviours", + string.Join(", ", bot.Behaviours.Values.ToList().ConvertAll(b => b.Name).ToArray())); + GridClient botClient = bot.Client; statusCdl.AddRow("SEND_AGENT_UPDATES", botClient.Settings.SEND_AGENT_UPDATES); MainConsole.Instance.Output(statusCdl.ToString()); } + /// + /// Get a specific bot from its number. + /// + /// null if no bot was found + /// + private Bot GetBotFromNumber(int botNumber) + { + string name = GenerateBotNameFromNumber(botNumber); + + Bot bot; + + lock (m_bots) + bot = m_bots.Find(b => b.Name == name); + + return bot; + } + + private string GenerateBotNameFromNumber(int botNumber) + { + return string.Format("{0} {1}_{2}", m_firstName, m_lastNameStem, botNumber); + } + internal void Grid_GridRegion(object o, GridRegionEventArgs args) { lock (RegionsKnown) -- cgit v1.1 From 1a2627031d8a80b1d5e21fd2d13e4dc2b123c0b4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 19:05:54 +0100 Subject: Add pCampbot "remove behaviour" console command for removing bot behaviours during operation. Doesn't currently work very well as stopping physics, for instance, can leave bot travelling in old direction --- OpenSim/Tools/pCampBot/Bot.cs | 12 ++++++++ OpenSim/Tools/pCampBot/BotManager.cs | 53 ++++++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 6037516..0bd8151 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -184,6 +184,12 @@ namespace pCampBot CreateLibOmvClient(); } + public bool TryGetBehaviour(string abbreviatedName, out IBehaviour behaviour) + { + lock (Behaviours) + return Behaviours.TryGetValue(abbreviatedName, out behaviour); + } + public bool AddBehaviour(IBehaviour behaviour) { lock (Behaviours) @@ -200,6 +206,12 @@ namespace pCampBot return false; } + public bool RemoveBehaviour(string abbreviatedName) + { + lock (Behaviours) + return Behaviours.Remove(abbreviatedName); + } + private void CreateLibOmvClient() { GridClient newClient = new GridClient(); diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 51c5ff4..6433c2e 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -200,11 +200,11 @@ namespace pCampBot "Can be performed on connected or disconnected bots.", HandleAddBehaviour); -// m_console.Commands.AddCommand( -// "bot", false, "remove behaviour", "remove behaviour ", -// "Remove a behaviour from a bot", -// "Can be performed on connected or disconnected bots.", -// HandleRemoveBehaviour); + m_console.Commands.AddCommand( + "bot", false, "remove behaviour", "remove behaviour ", + "Remove a behaviour from a bot", + "Can be performed on connected or disconnected bots.", + HandleRemoveBehaviour); m_console.Commands.AddCommand( "bot", false, "sit", "sit", "Sit all bots on the ground.", @@ -525,6 +525,49 @@ namespace pCampBot string.Join(", ", behavioursAdded.ConvertAll(b => b.Name).ToArray()), bot.Name); } + private void HandleRemoveBehaviour(string module, string[] cmd) + { + if (cmd.Length != 4) + { + MainConsole.Instance.OutputFormat("Usage: remove behaviour "); + return; + } + + string rawBehaviours = cmd[2]; + int botNumber; + + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) + return; + + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + + HashSet abbreviatedBehavioursToRemove = new HashSet(); + List behavioursRemoved = new List(); + + Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => abbreviatedBehavioursToRemove.Add(b)); + + foreach (string b in abbreviatedBehavioursToRemove) + { + IBehaviour behaviour; + + if (bot.TryGetBehaviour(b, out behaviour)) + { + bot.RemoveBehaviour(b); + behavioursRemoved.Add(behaviour); + } + } + + MainConsole.Instance.OutputFormat( + "Removed behaviours {0} to bot {1}", + string.Join(", ", behavioursRemoved.ConvertAll(b => b.Name).ToArray()), bot.Name); + } + private void HandleDisconnect(string module, string[] cmd) { lock (m_bots) -- cgit v1.1 From 3dbe7313d1c3fc28f0642531fbb6e238a98ac821 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 19:33:17 +0100 Subject: Add Close() method to IBehaviour to allow behaviours to cleanup when removed or bot it disconnected. In this case, it is used to turn off jump when physics testing behaviour is removed. --- OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs | 2 ++ OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | 5 +++++ OpenSim/Tools/pCampBot/Bot.cs | 16 +++++++++++++++- OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs | 8 ++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs index 66d5542..9bc8512 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/AbstractBehaviour.cs @@ -50,5 +50,7 @@ namespace pCampBot { Bot = bot; } + + public virtual void Close() {} } } diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs index 47b4d46..65a7c90 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs @@ -78,6 +78,11 @@ namespace pCampBot Bot.Client.Self.Chat(randomf, 0, ChatType.Normal); } + public override void Close() + { + Bot.Client.Self.Jump(false); + } + private string[] readexcuses() { string allexcuses = ""; diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index 0bd8151..f871b77 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -209,7 +209,17 @@ namespace pCampBot public bool RemoveBehaviour(string abbreviatedName) { lock (Behaviours) - return Behaviours.Remove(abbreviatedName); + { + IBehaviour behaviour; + + if (!Behaviours.TryGetValue(abbreviatedName, out behaviour)) + return false; + + behaviour.Close(); + Behaviours.Remove(abbreviatedName); + + return true; + } } private void CreateLibOmvClient() @@ -282,6 +292,10 @@ namespace pCampBot // XXX: This is a really shitty way of yielding so that behaviours can be added/removed Thread.Sleep(100); } + + lock (Behaviours) + foreach (IBehaviour b in Behaviours.Values) + b.Close(); } /// diff --git a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs index f8a661b..0ed4825 100644 --- a/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Interfaces/IBehaviour.cs @@ -51,6 +51,14 @@ namespace pCampBot.Interfaces void Initialize(Bot bot); /// + /// Close down this behaviour. + /// + /// + /// This is triggered if a behaviour is removed via explicit command and when a bot is disconnected + /// + void Close(); + + /// /// Action to take when this behaviour is invoked. /// /// -- cgit v1.1 From 76bd2e2d727a15e5d3bc9045bdef6faaeca4a08f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 19:41:12 +0100 Subject: Consistently give responsibility for thread sleeping to behaviours rather than controlling from the main action loop This is to avoid excessive and inconsistent delays between behaviours that currently need to embed sleeps in other actions (e.g. physics) and other behaviours. Might need a more sophisticated approach in the long term. --- OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs | 3 +++ OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs | 3 +++ OpenSim/Tools/pCampBot/Bot.cs | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs index 6acc27d..59f6244 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/GrabbingBehaviour.cs @@ -29,6 +29,7 @@ using OpenMetaverse; using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using pCampBot.Interfaces; namespace pCampBot @@ -60,6 +61,8 @@ namespace pCampBot Bot.Client.Self.Grab(prim.LocalID); Bot.Client.Self.GrabUpdate(prim.ID, Vector3.Zero); Bot.Client.Self.DeGrab(prim.LocalID); + + Thread.Sleep(1000); } } } \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs index 5f7edda..81f250d 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/TeleportBehaviour.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading; using log4net; using OpenMetaverse; using pCampBot.Interfaces; @@ -74,6 +75,8 @@ namespace pCampBot Bot.Name, sourceRegion.Name, Bot.Client.Self.SimPosition, destRegion.Name, destPosition); Bot.Client.Self.Teleport(destRegion.RegionHandle, destPosition); + + Thread.Sleep(Bot.Random.Next(3000, 10000)); } } } \ No newline at end of file diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index f871b77..d0a4ef3 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -282,7 +282,7 @@ namespace pCampBot { foreach (IBehaviour behaviour in Behaviours.Values) { - Thread.Sleep(Random.Next(3000, 10000)); +// Thread.Sleep(Random.Next(3000, 10000)); // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); behaviour.Action(); -- cgit v1.1 From 9c3c9b7f5f62a7ed892f691180b765a9190cbbcc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 19:57:34 +0100 Subject: Make pCampbot "add behaviour" and "remove behaviour" console commands work for all bots if no bot number is given --- OpenSim/Tools/pCampBot/BotManager.cs | 123 ++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 45 deletions(-) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 6433c2e..3c1b11e 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -195,15 +195,17 @@ namespace pCampBot HandleDisconnect); m_console.Commands.AddCommand( - "bot", false, "add behaviour", "add behaviour ", + "bot", false, "add behaviour", "add behaviour []", "Add a behaviour to a bot", - "Can be performed on connected or disconnected bots.", + "If no bot number is specified then behaviour is added to all bots.\n" + + "Can be performed on connected or disconnected bots.", HandleAddBehaviour); m_console.Commands.AddCommand( - "bot", false, "remove behaviour", "remove behaviour ", + "bot", false, "remove behaviour", "remove behaviour []", "Remove a behaviour from a bot", - "Can be performed on connected or disconnected bots.", + "If no bot number is specified then behaviour is added to all bots.\n" + + "Can be performed on connected or disconnected bots.", HandleRemoveBehaviour); m_console.Commands.AddCommand( @@ -224,7 +226,7 @@ namespace pCampBot "bot", false, "show bots", "show bots", "Shows the status of all bots", HandleShowBotsStatus); m_console.Commands.AddCommand( - "bot", false, "show bot", "show bot ", + "bot", false, "show bot", "show bot ", "Shows the detailed status and settings of a particular bot.", HandleShowBotStatus); m_bots = new List(); @@ -489,83 +491,114 @@ namespace pCampBot private void HandleAddBehaviour(string module, string[] cmd) { - if (cmd.Length != 4) + if (cmd.Length < 3 || cmd.Length > 4) { - MainConsole.Instance.OutputFormat("Usage: add behaviour "); + MainConsole.Instance.OutputFormat("Usage: add behaviour []"); return; } string rawBehaviours = cmd[2]; - int botNumber; - - if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) - return; - Bot bot = GetBotFromNumber(botNumber); + List botsToEffect = new List(); - if (bot == null) + if (cmd.Length == 3) { - MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); - return; + lock (m_bots) + botsToEffect.AddRange(m_bots); } + else + { + int botNumber; + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) + return; + + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + + botsToEffect.Add(bot); + } + HashSet rawAbbreviatedSwitchesToAdd = new HashSet(); Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => rawAbbreviatedSwitchesToAdd.Add(b)); - List behavioursAdded = new List(); - - foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd)) + foreach (Bot bot in botsToEffect) { - if (bot.AddBehaviour(behaviour)) - behavioursAdded.Add(behaviour); - } + List behavioursAdded = new List(); - MainConsole.Instance.OutputFormat( - "Added behaviours {0} to bot {1}", - string.Join(", ", behavioursAdded.ConvertAll(b => b.Name).ToArray()), bot.Name); + foreach (IBehaviour behaviour in CreateBehavioursFromAbbreviatedNames(rawAbbreviatedSwitchesToAdd)) + { + if (bot.AddBehaviour(behaviour)) + behavioursAdded.Add(behaviour); + } + + MainConsole.Instance.OutputFormat( + "Added behaviours {0} to bot {1}", + string.Join(", ", behavioursAdded.ConvertAll(b => b.Name).ToArray()), bot.Name); + } } private void HandleRemoveBehaviour(string module, string[] cmd) { - if (cmd.Length != 4) + if (cmd.Length < 3 || cmd.Length > 4) { - MainConsole.Instance.OutputFormat("Usage: remove behaviour "); + MainConsole.Instance.OutputFormat("Usage: remove behaviour []"); return; } string rawBehaviours = cmd[2]; - int botNumber; - - if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) - return; - Bot bot = GetBotFromNumber(botNumber); + List botsToEffect = new List(); - if (bot == null) + if (cmd.Length == 3) { - MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); - return; + lock (m_bots) + botsToEffect.AddRange(m_bots); } + else + { + int botNumber; + if (!ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, cmd[3], out botNumber)) + return; - HashSet abbreviatedBehavioursToRemove = new HashSet(); - List behavioursRemoved = new List(); + Bot bot = GetBotFromNumber(botNumber); + + if (bot == null) + { + MainConsole.Instance.OutputFormat("Error: No bot found with number {0}", botNumber); + return; + } + botsToEffect.Add(bot); + } + + HashSet abbreviatedBehavioursToRemove = new HashSet(); Array.ForEach(rawBehaviours.Split(new char[] { ',' }), b => abbreviatedBehavioursToRemove.Add(b)); - foreach (string b in abbreviatedBehavioursToRemove) + foreach (Bot bot in botsToEffect) { - IBehaviour behaviour; + List behavioursRemoved = new List(); - if (bot.TryGetBehaviour(b, out behaviour)) + foreach (string b in abbreviatedBehavioursToRemove) { - bot.RemoveBehaviour(b); - behavioursRemoved.Add(behaviour); + IBehaviour behaviour; + + if (bot.TryGetBehaviour(b, out behaviour)) + { + bot.RemoveBehaviour(b); + behavioursRemoved.Add(behaviour); + } } - } - MainConsole.Instance.OutputFormat( - "Removed behaviours {0} to bot {1}", - string.Join(", ", behavioursRemoved.ConvertAll(b => b.Name).ToArray()), bot.Name); + MainConsole.Instance.OutputFormat( + "Removed behaviours {0} to bot {1}", + string.Join(", ", behavioursRemoved.ConvertAll(b => b.Name).ToArray()), bot.Name); + } } private void HandleDisconnect(string module, string[] cmd) -- cgit v1.1 From b781a23c445bea0fd199eb756ebf6143959256a6 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 19:58:27 +0100 Subject: In pCampbot PhysicsBehaviour.Close(), only cancel jumping if bot is connected --- OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs index 65a7c90..6fd2b7c 100644 --- a/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs +++ b/OpenSim/Tools/pCampBot/Behaviours/PhysicsBehaviour.cs @@ -80,7 +80,8 @@ namespace pCampBot public override void Close() { - Bot.Client.Self.Jump(false); + if (Bot.ConnectionState == ConnectionState.Connected) + Bot.Client.Self.Jump(false); } private string[] readexcuses() -- cgit v1.1 From 5f0d54c209249e0640bc27b3d74a92e7c9d82428 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 26 Aug 2013 20:04:07 +0100 Subject: For a Hypergrid user, delay estate access checks until NewUserConnection() so that they work. This is necessary because the hypergrid groups checks (as referenced by estates) require an agent circuit to be present to construct the hypergrid ID. However, this is not around until Scene.NewUserConnection(), as called by CreateAgent() in EntityTransferModule. Therefore, if we're dealing with a hypergrid user, delay the check until NewUserConnection()/CreateAgent() The entity transfer impact should be minimal since CreateAgent() is the next significant call after NewUserConnection() However, to preserve the accuracy of query access we will only relax the check for HG users. --- OpenSim/Region/Framework/Scenes/Scene.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2a21a4c..8754024 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5788,9 +5788,13 @@ namespace OpenSim.Region.Framework.Scenes try { - if (!AuthorizeUser(aCircuit, false, out reason)) + // If this is a hypergrid user, then we can't perform a successful groups access check here since this + // currently relies on a circuit being present in the AuthenticateHandler to construct a Hypergrid ID. + // This is only present in NewUserConnection() which entity transfer calls very soon after QueryAccess(). + // Therefore, we'll defer to the check in NewUserConnection() instead. + if (!AuthorizeUser(aCircuit, !UserManagementModule.IsLocalGridUser(agentID), out reason)) { - // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); + //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); return false; } } -- cgit v1.1 From c7ded0618c303f8c24a91c83c2129292beebe466 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 27 Aug 2013 00:35:33 +0100 Subject: Also check user authorization if looking to upgrade from a child to a root agent. Relevant if a child agent has been allowed into the region which should not be upgraded to a root agent. --- OpenSim/Region/Framework/Scenes/Scene.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 8754024..3eaa8fd 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3860,6 +3860,19 @@ namespace OpenSim.Region.Framework.Scenes // Let the SP know how we got here. This has a lot of interesting // uses down the line. sp.TeleportFlags = (TPFlags)teleportFlags; + + // We must carry out a further authorization check if there's an + // attempt to make a child agent into a root agent, since SeeIntoRegion may have allowed a child + // agent to login to a region where a full avatar would not be allowed. + // + // We determine whether this is a CreateAgent for a future non-child agent by inspecting + // TeleportFlags, which will be default for a child connection. This relies on input from the source + // region. + if (sp.TeleportFlags != TPFlags.Default) + { + if (!AuthorizeUser(acd, false, out reason)) + return false; + } if (sp.IsChildAgent) { -- cgit v1.1 From dc74a50225a901e969ea83008555170f5742ca7a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 4 Sep 2013 23:48:24 +0100 Subject: Stop "show client stats" from throwing an exception if somehow Scene.m_clientManager still retains a reference to a dead client. Instead, "show client stats" now prints "Off!" so that exception is not thrown and we know which entries in ClientManager are in this state. There's a race condition which could trigger this, but the window is extremely short and exceptions would not be thrown consistently (which is the behaviour observed). It should otherwise be impossible for this condition to occur, so there may be a weakness in client manager IClientAPI removal. --- .../OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index 15dea17..1eb0a6b 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -624,9 +624,16 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden int avg_reqs = cinfo.AsyncRequests.Values.Sum() + cinfo.GenericRequests.Values.Sum() + cinfo.SyncRequests.Values.Sum(); avg_reqs = avg_reqs / ((DateTime.Now - cinfo.StartedTime).Minutes + 1); + string childAgentStatus; + + if (llClient.SceneAgent != null) + childAgentStatus = llClient.SceneAgent.IsChildAgent ? "N" : "Y"; + else + childAgentStatus = "Off!"; + m_log.InfoFormat("[INFO]: {0,-12} {1,-20} {2,-6} {3,-11} {4,-11} {5,-16}", scene.RegionInfo.RegionName, llClient.Name, - llClient.SceneAgent.IsChildAgent ? "N" : "Y", + childAgentStatus, (DateTime.Now - cinfo.StartedTime).Minutes, avg_reqs, string.Format( -- cgit v1.1 From b858be345a03448cf653efc725ec1fd4a57775f2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 5 Sep 2013 00:41:03 +0100 Subject: minor: add doc about DefaultHGRegion and some of the other GridService region settings (though not all as of yet) --- bin/Robust.HG.ini.example | 17 ++++++++++++++++- bin/Robust.ini.example | 20 ++++++++++++++++++-- bin/config-include/StandaloneCommon.ini.example | 20 ++++++++++++++++++-- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 0fbdf4e..8fe6d0c 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -170,7 +170,22 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset ;; The syntax is: Region_ = "" ;; or: Region_ = "" ;; where can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate - ;; For example: + ;; + ;; DefaultRegion If a local login cannot be placed in the required region (e.g. home region does not exist, avatar is not allowed entry, etc.) + ;; then this region becomes the destination. Only the first online default region will be used. If no DefaultHGRegion + ;; is specified then this will also be used as the region for hypergrid connections that require it (commonly because they have not specified + ;; an explicit region. + ;; + ;; DefaultHGRegion If an avatar connecting via the hypergrid does not specify a region, then they are placed here. Only the first online + ;; region will be used. + ;; + ;; FallbackRegion If the DefaultRegion is not available for a local login, then any FallbackRegions are tried instead. These are tried in the + ;; order specified. This only applies to local logins at this time, not Hypergrid connections. + ;; + ;; NoDirectLogin A hypergrid user cannot directly connect to this region. This does not apply to local logins. + ;; + ;; Persistent When the simulator is shutdown, the region is signalled as offline but left registered on the grid. + ;; ; Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; (replace spaces with underscore) diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index da1b43a..de6fc28 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -132,8 +132,24 @@ MapGetServiceConnector = "8002/OpenSim.Server.Handlers.dll:MapGetServiceConnecto ;; Next, we can specify properties of regions, including default and fallback regions ;; The syntax is: Region_ = "" ;; or: Region_ = "" - ;; where can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut,Reservation,NoMove,Authenticate - ;; For example: + ;; where can be DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate + ;; + ;; DefaultRegion If a local login cannot be placed in the required region (e.g. home region does not exist, avatar is not allowed entry, etc.) + ;; then this region becomes the destination. Only the first online default region will be used. If no DefaultHGRegion + ;; is specified then this will also be used as the region for hypergrid connections that require it (commonly because they have not specified + ;; an explicit region. + ;; + ;; DefaultHGRegion If an avatar connecting via the hypergrid does not specify a region, then they are placed here. Only the first online + ;; region will be used. + ;; + ;; FallbackRegion If the DefaultRegion is not available for a local login, then any FallbackRegions are tried instead. These are tried in the + ;; order specified. This only applies to local logins at this time, not Hypergrid connections. + ;; + ;; NoDirectLogin A hypergrid user cannot directly connect to this region. This does not apply to local logins. + ;; + ;; 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) diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 6b991a8..f7545d4 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -81,11 +81,27 @@ ;; Next, we can specify properties of regions, including default and fallback regions ;; The syntax is: Region_ = "" ;; where can be DefaultRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut + ;; + ;; DefaultRegion If a local login cannot be placed in the required region (e.g. home region does not exist, avatar is not allowed entry, etc.) + ;; then this region becomes the destination. Only the first online default region will be used. If no DefaultHGRegion + ;; is specified then this will also be used as the region for hypergrid connections that require it (commonly because they have not specified + ;; an explicit region. + ;; + ;; DefaultHGRegion If an avatar connecting via the hypergrid does not specify a region, then they are placed here. Only the first online + ;; region will be used. + ;; + ;; FallbackRegion If the DefaultRegion is not available for a local login, then any FallbackRegions are tried instead. These are tried in the + ;; order specified. This only applies to local logins at this time, not Hypergrid connections. + ;; + ;; NoDirectLogin A hypergrid user cannot directly connect to this region. This does not apply to local logins. + ;; + ;; Persistent When the simulator is shutdown, the region is signalled as offline but left registered on the grid. + ;; ;; For example: Region_Welcome_Area = "DefaultRegion, FallbackRegion" ; === HG ONLY === - ;; If you have this set under [Hypergrid], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; GatekeeperURI="http://127.0.0.1:9000" [LibraryModule] @@ -94,7 +110,7 @@ [LoginService] WelcomeMessage = "Welcome, Avatar!" - ;; If you have Gatekeeper set under [Hypergrid], no need to set it here, leave it commented + ;; If you have Gatekeeper set under [Hypergrid], no need to set it here, leave it commented ; GatekeeperURI = "http://127.0.0.1:9000" SRV_HomeURI = "http://127.0.0.1:9000" -- cgit v1.1 From 04619a9b139ac67c92b5b8be9607544be2621d7e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 5 Sep 2013 07:44:27 -0700 Subject: Restore group membership check for HG users in QueryAccess. --- .../Groups/Hypergrid/GroupsServiceHGConnectorModule.cs | 9 ++++++--- .../Framework/UserManagement/UserManagementModule.cs | 14 ++++++++++---- OpenSim/Region/Framework/Scenes/Scene.cs | 6 +----- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs index 4642b2a..7d48516 100644 --- a/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs +++ b/OpenSim/Addons/Groups/Hypergrid/GroupsServiceHGConnectorModule.cs @@ -623,10 +623,13 @@ namespace OpenSim.Groups if (agent != null) break; } - if (agent == null) // oops - return AgentID.ToString(); + 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); - return Util.ProduceUserUniversalIdentifier(agent); } private string AgentUUIForOutside(string AgentIDStr) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 7adb203..8c983e6 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -481,14 +481,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement public string GetUserUUI(UUID userID) { - UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, userID); - if (account != null) - return userID.ToString(); - UserData ud; lock (m_UserCache) m_UserCache.TryGetValue(userID, out ud); + if (ud == null) // It's not in the cache + { + string[] names = new string[2]; + // This will pull the data from either UserAccounts or GridUser + // and stick it into the cache + TryGetUserNamesFromServices(userID, names); + lock (m_UserCache) + m_UserCache.TryGetValue(userID, out ud); + } + if (ud != null) { string homeURL = ud.HomeURL; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 3eaa8fd..e00206f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5801,11 +5801,7 @@ namespace OpenSim.Region.Framework.Scenes try { - // If this is a hypergrid user, then we can't perform a successful groups access check here since this - // currently relies on a circuit being present in the AuthenticateHandler to construct a Hypergrid ID. - // This is only present in NewUserConnection() which entity transfer calls very soon after QueryAccess(). - // Therefore, we'll defer to the check in NewUserConnection() instead. - if (!AuthorizeUser(aCircuit, !UserManagementModule.IsLocalGridUser(agentID), out reason)) + if (!AuthorizeUser(aCircuit, false, out reason)) { //m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID); return false; -- cgit v1.1 From a97f6f86680026de6350f301d52307c187726875 Mon Sep 17 00:00:00 2001 From: BlueWall Date: Sat, 7 Sep 2013 13:11:31 -0400 Subject: Fix configuration/ini expansion issue. Thanks to smxy for testing. --- OpenSim/Region/Application/ConfigurationLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Application/ConfigurationLoader.cs b/OpenSim/Region/Application/ConfigurationLoader.cs index bc7ecb7..010ae5a 100644 --- a/OpenSim/Region/Application/ConfigurationLoader.cs +++ b/OpenSim/Region/Application/ConfigurationLoader.cs @@ -203,10 +203,10 @@ namespace OpenSim m_config.Source.Merge(envConfigSource); } - ReadConfigSettings(); - m_config.Source.ExpandKeyValues(); + ReadConfigSettings(); + return m_config; } -- cgit v1.1 From b05cb3b2bfd6f3912fb33a790b7c2d1ed898d539 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 9 Sep 2013 14:47:49 -0700 Subject: Change collision logic in SceneObjectPart so land_collision will happen. The previous logic would generate land_collision_start and land_collision_end but would not generate the land_collision itself. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index c9ff4f3..2e11162 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2464,12 +2464,9 @@ namespace OpenSim.Region.Framework.Scenes SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd); if (startedColliders.Contains(0)) - { - if (m_lastColliders.Contains(0)) - SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding); - else - SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart); - } + SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart); + if (m_lastColliders.Contains(0)) + SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding); if (endedColliders.Contains(0)) SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd); } -- cgit v1.1 From ec5f17b2cecc38a21ae3b1276b3a391f7c004c5d Mon Sep 17 00:00:00 2001 From: Michael Cerquoni Date: Tue, 10 Sep 2013 18:35:02 -0400 Subject: This extends the default max_distance for teleports to 16384, a big thank you to all of the viewer devs who made this possibe! --- bin/OpenSimDefaults.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 0a85085..28f0f4b 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -653,8 +653,8 @@ [EntityTransfer] ; The maximum distance in regions that an agent is allowed to teleport along the x or y axis - ; This is set to 4095 because current viewers can't handle teleports that are greater than this distance - max_distance = 4095 + ; This is set to 16384 because current viewers can't handle teleports that are greater than this distance + max_distance = 16384 ; Minimum user level required for HyperGrid teleports LevelHGTeleport = 0 -- cgit v1.1 From 663059ac5c65f5fcf9e4313a2c2edfb5b5df0829 Mon Sep 17 00:00:00 2001 From: Michael Cerquoni Date: Tue, 10 Sep 2013 19:56:39 -0400 Subject: chaning the default max_distance to 16383 as we actually start counting at zero, thank you dahlia for pointing this out. --- bin/OpenSimDefaults.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 28f0f4b..e168566 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -653,8 +653,8 @@ [EntityTransfer] ; The maximum distance in regions that an agent is allowed to teleport along the x or y axis - ; This is set to 16384 because current viewers can't handle teleports that are greater than this distance - max_distance = 16384 + ; This is set to 16383 because current viewers can't handle teleports that are greater than this distance + max_distance = 16383 ; Minimum user level required for HyperGrid teleports LevelHGTeleport = 0 -- cgit v1.1 From 725751fd6c0101b8610e84716d28b6af91e20b61 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 6 Aug 2013 10:32:56 -0700 Subject: BulletSim: fixes for change linkset implementation of physical linksets. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 29 +++++++++++++++++++++- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 6 ++--- .../Physics/BulletSPlugin/BSLinksetCompound.cs | 14 +++++------ .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 8 +++--- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 11 +++++--- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index d1d318c..4455df4 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -29,6 +29,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; +using System.Threading; using OpenSim.Framework; using OpenSim.Region.CoreModules; @@ -198,7 +199,33 @@ public class ExtendedPhysics : INonSharedRegionModule Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; if (rootPhysActor != null) { - ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + if (rootPhysActor.IsPhysical) + { + // Change a physical linkset by making non-physical, waiting for one heartbeat so all + // the prim and linkset state is updated, changing the type and making the + // linkset physical again. + containingGroup.ScriptSetPhysicsStatus(false); + Thread.Sleep(150); // longer than one heartbeat tick + + // A kludge for the moment. + // Since compound linksets move the children but don't generate position updates to the + // simulator, it is possible for compound linkset children to have out-of-sync simulator + // and physical positions. The following causes the simulator to push the real child positions + // down into the physics engine to get everything synced. + containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition); + containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation); + + ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + Thread.Sleep(150); // longer than one heartbeat tick + + containingGroup.ScriptSetPhysicsStatus(true); + } + else + { + // Non-physical linksets don't have a physical instantiation so there is no state to + // worry about being updated. + ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + } } else { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 3afd52e..a051002 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -148,7 +148,7 @@ public abstract class BSLinkset // Returns a new linkset for the child which is a linkset of one (just the // orphened child). // Called at runtime. - public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child) + public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) { lock (m_linksetActivityLock) { @@ -157,7 +157,7 @@ public abstract class BSLinkset // Cannot remove the root from a linkset. return this; } - RemoveChildFromLinkset(child); + RemoveChildFromLinkset(child, inTaintTime); LinksetMass = ComputeLinksetMass(); } @@ -255,7 +255,7 @@ public abstract class BSLinkset // I am the root of a linkset and one of my children is being removed. // Safe to call even if the child is not really in my linkset. - protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); + protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); // When physical properties are changed the linkset needs to recalculate // its internal properties. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 085d195..47ab842 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -242,7 +242,7 @@ public sealed class BSLinksetCompound : BSLinkset { bool ret = false; - DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", + DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); ScheduleRebuild(child); @@ -270,7 +270,7 @@ public sealed class BSLinksetCompound : BSLinkset // Remove the specified child from the linkset. // Safe to call even if the child is not really in the linkset. - protected override void RemoveChildFromLinkset(BSPrimLinkable child) + protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) { child.ClearDisplacement(); @@ -282,12 +282,12 @@ public sealed class BSLinksetCompound : BSLinkset child.LocalID, child.PhysBody.AddrString); // Cause the child's body to be rebuilt and thus restored to normal operation - child.ForceBodyShapeRebuild(false); + child.ForceBodyShapeRebuild(inTaintTime); if (!HasAnyChildren) { // The linkset is now empty. The root needs rebuilding. - LinksetRoot.ForceBodyShapeRebuild(false); + LinksetRoot.ForceBodyShapeRebuild(inTaintTime); } else { @@ -318,10 +318,10 @@ public sealed class BSLinksetCompound : BSLinkset // being destructed and going non-physical. LinksetRoot.ForceBodyShapeRebuild(true); - // There is no reason to build all this physical stuff for a non-physical linkset. - if (!LinksetRoot.IsPhysicallyActive) + // There is no reason to build all this physical stuff for a non-physical or empty linkset. + if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) { - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); return; // Note the 'finally' clause at the botton which will get executed. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 4bac222..d4ee27d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -224,7 +224,7 @@ public sealed class BSLinksetConstraints : BSLinkset // Remove the specified child from the linkset. // Safe to call even if the child is not really in my linkset. - protected override void RemoveChildFromLinkset(BSPrimLinkable child) + protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) { if (m_children.Remove(child)) { @@ -236,7 +236,7 @@ public sealed class BSLinksetConstraints : BSLinkset rootx.LocalID, rootx.PhysBody.AddrString, childx.LocalID, childx.PhysBody.AddrString); - m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() + m_physicsScene.TaintedObject(inTaintTime, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() { PhysicallyUnlinkAChildFromRoot(rootx, childx); }); @@ -382,9 +382,9 @@ public sealed class BSLinksetConstraints : BSLinkset Rebuilding = true; // There is no reason to build all this physical stuff for a non-physical linkset. - if (!LinksetRoot.IsPhysicallyActive) + if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) { - DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); return; // Note the 'finally' clause at the botton which will get executed. } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 7179a6d..38d1f88 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -66,7 +66,7 @@ public class BSPrimLinkable : BSPrimDisplaced public override void Destroy() { - Linkset = Linkset.RemoveMeFromLinkset(this); + Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */); base.Destroy(); } @@ -94,7 +94,7 @@ public class BSPrimLinkable : BSPrimDisplaced BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG int childrenBefore = Linkset.NumberOfChildren; // DEBUG - Linkset = Linkset.RemoveMeFromLinkset(this); + Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/); DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); @@ -240,6 +240,8 @@ public class BSPrimLinkable : BSPrimDisplaced bool ret = false; if (LinksetType != newType) { + DetailLog("{0},BSPrimLinkset.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); + // Set the implementation type first so the call to BSLinkset.Factory gets the new type. this.LinksetType = newType; @@ -263,7 +265,10 @@ public class BSPrimLinkable : BSPrimDisplaced // Remove the children from the old linkset and add to the new (will be a new instance from the factory) foreach (BSPrimLinkable child in children) { - oldLinkset.RemoveMeFromLinkset(child); + oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/); + } + foreach (BSPrimLinkable child in children) + { newLinkset.AddMeToLinkset(child); child.Linkset = newLinkset; } -- cgit v1.1 From 48ee73bfa771de64685a694417b34188f0a3350e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 07:54:47 -0700 Subject: BulletSim: add API and calls for spring constraint parameters. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 36 ++++++++++++++++++++ OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 38 ++++++++++++++++++++++ .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 8 +++++ 3 files changed, 82 insertions(+) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 12a0c17..6c36485 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -596,6 +596,30 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); } +public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse); +} + +public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint); +} + +public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss); +} + +public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping); +} + public override bool CalculateTransforms(BulletConstraint constrain) { BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; @@ -1601,6 +1625,18 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool CalculateTransforms2(IntPtr constrain); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 2a820be..9ad12a9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -752,6 +752,44 @@ private sealed class BulletConstraintXNA : BulletConstraint constraint.SetBreakingImpulseThreshold(threshold); return true; } + public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true)); + return true; + } + + public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + if (index == -1) + { + constraint.SetEquilibriumPoint(); + } + else + { + if (equilibriumPoint == -1) + constraint.SetEquilibriumPoint(index); + else + constraint.SetEquilibriumPoint(index, equilibriumPoint); + } + return true; + } + + public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.SetStiffness(index, stiffness); + return true; + } + + public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.SetDamping(index, damping); + return true; + } + //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); public override void SetAngularDamping(BulletBody pBody, float angularDamping) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 6cdc112..8cca29f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -441,6 +441,14 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); +public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse); + +public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint); + +public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss); + +public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping); + public abstract bool CalculateTransforms(BulletConstraint constrain); public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); -- cgit v1.1 From 9a7d0e489cf726f00379917cd507839d5fe56725 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 07:55:46 -0700 Subject: BulletSim: add spring constraint to linkset constraint types. --- .../Physics/BulletSPlugin/BSConstraintSpring.cs | 85 ++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs new file mode 100755 index 0000000..01d67d4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs @@ -0,0 +1,85 @@ +/* + * 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 copyrightD + * 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.Text; +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ + +public sealed class BSConstraintSpring : BSConstraint6Dof +{ + public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } } + + public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1Loc, Quaternion frame1Rot, + Vector3 frame2Loc, Quaternion frame2Rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + :base(world, obj1, obj2) + { + m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2, + frame1Loc, frame1Rot, frame2Loc, frame2Rot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + + world.physicsScene.DetailLog("{0},BSConstraintSpring,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + BSScene.DetailLogZero, world.worldID, + obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + } + + public bool SetEnable(int index, bool axisEnable) + { + bool ret = false; + + return ret; + } + + public bool SetStiffness(int index, float stiffness) + { + bool ret = false; + + return ret; + } + + public bool SetDamping(int index, float damping) + { + bool ret = false; + + return ret; + } + + public bool SetEquilibriumPoint(int index, float eqPoint) + { + bool ret = false; + + return ret; + } + +} + +} \ No newline at end of file -- cgit v1.1 From 0971c7ae77cae3d238be31f46994b4692af949e3 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 07:56:37 -0700 Subject: BulletSim: complete linkage of spring constraint into linkset constraint. --- .../Physics/BulletSPlugin/BSConstraint6Dof.cs | 9 ++- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 2 + .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 81 ++++++++++++++++++---- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index d0949f5..5008ff7 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs @@ -32,12 +32,19 @@ using OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { -public sealed class BSConstraint6Dof : BSConstraint +public class BSConstraint6Dof : BSConstraint { private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_enabled = false; + } + // Create a btGeneric6DofConstraint public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, Vector3 frame1, Quaternion frame1rot, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index a051002..d4b1c1e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -77,6 +77,8 @@ public abstract class BSLinkset { member = pMember; } + public virtual void ResetLink() { } + public virtual void SetLinkParameters(BSConstraint constrain) { } } public LinksetImplementation LinksetImpl { get; protected set; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index d4ee27d..f3b70c3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -51,16 +51,26 @@ public sealed class BSLinksetConstraints : BSLinkset public float cfm; public float erp; public float solverIterations; + // + public OMV.Vector3 frameInAloc; + public OMV.Quaternion frameInArot; + public OMV.Vector3 frameInBloc; + public OMV.Quaternion frameInBrot; + // Spring + public float springDamping; + public float springStiffness; + + public BSLinkInfoConstraint(BSPrimLinkable pMember) : base(pMember) { constraint = null; - ResetToFixedConstraint(); + ResetLink(); } // Set all the parameters for this constraint to a fixed, non-movable constraint. - public void ResetToFixedConstraint() + public override void ResetLink() { constraintType = ConstraintType.D6_CONSTRAINT_TYPE; linearLimitLow = OMV.Vector3.Zero; @@ -74,10 +84,16 @@ public sealed class BSLinksetConstraints : BSLinkset cfm = BSParam.LinkConstraintCFM; erp = BSParam.LinkConstraintERP; solverIterations = BSParam.LinkConstraintSolverIterations; + frameInAloc = OMV.Vector3.Zero; + frameInArot = OMV.Quaternion.Identity; + frameInBloc = OMV.Vector3.Zero; + frameInBrot = OMV.Quaternion.Identity; + springDamping = -1f; + springStiffness = -1f; } // Given a constraint, apply the current constraint parameters to same. - public void SetConstraintParameters(BSConstraint constrain) + public override void SetLinkParameters(BSConstraint constrain) { switch (constraintType) { @@ -85,6 +101,7 @@ public sealed class BSLinksetConstraints : BSLinkset BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; if (constrain6dof != null) { + // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. // zero linear and angular limits makes the objects unable to move in relation to each other constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); @@ -99,6 +116,31 @@ public sealed class BSLinksetConstraints : BSLinkset } } break; + case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: + BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; + if (constrainSpring != null) + { + // zero linear and angular limits makes the objects unable to move in relation to each other + constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); + constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); + + // tweek the constraint to increase stability + constrainSpring.UseFrameOffset(useFrameOffset); + constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); + constrainSpring.SetCFMAndERP(cfm, erp); + if (solverIterations != 0f) + { + constrainSpring.SetSolverIterations(solverIterations); + } + for (int ii = 0; ii < 6; ii++) + { + if (springDamping != -1) + constrainSpring.SetDamping(ii, springDamping); + if (springStiffness != -1) + constrainSpring.SetStiffness(ii, springStiffness); + } + } + break; default: break; } @@ -262,8 +304,8 @@ public sealed class BSLinksetConstraints : BSLinkset // Create a static constraint between the two passed objects private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) { - BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint; - if (liConstraint == null) + BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; + if (linkInfo == null) return null; // Zero motion for children so they don't interpolate @@ -271,27 +313,25 @@ public sealed class BSLinksetConstraints : BSLinkset BSConstraint constrain = null; - switch (liConstraint.constraintType) + switch (linkInfo.constraintType) { case ConstraintType.D6_CONSTRAINT_TYPE: // Relative position normalized to the root prim // Essentually a vector pointing from center of rootPrim to center of li.member - OMV.Vector3 childRelativePosition = liConstraint.member.Position - rootPrim.Position; + OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; // real world coordinate of midpoint between the two objects OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); - DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.AddrString, - liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString, - rootPrim.Position, liConstraint.member.Position, midPoint); + DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={7}", + rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, + rootPrim.Position, linkInfo.member.Position, midPoint); // create a constraint that allows no freedom of movement between the two objects // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 constrain = new BSConstraint6Dof( - m_physicsScene.World, rootPrim.PhysBody, liConstraint.member.PhysBody, midPoint, true, true ); + m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); /* NOTE: below is an attempt to build constraint with full frame computation, etc. * Using the midpoint is easier since it lets the Bullet code manipulate the transforms @@ -320,11 +360,23 @@ public sealed class BSLinksetConstraints : BSLinkset */ break; + case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: + constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, + linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, + true /*useLinearReferenceFrameA*/, + true /*disableCollisionsBetweenLinkedBodies*/); + DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", + rootPrim.LocalID, + rootPrim.LocalID, rootPrim.PhysBody.AddrString, + linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, + rootPrim.Position, linkInfo.member.Position); + + break; default: break; } - liConstraint.SetConstraintParameters(constrain); + linkInfo.SetLinkParameters(constrain); m_physicsScene.Constraints.AddConstraint(constrain); @@ -401,6 +453,7 @@ public sealed class BSLinksetConstraints : BSLinkset // If constraint doesn't exist yet, create it. constrain = BuildConstraint(LinksetRoot, li); } + li.SetLinkParameters(constrain); constrain.RecomputeConstraintVariables(linksetMass); // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG -- cgit v1.1 From 993bcec088ce5c3ec2f76f61842f19cbdcc89384 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 10:15:28 -0700 Subject: BulletSim: add unmanaged and XNA functions for hinge, slider and spring constraints. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 45 ++++++ OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 174 ++++++++++++++++++++- .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 24 +++ 3 files changed, 241 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 6c36485..8dfb01c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -596,6 +596,12 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); } +public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation); +} + public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse) { BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; @@ -620,6 +626,30 @@ public override bool SpringSetDamping(BulletConstraint constrain, int index, flo return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping); } +public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val); +} + +public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val); +} + +public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse); +} + +public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val) +{ + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val); +} + public override bool CalculateTransforms(BulletConstraint constrain) { BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; @@ -1625,6 +1655,9 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] @@ -1637,6 +1670,18 @@ public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int in public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool CalculateTransforms2(IntPtr constrain); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 9ad12a9..ff2b497 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -752,6 +752,15 @@ private sealed class BulletConstraintXNA : BulletConstraint constraint.SetBreakingImpulseThreshold(threshold); return true; } + public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation) + { + HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint; + if (softness == HINGE_NOT_SPECIFIED) + constraint.SetLimit(low, high); + else + constraint.SetLimit(low, high, softness, bias, relaxation); + return true; + } public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse) { Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; @@ -762,13 +771,13 @@ private sealed class BulletConstraintXNA : BulletConstraint public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint) { Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; - if (index == -1) + if (index == SPRING_NOT_SPECIFIED) { constraint.SetEquilibriumPoint(); } else { - if (equilibriumPoint == -1) + if (equilibriumPoint == SPRING_NOT_SPECIFIED) constraint.SetEquilibriumPoint(index); else constraint.SetEquilibriumPoint(index, equilibriumPoint); @@ -790,6 +799,167 @@ private sealed class BulletConstraintXNA : BulletConstraint return true; } + public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (lowerUpper) + { + case SLIDER_LOWER_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetLowerLinLimit(val); + break; + case SLIDER_ANGULAR: + constraint.SetLowerAngLimit(val); + break; + } + break; + case SLIDER_UPPER_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetUpperLinLimit(val); + break; + case SLIDER_ANGULAR: + constraint.SetUpperAngLimit(val); + break; + } + break; + } + return true; + } + public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (softRestDamp) + { + case SLIDER_SET_SOFTNESS: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break; + } + break; + } + break; + case SLIDER_SET_RESTITUTION: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break; + } + break; + } + break; + case SLIDER_SET_DAMPING: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break; + } + break; + } + break; + } + return true; + } + public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true); + break; + case SLIDER_ANGULAR: + constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true); + break; + } + return true; + } + public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (forceVel) + { + case SLIDER_MOTOR_VELOCITY: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetTargetLinMotorVelocity(val); + break; + case SLIDER_ANGULAR: + constraint.SetTargetAngMotorVelocity(val); + break; + } + break; + case SLIDER_MAX_MOTOR_FORCE: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetMaxLinMotorForce(val); + break; + case SLIDER_ANGULAR: + constraint.SetMaxAngMotorForce(val); + break; + } + break; + } + return true; + } + //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); public override void SetAngularDamping(BulletBody pBody, float angularDamping) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 8cca29f..b241059 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -441,14 +441,38 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); +public const int HINGE_NOT_SPECIFIED = -1; +public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation); + public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse); +public const int SPRING_NOT_SPECIFIED = -1; public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint); public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss); public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping); +public const int SLIDER_LOWER_LIMIT = 0; +public const int SLIDER_UPPER_LIMIT = 1; +public const int SLIDER_LINEAR = 2; +public const int SLIDER_ANGULAR = 3; +public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val); + +public const int SLIDER_SET_SOFTNESS = 4; +public const int SLIDER_SET_RESTITUTION = 5; +public const int SLIDER_SET_DAMPING = 6; +public const int SLIDER_SET_DIRECTION = 7; +public const int SLIDER_SET_LIMIT = 8; +public const int SLIDER_SET_ORTHO = 9; +public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); + +public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse); + +public const int SLIDER_MOTOR_VELOCITY = 10; +public const int SLIDER_MAX_MOTOR_FORCE = 11; +public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val); + public abstract bool CalculateTransforms(BulletConstraint constrain); public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); -- cgit v1.1 From c6a6631efc74ac8c139e0ae8cad683496fdd0050 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 10:24:37 -0700 Subject: BulletSim: move linkset extension operations into BSPrimLinkable where they should be. --- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 32 +---------------- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 41 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index d5b999d..4685b48 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -41,7 +41,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin [Serializable] public class BSPrim : BSPhysObject { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[BULLETS PRIM]"; // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. @@ -1555,36 +1555,6 @@ public class BSPrim : BSPhysObject object ret = null; switch (pFunct) { - case BSScene.PhysFunctGetLinksetType: - { - BSPrimLinkable myHandle = this as BSPrimLinkable; - if (myHandle != null) - { - ret = (object)myHandle.LinksetType; - } - m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); - break; - } - case BSScene.PhysFunctSetLinksetType: - { - if (pParams.Length > 0) - { - BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0]; - BSPrimLinkable myHandle = this as BSPrimLinkable; - if (myHandle != null && myHandle.Linkset.IsRoot(myHandle)) - { - PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate() - { - // Cause the linkset type to change - m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}", - LogHeader, myHandle.Linkset.LinksetImpl, linksetType); - myHandle.ConvertLinkset(linksetType); - }); - } - ret = (object)(int)linksetType; - } - break; - } default: ret = base.Extension(pFunct, pParams); break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 38d1f88..fc639ad 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -41,6 +41,8 @@ public class BSPrimLinkable : BSPrimDisplaced // operations necessary for keeping the linkset created and, additionally, this // calls the linkset implementation for its creation and management. + private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]"; + // This adds the overrides for link() and delink() so the prim is linkable. public BSLinkset Linkset { get; set; } @@ -279,5 +281,44 @@ public class BSPrimLinkable : BSPrimDisplaced } return ret; } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + object ret = null; + switch (pFunct) + { + case BSScene.PhysFunctGetLinksetType: + { + ret = (object)LinksetType; + m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); + break; + } + case BSScene.PhysFunctSetLinksetType: + { + if (pParams.Length > 0) + { + BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0]; + if (Linkset.IsRoot(this)) + { + PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate() + { + // Cause the linkset type to change + m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}", + LogHeader, Linkset.LinksetImpl, linksetType); + ConvertLinkset(linksetType); + }); + } + ret = (object)(int)linksetType; + } + break; + } + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + #endregion // Extension } } -- cgit v1.1 From f3cc20050e8e4ce047509589f828ccafbc59e3a9 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 11:13:53 -0700 Subject: BulletSim: initial implementation of physChangeLinkFixed that resets a linkset's link back to a fixed, non-moving connection. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 82 +++++++++++++++++++++- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 29 +++++--- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 4 ++ 3 files changed, 105 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 4455df4..decb61a 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -61,6 +61,10 @@ public class ExtendedPhysics : INonSharedRegionModule // Per prim functions. See BSPrim. public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; + public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed"; + public const string PhysFunctChangeLinkHinge = "BulletSim.ChangeLinkHinge"; + public const string PhysFunctChangeLinkSpring = "BulletSim.ChangeLinkSpring"; + public const string PhysFunctChangeLinkSlider = "BulletSim.ChangeLinkSlider"; // ============================================================= @@ -250,7 +254,6 @@ public class ExtendedPhysics : INonSharedRegionModule public int physGetLinksetType(UUID hostID, UUID scriptID) { int ret = -1; - if (!Enabled) return ret; // The part that is requesting the change. @@ -287,5 +290,82 @@ public class ExtendedPhysics : INonSharedRegionModule } return ret; } + + [ScriptInvocation] + public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum) + { + int ret = -1; + if (!Enabled) return ret; + + // The part that is requesting the change. + SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); + + if (requestingPart != null) + { + // The type is is always on the root of a linkset. + SceneObjectGroup containingGroup = requestingPart.ParentGroup; + SceneObjectPart rootPart = containingGroup.RootPart; + + if (rootPart != null) + { + Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) + { + SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum); + if (linkPart != null) + { + Physics.Manager.PhysicsActor linkPhysActor = linkPart.PhysActor; + if (linkPhysActor != null) + { + ret = (int)rootPhysActor.Extension(PhysFunctChangeLinkFixed, linkNum, linkPhysActor); + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); + } + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); + } + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } + return ret; + } + + [ScriptInvocation] + public int physChangeLinkHinge(UUID hostID, UUID scriptID, int linkNum) + { + return 0; + } + + [ScriptInvocation] + public int physChangeLinkSpring(UUID hostID, UUID scriptID, int linkNum) + { + return 0; + } + + [ScriptInvocation] + public int physChangeLinkSlider(UUID hostID, UUID scriptID, int linkNum) + { + return 0; + } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index fc639ad..77d8246 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -60,10 +60,7 @@ public class BSPrimLinkable : BSPrimDisplaced Linkset = BSLinkset.Factory(PhysScene, this); - PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() - { - Linkset.Refresh(this); - }); + Linkset.Refresh(this); } public override void Destroy() @@ -82,7 +79,7 @@ public class BSPrimLinkable : BSPrimDisplaced Linkset = parent.Linkset.AddMeToLinkset(this); - DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", + DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); } return; @@ -98,7 +95,7 @@ public class BSPrimLinkable : BSPrimDisplaced Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/); - DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", + DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); return; } @@ -110,7 +107,7 @@ public class BSPrimLinkable : BSPrimDisplaced set { base.Position = value; - PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate() + PhysScene.TaintedObject("BSPrimLinkable.setPosition", delegate() { Linkset.UpdateProperties(UpdatedProperties.Position, this); }); @@ -124,7 +121,7 @@ public class BSPrimLinkable : BSPrimDisplaced set { base.Orientation = value; - PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() + PhysScene.TaintedObject("BSPrimLinkable.setOrientation", delegate() { Linkset.UpdateProperties(UpdatedProperties.Orientation, this); }); @@ -242,7 +239,7 @@ public class BSPrimLinkable : BSPrimDisplaced bool ret = false; if (LinksetType != newType) { - DetailLog("{0},BSPrimLinkset.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); + DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); // Set the implementation type first so the call to BSLinkset.Factory gets the new type. this.LinksetType = newType; @@ -288,12 +285,14 @@ public class BSPrimLinkable : BSPrimDisplaced object ret = null; switch (pFunct) { + // physGetLinksetType(); case BSScene.PhysFunctGetLinksetType: { ret = (object)LinksetType; m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); break; } + // physSetLinksetType(type); case BSScene.PhysFunctSetLinksetType: { if (pParams.Length > 0) @@ -313,6 +312,18 @@ public class BSPrimLinkable : BSPrimDisplaced } break; } + // physChangeLinkFixed(linknum); + // Params: int linkNum, PhysActor linkedPrim + case BSScene.PhysFunctChangeLinkFixed: + { + if (pParams.Length > 1) + { + int linkNum = (int)pParams[0]; + Manager.PhysicsActor linkActor = (Manager.PhysicsActor)pParams[1]; + Linkset.Refresh(this); + } + break; + } default: ret = base.Extension(pFunct, pParams); break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index c92c9b9..571db86 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -875,6 +875,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // Per prim functions. See BSPrim. public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; + public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed"; + public const string PhysFunctChangeLinkHinge = "BulletSim.ChangeLinkHinge"; + public const string PhysFunctChangeLinkSpring = "BulletSim.ChangeLinkSpring"; + public const string PhysFunctChangeLinkSlider = "BulletSim.ChangeLinkSlider"; // ============================================================= public override object Extension(string pFunct, params object[] pParams) -- cgit v1.1 From dff0fb56902f62b070ec6fd05769babfad32ed2e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 7 Aug 2013 11:18:23 -0700 Subject: BulletSim: Linkset.Refresh() calls internal ScheduleRebuild() to recreate the linkset physics at next PostTaint time. Replace the existing calls to ScheduleRebuild to be calls to Refresh(). This allows external routines to make changes to parameters and then cause the linkset to rebuild. --- .../Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 17 ++++++++--------- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 11 ++++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 47ab842..8f12189 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -90,10 +90,9 @@ public sealed class BSLinksetCompound : BSLinkset // its internal properties. public override void Refresh(BSPrimLinkable requestor) { - base.Refresh(requestor); - // Something changed so do the rebuilding thing - // ScheduleRebuild(); + ScheduleRebuild(requestor); + base.Refresh(requestor); } // Schedule a refresh to happen after all the other taint processing. @@ -127,7 +126,7 @@ public sealed class BSLinksetCompound : BSLinkset if (IsRoot(child)) { // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return ret; } @@ -144,7 +143,7 @@ public sealed class BSLinksetCompound : BSLinkset if (IsRoot(child)) { // Schedule a rebuild to verify that the root shape is set to the real shape. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return ret; } @@ -227,7 +226,7 @@ public sealed class BSLinksetCompound : BSLinkset // there will already be a rebuild scheduled. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", updated.LocalID, whichUpdated); - ScheduleRebuild(updated); + Refresh(updated); } } } @@ -245,7 +244,7 @@ public sealed class BSLinksetCompound : BSLinkset DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); - ScheduleRebuild(child); + Refresh(child); return ret; } @@ -263,7 +262,7 @@ public sealed class BSLinksetCompound : BSLinkset DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); // Rebuild the compound shape with the new child shape included - ScheduleRebuild(child); + Refresh(child); } return; } @@ -292,7 +291,7 @@ public sealed class BSLinksetCompound : BSLinkset else { // Rebuild the compound shape with the child removed - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } } return; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index f3b70c3..db323c2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -158,6 +158,7 @@ public sealed class BSLinksetConstraints : BSLinkset // refresh will happen once after all the other taints are applied. public override void Refresh(BSPrimLinkable requestor) { + ScheduleRebuild(requestor); base.Refresh(requestor); } @@ -194,7 +195,7 @@ public sealed class BSLinksetConstraints : BSLinkset if (IsRoot(child)) { // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return ret; } @@ -213,7 +214,7 @@ public sealed class BSLinksetConstraints : BSLinkset if (IsRoot(child)) { // Schedule a rebuild to verify that the root shape is set to the real shape. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return ret; } @@ -241,7 +242,7 @@ public sealed class BSLinksetConstraints : BSLinkset // Just undo all the constraints for this linkset. Rebuild at the end of the step. ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); // Cause the constraints, et al to be rebuilt before the next simulation step. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return ret; } @@ -259,7 +260,7 @@ public sealed class BSLinksetConstraints : BSLinkset DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); // Cause constraints and assorted properties to be recomputed before the next simulation step. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } return; } @@ -283,7 +284,7 @@ public sealed class BSLinksetConstraints : BSLinkset PhysicallyUnlinkAChildFromRoot(rootx, childx); }); // See that the linkset parameters are recomputed at the end of the taint time. - ScheduleRebuild(LinksetRoot); + Refresh(LinksetRoot); } else { -- cgit v1.1 From 6aee08ac3c48b55ebd8e945c8b11f17dc1ab3151 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 8 Aug 2013 08:36:36 -0700 Subject: BulletSim: add physChangeLinkSpring to change linkset link to be a spring constraint. Add implementation to create spring constraint. Send up property updates for linkset children at the end of flexible linkset links. The simulator probably doesn't do the right thing yet. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 73 ++++++++++++++- .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 24 +++++ .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 102 ++++++++++++++++++++- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 9 +- 5 files changed, 198 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index decb61a..278e9e7 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -291,6 +291,10 @@ public class ExtendedPhysics : INonSharedRegionModule return ret; } + // physChangeLinkFixed(integer linkNum) + // Change the link between the root and the linkNum into a fixed, static physical connection. + // This needs to change 'linkNum' into the physical object because lower level code has + // no access to the link numbers. [ScriptInvocation] public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum) { @@ -353,13 +357,76 @@ public class ExtendedPhysics : INonSharedRegionModule [ScriptInvocation] public int physChangeLinkHinge(UUID hostID, UUID scriptID, int linkNum) { - return 0; + return -1; } [ScriptInvocation] - public int physChangeLinkSpring(UUID hostID, UUID scriptID, int linkNum) + public int physChangeLinkSpring(UUID hostID, UUID scriptID, int linkNum, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + Vector3 linearLimitLow, Vector3 linearLimitHigh, + Vector3 angularLimitLow, Vector3 angularLimitHigh + ) { - return 0; + int ret = -1; + if (!Enabled) return ret; + + // The part that is requesting the change. + SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); + + if (requestingPart != null) + { + // The type is is always on the root of a linkset. + SceneObjectGroup containingGroup = requestingPart.ParentGroup; + SceneObjectPart rootPart = containingGroup.RootPart; + + if (rootPart != null) + { + Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) + { + SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum); + if (linkPart != null) + { + Physics.Manager.PhysicsActor linkPhysActor = linkPart.PhysActor; + if (linkPhysActor != null) + { + ret = (int)rootPhysActor.Extension(PhysFunctChangeLinkSpring, linkNum, linkPhysActor, + frameInAloc, frameInArot, + frameInBloc, frameInBrot, + linearLimitLow, linearLimitHigh, + angularLimitLow, angularLimitHigh + ); + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); + } + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); + } + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); + } + } + else + { + m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + } + return ret; } [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index b241059..9d8838b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -43,7 +43,9 @@ public enum ConstraintType : int SLIDER_CONSTRAINT_TYPE, CONTACT_CONSTRAINT_TYPE, D6_SPRING_CONSTRAINT_TYPE, - MAX_CONSTRAINT_TYPE + MAX_CONSTRAINT_TYPE, // last type defined by Bullet + // + FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving } // =============================================================================== diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index d4b1c1e..2058e3a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -79,6 +79,8 @@ public abstract class BSLinkset } public virtual void ResetLink() { } public virtual void SetLinkParameters(BSConstraint constrain) { } + // Returns 'true' if physical property updates from the child should be reported to the simulator + public virtual bool ShouldUpdateChildProperties() { return false; } } public LinksetImplementation LinksetImpl { get; protected set; } @@ -224,6 +226,21 @@ public abstract class BSLinkset return ret; } + // Check the type of the link and return 'true' if the link is flexible and the + // updates from the child should be sent to the simulator so things change. + public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) + { + bool ret = false; + + BSLinkInfo linkInfo; + if (m_children.TryGetValue(child, out linkInfo)) + { + ret = linkInfo.ShouldUpdateChildProperties(); + } + + return ret; + } + // Called after a simulation step to post a collision with this object. // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have // anything to add for the collision and it should be passed through normal processing. @@ -432,6 +449,13 @@ public abstract class BSLinkset return com; } + #region Extension + public virtual object Extension(string pFunct, params object[] pParams) + { + return null; + } + #endregion // Extension + // Invoke the detailed logger and output something if it's enabled. protected void DetailLog(string msg, params Object[] args) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index db323c2..17fec9d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -60,8 +60,6 @@ public sealed class BSLinksetConstraints : BSLinkset public float springDamping; public float springStiffness; - - public BSLinkInfoConstraint(BSPrimLinkable pMember) : base(pMember) { @@ -72,7 +70,8 @@ public sealed class BSLinksetConstraints : BSLinkset // Set all the parameters for this constraint to a fixed, non-movable constraint. public override void ResetLink() { - constraintType = ConstraintType.D6_CONSTRAINT_TYPE; + // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; + constraintType = ConstraintType.FIXED_CONSTRAINT_TYPE; linearLimitLow = OMV.Vector3.Zero; linearLimitHigh = OMV.Vector3.Zero; angularLimitLow = OMV.Vector3.Zero; @@ -97,6 +96,7 @@ public sealed class BSLinksetConstraints : BSLinkset { switch (constraintType) { + case ConstraintType.FIXED_CONSTRAINT_TYPE: case ConstraintType.D6_CONSTRAINT_TYPE: BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; if (constrain6dof != null) @@ -145,6 +145,20 @@ public sealed class BSLinksetConstraints : BSLinkset break; } } + + // Return 'true' if the property updates from the physics engine should be reported + // to the simulator. + // If the constraint is fixed, we don't need to report as the simulator and viewer will + // report the right things. + public override bool ShouldUpdateChildProperties() + { + bool ret = true; + + if (constraintType == ConstraintType.FIXED_CONSTRAINT_TYPE) + ret = false; + + return ret; + } } public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) @@ -316,6 +330,7 @@ public sealed class BSLinksetConstraints : BSLinkset switch (linkInfo.constraintType) { + case ConstraintType.FIXED_CONSTRAINT_TYPE: case ConstraintType.D6_CONSTRAINT_TYPE: // Relative position normalized to the root prim // Essentually a vector pointing from center of rootPrim to center of li.member @@ -466,5 +481,86 @@ public sealed class BSLinksetConstraints : BSLinkset Rebuilding = false; } } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + object ret = null; + switch (pFunct) + { + // pParams = (int linkNUm, PhysActor linkChild) + case BSScene.PhysFunctChangeLinkFixed: + if (pParams.Length > 1) + { + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + if (child != null) + { + m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate() + { + // Pick up all the constraints currently created. + RemoveDependencies(child); + + BSLinkInfo linkInfo = null; + if (m_children.TryGetValue(child, out linkInfo)) + { + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + // Setting to fixed is easy. The reset state is the fixed link configuration. + linkInfoC.ResetLink(); + ret = (object)true; + } + } + // Cause the whole linkset to be rebuilt in post-taint time. + Refresh(child); + }); + } + } + break; + case BSScene.PhysFunctChangeLinkSpring: + if (pParams.Length > 11) + { + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + if (child != null) + { + m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate() + { + // Pick up all the constraints currently created. + RemoveDependencies(child); + + BSLinkInfo linkInfo = null; + if (m_children.TryGetValue(child, out linkInfo)) + { + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + // Start with a reset link definition + linkInfoC.ResetLink(); + linkInfoC.constraintType = ConstraintType.D6_SPRING_CONSTRAINT_TYPE; + linkInfoC.frameInAloc = (OMV.Vector3)pParams[2]; + linkInfoC.frameInArot = (OMV.Quaternion)pParams[3]; + linkInfoC.frameInBloc = (OMV.Vector3)pParams[4]; + linkInfoC.frameInBrot = (OMV.Quaternion)pParams[5]; + linkInfoC.linearLimitLow = (OMV.Vector3)pParams[6]; + linkInfoC.linearLimitHigh = (OMV.Vector3)pParams[7]; + linkInfoC.angularLimitLow = (OMV.Vector3)pParams[8]; + linkInfoC.angularLimitHigh = (OMV.Vector3)pParams[9]; + ret = (object)true; + } + } + // Cause the whole linkset to be rebuilt in post-taint time. + Refresh(child); + }); + } + } + break; + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + #endregion // Extension + } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 77d8246..4c384a6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -179,7 +179,7 @@ public class BSPrimLinkable : BSPrimDisplaced // Do any filtering/modification needed for linksets. public override void UpdateProperties(EntityProperties entprop) { - if (Linkset.IsRoot(this)) + if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this)) { // Properties are only updated for the roots of a linkset. // TODO: this will have to change when linksets are articulated. @@ -316,12 +316,7 @@ public class BSPrimLinkable : BSPrimDisplaced // Params: int linkNum, PhysActor linkedPrim case BSScene.PhysFunctChangeLinkFixed: { - if (pParams.Length > 1) - { - int linkNum = (int)pParams[0]; - Manager.PhysicsActor linkActor = (Manager.PhysicsActor)pParams[1]; - Linkset.Refresh(this); - } + Linkset.Extension(pFunct, pParams); break; } default: -- cgit v1.1 From b2a1348adc2bd27d3266a7d7c7594a2aa8272100 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 8 Aug 2013 16:37:37 -0700 Subject: BulletSim: update C++ HACD parameters to values that handle enclosed hollow spaces better. This shouldn't affect many since this HACD routine is off by default. --- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index fcb892a..737dda1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -683,21 +683,21 @@ public static class BSParam 0f ), new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", - 100f ), + 200f ), new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", - 2f ), + 10f ), new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", - 0.1f ), + 20f ), new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", - 0f ), + 0.1f ), new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", - 100f ), + 10f ), new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", - false ), + true ), new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", - false ), + true ), new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", - false ), + true ), new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", false ), -- cgit v1.1 From 455d36c4c70a55c5d48dc1410b8729929fafedf6 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 9 Aug 2013 10:59:10 -0700 Subject: BulletSim: add physChangeLinkParams to set individual parameters on link constraints. Not fully functional. Remove double definition of ExtendedPhysics parameters by having BulletSim reference the optional module (addition to prebuild.xml and usings). --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 265 +++++++++++++-------- .../Physics/BulletSPlugin/BSConstraintConeTwist.cs | 54 +++++ .../Physics/BulletSPlugin/BSConstraintSlider.cs | 55 +++++ .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 85 +++---- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 18 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 14 -- prebuild.xml | 1 + 7 files changed, 325 insertions(+), 167 deletions(-) create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 278e9e7..baf5a5b 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -36,6 +36,7 @@ using OpenSim.Region.CoreModules; using OpenSim.Region.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Physics.Manager; using Mono.Addins; using Nini.Config; @@ -62,9 +63,8 @@ public class ExtendedPhysics : INonSharedRegionModule public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed"; - public const string PhysFunctChangeLinkHinge = "BulletSim.ChangeLinkHinge"; - public const string PhysFunctChangeLinkSpring = "BulletSim.ChangeLinkSpring"; - public const string PhysFunctChangeLinkSlider = "BulletSim.ChangeLinkSlider"; + public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType"; + public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams"; // ============================================================= @@ -200,7 +200,7 @@ public class ExtendedPhysics : INonSharedRegionModule if (rootPart != null) { - Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; + PhysicsActor rootPhysActor = rootPart.PhysActor; if (rootPhysActor != null) { if (rootPhysActor.IsPhysical) @@ -219,7 +219,7 @@ public class ExtendedPhysics : INonSharedRegionModule containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition); containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation); - ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType)); Thread.Sleep(150); // longer than one heartbeat tick containingGroup.ScriptSetPhysicsStatus(true); @@ -228,7 +228,7 @@ public class ExtendedPhysics : INonSharedRegionModule { // Non-physical linksets don't have a physical instantiation so there is no state to // worry about being updated. - ret = (int)rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType)); } } else @@ -267,10 +267,10 @@ public class ExtendedPhysics : INonSharedRegionModule if (rootPart != null) { - Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; + PhysicsActor rootPhysActor = rootPart.PhysActor; if (rootPhysActor != null) { - ret = (int)rootPhysActor.Extension(PhysFunctGetLinksetType); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType)); } else { @@ -291,148 +291,225 @@ public class ExtendedPhysics : INonSharedRegionModule return ret; } + [ScriptConstant] + public static int PHYS_LINK_TYPE_FIXED = 1234; + [ScriptConstant] + public static int PHYS_LINK_TYPE_HINGE = 4; + [ScriptConstant] + public static int PHYS_LINK_TYPE_SPRING = 9; + [ScriptConstant] + public static int PHYS_LINK_TYPE_6DOF = 6; + [ScriptConstant] + public static int PHYS_LINK_TYPE_SLIDER = 7; + + // physChangeLinkType(integer linkNum, integer typeCode) + [ScriptInvocation] + public int physChangeLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, childPhysActor, typeCode)); + } + + return ret; + } + // physChangeLinkFixed(integer linkNum) // Change the link between the root and the linkNum into a fixed, static physical connection. - // This needs to change 'linkNum' into the physical object because lower level code has - // no access to the link numbers. [ScriptInvocation] public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum) { int ret = -1; if (!Enabled) return ret; - // The part that is requesting the change. - SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, childPhysActor, PHYS_LINK_TYPE_FIXED)); + } + + return ret; + } + + // Code for specifying params. + // The choice if 14400 is arbitrary and only serves to catch parameter code misuse. + public static int PHYS_PARAM_MIN = 14401; + [ScriptConstant] + public static int PHYS_PARAM_FRAMEINA_LOC = 14401; + [ScriptConstant] + public static int PHYS_PARAM_FRAMEINA_ROT = 14402; + [ScriptConstant] + public static int PHYS_PARAM_FRAMEINB_LOC = 14403; + [ScriptConstant] + public static int PHYS_PARAM_FRAMEINB_ROT = 14404; + [ScriptConstant] + public static int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405; + [ScriptConstant] + public static int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406; + [ScriptConstant] + public static int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407; + [ScriptConstant] + public static int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408; + [ScriptConstant] + public static int PHYS_PARAM_USE_FRAME_OFFSET = 14409; + [ScriptConstant] + public static int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410; + [ScriptConstant] + public static int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411; + [ScriptConstant] + public static int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412; + [ScriptConstant] + public static int PHYS_PARAM_CFM = 14413; + [ScriptConstant] + public static int PHYS_PARAM_ERP = 14414; + [ScriptConstant] + public static int PHYS_PARAM_SOLVER_ITERATIONS = 14415; + [ScriptConstant] + public static int PHYS_PARAM_SPRING_DAMPING = 14416; + [ScriptConstant] + public static int PHYS_PARAM_SPRING_STIFFNESS = 14417; + public static int PHYS_PARAM_MAX = 14417; + // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) + [ScriptInvocation] + public int physChangeLinkParams(UUID hostID, UUID scriptID, int linkNum, object[] parms) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, childPhysActor, parms)); + } + + return ret; + } + + private bool GetRootPhysActor(UUID hostID, out PhysicsActor rootPhysActor) + { + SceneObjectGroup containingGroup; + SceneObjectPart rootPart; + return GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor); + } + + private bool GetRootPhysActor(UUID hostID, out SceneObjectGroup containingGroup, out SceneObjectPart rootPart, out PhysicsActor rootPhysActor) + { + bool ret = false; + rootPhysActor = null; + containingGroup = null; + rootPart = null; + + SceneObjectPart requestingPart; + + requestingPart = BaseScene.GetSceneObjectPart(hostID); if (requestingPart != null) { // The type is is always on the root of a linkset. - SceneObjectGroup containingGroup = requestingPart.ParentGroup; - SceneObjectPart rootPart = containingGroup.RootPart; - - if (rootPart != null) + containingGroup = requestingPart.ParentGroup; + if (containingGroup != null && !containingGroup.IsDeleted) { - Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; - if (rootPhysActor != null) + rootPart = containingGroup.RootPart; + if (rootPart != null) { - SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum); - if (linkPart != null) + rootPhysActor = rootPart.PhysActor; + if (rootPhysActor != null) { - Physics.Manager.PhysicsActor linkPhysActor = linkPart.PhysActor; - if (linkPhysActor != null) - { - ret = (int)rootPhysActor.Extension(PhysFunctChangeLinkFixed, linkNum, linkPhysActor); - } - else - { - m_log.WarnFormat("{0} physChangeLinkFixed: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}", - LogHeader, rootPart.Name, hostID, linkNum); - } + ret = true; } else { - m_log.WarnFormat("{0} physChangeLinkFixed: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}", - LogHeader, rootPart.Name, hostID, linkNum); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); } } else { - m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not have a physics actor. rootName={1}, hostID={2}", - LogHeader, rootPart.Name, hostID); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not exist. RequestingPartName={1}, hostID={2}", + LogHeader, requestingPart.Name, hostID); } } else { - m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not exist. RequestingPartName={1}, hostID={2}", - LogHeader, requestingPart.Name, hostID); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Containing group missing or deleted. hostID={1}", LogHeader, hostID); } } else { - m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: cannot find script object in scene. hostID={1}", LogHeader, hostID); } + return ret; } - [ScriptInvocation] - public int physChangeLinkHinge(UUID hostID, UUID scriptID, int linkNum) + // Find the root and child PhysActors based on the linkNum. + // Return 'true' if both are found and returned. + private bool GetRootAndChildPhysActors(UUID hostID, int linkNum, out PhysicsActor rootPhysActor, out PhysicsActor childPhysActor) { - return -1; - } + bool ret = false; + rootPhysActor = null; + childPhysActor = null; - [ScriptInvocation] - public int physChangeLinkSpring(UUID hostID, UUID scriptID, int linkNum, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - Vector3 linearLimitLow, Vector3 linearLimitHigh, - Vector3 angularLimitLow, Vector3 angularLimitHigh - ) - { - int ret = -1; - if (!Enabled) return ret; + SceneObjectGroup containingGroup; + SceneObjectPart rootPart; - // The part that is requesting the change. - SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID); - - if (requestingPart != null) + if (GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor)) { - // The type is is always on the root of a linkset. - SceneObjectGroup containingGroup = requestingPart.ParentGroup; - SceneObjectPart rootPart = containingGroup.RootPart; - - if (rootPart != null) + SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum); + if (linkPart != null) { - Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor; - if (rootPhysActor != null) + childPhysActor = linkPart.PhysActor; + if (childPhysActor != null) { - SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum); - if (linkPart != null) - { - Physics.Manager.PhysicsActor linkPhysActor = linkPart.PhysActor; - if (linkPhysActor != null) - { - ret = (int)rootPhysActor.Extension(PhysFunctChangeLinkSpring, linkNum, linkPhysActor, - frameInAloc, frameInArot, - frameInBloc, frameInBrot, - linearLimitLow, linearLimitHigh, - angularLimitLow, angularLimitHigh - ); - } - else - { - m_log.WarnFormat("{0} physChangeLinkFixed: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}", - LogHeader, rootPart.Name, hostID, linkNum); - } - } - else - { - m_log.WarnFormat("{0} physChangeLinkFixed: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}", - LogHeader, rootPart.Name, hostID, linkNum); - } + ret = true; } else { - m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not have a physics actor. rootName={1}, hostID={2}", - LogHeader, rootPart.Name, hostID); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); } } else { - m_log.WarnFormat("{0} physChangeLinkFixed: Root part does not exist. RequestingPartName={1}, hostID={2}", - LogHeader, requestingPart.Name, hostID); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}", + LogHeader, rootPart.Name, hostID, linkNum); } } else { - m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID); + m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}", + LogHeader, rootPart.Name, hostID); } + return ret; } - [ScriptInvocation] - public int physChangeLinkSlider(UUID hostID, UUID scriptID, int linkNum) + // Extension() returns an object. Convert that object into the integer error we expect to return. + private int MakeIntError(object extensionRet) { - return 0; + int ret = -1; + if (extensionRet != null) + { + try + { + ret = (int)extensionRet; + } + catch + { + ret = -1; + } + } + return ret; } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs new file mode 100755 index 0000000..7a76a9a --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs @@ -0,0 +1,54 @@ +/* + * 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 copyrightD + * 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.Text; +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ + +public sealed class BSConstraintConeTwist : BSConstraint +{ + public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } } + + public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2, + frameInAloc, frameInArot, frameInBloc, frameInBrot, + disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } +} + +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs new file mode 100755 index 0000000..37cfa07 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs @@ -0,0 +1,55 @@ +/* + * 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 copyrightD + * 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.Text; +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ + +public sealed class BSConstraintSlider : BSConstraint +{ + public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } } + + public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2, + frameInAloc, frameInArot, frameInBloc, frameInBrot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } + +} + +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 17fec9d..c09dd42 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -28,6 +28,8 @@ using System; using System.Collections.Generic; using System.Text; +using OpenSim.Region.OptionalModules.Scripting; + using OMV = OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin @@ -489,71 +491,46 @@ public sealed class BSLinksetConstraints : BSLinkset switch (pFunct) { // pParams = (int linkNUm, PhysActor linkChild) - case BSScene.PhysFunctChangeLinkFixed: + case ExtendedPhysics.PhysFunctChangeLinkType: if (pParams.Length > 1) { - BSPrimLinkable child = pParams[1] as BSPrimLinkable; - if (child != null) + int requestedType = (int)pParams[1]; + if (requestedType == (int)ConstraintType.FIXED_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) { - m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate() + BSPrimLinkable child = pParams[0] as BSPrimLinkable; + if (child != null) { - // Pick up all the constraints currently created. - RemoveDependencies(child); - - BSLinkInfo linkInfo = null; - if (m_children.TryGetValue(child, out linkInfo)) + m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate() { - BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; - if (linkInfoC != null) - { - // Setting to fixed is easy. The reset state is the fixed link configuration. - linkInfoC.ResetLink(); - ret = (object)true; - } - } - // Cause the whole linkset to be rebuilt in post-taint time. - Refresh(child); - }); - } - } - break; - case BSScene.PhysFunctChangeLinkSpring: - if (pParams.Length > 11) - { - BSPrimLinkable child = pParams[1] as BSPrimLinkable; - if (child != null) - { - m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate() - { - // Pick up all the constraints currently created. - RemoveDependencies(child); + // Pick up all the constraints currently created. + RemoveDependencies(child); - BSLinkInfo linkInfo = null; - if (m_children.TryGetValue(child, out linkInfo)) - { - BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; - if (linkInfoC != null) + BSLinkInfo linkInfo = null; + if (m_children.TryGetValue(child, out linkInfo)) { - // Start with a reset link definition - linkInfoC.ResetLink(); - linkInfoC.constraintType = ConstraintType.D6_SPRING_CONSTRAINT_TYPE; - linkInfoC.frameInAloc = (OMV.Vector3)pParams[2]; - linkInfoC.frameInArot = (OMV.Quaternion)pParams[3]; - linkInfoC.frameInBloc = (OMV.Vector3)pParams[4]; - linkInfoC.frameInBrot = (OMV.Quaternion)pParams[5]; - linkInfoC.linearLimitLow = (OMV.Vector3)pParams[6]; - linkInfoC.linearLimitHigh = (OMV.Vector3)pParams[7]; - linkInfoC.angularLimitLow = (OMV.Vector3)pParams[8]; - linkInfoC.angularLimitHigh = (OMV.Vector3)pParams[9]; - ret = (object)true; + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + // Setting to fixed is easy. The reset state is the fixed link configuration. + linkInfoC.ResetLink(); + linkInfoC.constraintType = (ConstraintType)requestedType; + ret = (object)true; + } } - } - // Cause the whole linkset to be rebuilt in post-taint time. - Refresh(child); - }); + // Cause the whole linkset to be rebuilt in post-taint time. + Refresh(child); + }); + } } } break; + case ExtendedPhysics.PhysFunctChangeLinkParams: + break; default: ret = base.Extension(pFunct, pParams); break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 4c384a6..6136257 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -30,6 +30,7 @@ using System.Linq; using System.Text; using OpenSim.Framework; +using OpenSim.Region.OptionalModules.Scripting; using OMV = OpenMetaverse; @@ -286,14 +287,14 @@ public class BSPrimLinkable : BSPrimDisplaced switch (pFunct) { // physGetLinksetType(); - case BSScene.PhysFunctGetLinksetType: + case ExtendedPhysics.PhysFunctGetLinksetType: { ret = (object)LinksetType; m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); break; } // physSetLinksetType(type); - case BSScene.PhysFunctSetLinksetType: + case ExtendedPhysics.PhysFunctSetLinksetType: { if (pParams.Length > 0) { @@ -312,9 +313,16 @@ public class BSPrimLinkable : BSPrimDisplaced } break; } - // physChangeLinkFixed(linknum); - // Params: int linkNum, PhysActor linkedPrim - case BSScene.PhysFunctChangeLinkFixed: + // physChangeLinkType(linknum, typeCode); + // Params: PhysActor linkedPrim, int typeCode + case ExtendedPhysics.PhysFunctChangeLinkType: + { + Linkset.Extension(pFunct, pParams); + break; + } + // physChangeLinkParams(linknum, [code, value, code, value, ...]); + // Params: PhysActor linkedPrim, object[] params + case ExtendedPhysics.PhysFunctChangeLinkParams: { Linkset.Extension(pFunct, pParams); break; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 571db86..7440468 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -867,20 +867,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public override bool IsThreaded { get { return false; } } #region Extensions - // ============================================================= - // Per scene functions. See below. - - // Per avatar functions. See BSCharacter. - - // Per prim functions. See BSPrim. - public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; - public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; - public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed"; - public const string PhysFunctChangeLinkHinge = "BulletSim.ChangeLinkHinge"; - public const string PhysFunctChangeLinkSpring = "BulletSim.ChangeLinkSpring"; - public const string PhysFunctChangeLinkSlider = "BulletSim.ChangeLinkSlider"; - // ============================================================= - public override object Extension(string pFunct, params object[] pParams) { return base.Extension(pFunct, pParams); diff --git a/prebuild.xml b/prebuild.xml index af8f686..585f96d 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1795,6 +1795,7 @@ + -- cgit v1.1 From f6fdfd16f55c3e1bd55775f1f21e0ac9e44ff2ee Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 9 Aug 2013 17:01:35 -0700 Subject: BulletSim: change ExtendedPhysics constants to 'const' so they can be used as case variables in switch statements. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 56 +++++++++++----------- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 22 +++++++++ 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index baf5a5b..e0f16d6 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -160,7 +160,7 @@ public class ExtendedPhysics : INonSharedRegionModule } [ScriptConstant] - public static int PHYS_CENTER_OF_MASS = 1 << 0; + public const int PHYS_CENTER_OF_MASS = 1 << 0; [ScriptInvocation] public string physGetEngineType(UUID hostID, UUID scriptID) @@ -176,11 +176,11 @@ public class ExtendedPhysics : INonSharedRegionModule } [ScriptConstant] - public static int PHYS_LINKSET_TYPE_CONSTRAINT = 0; + public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0; [ScriptConstant] - public static int PHYS_LINKSET_TYPE_COMPOUND = 1; + public const int PHYS_LINKSET_TYPE_COMPOUND = 1; [ScriptConstant] - public static int PHYS_LINKSET_TYPE_MANUAL = 2; + public const int PHYS_LINKSET_TYPE_MANUAL = 2; [ScriptInvocation] public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) @@ -292,15 +292,15 @@ public class ExtendedPhysics : INonSharedRegionModule } [ScriptConstant] - public static int PHYS_LINK_TYPE_FIXED = 1234; + public const int PHYS_LINK_TYPE_FIXED = 1234; [ScriptConstant] - public static int PHYS_LINK_TYPE_HINGE = 4; + public const int PHYS_LINK_TYPE_HINGE = 4; [ScriptConstant] - public static int PHYS_LINK_TYPE_SPRING = 9; + public const int PHYS_LINK_TYPE_SPRING = 9; [ScriptConstant] - public static int PHYS_LINK_TYPE_6DOF = 6; + public const int PHYS_LINK_TYPE_6DOF = 6; [ScriptConstant] - public static int PHYS_LINK_TYPE_SLIDER = 7; + public const int PHYS_LINK_TYPE_SLIDER = 7; // physChangeLinkType(integer linkNum, integer typeCode) [ScriptInvocation] @@ -341,42 +341,42 @@ public class ExtendedPhysics : INonSharedRegionModule // Code for specifying params. // The choice if 14400 is arbitrary and only serves to catch parameter code misuse. - public static int PHYS_PARAM_MIN = 14401; + public const int PHYS_PARAM_MIN = 14401; [ScriptConstant] - public static int PHYS_PARAM_FRAMEINA_LOC = 14401; + public const int PHYS_PARAM_FRAMEINA_LOC = 14401; [ScriptConstant] - public static int PHYS_PARAM_FRAMEINA_ROT = 14402; + public const int PHYS_PARAM_FRAMEINA_ROT = 14402; [ScriptConstant] - public static int PHYS_PARAM_FRAMEINB_LOC = 14403; + public const int PHYS_PARAM_FRAMEINB_LOC = 14403; [ScriptConstant] - public static int PHYS_PARAM_FRAMEINB_ROT = 14404; + public const int PHYS_PARAM_FRAMEINB_ROT = 14404; [ScriptConstant] - public static int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405; + public const int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405; [ScriptConstant] - public static int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406; + public const int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406; [ScriptConstant] - public static int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407; + public const int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407; [ScriptConstant] - public static int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408; + public const int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408; [ScriptConstant] - public static int PHYS_PARAM_USE_FRAME_OFFSET = 14409; + public const int PHYS_PARAM_USE_FRAME_OFFSET = 14409; [ScriptConstant] - public static int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410; + public const int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410; [ScriptConstant] - public static int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411; + public const int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411; [ScriptConstant] - public static int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412; + public const int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412; [ScriptConstant] - public static int PHYS_PARAM_CFM = 14413; + public const int PHYS_PARAM_CFM = 14413; [ScriptConstant] - public static int PHYS_PARAM_ERP = 14414; + public const int PHYS_PARAM_ERP = 14414; [ScriptConstant] - public static int PHYS_PARAM_SOLVER_ITERATIONS = 14415; + public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415; [ScriptConstant] - public static int PHYS_PARAM_SPRING_DAMPING = 14416; + public const int PHYS_PARAM_SPRING_DAMPING = 14416; [ScriptConstant] - public static int PHYS_PARAM_SPRING_STIFFNESS = 14417; - public static int PHYS_PARAM_MAX = 14417; + public const int PHYS_PARAM_SPRING_STIFFNESS = 14417; + public const int PHYS_PARAM_MAX = 14417; // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index c09dd42..b72afc0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -530,6 +530,28 @@ public sealed class BSLinksetConstraints : BSLinkset } break; case ExtendedPhysics.PhysFunctChangeLinkParams: + int setParam = 2; + switch (setParam) + { + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: + case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: + case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: + case ExtendedPhysics.PHYS_PARAM_CFM: + case ExtendedPhysics.PHYS_PARAM_ERP: + case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: + case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: + case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: + break; + } break; default: ret = base.Extension(pFunct, pParams); -- cgit v1.1 From 8755aeb348ed96ef78986e044ec83e7836a6c65a Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 16 Aug 2013 13:42:31 -0700 Subject: BulletSim: update DLLs and SOs with Bullet svn version 2644 (no major fixes) and with BulletSim implementing more of the constraint types and parameter settings. --- bin/lib32/BulletSim.dll | Bin 982528 -> 1086976 bytes bin/lib32/libBulletSim.so | Bin 2271724 -> 2317618 bytes bin/lib64/BulletSim.dll | Bin 1222656 -> 1229824 bytes bin/lib64/libBulletSim.so | Bin 2454796 -> 2491923 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index bc0e222..7987434 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index e09dd27..114a597 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 5fc09f6..b69fcf3 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 925269d..e4d2581 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From e1120cb74db9092cc0f9a7fc245d2f2ed6160b7a Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 16 Aug 2013 13:44:31 -0700 Subject: BulletSim: add extended physics function physGetLinkType(linkNum). Add implementation of physChangeLinkParams() in BSLinksetConstraint. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 19 +++ OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 11 ++ .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 145 ++++++++++++++++++--- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 11 +- 4 files changed, 163 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index e0f16d6..d035f7b 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -64,6 +64,7 @@ public class ExtendedPhysics : INonSharedRegionModule public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed"; public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType"; + public const string PhysFunctGetLinkType = "BulletSim.GetLinkType"; public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams"; // ============================================================= @@ -320,6 +321,24 @@ public class ExtendedPhysics : INonSharedRegionModule return ret; } + // physGetLinkType(integer linkNum) + [ScriptInvocation] + public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode) + { + int ret = -1; + if (!Enabled) return ret; + + PhysicsActor rootPhysActor; + PhysicsActor childPhysActor; + + if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) + { + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, childPhysActor)); + } + + return ret; + } + // physChangeLinkFixed(integer linkNum) // Change the link between the root and the linkNum into a fixed, static physical connection. [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 2058e3a..77f69a5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -209,6 +209,17 @@ public abstract class BSLinkset return ret; } + public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) + { + bool ret = false; + BSLinkInfo found = null; + lock (m_linksetActivityLock) + { + ret = m_children.TryGetValue(child, out found); + } + foundInfo = found; + return ret; + } // Perform an action on each member of the linkset including root prim. // Depends on the action on whether this should be done at taint time. public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index b72afc0..92df84e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -168,6 +168,8 @@ public sealed class BSLinksetConstraints : BSLinkset LinksetImpl = LinksetImplementation.Constraint; } + private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; + // When physical properties are changed the linkset needs to recalculate // its internal properties. // This is queued in the 'post taint' queue so the @@ -511,7 +513,7 @@ public sealed class BSLinksetConstraints : BSLinkset RemoveDependencies(child); BSLinkInfo linkInfo = null; - if (m_children.TryGetValue(child, out linkInfo)) + if (TryGetLinkInfo(child, out linkInfo)) { BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; if (linkInfoC != null) @@ -529,28 +531,129 @@ public sealed class BSLinksetConstraints : BSLinkset } } break; + case ExtendedPhysics.PhysFunctGetLinkType: + if (pParams.Length > 0) + { + BSPrimLinkable child = pParams[0] as BSPrimLinkable; + if (child != null) + { + BSLinkInfo linkInfo = null; + if (TryGetLinkInfo(child, out linkInfo)) + { + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + ret = (object)(int)linkInfoC.constraintType; + } + } + } + } + break; case ExtendedPhysics.PhysFunctChangeLinkParams: - int setParam = 2; - switch (setParam) + // There should be two parameters: the childActor and a list of parameters to set + try + { + if (pParams.Length > 1) + { + BSPrimLinkable child = pParams[0] as BSPrimLinkable; + object[] setOps = (object[])pParams[1]; + BSLinkInfo baseLinkInfo = null; + if (TryGetLinkInfo(child, out baseLinkInfo)) + { + BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; + if (linkInfo != null) + { + float valueFloat; + bool valueBool; + OMV.Vector3 valueVector; + OMV.Quaternion valueQuaternion; + + int opIndex = 0; + while (opIndex < setOps.Length) + { + int thisOp = (int)setOps[opIndex]; + switch (thisOp) + { + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: + valueVector = (OMV.Vector3)setOps[opIndex + 1]; + linkInfo.frameInAloc = valueVector; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: + valueQuaternion = (OMV.Quaternion)setOps[opIndex + 1]; + linkInfo.frameInArot = valueQuaternion; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: + valueVector = (OMV.Vector3)setOps[opIndex + 1]; + linkInfo.frameInBloc = valueVector; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: + valueQuaternion = (OMV.Quaternion)setOps[opIndex + 1]; + linkInfo.frameInBrot = valueQuaternion; + break; + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: + valueVector = (OMV.Vector3)setOps[opIndex + 1]; + linkInfo.linearLimitLow = valueVector; + break; + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: + valueVector = (OMV.Vector3)setOps[opIndex + 1]; + linkInfo.linearLimitHigh = valueVector; + break; + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: + valueVector = (OMV.Vector3)setOps[opIndex + 1]; + linkInfo.angularLimitLow = valueVector; + break; + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: + valueVector = (OMV.Vector3)setOps[opIndex + 1]; + linkInfo.angularLimitHigh = valueVector; + break; + case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: + valueBool = (bool)setOps[opIndex + 1]; + linkInfo.useFrameOffset = valueBool; + break; + case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: + valueBool = (bool)setOps[opIndex + 1]; + linkInfo.enableTransMotor = valueBool; + break; + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.transMotorMaxVel = valueFloat; + break; + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.transMotorMaxForce = valueFloat; + break; + case ExtendedPhysics.PHYS_PARAM_CFM: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.cfm = valueFloat; + break; + case ExtendedPhysics.PHYS_PARAM_ERP: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.erp = valueFloat; + break; + case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.solverIterations = valueFloat; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.springDamping = valueFloat; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: + valueFloat = (float)setOps[opIndex + 1]; + linkInfo.springStiffness = valueFloat; + break; + default: + break; + } + } + } + } + } + } + catch (Exception e) { - case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: - case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: - case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: - case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: - case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: - case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: - case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: - case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: - case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: - case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: - case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: - case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: - case ExtendedPhysics.PHYS_PARAM_CFM: - case ExtendedPhysics.PHYS_PARAM_ERP: - case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: - case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: - case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: - break; + // There are many ways to mess up the parameters. If not just right don't fail without some error. + m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); } break; default: diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 6136257..28ea8c0 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -317,14 +317,21 @@ public class BSPrimLinkable : BSPrimDisplaced // Params: PhysActor linkedPrim, int typeCode case ExtendedPhysics.PhysFunctChangeLinkType: { - Linkset.Extension(pFunct, pParams); + ret = Linkset.Extension(pFunct, pParams); + break; + } + // physGetLinkType(linknum); + // Params: PhysActor linkedPrim + case ExtendedPhysics.PhysFunctGetLinkType: + { + ret = Linkset.Extension(pFunct, pParams); break; } // physChangeLinkParams(linknum, [code, value, code, value, ...]); // Params: PhysActor linkedPrim, object[] params case ExtendedPhysics.PhysFunctChangeLinkParams: { - Linkset.Extension(pFunct, pParams); + ret = Linkset.Extension(pFunct, pParams); break; } default: -- cgit v1.1 From 6d83f3f02190509119f65da92def19d08ef825f9 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 19 Aug 2013 11:08:22 -0700 Subject: BulletSim: adjust avatar capsule height calculation to be closer to defined SL heights. Correct BSParam avatar height defaults to be what's in OpenSimDefaults.ini. --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 15 ++++++++++----- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 291dfcd..28b2a7e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -676,18 +676,20 @@ public sealed class BSCharacter : BSPhysObject float heightAdjust = BSParam.AvatarHeightMidFudge; if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) { - // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. - // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 - float midHeightOffset = size.Z - 1.87f; + const float AVATAR_LOW = 1.1f; + const float AVATAR_MID = 1.775f; // 1.87f + const float AVATAR_HI = 2.45f; + // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. + float midHeightOffset = size.Z - AVATAR_MID; if (midHeightOffset < 0f) { // Small avatar. Add the adjustment based on the distance from midheight - heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; + heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; } else { // Large avatar. Add the adjustment based on the distance from midheight - heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; + heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; } } // The total scale height is the central cylindar plus the caps on the two ends. @@ -698,6 +700,9 @@ public sealed class BSCharacter : BSPhysObject if (newScale.Z < 0) newScale.Z = 0.1f; + DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", + LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); + return newScale; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 737dda1..4e92e6d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -570,9 +570,9 @@ public static class BSParam new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", -0.2f ), new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", - 0.2f ), + 0.1f ), new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", - 0.2f ), + 0.1f ), new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", -- cgit v1.1 From 4781297b4ee5908b76039ce3b38291eb2e89e157 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 20 Aug 2013 08:14:08 -0700 Subject: BulletSim: Extension parameters passed through the classes made to pass just and array of objects rather than a mixture of parameters and array. Makes understanding and parsing what is being passed much easier. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 23 ++++-- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 93 ++++++++++++++++------ OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 1 + .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 15 ++-- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 1 + 5 files changed, 98 insertions(+), 35 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index d035f7b..90cf15a 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -315,7 +315,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, childPhysActor, typeCode)); + object[] parms = { childPhysActor, typeCode }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms)); } return ret; @@ -323,7 +324,7 @@ public class ExtendedPhysics : INonSharedRegionModule // physGetLinkType(integer linkNum) [ScriptInvocation] - public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode) + public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum) { int ret = -1; if (!Enabled) return ret; @@ -333,7 +334,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, childPhysActor)); + object[] parms = { childPhysActor }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms)); } return ret; @@ -352,7 +354,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, childPhysActor, PHYS_LINK_TYPE_FIXED)); + object[] parms = { childPhysActor , PHYS_LINK_TYPE_FIXED }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms)); } return ret; @@ -409,7 +412,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, childPhysActor, parms)); + object[] parms2 = AddToBeginningOfArray(childPhysActor, parms); + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2)); } return ret; @@ -513,6 +517,15 @@ public class ExtendedPhysics : INonSharedRegionModule return ret; } + // Return an array of objects with the passed object as the first object of a new array + private object[] AddToBeginningOfArray(object firstOne, object[] prevArray) + { + object[] newArray = new object[1 + prevArray.Length]; + newArray[0] = firstOne; + prevArray.CopyTo(newArray, 1); + return newArray; + } + // Extension() returns an object. Convert that object into the integer error we expect to return. private int MakeIntError(object extensionRet) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 92df84e..87716b4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -343,7 +343,7 @@ public sealed class BSLinksetConstraints : BSLinkset // real world coordinate of midpoint between the two objects OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); - DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={7}", + DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, rootPrim.Position, linkInfo.member.Position, midPoint); @@ -492,11 +492,12 @@ public sealed class BSLinksetConstraints : BSLinkset object ret = null; switch (pFunct) { - // pParams = (int linkNUm, PhysActor linkChild) + // pParams = [ BSPhysObject child, integer linkType ] case ExtendedPhysics.PhysFunctChangeLinkType: if (pParams.Length > 1) { int requestedType = (int)pParams[1]; + DetailLog("{0},BSLinksetConstraint.SetLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); if (requestedType == (int)ConstraintType.FIXED_CONSTRAINT_TYPE || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE @@ -507,7 +508,7 @@ public sealed class BSLinksetConstraints : BSLinkset BSPrimLinkable child = pParams[0] as BSPrimLinkable; if (child != null) { - m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkFixed", delegate() + m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkType", delegate() { // Pick up all the constraints currently created. RemoveDependencies(child); @@ -522,15 +523,35 @@ public sealed class BSLinksetConstraints : BSLinkset linkInfoC.ResetLink(); linkInfoC.constraintType = (ConstraintType)requestedType; ret = (object)true; + DetailLog("{0},BSLinksetConstraint.SetLinkType,link={1},type={2}", + linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); } } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); + } // Cause the whole linkset to be rebuilt in post-taint time. Refresh(child); }); } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); + } + } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", + LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); } } break; + // pParams = [] case ExtendedPhysics.PhysFunctGetLinkType: if (pParams.Length > 0) { @@ -544,11 +565,15 @@ public sealed class BSLinksetConstraints : BSLinkset if (linkInfoC != null) { ret = (object)(int)linkInfoC.constraintType; + DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", + linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + } } } } break; + // pParams = [ BSPhysObject child, int op, object opParams, int op, object opParams, ... ] case ExtendedPhysics.PhysFunctChangeLinkParams: // There should be two parameters: the childActor and a list of parameters to set try @@ -556,7 +581,6 @@ public sealed class BSLinksetConstraints : BSLinkset if (pParams.Length > 1) { BSPrimLinkable child = pParams[0] as BSPrimLinkable; - object[] setOps = (object[])pParams[1]; BSLinkInfo baseLinkInfo = null; if (TryGetLinkInfo(child, out baseLinkInfo)) { @@ -568,85 +592,106 @@ public sealed class BSLinksetConstraints : BSLinkset OMV.Vector3 valueVector; OMV.Quaternion valueQuaternion; - int opIndex = 0; - while (opIndex < setOps.Length) + int opIndex = 1; + while (opIndex < pParams.Length) { - int thisOp = (int)setOps[opIndex]; + int thisOp = (int)pParams[opIndex]; + DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", + linkInfo.member.LocalID, thisOp, pParams[opIndex+1]); switch (thisOp) { case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: - valueVector = (OMV.Vector3)setOps[opIndex + 1]; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.frameInAloc = valueVector; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: - valueQuaternion = (OMV.Quaternion)setOps[opIndex + 1]; + valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; linkInfo.frameInArot = valueQuaternion; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: - valueVector = (OMV.Vector3)setOps[opIndex + 1]; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.frameInBloc = valueVector; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: - valueQuaternion = (OMV.Quaternion)setOps[opIndex + 1]; + valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; linkInfo.frameInBrot = valueQuaternion; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: - valueVector = (OMV.Vector3)setOps[opIndex + 1]; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.linearLimitLow = valueVector; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: - valueVector = (OMV.Vector3)setOps[opIndex + 1]; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.linearLimitHigh = valueVector; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: - valueVector = (OMV.Vector3)setOps[opIndex + 1]; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.angularLimitLow = valueVector; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: - valueVector = (OMV.Vector3)setOps[opIndex + 1]; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.angularLimitHigh = valueVector; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: - valueBool = (bool)setOps[opIndex + 1]; + valueBool = (bool)pParams[opIndex + 1]; linkInfo.useFrameOffset = valueBool; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: - valueBool = (bool)setOps[opIndex + 1]; + valueBool = (bool)pParams[opIndex + 1]; linkInfo.enableTransMotor = valueBool; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.transMotorMaxVel = valueFloat; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.transMotorMaxForce = valueFloat; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_CFM: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.cfm = valueFloat; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ERP: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.erp = valueFloat; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.solverIterations = valueFloat; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.springDamping = valueFloat; + opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: - valueFloat = (float)setOps[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 1]; linkInfo.springStiffness = valueFloat; + opIndex += 2; break; default: break; } } } + // Something changed so a rebuild is in order + Refresh(child); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 4685b48..45056bc 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -1552,6 +1552,7 @@ public class BSPrim : BSPhysObject #region Extension public override object Extension(string pFunct, params object[] pParams) { + DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct); object ret = null; switch (pFunct) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 28ea8c0..531f8fb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -283,17 +283,20 @@ public class BSPrimLinkable : BSPrimDisplaced #region Extension public override object Extension(string pFunct, params object[] pParams) { + DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length); object ret = null; switch (pFunct) { // physGetLinksetType(); + // pParams = [] case ExtendedPhysics.PhysFunctGetLinksetType: { ret = (object)LinksetType; - m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); + DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret); break; } // physSetLinksetType(type); + // pParams = [ BSPhysObject child, integer type ] case ExtendedPhysics.PhysFunctSetLinksetType: { if (pParams.Length > 0) @@ -304,8 +307,8 @@ public class BSPrimLinkable : BSPrimDisplaced PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate() { // Cause the linkset type to change - m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}", - LogHeader, Linkset.LinksetImpl, linksetType); + DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}", + LocalID, Linkset.LinksetImpl, linksetType); ConvertLinkset(linksetType); }); } @@ -314,21 +317,21 @@ public class BSPrimLinkable : BSPrimDisplaced break; } // physChangeLinkType(linknum, typeCode); - // Params: PhysActor linkedPrim, int typeCode + // pParams = [ BSPhysObject child, integer linkType ] case ExtendedPhysics.PhysFunctChangeLinkType: { ret = Linkset.Extension(pFunct, pParams); break; } // physGetLinkType(linknum); - // Params: PhysActor linkedPrim + // pParams = [ BSPhysObject child ] case ExtendedPhysics.PhysFunctGetLinkType: { ret = Linkset.Extension(pFunct, pParams); break; } // physChangeLinkParams(linknum, [code, value, code, value, ...]); - // Params: PhysActor linkedPrim, object[] params + // pParams = [ BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] case ExtendedPhysics.PhysFunctChangeLinkParams: { ret = Linkset.Extension(pFunct, pParams); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 7440468..b2ec0e5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -869,6 +869,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters #region Extensions public override object Extension(string pFunct, params object[] pParams) { + DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct); return base.Extension(pFunct, pParams); } #endregion // Extensions -- cgit v1.1 From 995314f91f72eef0048a58f30e8dd8051f6bf14e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 20 Aug 2013 09:20:48 -0700 Subject: BulletSim: add ID parameter to TaintedObject calls so logging will include LocalID of object which created the taint. --- .../Physics/BulletSPlugin/BSActorAvatarMove.cs | 2 +- .../Region/Physics/BulletSPlugin/BSCharacter.cs | 26 +++++----- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 4 +- OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 2 +- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 6 +-- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 58 +++++++++++----------- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 6 +-- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 55 +++++++++++++------- 8 files changed, 89 insertions(+), 70 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 68bc1b9..04a4a32 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -105,7 +105,7 @@ public class BSActorAvatarMove : BSActor // into the movement motor. public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) { - m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() + m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() { if (m_velocityMotor != null) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 28b2a7e..fc18960 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -93,7 +93,7 @@ public sealed class BSCharacter : BSPhysObject LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos); // do actual creation in taint time - PhysScene.TaintedObject("BSCharacter.create", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() { DetailLog("{0},BSCharacter.create,taint", LocalID); // New body and shape into PhysBody and PhysShape @@ -121,7 +121,7 @@ public sealed class BSCharacter : BSPhysObject base.Destroy(); DetailLog("{0},BSCharacter.Destroy", LocalID); - PhysScene.TaintedObject("BSCharacter.destroy", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate() { PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); PhysBody.Clear(); @@ -209,7 +209,7 @@ public sealed class BSCharacter : BSPhysObject DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", LocalID, _size, Scale, Density, _avatarVolume, RawMass); - PhysScene.TaintedObject("BSCharacter.setSize", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() { if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) { @@ -257,7 +257,7 @@ public sealed class BSCharacter : BSPhysObject _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties directly into the physics engine - PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) PhysScene.PE.ClearAllForces(PhysBody); @@ -267,7 +267,7 @@ public sealed class BSCharacter : BSPhysObject { _rotationalVelocity = OMV.Vector3.Zero; - PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) { @@ -291,7 +291,7 @@ public sealed class BSCharacter : BSPhysObject set { RawPosition = value; - PhysScene.TaintedObject("BSCharacter.setPosition", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate() { DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); PositionSanityCheck(); @@ -363,7 +363,7 @@ public sealed class BSCharacter : BSPhysObject { // The new position value must be pushed into the physics engine but we can't // just assign to "Position" because of potential call loops. - PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() { DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); ForcePosition = RawPosition; @@ -390,7 +390,7 @@ public sealed class BSCharacter : BSPhysObject set { RawForce = value; // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); - PhysScene.TaintedObject("BSCharacter.SetForce", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate() { DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); if (PhysBody.HasPhysicalBody) @@ -438,7 +438,7 @@ public sealed class BSCharacter : BSPhysObject set { RawVelocity = value; // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); - PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() { if (m_moveActor != null) m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); @@ -480,7 +480,7 @@ public sealed class BSCharacter : BSPhysObject if (RawOrientation != value) { RawOrientation = value; - PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate() { // Bullet assumes we know what we are doing when forcing orientation // so it lets us go against all the rules and just compensates for them later. @@ -560,7 +560,7 @@ public sealed class BSCharacter : BSPhysObject public override bool FloatOnWater { set { _floatOnWater = value; - PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate() { if (PhysBody.HasPhysicalBody) { @@ -588,7 +588,7 @@ public sealed class BSCharacter : BSPhysObject public override float Buoyancy { get { return _buoyancy; } set { _buoyancy = value; - PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() + PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate() { DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); ForceBuoyancy = _buoyancy; @@ -633,7 +633,7 @@ public sealed class BSCharacter : BSPhysObject OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); - PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() { // Bullet adds this central force to the total force for this tick // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 87716b4..b2a9501 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -297,7 +297,7 @@ public sealed class BSLinksetConstraints : BSLinkset rootx.LocalID, rootx.PhysBody.AddrString, childx.LocalID, childx.PhysBody.AddrString); - m_physicsScene.TaintedObject(inTaintTime, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() + m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() { PhysicallyUnlinkAChildFromRoot(rootx, childx); }); @@ -508,7 +508,7 @@ public sealed class BSLinksetConstraints : BSLinkset BSPrimLinkable child = pParams[0] as BSPrimLinkable; if (child != null) { - m_physicsScene.TaintedObject("BSLinksetConstraint.PhysFunctChangeLinkType", delegate() + m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() { // Pick up all the constraints currently created. RemoveDependencies(child); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 4e92e6d..2f1799b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -826,7 +826,7 @@ public static class BSParam private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) { BSScene physScene = pPhysScene; - physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate() + physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate() { physScene.PE.ResetConstraintSolver(physScene.World); }); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 9dc52d5..2efb1a5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -121,7 +121,7 @@ public abstract class BSPhysObject : PhysicsActor public virtual void Destroy() { PhysicalActors.Enable(false); - PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() + PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate() { PhysicalActors.Dispose(); }); @@ -509,7 +509,7 @@ public abstract class BSPhysObject : PhysicsActor // make sure first collision happens NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); - PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() + PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate() { if (PhysBody.HasPhysicalBody) CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); @@ -524,7 +524,7 @@ public abstract class BSPhysObject : PhysicsActor public override void UnSubscribeEvents() { // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); SubscribedEventsMs = 0; - PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() + PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate() { // Make sure there is a body there because sometimes destruction happens in an un-ideal order. if (PhysBody.HasPhysicalBody) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 45056bc..15b7090 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -102,7 +102,7 @@ public class BSPrim : BSPhysObject // DetailLog("{0},BSPrim.constructor,call", LocalID); // do the actual object creation at taint time - PhysScene.TaintedObject("BSPrim.create", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() { // Make sure the object is being created with some sanity. ExtremeSanityCheck(true /* inTaintTime */); @@ -126,7 +126,7 @@ public class BSPrim : BSPhysObject // Undo any vehicle properties this.VehicleType = (int)Vehicle.TYPE_NONE; - PhysScene.TaintedObject("BSPrim.Destroy", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate() { DetailLog("{0},BSPrim.Destroy,taint,", LocalID); // If there are physical body and shape, release my use of same. @@ -161,7 +161,7 @@ public class BSPrim : BSPhysObject } public override bool ForceBodyShapeRebuild(bool inTaintTime) { - PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() { _mass = CalculateMass(); // changing the shape changes the mass CreateGeomAndObject(true); @@ -178,7 +178,7 @@ public class BSPrim : BSPhysObject if (value != _isSelected) { _isSelected = value; - PhysScene.TaintedObject("BSPrim.setSelected", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate() { DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); SetObjectDynamic(false); @@ -224,7 +224,7 @@ public class BSPrim : BSPhysObject _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties in the physics engine - PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() { if (PhysBody.HasPhysicalBody) PhysScene.PE.ClearAllForces(PhysBody); @@ -234,7 +234,7 @@ public class BSPrim : BSPhysObject { _rotationalVelocity = OMV.Vector3.Zero; // Zero some other properties in the physics engine - PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() { // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); if (PhysBody.HasPhysicalBody) @@ -262,7 +262,7 @@ public class BSPrim : BSPhysObject }); // Update parameters so the new actor's Refresh() action is called at the right time. - PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.LockAngularMotion", delegate() { UpdatePhysicalParameters(); }); @@ -287,7 +287,7 @@ public class BSPrim : BSPhysObject RawPosition = value; PositionSanityCheck(false); - PhysScene.TaintedObject("BSPrim.setPosition", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate() { DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); ForcePosition = RawPosition; @@ -531,7 +531,7 @@ public class BSPrim : BSPhysObject set { Vehicle type = (Vehicle)value; - PhysScene.TaintedObject("setVehicleType", delegate() + PhysScene.TaintedObject(LocalID, "setVehicleType", delegate() { // Some vehicle scripts change vehicle type on the fly as an easy way to // change all the parameters. Like a plane changing to CAR when on the @@ -561,7 +561,7 @@ public class BSPrim : BSPhysObject } public override void VehicleFloatParam(int param, float value) { - PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate() { BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) @@ -573,7 +573,7 @@ public class BSPrim : BSPhysObject } public override void VehicleVectorParam(int param, OMV.Vector3 value) { - PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate() { BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) @@ -585,7 +585,7 @@ public class BSPrim : BSPhysObject } public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { - PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate() { BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) @@ -597,7 +597,7 @@ public class BSPrim : BSPhysObject } public override void VehicleFlags(int param, bool remove) { - PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate() { BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); if (vehicleActor != null) @@ -613,7 +613,7 @@ public class BSPrim : BSPhysObject if (_isVolumeDetect != newValue) { _isVolumeDetect = newValue; - PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate() { // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); SetObjectDynamic(true); @@ -628,7 +628,7 @@ public class BSPrim : BSPhysObject public override void SetMaterial(int material) { base.SetMaterial(material); - PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate() { UpdatePhysicalParameters(); }); @@ -641,7 +641,7 @@ public class BSPrim : BSPhysObject if (base.Friction != value) { base.Friction = value; - PhysScene.TaintedObject("BSPrim.setFriction", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate() { UpdatePhysicalParameters(); }); @@ -656,7 +656,7 @@ public class BSPrim : BSPhysObject if (base.Restitution != value) { base.Restitution = value; - PhysScene.TaintedObject("BSPrim.setRestitution", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate() { UpdatePhysicalParameters(); }); @@ -673,7 +673,7 @@ public class BSPrim : BSPhysObject if (base.Density != value) { base.Density = value; - PhysScene.TaintedObject("BSPrim.setDensity", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate() { UpdatePhysicalParameters(); }); @@ -688,7 +688,7 @@ public class BSPrim : BSPhysObject if (base.GravModifier != value) { base.GravModifier = value; - PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate() { UpdatePhysicalParameters(); }); @@ -699,7 +699,7 @@ public class BSPrim : BSPhysObject get { return RawVelocity; } set { RawVelocity = value; - PhysScene.TaintedObject("BSPrim.setVelocity", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate() { // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); ForceVelocity = RawVelocity; @@ -745,7 +745,7 @@ public class BSPrim : BSPhysObject return; RawOrientation = value; - PhysScene.TaintedObject("BSPrim.setOrientation", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate() { ForceOrientation = RawOrientation; }); @@ -776,7 +776,7 @@ public class BSPrim : BSPhysObject if (_isPhysical != value) { _isPhysical = value; - PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate() { DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); SetObjectDynamic(true); @@ -1020,7 +1020,7 @@ public class BSPrim : BSPhysObject public override bool FloatOnWater { set { _floatOnWater = value; - PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate() { if (_floatOnWater) CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); @@ -1037,7 +1037,7 @@ public class BSPrim : BSPhysObject _rotationalVelocity = value; Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); - PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate() { ForceRotationalVelocity = _rotationalVelocity; }); @@ -1068,7 +1068,7 @@ public class BSPrim : BSPhysObject get { return _buoyancy; } set { _buoyancy = value; - PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate() { ForceBuoyancy = _buoyancy; }); @@ -1142,7 +1142,7 @@ public class BSPrim : BSPhysObject // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); OMV.Vector3 addForce = force; - PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate() { // Bullet adds this central force to the total force for this tick. // Deep down in Bullet: @@ -1172,7 +1172,7 @@ public class BSPrim : BSPhysObject OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); - PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate() { // Bullet adds this impulse immediately to the velocity DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); @@ -1197,7 +1197,7 @@ public class BSPrim : BSPhysObject if (force.IsFinite()) { OMV.Vector3 angForce = force; - PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate() { if (PhysBody.HasPhysicalBody) { @@ -1221,7 +1221,7 @@ public class BSPrim : BSPhysObject public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) { OMV.Vector3 applyImpulse = impulse; - PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate() { if (PhysBody.HasPhysicalBody) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 531f8fb..840265b 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -108,7 +108,7 @@ public class BSPrimLinkable : BSPrimDisplaced set { base.Position = value; - PhysScene.TaintedObject("BSPrimLinkable.setPosition", delegate() + PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate() { Linkset.UpdateProperties(UpdatedProperties.Position, this); }); @@ -122,7 +122,7 @@ public class BSPrimLinkable : BSPrimDisplaced set { base.Orientation = value; - PhysScene.TaintedObject("BSPrimLinkable.setOrientation", delegate() + PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate() { Linkset.UpdateProperties(UpdatedProperties.Orientation, this); }); @@ -304,7 +304,7 @@ public class BSPrimLinkable : BSPrimDisplaced BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0]; if (Linkset.IsRoot(this)) { - PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate() + PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate() { // Cause the linkset type to change DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}", diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index b2ec0e5..24233cc 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -157,12 +157,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public delegate void TaintCallback(); private struct TaintCallbackEntry { + public String originator; public String ident; public TaintCallback callback; - public TaintCallbackEntry(string i, TaintCallback c) + public TaintCallbackEntry(string pIdent, TaintCallback pCallBack) { - ident = i; - callback = c; + originator = BSScene.DetailLogZero; + ident = pIdent; + callback = pCallBack; + } + public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack) + { + originator = pOrigin; + ident = pIdent; + callback = pCallBack; } } private Object _taintLock = new Object(); // lock for using the next object @@ -888,26 +896,37 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // Calls to the PhysicsActors can't directly call into the physics engine // because it might be busy. We delay changes to a known time. // We rely on C#'s closure to save and restore the context for the delegate. - public void TaintedObject(String ident, TaintCallback callback) + public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback) { - if (!m_initialized) return; - - lock (_taintLock) - { - _taintOperations.Add(new TaintCallbackEntry(ident, callback)); - } - - return; + TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback); + } + public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback) + { + TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); + } + public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback) + { + TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback); + } + public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback) + { + TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback); } - // Sometimes a potentially tainted operation can be used in and out of taint time. // This routine executes the command immediately if in taint-time otherwise it is queued. - public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) + public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback) { + if (!m_initialized) return; + if (inTaintTime) - callback(); + pCallback(); else - TaintedObject(ident, callback); + { + lock (_taintLock) + { + _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback)); + } + } } private void TriggerPreStepEvent(float timeStep) @@ -951,7 +970,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters { try { - DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG + DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG tcbe.callback(); } catch (Exception e) @@ -1081,7 +1100,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters string xval = val; List xlIDs = lIDs; string xparm = parm; - TaintedObject("BSScene.UpdateParameterSet", delegate() { + TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() { BSParam.ParameterDefnBase thisParam; if (BSParam.TryGetParameter(xparm, out thisParam)) { -- cgit v1.1 From d09c35f5063114880aecb94a938bfc49f5af5f7d Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 20 Aug 2013 13:09:40 -0700 Subject: BulletSim: pass both root and child BSPhysObjects to Extension function. Update routines to use the new parameters list from above change. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 30 +++++++++++--------- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 32 ++++++++++++---------- .../Region/Physics/BulletSPlugin/BSPrimLinkable.cs | 14 +++++----- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 90cf15a..10e13b9 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -220,7 +220,8 @@ public class ExtendedPhysics : INonSharedRegionModule containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition); containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation); - ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType)); + object[] parms2 = { rootPhysActor, null, linksetType }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2)); Thread.Sleep(150); // longer than one heartbeat tick containingGroup.ScriptSetPhysicsStatus(true); @@ -229,7 +230,8 @@ public class ExtendedPhysics : INonSharedRegionModule { // Non-physical linksets don't have a physical instantiation so there is no state to // worry about being updated. - ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType)); + object[] parms2 = { rootPhysActor, null, linksetType }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2)); } } else @@ -271,7 +273,8 @@ public class ExtendedPhysics : INonSharedRegionModule PhysicsActor rootPhysActor = rootPart.PhysActor; if (rootPhysActor != null) { - ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType)); + object[] parms2 = { rootPhysActor, null }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2)); } else { @@ -315,8 +318,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - object[] parms = { childPhysActor, typeCode }; - ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms)); + object[] parms2 = { rootPhysActor, childPhysActor, typeCode }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2)); } return ret; @@ -334,8 +337,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - object[] parms = { childPhysActor }; - ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms)); + object[] parms2 = { rootPhysActor, childPhysActor }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms2)); } return ret; @@ -354,8 +357,8 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - object[] parms = { childPhysActor , PHYS_LINK_TYPE_FIXED }; - ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms)); + object[] parms2 = { rootPhysActor, childPhysActor , PHYS_LINK_TYPE_FIXED }; + ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2)); } return ret; @@ -412,7 +415,7 @@ public class ExtendedPhysics : INonSharedRegionModule if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor)) { - object[] parms2 = AddToBeginningOfArray(childPhysActor, parms); + object[] parms2 = AddToBeginningOfArray(rootPhysActor, childPhysActor, parms); ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2)); } @@ -518,11 +521,12 @@ public class ExtendedPhysics : INonSharedRegionModule } // Return an array of objects with the passed object as the first object of a new array - private object[] AddToBeginningOfArray(object firstOne, object[] prevArray) + private object[] AddToBeginningOfArray(object firstOne, object secondOne, object[] prevArray) { - object[] newArray = new object[1 + prevArray.Length]; + object[] newArray = new object[2 + prevArray.Length]; newArray[0] = firstOne; - prevArray.CopyTo(newArray, 1); + newArray[1] = secondOne; + prevArray.CopyTo(newArray, 2); return newArray; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index b2a9501..a9ae89d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -385,7 +385,7 @@ public sealed class BSLinksetConstraints : BSLinkset linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/); - DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", + DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", rootPrim.LocalID, rootPrim.LocalID, rootPrim.PhysBody.AddrString, linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, @@ -492,12 +492,12 @@ public sealed class BSLinksetConstraints : BSLinkset object ret = null; switch (pFunct) { - // pParams = [ BSPhysObject child, integer linkType ] + // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] case ExtendedPhysics.PhysFunctChangeLinkType: - if (pParams.Length > 1) + if (pParams.Length > 2) { - int requestedType = (int)pParams[1]; - DetailLog("{0},BSLinksetConstraint.SetLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); + int requestedType = (int)pParams[2]; + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); if (requestedType == (int)ConstraintType.FIXED_CONSTRAINT_TYPE || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE @@ -505,9 +505,11 @@ public sealed class BSLinksetConstraints : BSLinkset || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) { - BSPrimLinkable child = pParams[0] as BSPrimLinkable; + BSPrimLinkable child = pParams[1] as BSPrimLinkable; if (child != null) { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", + LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() { // Pick up all the constraints currently created. @@ -523,17 +525,17 @@ public sealed class BSLinksetConstraints : BSLinkset linkInfoC.ResetLink(); linkInfoC.constraintType = (ConstraintType)requestedType; ret = (object)true; - DetailLog("{0},BSLinksetConstraint.SetLinkType,link={1},type={2}", + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); } else { - DetailLog("{0},BSLinksetConstraint.SetLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); } } else { - DetailLog("{0},BSLinksetConstraint.SetLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); } // Cause the whole linkset to be rebuilt in post-taint time. Refresh(child); @@ -551,11 +553,11 @@ public sealed class BSLinksetConstraints : BSLinkset } } break; - // pParams = [] + // pParams = [ BSPhysObject root, BSPhysObject child ] case ExtendedPhysics.PhysFunctGetLinkType: if (pParams.Length > 0) { - BSPrimLinkable child = pParams[0] as BSPrimLinkable; + BSPrimLinkable child = pParams[1] as BSPrimLinkable; if (child != null) { BSLinkInfo linkInfo = null; @@ -573,14 +575,14 @@ public sealed class BSLinksetConstraints : BSLinkset } } break; - // pParams = [ BSPhysObject child, int op, object opParams, int op, object opParams, ... ] + // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] case ExtendedPhysics.PhysFunctChangeLinkParams: // There should be two parameters: the childActor and a list of parameters to set try { - if (pParams.Length > 1) + if (pParams.Length > 2) { - BSPrimLinkable child = pParams[0] as BSPrimLinkable; + BSPrimLinkable child = pParams[1] as BSPrimLinkable; BSLinkInfo baseLinkInfo = null; if (TryGetLinkInfo(child, out baseLinkInfo)) { @@ -592,7 +594,7 @@ public sealed class BSLinksetConstraints : BSLinkset OMV.Vector3 valueVector; OMV.Quaternion valueQuaternion; - int opIndex = 1; + int opIndex = 2; while (opIndex < pParams.Length) { int thisOp = (int)pParams[opIndex]; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 840265b..126b146 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -288,7 +288,7 @@ public class BSPrimLinkable : BSPrimDisplaced switch (pFunct) { // physGetLinksetType(); - // pParams = [] + // pParams = [ BSPhysObject root, null ] case ExtendedPhysics.PhysFunctGetLinksetType: { ret = (object)LinksetType; @@ -296,12 +296,12 @@ public class BSPrimLinkable : BSPrimDisplaced break; } // physSetLinksetType(type); - // pParams = [ BSPhysObject child, integer type ] + // pParams = [ BSPhysObject root, null, integer type ] case ExtendedPhysics.PhysFunctSetLinksetType: { - if (pParams.Length > 0) + if (pParams.Length > 2) { - BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0]; + BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2]; if (Linkset.IsRoot(this)) { PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate() @@ -317,21 +317,21 @@ public class BSPrimLinkable : BSPrimDisplaced break; } // physChangeLinkType(linknum, typeCode); - // pParams = [ BSPhysObject child, integer linkType ] + // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] case ExtendedPhysics.PhysFunctChangeLinkType: { ret = Linkset.Extension(pFunct, pParams); break; } // physGetLinkType(linknum); - // pParams = [ BSPhysObject child ] + // pParams = [ BSPhysObject root, BSPhysObject child ] case ExtendedPhysics.PhysFunctGetLinkType: { ret = Linkset.Extension(pFunct, pParams); break; } // physChangeLinkParams(linknum, [code, value, code, value, ...]); - // pParams = [ BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] + // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] case ExtendedPhysics.PhysFunctChangeLinkParams: { ret = Linkset.Extension(pFunct, pParams); -- cgit v1.1 From e0b457d3c3daabc065aa66376bc17472d4b43e8f Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 21 Aug 2013 16:02:42 -0700 Subject: BulletSim: add position and rotation update for child prim physics update events. Normally, physics engines do not return updates for child prims so, under normal operation, this code should never execute. Will only be used when using flexible linkset linkages. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 2e11162..b30c024 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2502,6 +2502,26 @@ namespace OpenSim.Region.Framework.Scenes //ParentGroup.RootPart.m_groupPosition = newpos; } + if (pa != null && ParentID != 0 && ParentGroup != null) + { + // RA: Special case where a child object is requesting property updates. + // This happens when linksets are modified to use flexible links rather than + // the default links. + // The simulator code presumes that child parts are only modified by scripts + // so the logic for changing position/rotation/etc does not take into + // account the physical object actually moving. + // This code updates the offset position and rotation of the child and then + // lets the update code push the update to the viewer. + // Since physics engines do not normally generate this event for linkset children, + // this code will not be active unless you have a specially configured + // physics engine. + Quaternion invRootRotation = Quaternion.Normalize(Quaternion.Inverse(ParentGroup.RootPart.RotationOffset)); + m_offsetPosition = pa.Position - m_groupPosition; + RotationOffset = pa.Orientation * invRootRotation; + m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}", + "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset); + } + ScheduleTerseUpdate(); } -- cgit v1.1 From 3dbf4a1002216e2d14c20353a5993ea63413d03d Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 22 Aug 2013 09:05:26 -0700 Subject: BulletSim: remove chatty debug message from previous commit. --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index b30c024..b3e6b67 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2504,7 +2504,7 @@ namespace OpenSim.Region.Framework.Scenes if (pa != null && ParentID != 0 && ParentGroup != null) { - // RA: Special case where a child object is requesting property updates. + // Special case where a child object is requesting property updates. // This happens when linksets are modified to use flexible links rather than // the default links. // The simulator code presumes that child parts are only modified by scripts @@ -2518,8 +2518,8 @@ namespace OpenSim.Region.Framework.Scenes Quaternion invRootRotation = Quaternion.Normalize(Quaternion.Inverse(ParentGroup.RootPart.RotationOffset)); m_offsetPosition = pa.Position - m_groupPosition; RotationOffset = pa.Orientation * invRootRotation; - m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}", - "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset); + // m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}", + // "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset); } ScheduleTerseUpdate(); -- cgit v1.1 From 67195618d580eb6cd848cf1e6462572ad2b2b118 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 22 Aug 2013 09:07:58 -0700 Subject: BulletSim: add requestor's ID to post taint detail log message. --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 24233cc..b3dfa41 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -987,10 +987,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // will replace any previous operation by the same object. public void PostTaintObject(String ident, uint ID, TaintCallback callback) { - string uniqueIdent = ident + "-" + ID.ToString(); + string IDAsString = ID.ToString(); + string uniqueIdent = ident + "-" + IDAsString; lock (_taintLock) { - _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); + _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback); } return; -- cgit v1.1 From 30b3657a66e5a4012b96baae2c0424ec13409f83 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 22 Aug 2013 09:08:58 -0700 Subject: BulletSim: implementation of setting spring specific physical parameters. Add setting of linkset type to physChangeLinkParams. Lots of detail logging for setting of linkset constraint parameters. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 6 ++- .../Physics/BulletSPlugin/BSConstraint6Dof.cs | 16 ++++--- .../Physics/BulletSPlugin/BSConstraintSpring.cs | 43 ++++++++++-------- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 52 +++++++++++++++++----- 4 files changed, 81 insertions(+), 36 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 10e13b9..2f88e2b 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -367,6 +367,7 @@ public class ExtendedPhysics : INonSharedRegionModule // Code for specifying params. // The choice if 14400 is arbitrary and only serves to catch parameter code misuse. public const int PHYS_PARAM_MIN = 14401; + [ScriptConstant] public const int PHYS_PARAM_FRAMEINA_LOC = 14401; [ScriptConstant] @@ -401,7 +402,10 @@ public class ExtendedPhysics : INonSharedRegionModule public const int PHYS_PARAM_SPRING_DAMPING = 14416; [ScriptConstant] public const int PHYS_PARAM_SPRING_STIFFNESS = 14417; - public const int PHYS_PARAM_MAX = 14417; + [ScriptConstant] + public const int PHYS_PARAM_LINK_TYPE = 14418; + + public const int PHYS_PARAM_MAX = 14418; // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 5008ff7..7fcb75c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs @@ -59,9 +59,11 @@ public class BSConstraint6Dof : BSConstraint frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); m_enabled = true; - world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, + PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + m_body1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", + m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); } // 6 Dof constraint based on a midpoint between the two constrained bodies @@ -86,9 +88,11 @@ public class BSConstraint6Dof : BSConstraint m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", - BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, + m_body1.ID, world.worldID, m_constraint.AddrString, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + if (!m_constraint.HasPhysicalConstraint) { world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", @@ -113,8 +117,10 @@ public class BSConstraint6Dof : BSConstraint frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); m_enabled = true; - world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", - BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", + m_body1.ID, world.worldID, obj1.ID, obj1.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}", + m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); } public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs index 01d67d4..410584d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs @@ -47,37 +47,42 @@ public sealed class BSConstraintSpring : BSConstraint6Dof useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); m_enabled = true; - world.physicsScene.DetailLog("{0},BSConstraintSpring,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, - obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", + m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); } - public bool SetEnable(int index, bool axisEnable) + public bool SetEnable(int pIndex, bool pAxisEnable) { - bool ret = false; - - return ret; + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable); + PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable)); + return true; } - public bool SetStiffness(int index, float stiffness) + public bool SetStiffness(int pIndex, float pStiffness) { - bool ret = false; - - return ret; + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},enable={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness); + PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness); + return true; } - public bool SetDamping(int index, float damping) + public bool SetDamping(int pIndex, float pDamping) { - bool ret = false; - - return ret; + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},enable={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping); + PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping); + return true; } - public bool SetEquilibriumPoint(int index, float eqPoint) + public bool SetEquilibriumPoint(int pIndex, float pEqPoint) { - bool ret = false; - - return ret; + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},enable={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint); + return true; } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index a9ae89d..be97c29 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -67,6 +67,7 @@ public sealed class BSLinksetConstraints : BSLinkset { constraint = null; ResetLink(); + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); } // Set all the parameters for this constraint to a fixed, non-movable constraint. @@ -91,11 +92,13 @@ public sealed class BSLinksetConstraints : BSLinkset frameInBrot = OMV.Quaternion.Identity; springDamping = -1f; springStiffness = -1f; + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); } // Given a constraint, apply the current constraint parameters to same. public override void SetLinkParameters(BSConstraint constrain) { + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); switch (constraintType) { case ConstraintType.FIXED_CONSTRAINT_TYPE: @@ -139,7 +142,7 @@ public sealed class BSLinksetConstraints : BSLinkset if (springDamping != -1) constrainSpring.SetDamping(ii, springDamping); if (springStiffness != -1) - constrainSpring.SetStiffness(ii, springStiffness); + constrainSpring.SetStiffness(ii, springStiffness); } } break; @@ -155,7 +158,6 @@ public sealed class BSLinksetConstraints : BSLinkset public override bool ShouldUpdateChildProperties() { bool ret = true; - if (constraintType == ConstraintType.FIXED_CONSTRAINT_TYPE) ret = false; @@ -193,10 +195,16 @@ public sealed class BSLinksetConstraints : BSLinkset { // Queue to happen after all the other taint processing m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + { + if (HasAnyChildren) { - if (HasAnyChildren) - RecomputeLinksetConstraints(); - }); + // Constraints that have not been changed are not rebuild but make sure + // the constraint of the requestor is rebuilt. + PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); + // Rebuild the linkset and all its constraints. + RecomputeLinksetConstraints(); + } + }); } } @@ -415,13 +423,22 @@ public sealed class BSLinksetConstraints : BSLinkset rootPrim.LocalID, rootPrim.PhysBody.AddrString, childPrim.LocalID, childPrim.PhysBody.AddrString); - // Find the constraint for this link and get rid of it from the overall collection and from my list - if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) + // If asked to unlink root from root, just remove all the constraints + if (rootPrim == childPrim || childPrim == LinksetRoot) { - // Make the child refresh its location - m_physicsScene.PE.PushUpdate(childPrim.PhysBody); + PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); ret = true; } + else + { + // Find the constraint for this link and get rid of it from the overall collection and from my list + if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) + { + // Make the child refresh its location + m_physicsScene.PE.PushUpdate(childPrim.PhysBody); + ret = true; + } + } return ret; } @@ -521,8 +538,6 @@ public sealed class BSLinksetConstraints : BSLinkset BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; if (linkInfoC != null) { - // Setting to fixed is easy. The reset state is the fixed link configuration. - linkInfoC.ResetLink(); linkInfoC.constraintType = (ConstraintType)requestedType; ret = (object)true; DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", @@ -589,6 +604,7 @@ public sealed class BSLinksetConstraints : BSLinkset BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; if (linkInfo != null) { + int valueInt; float valueFloat; bool valueBool; OMV.Vector3 valueVector; @@ -602,6 +618,20 @@ public sealed class BSLinksetConstraints : BSLinkset linkInfo.member.LocalID, thisOp, pParams[opIndex+1]); switch (thisOp) { + case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: + valueInt = (int)pParams[opIndex + 1]; + ConstraintType valueType = (ConstraintType)valueInt; + if (valueType == ConstraintType.FIXED_CONSTRAINT_TYPE + || valueType == ConstraintType.D6_CONSTRAINT_TYPE + || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE + || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE + || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE + || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) + { + linkInfo.constraintType = valueType; + } + opIndex += 2; + break; case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.frameInAloc = valueVector; -- cgit v1.1 From 7c54630a2dde768e92b3034d76314cb1e061c348 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 22 Aug 2013 16:31:17 -0700 Subject: BulletSim: add axis parameter for specifying enable, damping, and stiffness for spring constraints. Renumber parameter ops since I can as no one is using them yet. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 10 +++-- .../Region/Physics/BulletSPlugin/BSApiTemplate.cs | 2 +- .../Physics/BulletSPlugin/BSConstraintSpring.cs | 2 +- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 51 +++++++++++++++------- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 2f88e2b..ef106bd 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -399,13 +399,15 @@ public class ExtendedPhysics : INonSharedRegionModule [ScriptConstant] public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415; [ScriptConstant] - public const int PHYS_PARAM_SPRING_DAMPING = 14416; + public const int PHYS_PARAM_SPRING_AXIS_ENABLE = 14416; [ScriptConstant] - public const int PHYS_PARAM_SPRING_STIFFNESS = 14417; + public const int PHYS_PARAM_SPRING_DAMPING = 14417; [ScriptConstant] - public const int PHYS_PARAM_LINK_TYPE = 14418; + public const int PHYS_PARAM_SPRING_STIFFNESS = 14418; + [ScriptConstant] + public const int PHYS_PARAM_LINK_TYPE = 14419; - public const int PHYS_PARAM_MAX = 14418; + public const int PHYS_PARAM_MAX = 14419; // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 9d8838b..0b3f467 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -292,7 +292,7 @@ public enum ConstraintParamAxis : int AXIS_ANGULAR_X, AXIS_ANGULAR_Y, AXIS_ANGULAR_Z, - AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls + AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls AXIS_ANGULAR_ALL, AXIS_ALL }; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs index 410584d..432e5b2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs @@ -53,7 +53,7 @@ public sealed class BSConstraintSpring : BSConstraint6Dof m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); } - public bool SetEnable(int pIndex, bool pAxisEnable) + public bool SetAxisEnable(int pIndex, bool pAxisEnable) { PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}", m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index be97c29..f623231 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -59,8 +59,9 @@ public sealed class BSLinksetConstraints : BSLinkset public OMV.Vector3 frameInBloc; public OMV.Quaternion frameInBrot; // Spring - public float springDamping; - public float springStiffness; + public bool[] springAxisEnable; + public float[] springDamping; + public float[] springStiffness; public BSLinkInfoConstraint(BSPrimLinkable pMember) : base(pMember) @@ -90,8 +91,15 @@ public sealed class BSLinksetConstraints : BSLinkset frameInArot = OMV.Quaternion.Identity; frameInBloc = OMV.Vector3.Zero; frameInBrot = OMV.Quaternion.Identity; - springDamping = -1f; - springStiffness = -1f; + springAxisEnable = new bool[6]; + springDamping = new float[6]; + springStiffness = new float[6]; + for (int ii = 0; ii < springAxisEnable.Length; ii++) + { + springAxisEnable[ii] = false; + springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + } member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); } @@ -139,11 +147,13 @@ public sealed class BSLinksetConstraints : BSLinkset } for (int ii = 0; ii < 6; ii++) { - if (springDamping != -1) - constrainSpring.SetDamping(ii, springDamping); - if (springStiffness != -1) - constrainSpring.SetStiffness(ii, springStiffness); + constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); + if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) + constrainSpring.SetDamping(ii, springDamping[ii]); + if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) + constrainSpring.SetStiffness(ii, springStiffness[ii]); } + constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); } break; default: @@ -707,15 +717,26 @@ public sealed class BSLinksetConstraints : BSLinkset linkInfo.solverIterations = valueFloat; opIndex += 2; break; + case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: + valueInt = (int)pParams[opIndex + 1]; + valueBool = ((int)pParams[opIndex + 2] != 0); + if (valueInt >=0 && valueInt < linkInfo.springAxisEnable.Length) + linkInfo.springAxisEnable[valueInt] = valueBool; + opIndex += 3; + break; case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.springDamping = valueFloat; - opIndex += 2; + valueInt = (int)pParams[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 2]; + if (valueInt >=0 && valueInt < linkInfo.springDamping.Length) + linkInfo.springDamping[valueInt] = valueFloat; + opIndex += 3; break; case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.springStiffness = valueFloat; - opIndex += 2; + valueInt = (int)pParams[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 2]; + if (valueInt >=0 && valueInt < linkInfo.springStiffness.Length) + linkInfo.springStiffness[valueInt] = valueFloat; + opIndex += 3; break; default: break; -- cgit v1.1 From cf2cdc191d0a93860da1ff4c42d34138e8f369fb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 24 Aug 2013 08:33:28 -0700 Subject: BulletSim: ability to specify groups of axis to modify in constraint parameters that control multiple axis. Add useLinearReferenceFrameA constraint parameter. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 12 ++++- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 53 ++++++++++++++++++---- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index ef106bd..94367f5 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -406,8 +406,18 @@ public class ExtendedPhysics : INonSharedRegionModule public const int PHYS_PARAM_SPRING_STIFFNESS = 14418; [ScriptConstant] public const int PHYS_PARAM_LINK_TYPE = 14419; + [ScriptConstant] + public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420; + + public const int PHYS_PARAM_MAX = 14420; - public const int PHYS_PARAM_MAX = 14419; + // Used when specifying a parameter that has settings for the three linear and three angular axis + [ScriptConstant] + public const int PHYS_AXIS_ALL = -1; + [ScriptConstant] + public const int PHYS_AXIS_ALL_LINEAR = -2; + [ScriptConstant] + public const int PHYS_AXIS_ALL_ANGULAR = -3; // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index f623231..ff5ac0e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -58,6 +58,7 @@ public sealed class BSLinksetConstraints : BSLinkset public OMV.Quaternion frameInArot; public OMV.Vector3 frameInBloc; public OMV.Quaternion frameInBrot; + public bool useLinearReferenceFrameA; // Spring public bool[] springAxisEnable; public float[] springDamping; @@ -91,6 +92,7 @@ public sealed class BSLinksetConstraints : BSLinkset frameInArot = OMV.Quaternion.Identity; frameInBloc = OMV.Vector3.Zero; frameInBrot = OMV.Quaternion.Identity; + useLinearReferenceFrameA = true; springAxisEnable = new bool[6]; springDamping = new float[6]; springStiffness = new float[6]; @@ -145,7 +147,7 @@ public sealed class BSLinksetConstraints : BSLinkset { constrainSpring.SetSolverIterations(solverIterations); } - for (int ii = 0; ii < 6; ii++) + for (int ii = 0; ii < springAxisEnable.Length; ii++) { constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) @@ -401,7 +403,7 @@ public sealed class BSLinksetConstraints : BSLinkset case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, - true /*useLinearReferenceFrameA*/, + linkInfo.useLinearReferenceFrameA, true /*disableCollisionsBetweenLinkedBodies*/); DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", rootPrim.LocalID, @@ -619,6 +621,7 @@ public sealed class BSLinksetConstraints : BSLinkset bool valueBool; OMV.Vector3 valueVector; OMV.Quaternion valueQuaternion; + int axisLow, axisHigh; int opIndex = 2; while (opIndex < pParams.Length) @@ -720,24 +723,32 @@ public sealed class BSLinksetConstraints : BSLinkset case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: valueInt = (int)pParams[opIndex + 1]; valueBool = ((int)pParams[opIndex + 2] != 0); - if (valueInt >=0 && valueInt < linkInfo.springAxisEnable.Length) - linkInfo.springAxisEnable[valueInt] = valueBool; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springAxisEnable[ii] = valueBool; opIndex += 3; break; case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: valueInt = (int)pParams[opIndex + 1]; valueFloat = (float)pParams[opIndex + 2]; - if (valueInt >=0 && valueInt < linkInfo.springDamping.Length) - linkInfo.springDamping[valueInt] = valueFloat; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springDamping[ii] = valueFloat; opIndex += 3; break; case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: valueInt = (int)pParams[opIndex + 1]; valueFloat = (float)pParams[opIndex + 2]; - if (valueInt >=0 && valueInt < linkInfo.springStiffness.Length) - linkInfo.springStiffness[valueInt] = valueFloat; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springStiffness[ii] = valueFloat; opIndex += 3; break; + case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: + valueBool = (bool)pParams[opIndex + 1]; + linkInfo.useLinearReferenceFrameA = valueBool; + opIndex += 2; + break; default: break; } @@ -760,6 +771,32 @@ public sealed class BSLinksetConstraints : BSLinkset } return ret; } + + // Bullet constraints keep some limit parameters for each linear and angular axis. + // Setting same is easier if there is an easy way to see all or types. + // This routine returns the array limits for the set of axis. + private void GetAxisRange(int rangeSpec, out int low, out int high) + { + switch (rangeSpec) + { + case ExtendedPhysics.PHYS_AXIS_ALL_LINEAR: + low = 0; + high = 2; + break; + case ExtendedPhysics.PHYS_AXIS_ALL_ANGULAR: + low = 3; + high = 5; + break; + case ExtendedPhysics.PHYS_AXIS_ALL: + low = 0; + high = 5; + break; + default: + low = high = rangeSpec; + break; + } + return; + } #endregion // Extension } -- cgit v1.1 From 5827b6e1aabf2e19624faf0141b9611917fb84c5 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 4 Sep 2013 07:56:59 -0700 Subject: BulletSim: add extended physics LSL constants for axis specification. Add specific error warnings for mis-matched parameter types in extended physics functions. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 16 +++- .../Physics/BulletSPlugin/BSConstraintSpring.cs | 6 +- .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 89 ++++++++++++++-------- 3 files changed, 74 insertions(+), 37 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index 94367f5..b0b0bc6 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -415,9 +415,21 @@ public class ExtendedPhysics : INonSharedRegionModule [ScriptConstant] public const int PHYS_AXIS_ALL = -1; [ScriptConstant] - public const int PHYS_AXIS_ALL_LINEAR = -2; + public const int PHYS_AXIS_LINEAR_ALL = -2; [ScriptConstant] - public const int PHYS_AXIS_ALL_ANGULAR = -3; + public const int PHYS_AXIS_ANGULAR_ALL = -3; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_X = 0; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_Y = 1; + [ScriptConstant] + public const int PHYS_AXIS_LINEAR_Z = 2; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_X = 3; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_Y = 4; + [ScriptConstant] + public const int PHYS_AXIS_ANGULAR_Z = 5; // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...]) [ScriptInvocation] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs index 432e5b2..652c94a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs @@ -63,7 +63,7 @@ public sealed class BSConstraintSpring : BSConstraint6Dof public bool SetStiffness(int pIndex, float pStiffness) { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},enable={4}", + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}", m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness); PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness); return true; @@ -71,7 +71,7 @@ public sealed class BSConstraintSpring : BSConstraint6Dof public bool SetDamping(int pIndex, float pDamping) { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},enable={4}", + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}", m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping); PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping); return true; @@ -79,7 +79,7 @@ public sealed class BSConstraintSpring : BSConstraint6Dof public bool SetEquilibriumPoint(int pIndex, float pEqPoint) { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},enable={4}", + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}", m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint); PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint); return true; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index ff5ac0e..b3347bf 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -605,30 +605,32 @@ public sealed class BSLinksetConstraints : BSLinkset // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] case ExtendedPhysics.PhysFunctChangeLinkParams: // There should be two parameters: the childActor and a list of parameters to set - try + if (pParams.Length > 2) { - if (pParams.Length > 2) + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + BSLinkInfo baseLinkInfo = null; + if (TryGetLinkInfo(child, out baseLinkInfo)) { - BSPrimLinkable child = pParams[1] as BSPrimLinkable; - BSLinkInfo baseLinkInfo = null; - if (TryGetLinkInfo(child, out baseLinkInfo)) + BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; + if (linkInfo != null) { - BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; - if (linkInfo != null) + int valueInt; + float valueFloat; + bool valueBool; + OMV.Vector3 valueVector; + OMV.Quaternion valueQuaternion; + int axisLow, axisHigh; + + int opIndex = 2; + while (opIndex < pParams.Length) { - int valueInt; - float valueFloat; - bool valueBool; - OMV.Vector3 valueVector; - OMV.Quaternion valueQuaternion; - int axisLow, axisHigh; - - int opIndex = 2; - while (opIndex < pParams.Length) + int thisOp = 0; + string errMsg = ""; + try { - int thisOp = (int)pParams[opIndex]; + thisOp = (int)pParams[opIndex]; DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", - linkInfo.member.LocalID, thisOp, pParams[opIndex+1]); + linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); switch (thisOp) { case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: @@ -646,89 +648,106 @@ public sealed class BSLinksetConstraints : BSLinkset opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: + errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.frameInAloc = valueVector; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: + errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; linkInfo.frameInArot = valueQuaternion; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: + errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.frameInBloc = valueVector; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: + errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; linkInfo.frameInBrot = valueQuaternion; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: + errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.linearLimitLow = valueVector; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: + errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.linearLimitHigh = valueVector; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: + errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.angularLimitLow = valueVector; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: + errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; valueVector = (OMV.Vector3)pParams[opIndex + 1]; linkInfo.angularLimitHigh = valueVector; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: - valueBool = (bool)pParams[opIndex + 1]; + errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; linkInfo.useFrameOffset = valueBool; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: - valueBool = (bool)pParams[opIndex + 1]; + errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; linkInfo.enableTransMotor = valueBool; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: + errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; valueFloat = (float)pParams[opIndex + 1]; linkInfo.transMotorMaxVel = valueFloat; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: + errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; valueFloat = (float)pParams[opIndex + 1]; linkInfo.transMotorMaxForce = valueFloat; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_CFM: + errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; valueFloat = (float)pParams[opIndex + 1]; linkInfo.cfm = valueFloat; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_ERP: + errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; valueFloat = (float)pParams[opIndex + 1]; linkInfo.erp = valueFloat; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: + errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; valueFloat = (float)pParams[opIndex + 1]; linkInfo.solverIterations = valueFloat; opIndex += 2; break; case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: + errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; valueInt = (int)pParams[opIndex + 1]; - valueBool = ((int)pParams[opIndex + 2] != 0); + valueBool = ((int)pParams[opIndex + 2]) != 0; GetAxisRange(valueInt, out axisLow, out axisHigh); for (int ii = axisLow; ii <= axisHigh; ii++) linkInfo.springAxisEnable[ii] = valueBool; opIndex += 3; break; case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: + errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; valueInt = (int)pParams[opIndex + 1]; valueFloat = (float)pParams[opIndex + 2]; GetAxisRange(valueInt, out axisLow, out axisHigh); @@ -737,6 +756,7 @@ public sealed class BSLinksetConstraints : BSLinkset opIndex += 3; break; case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: + errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; valueInt = (int)pParams[opIndex + 1]; valueFloat = (float)pParams[opIndex + 2]; GetAxisRange(valueInt, out axisLow, out axisHigh); @@ -745,7 +765,8 @@ public sealed class BSLinksetConstraints : BSLinkset opIndex += 3; break; case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: - valueBool = (bool)pParams[opIndex + 1]; + errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; linkInfo.useLinearReferenceFrameA = valueBool; opIndex += 2; break; @@ -753,18 +774,22 @@ public sealed class BSLinksetConstraints : BSLinkset break; } } + catch (InvalidCastException e) + { + m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", + LogHeader, errMsg, e); + } + catch (Exception e) + { + m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); + } } - // Something changed so a rebuild is in order - Refresh(child); } + // Something changed so a rebuild is in order + Refresh(child); } } - catch (Exception e) - { - // There are many ways to mess up the parameters. If not just right don't fail without some error. - m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); - } - break; + break; default: ret = base.Extension(pFunct, pParams); break; @@ -779,11 +804,11 @@ public sealed class BSLinksetConstraints : BSLinkset { switch (rangeSpec) { - case ExtendedPhysics.PHYS_AXIS_ALL_LINEAR: + case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: low = 0; high = 2; break; - case ExtendedPhysics.PHYS_AXIS_ALL_ANGULAR: + case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: low = 3; high = 5; break; -- cgit v1.1 From c5eabb28b4c933cfacefa85381e290372fbc094e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 9 Sep 2013 14:53:16 -0700 Subject: BulletSim: add LSL function and plumbing for setting a spring equilibrium point in the physics engine constraint. --- .../Scripting/ExtendedPhysics/ExtendedPhysics.cs | 4 +++- OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | 6 +++++- .../Physics/BulletSPlugin/BSConstraintSpring.cs | 13 +++++++++++++ .../Physics/BulletSPlugin/BSLinksetConstraints.cs | 20 +++++++++++++++++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs index b0b0bc6..9daf9d7 100755 --- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs @@ -408,8 +408,10 @@ public class ExtendedPhysics : INonSharedRegionModule public const int PHYS_PARAM_LINK_TYPE = 14419; [ScriptConstant] public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420; + [ScriptConstant] + public const int PHYS_PARAM_SPRING_EQUILIBRIUM_POINT = 14421; - public const int PHYS_PARAM_MAX = 14420; + public const int PHYS_PARAM_MAX = 14421; // Used when specifying a parameter that has settings for the three linear and three angular axis [ScriptConstant] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 42b5c49..b47e9a8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs @@ -64,7 +64,7 @@ public abstract class BSConstraint : IDisposable { bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", - BSScene.DetailLogZero, + m_body1.ID, m_body1.ID, m_body1.AddrString, m_body2.ID, m_body2.AddrString, success); @@ -77,7 +77,10 @@ public abstract class BSConstraint : IDisposable { bool ret = false; if (m_enabled) + { + m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high); ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); + } return ret; } @@ -86,6 +89,7 @@ public abstract class BSConstraint : IDisposable bool ret = false; if (m_enabled) { + m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high); ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); } return ret; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs index 652c94a..8e7ddff 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs @@ -85,6 +85,19 @@ public sealed class BSConstraintSpring : BSConstraint6Dof return true; } + public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}", + m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z); + return true; + } + } } \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index b3347bf..aaf92c8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -63,6 +63,8 @@ public sealed class BSLinksetConstraints : BSLinkset public bool[] springAxisEnable; public float[] springDamping; public float[] springStiffness; + public OMV.Vector3 springLinearEquilibriumPoint; + public OMV.Vector3 springAngularEquilibriumPoint; public BSLinkInfoConstraint(BSPrimLinkable pMember) : base(pMember) @@ -102,6 +104,8 @@ public sealed class BSLinksetConstraints : BSLinkset springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; } + springLinearEquilibriumPoint = OMV.Vector3.Zero; + springAngularEquilibriumPoint = OMV.Vector3.Zero; member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); } @@ -155,7 +159,12 @@ public sealed class BSLinksetConstraints : BSLinkset if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) constrainSpring.SetStiffness(ii, springStiffness[ii]); } - constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); + constrainSpring.CalculateTransforms(); + + if (springLinearEquilibriumPoint != OMV.Vector3.Zero) + constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); + else + constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); } break; default: @@ -618,6 +627,7 @@ public sealed class BSLinksetConstraints : BSLinkset float valueFloat; bool valueBool; OMV.Vector3 valueVector; + OMV.Vector3 valueVector2; OMV.Quaternion valueQuaternion; int axisLow, axisHigh; @@ -764,6 +774,14 @@ public sealed class BSLinksetConstraints : BSLinkset linkInfo.springStiffness[ii] = valueFloat; opIndex += 3; break; + case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: + errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; + linkInfo.springLinearEquilibriumPoint = valueVector; + linkInfo.springAngularEquilibriumPoint = valueVector2; + opIndex += 3; + break; case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; valueBool = ((int)pParams[opIndex + 1]) != 0; -- cgit v1.1 From e34385634b56769516c4e0284860f48a5ce371c4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 9 Sep 2013 15:42:57 -0700 Subject: BulletSim: update DLLs and SOs for spring parameters and constraint debugging dump code. --- bin/lib32/BulletSim.dll | Bin 1086976 -> 1095680 bytes bin/lib32/libBulletSim.so | Bin 2317618 -> 2342728 bytes bin/lib64/BulletSim.dll | Bin 1229824 -> 1233920 bytes bin/lib64/libBulletSim.so | Bin 2491923 -> 2520385 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 7987434..9bb7bcd 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 114a597..a4e0f4a 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index b69fcf3..8c96eb7 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index e4d2581..1f76a40 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From 6e39cc316f502855a89c51775e7394b73135ab86 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 10 Sep 2013 17:32:01 -0700 Subject: BulletSim: add ClearCollisionProxyCache function to API. Add proxy cache clearing when some properties are changed. This fixes a problem where objects would stop colliding of they were moved with setPosition mulitple times. --- OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | 10 ++++++++++ OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | 13 +++++++++++++ OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs | 2 ++ OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 12 ++++++++++-- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 8dfb01c..3bd81d4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs @@ -725,6 +725,13 @@ public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); } +public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj) +{ + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr); +} + public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) { BulletWorldUnman worldu = world as BulletWorldUnman; @@ -1713,6 +1720,9 @@ public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index ff2b497..17ebed2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs @@ -169,6 +169,19 @@ private sealed class BulletConstraintXNA : BulletConstraint return true; } + public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body = ((BulletBodyXNA)pBody).rigidBody; + CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; + if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null) + { + world.RemoveCollisionObject(collisionObject); + world.AddCollisionObject(collisionObject); + } + return true; + } + public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) { DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 0b3f467..f7dd158 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs @@ -498,6 +498,8 @@ public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); +public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj); + public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 2efb1a5..47df611 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -300,8 +300,16 @@ public abstract class BSPhysObject : PhysicsActor // Called in taint-time!! public void ActivateIfPhysical(bool forceIt) { - if (IsPhysical && PhysBody.HasPhysicalBody) - PhysScene.PE.Activate(PhysBody, forceIt); + if (PhysBody.HasPhysicalBody) + { + // Clear the collision cache since we've changed some properties. + PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); + if (IsPhysical) + { + // Physical objects might need activating + PhysScene.PE.Activate(PhysBody, forceIt); + } + } } // 'actors' act on the physical object to change or constrain its motion. These can range from -- cgit v1.1 From 8bcf75312739ae382175e21df0ad977ec493ddda Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 10 Sep 2013 17:42:22 -0700 Subject: BulletSim: update DLLs and SOs with ClearCollisionCache inteface calls and constraint debugging messages. --- bin/lib32/BulletSim.dll | Bin 1095680 -> 1096192 bytes bin/lib32/libBulletSim.so | Bin 2342728 -> 2342970 bytes bin/lib64/BulletSim.dll | Bin 1233920 -> 1233920 bytes bin/lib64/libBulletSim.so | Bin 2520385 -> 2520691 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 9bb7bcd..e344f84 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index a4e0f4a..94e1682 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 8c96eb7..31949c8 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 1f76a40..399f4f8 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From b29e9d37e7705e461f71a3a599d95ad79b57e18a Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 11 Sep 2013 12:15:16 -0700 Subject: Change handling of the FetchInventoryDescendents2 capability configuration to allow for external handlers. --- .../Linden/Caps/WebFetchInvDescModule.cs | 59 +++++++++++++--------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 164adeb..340d2e7 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ClientStack.Linden public List folders; } -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; @@ -115,7 +115,7 @@ namespace OpenSim.Region.ClientStack.Linden m_scene.EventManager.OnRegisterCaps -= RegisterCaps; foreach (Thread t in m_workerThreads) - Watchdog.AbortThread(t.ManagedThreadId); + Watchdog.AbortThread(t.ManagedThreadId); m_scene = null; } @@ -296,36 +296,49 @@ namespace OpenSim.Region.ClientStack.Linden requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); lock (responses) - responses[requestID] = response; + responses[requestID] = response; } } private void RegisterCaps(UUID agentID, Caps caps) { - if (m_fetchInventoryDescendents2Url == "") + RegisterFetchDescendentsCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url); + } + + private void RegisterFetchDescendentsCap(UUID agentID, Caps caps, string capName, string url) + { + string capUrl; + + // disable the cap clause + if (url == "") + { return; + } + // handled by the simulator + else if (url == "localhost") + { + capUrl = "/CAPS/" + UUID.Random() + "/"; - // Register this as a poll service - PollServiceInventoryEventArgs args - = new PollServiceInventoryEventArgs(m_scene, "/CAPS/" + UUID.Random() + "/", agentID); - args.Type = PollServiceEventArgs.EventType.Inventory; + // Register this as a poll service + PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, capUrl, agentID); + args.Type = PollServiceEventArgs.EventType.Inventory; - caps.RegisterPollHandler("FetchInventoryDescendents2", args); + caps.RegisterPollHandler(capName, args); + } + // external handler + else + { + capUrl = url; + IExternalCapsModule handler = m_scene.RequestModuleInterface(); + if (handler != null) + handler.RegisterExternalUserCapsHandler(agentID,caps,capName,capUrl); + else + caps.RegisterHandler(capName, capUrl); + } -// MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args); -// -// string hostName = m_scene.RegionInfo.ExternalHostName; -// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; -// string protocol = "http"; -// -// if (MainServer.Instance.UseSSL) -// { -// hostName = MainServer.Instance.SSLCommonName; -// port = MainServer.Instance.SSLPort; -// protocol = "https"; -// } -// -// caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); + // m_log.DebugFormat( + // "[FETCH INVENTORY DESCENDENTS2 MODULE]: Registered capability {0} at {1} in region {2} for {3}", + // capName, capUrl, m_scene.RegionInfo.RegionName, agentID); } // private void DeregisterCaps(UUID agentID, Caps caps) -- cgit v1.1 From dacc20ee48883efe3702c284edff5ee3fa0e96b0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Wed, 11 Sep 2013 16:48:15 -0700 Subject: BulletSim: remove collision cache clearing logic for physical objects. This fixes constraints from getting messed up when properties change. --- OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 47df611..f89b376 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -302,13 +302,16 @@ public abstract class BSPhysObject : PhysicsActor { if (PhysBody.HasPhysicalBody) { - // Clear the collision cache since we've changed some properties. - PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); if (IsPhysical) { // Physical objects might need activating PhysScene.PE.Activate(PhysBody, forceIt); } + else + { + // Clear the collision cache since we've changed some properties. + PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); + } } } -- cgit v1.1 From 3c85afbb431d14a676c00d20bfeeb5e2d13e8eaf Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 12 Sep 2013 11:46:12 -0400 Subject: Allow setting the EntityTransfer-max_distance to 0 to override distance checks. This is to facilitate current viewer work fixing the distance limitations for teleporting. --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 3 +++ bin/OpenSimDefaults.ini | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 4219254..9302784 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -518,6 +518,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) { + if(MaxTransferDistance == 0) + return true; + // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); // // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index e168566..c16dee2 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -652,8 +652,11 @@ [EntityTransfer] - ; The maximum distance in regions that an agent is allowed to teleport along the x or y axis - ; This is set to 16383 because current viewers can't handle teleports that are greater than this distance + ; The maximum distance in regions that an agent is allowed to teleport + ; along the x or y axis. This is set to 16383 because current viewers + ; can't handle teleports that are greater than this distance + ; Setting to 0 will allow teleports of any distance + ; max_distance = 16383 ; Minimum user level required for HyperGrid teleports -- cgit v1.1 From 2d7adcb22fdd349b819ac4ffc85029a7664406cc Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 12 Sep 2013 13:07:18 -0700 Subject: BulletSim: update DLLs and SOs to disable Bullet's internal profiling. This was accidentily left on. This version should make performance better and fix the memory leak. --- bin/lib32/BulletSim.dll | Bin 1096192 -> 1093632 bytes bin/lib32/libBulletSim.so | Bin 2342970 -> 2332216 bytes bin/lib64/BulletSim.dll | Bin 1233920 -> 1230848 bytes bin/lib64/libBulletSim.so | Bin 2520691 -> 2522559 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index e344f84..7c16cb5 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 94e1682..3d2737b 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 31949c8..3afdf63 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 399f4f8..6a17848 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ -- cgit v1.1 From 07d6a0385fdbb0559a878f0884505459e08e7867 Mon Sep 17 00:00:00 2001 From: Talun Date: Tue, 10 Sep 2013 10:56:34 +0100 Subject: 6762: llList2Key fails to convert a string in a list to a key llGetPrimitiveParams changed to return the sculpty key as an LSL_String so that type checking in llList2Key will work --- OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 34e2b4d..924f4d9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -8483,7 +8483,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; case ScriptBaseClass.PRIM_TYPE_SCULPT: - res.Add(Shape.SculptTexture.ToString()); + res.Add(new LSL_String(Shape.SculptTexture.ToString())); res.Add(new LSL_Integer(Shape.SculptType)); break; -- cgit v1.1 From 53de6d94ea5e80b873864be32f1781bc2f7017c9 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 12 Sep 2013 23:38:50 +0100 Subject: minor: replace spaces with tabs for see_into_region setting --- bin/OpenSimDefaults.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index c16dee2..7954a14 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -86,8 +86,8 @@ ;; from the selected region_info_source. allow_regionless = false - ;; Allow child agents to see into the region even if their root counterpart isn't allowed in here - see_into_region = true + ;; Allow child agents to see into the region even if their root counterpart isn't allowed in here + see_into_region = true ; Maximum number of position, rotation and scale changes for each prim that the simulator will store for later undos ; Increasing this number will increase memory usage. -- cgit v1.1 From 1c7accf9500250abad243eaeb6f6baadf7644e78 Mon Sep 17 00:00:00 2001 From: teravus Date: Sat, 24 Aug 2013 05:55:53 -0500 Subject: * Fix a null ref that causes a stack unwind when crossing borders. Less stack unwinding.. the faster it goes. * Tweak XEngine so that it's partially functional again. It's still not great, but basic things work. (cherry picked from commit 01c3be27460fd3f28efd17b8d6606b883350f653) --- .../CoreModules/Avatar/Combat/CombatModule.cs | 2 + .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 3 +- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 56 +++++++++++++++++----- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs index 343cdb5..c52d586 100644 --- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs @@ -182,6 +182,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule try { ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); + if (obj == null) + return; if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) { diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 2fb073d..275b608 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -231,6 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance ItemID = ScriptTask.ItemID; AssetID = ScriptTask.AssetID; } + LocalID = part.LocalId; PrimName = part.ParentGroup.Name; StartParam = startParam; @@ -1240,4 +1241,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance return null; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 9d1e143..27d7674 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1316,13 +1316,21 @@ namespace OpenSim.Region.ScriptEngine.XEngine ScriptInstance instance = null; // Create the object record + UUID appDomain = assetID; + + + lockScriptsForRead(true); if ((!m_Scripts.ContainsKey(itemID)) || (m_Scripts[itemID].AssetID != assetID)) { lockScriptsForRead(false); - - UUID appDomain = assetID; + instance = new ScriptInstance(this, part, + item, + startParam, postOnRez, + m_MaxScriptQueue); + + if (part.ParentGroup.IsAttachment) appDomain = part.ParentGroup.RootPart.UUID; @@ -1345,9 +1353,39 @@ namespace OpenSim.Region.ScriptEngine.XEngine sandbox = AppDomain.CreateDomain( m_Scene.RegionInfo.RegionID.ToString(), evidence, appSetup); - m_AppDomains[appDomain].AssemblyResolve += - new ResolveEventHandler( - AssemblyResolver.OnAssemblyResolve); + if (m_AppDomains.ContainsKey(appDomain)) + { + m_AppDomains[appDomain].AssemblyResolve += + new ResolveEventHandler( + AssemblyResolver.OnAssemblyResolve); + if (m_DomainScripts.ContainsKey(appDomain)) + { + m_DomainScripts[appDomain].Add(itemID); + } + else + { + m_DomainScripts.Add(appDomain, new List()); + m_DomainScripts[appDomain].Add(itemID); + } + } + else + { + m_AppDomains.Add(appDomain, sandbox); + m_AppDomains[appDomain].AssemblyResolve += + new ResolveEventHandler( + AssemblyResolver.OnAssemblyResolve); + if (m_DomainScripts.ContainsKey(appDomain)) + { + m_DomainScripts[appDomain].Add(itemID); + } + else + { + m_DomainScripts.Add(appDomain, new List()); + m_DomainScripts[appDomain].Add(itemID); + } + + } + } else { @@ -1373,12 +1411,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine return false; } } - m_DomainScripts[appDomain].Add(itemID); - - instance = new ScriptInstance(this, part, - item, - startParam, postOnRez, - m_MaxScriptQueue); + instance.Load(m_AppDomains[appDomain], assembly, stateSource); // m_log.DebugFormat( @@ -1502,6 +1535,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (handlerObjectRemoved != null) { SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); + if (part != null) handlerObjectRemoved(part.UUID); } -- cgit v1.1 From 120b6948ed873a3af7713b411b956b8cb4c7f516 Mon Sep 17 00:00:00 2001 From: teravus Date: Sat, 24 Aug 2013 18:55:21 -0500 Subject: * This fixes the border crossing offsets by storing the final keyframe location in the hijacked variable KeyFrame.AngularVelocity. When steps in OnTimer <= 0.0, normalize the final position by Constants.RegionSize and move the object there. The hack here is KeyFrame.AngularVelocity probably isn't the right name for this variable because it's the un-mucked with keyframe position. When you determine the feasibility of changing the name without affecting the serialization of existing objects in world... It's simply a name change to KeyFrame.FinalPosition or something proper. (cherry picked from commit e0399ccaec68889c12e4679b4d62142b49b379df) --- OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index 29652aa..4d153da 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs @@ -498,6 +498,7 @@ namespace OpenSim.Region.Framework.Scenes k.Position = pos; // k.Velocity = Vector3.Zero; } + k.AngularVelocity = (Vector3)k.Position; k.StartRotation = rot; if (k.Rotation.HasValue) @@ -632,13 +633,13 @@ namespace OpenSim.Region.Framework.Scenes // Do the frame processing double steps = (double)m_currentFrame.TimeMS / tickDuration; - + if (steps <= 0.0) { m_group.RootPart.Velocity = Vector3.Zero; m_group.RootPart.AngularVelocity = Vector3.Zero; - m_nextPosition = (Vector3)m_currentFrame.Position; + m_nextPosition = NormalizeVector(m_currentFrame.AngularVelocity); m_group.AbsolutePosition = m_nextPosition; // we are sending imediate updates, no doing force a extra terseUpdate @@ -726,7 +727,26 @@ namespace OpenSim.Region.Framework.Scenes m_group.SendGroupRootTerseUpdate(); } } + private Vector3 NormalizeVector(Vector3? pPosition) + { + if (pPosition == null) + return Vector3.Zero; + + Vector3 tmp = (Vector3) pPosition; + while (tmp.X > Constants.RegionSize) + tmp.X -= Constants.RegionSize; + while (tmp.X < 0) + tmp.X += Constants.RegionSize; + while (tmp.Y > Constants.RegionSize) + tmp.Y -= Constants.RegionSize; + while (tmp.Y < 0) + tmp.Y += Constants.RegionSize; + + return tmp; + + + } public Byte[] Serialize() { StopTimer(); -- cgit v1.1 From 3f0fa9f707e7e09f6dd9ad0becad18d5ffa4cb7b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 16 Sep 2013 19:45:42 +0100 Subject: To avoid viewers (particularly on the Hypergrid) from permanently caching a UUID -> "Unknown User" binding, drop the binding request rather than replying with "Unknown User" By not binding UUID -> "Unknown User", we leave open the possibility that the binding may be correctly resolved at a later time, which can still happen in some Hypergrid situations. Observed behaviour of LL viewer 3.3.4 is that a dropped bind request is not retried until the next session. --- .../UserManagement/UserManagementModule.cs | 77 ++++++++++++---------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 8c983e6..25e8d69 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -178,17 +178,20 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); - bool foundRealName = TryGetUserNames(uuid, names); - - if (names.Length == 2) - { - if (!foundRealName) - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, client.Name); + // As least upto September 2013, clients permanently cache UUID -> Name bindings. Some clients + // appear to clear this when the user asks it to clear the cache, but others may not. + // + // So to avoid clients + // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will + // instead drop the request entirely. + if (TryGetUserNames(uuid, names)) client.SendNameReply(uuid, names[0], names[1]); - } +// else +// m_log.DebugFormat( +// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", +// uuid, client.Name); }); - } } @@ -391,7 +394,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } names[0] = "Unknown"; - names[1] = "UserUMMTGUN8"; + names[1] = "UserUMMTGUN9"; return false; } @@ -539,7 +542,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement AddUser(uuid, homeURL + ";" + first + " " + last); } - public void AddUser (UUID id, string creatorData) + public void AddUser(UUID id, string creatorData) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); @@ -549,24 +552,24 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (oldUser != null) { - if (creatorData == null || creatorData == String.Empty) - { - //ignore updates without creator data - return; - } - - //try update unknown users, but don't update anyone else - if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) - { - lock (m_UserCache) - m_UserCache.Remove(id); - m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); - } - else - { +// if (creatorData == null || creatorData == String.Empty) +// { +// //ignore updates without creator data +// return; +// } +// +// //try update unknown users, but don't update anyone else +// if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) +// { +// lock (m_UserCache) +// m_UserCache.Remove(id); +// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); +// } +// else +// { //we have already a valid user within the cache return; - } +// } } UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); @@ -602,15 +605,19 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (parts.Length >= 2) user.FirstName = parts[1].Replace(' ', '.'); } - else - { - // Temporarily add unknown user entries of this type into the cache so that we can distinguish - // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding - // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or - // disappeared. - user.FirstName = "Unknown"; - user.LastName = "UserUMMAU4"; - } + + // To avoid issues with clients, particularly Hypergrid ones, permanently caching + // UUID -> "Unknown User" name bindings, elsewhere we will drop such requests rather than replying. + // This also means that we cannot add an unknown user binding to the cache here. +// else +// { +// // Temporarily add unknown user entries of this type into the cache so that we can distinguish +// // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding +// // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or +// // disappeared. +// user.FirstName = "Unknown"; +// user.LastName = "UserUMMAU4"; +// } AddUserInternal(user); } -- cgit v1.1 From 60cf42cb8dda3931c87267c989eb7bb9abe5da2f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 16 Sep 2013 22:56:08 +0100 Subject: Make llGetLinkPrimitiveParams() abort and return existing list of params when it encounters an invalid link number, rather than throwing an exception Addresses http://opensimulator.org/mantis/view.php?id=6768 Thanks to talun for the patch on that commit - in the end I took a different approach that also deals with invalid PRIM_LINK_TARGET However, not yet generating the same warning on invalid PRIM_LINK_TARGET as seen on LL grid This commit also adds regression tests for some cases of llGetLinkPrimitiveParams() --- .../Shared/Api/Implementation/LSL_Api.cs | 13 +- .../Shared/Tests/LSL_ApiObjectTests.cs | 385 +++++++++++++++++++++ .../ScriptEngine/Shared/Tests/LSL_ApiTest.cs | 238 +------------ 3 files changed, 397 insertions(+), 239 deletions(-) create mode 100644 OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 924f4d9..bd451a5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -8190,6 +8190,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api while (true) { +// m_log.DebugFormat( +// "[LSL API]: GetEntityParams has {0} rules with scene entity named {1}", +// rules.Length, entity != null ? entity.Name : "NULL"); + + if (entity == null) + return result; + if (entity is SceneObjectPart) remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result); else @@ -8400,7 +8407,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api while (idx < rules.Length) { int code = (int)rules.GetLSLIntegerItem(idx++); - int remain = rules.Length-idx; + int remain = rules.Length - idx; switch (code) { @@ -8777,7 +8784,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api )); break; case (int)ScriptBaseClass.PRIM_LINK_TARGET: - if(remain < 3) + + // TODO: Should be issuing a runtime script warning in this case. + if (remain < 3) return null; return rules.GetSublist(idx, -1); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs new file mode 100644 index 0000000..ff87cc1 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs @@ -0,0 +1,385 @@ +/* + * 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.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.Instance; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; +using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; +using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + [TestFixture] + public class LSL_ApiObjectTests : OpenSimTestCase + { + private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; + private const float FLOAT_ACCURACY = 0.00005f; + + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestllGetLinkPrimitiveParams() + { + TestHelpers.InMethod(); + TestHelpers.EnableLogging(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 11, 12); + m_scene.AddSceneObject(grp1); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, null, null); + + // Check simple 1 prim case + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams(1, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(1)); + } + + // Check invalid parameters are ignored + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams(3, new LSL_List(new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(0)); + } + + // Check all parameters are ignored if an initial bad link is given + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 3, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(1), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(0)); + } + + // Check only subsequent parameters are ignored when we hit the first bad link number + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 1, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(3), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(1)); + } + } + + [Test] + // llSetPrimitiveParams and llGetPrimitiveParams test. + public void TestllSetPrimitiveParams() + { + TestHelpers.InMethod(); + + // Create Prim1. + Scene scene = new SceneHelpers().SetupScene(); + string obj1Name = "Prim1"; + UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); + SceneObjectPart part1 = + new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, + Vector3.Zero, Quaternion.Identity, + Vector3.Zero) { Name = obj1Name, UUID = objUuid }; + Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, part1, null, null); + + // Note that prim hollow check is passed with the other prim params in order to allow the + // specification of a different check value from the prim param. A cylinder, prism, sphere, + // torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below + // specifies a value of 95% and checks to see if 70% was properly returned. + + // Test a sphere. + CheckllSetPrimitiveParams( + apiGrp1, + "test 1", // Prim test identification string + new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size + ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type + ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type + new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut + 0.80f, // Prim hollow + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple + 0.80f); // Prim hollow check + + // Test a prism. + CheckllSetPrimitiveParams( + apiGrp1, + "test 2", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type + ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.90f, // Prim hollow + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.90f); // Prim hollow check + + // Test a box. + CheckllSetPrimitiveParams( + apiGrp1, + "test 3", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_BOX, // Prim type + ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.95f, // Prim hollow + new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.95f); // Prim hollow check + + // Test a tube. + CheckllSetPrimitiveParams( + apiGrp1, + "test 4", // Prim test identification string + new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size + ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type + ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.00f, // Prim hollow + new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist + new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size + // Expression for y selected to test precision problems during byte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper + 1.11f, // Prim revolutions + 0.88f, // Prim radius + 0.95f, // Prim skew + 0.00f); // Prim hollow check + + // Test a prism. + CheckllSetPrimitiveParams( + apiGrp1, + "test 5", // Prim test identification string + new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size + ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type + ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type + new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut + 0.95f, // Prim hollow + // Expression for x selected to test precision problems during sbyte + // cast in SetPrimitiveShapeBlockParams. + new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper + new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + 0.70f); // Prim hollow check + + // Test a sculpted prim. + CheckllSetPrimitiveParams( + apiGrp1, + "test 6", // Prim test identification string + new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size + ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type + "be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map + ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type + } + + // Set prim params for a box, cylinder or prism and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, + float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primTaper, primShear)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 6), primTest + " prim taper"); + CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear"); + } + + // Set prim params for a sphere and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primDimple)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primDimple, api.llList2Vector(primParams, 6), primTest + " prim dimple"); + } + + // Set prim params for a torus, tube or ring and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, + LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, + float primRev, float primRadius, float primSkew, float primHollowCheck) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primHoleType, + primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut, + primTaper, primRev, primRadius, primSkew)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Valdate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primHoleType, api.llList2Integer(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); + CheckllSetPrimitiveParamsVector(primCut, api.llList2Vector(primParams, 3), primTest + " prim cut"); + Assert.AreEqual(primHollowCheck, api.llList2Float(primParams, 4), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); + CheckllSetPrimitiveParamsVector(primTwist, api.llList2Vector(primParams, 5), primTest + " prim twist"); + CheckllSetPrimitiveParamsVector(primHoleSize, api.llList2Vector(primParams, 6), primTest + " prim hole size"); + CheckllSetPrimitiveParamsVector(primShear, api.llList2Vector(primParams, 7), primTest + " prim shear"); + CheckllSetPrimitiveParamsVector(primProfCut, api.llList2Vector(primParams, 8), primTest + " prim profile cut"); + CheckllSetPrimitiveParamsVector(primTaper, api.llList2Vector(primParams, 9), primTest + " prim taper"); + Assert.AreEqual(primRev, api.llList2Float(primParams, 10), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim revolutions fail"); + Assert.AreEqual(primRadius, api.llList2Float(primParams, 11), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim radius fail"); + Assert.AreEqual(primSkew, api.llList2Float(primParams, 12), FLOAT_ACCURACY, + "TestllSetPrimitiveParams " + primTest + " prim skew fail"); + } + + // Set prim params for a sculpted prim and check results. + public void CheckllSetPrimitiveParams(LSL_Api api, string primTest, + LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType) + { + // Set the prim params. + api.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, + ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType)); + + // Get params for prim to validate settings. + LSL_Types.list primParams = + api.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); + + // Validate settings. + CheckllSetPrimitiveParamsVector(primSize, api.llList2Vector(primParams, 0), primTest + " prim size"); + Assert.AreEqual(primType, api.llList2Integer(primParams, 1), + "TestllSetPrimitiveParams " + primTest + " prim type check fail"); + Assert.AreEqual(primMap, (string)api.llList2String(primParams, 2), + "TestllSetPrimitiveParams " + primTest + " prim map check fail"); + Assert.AreEqual(primSculptType, api.llList2Integer(primParams, 3), + "TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail"); + } + + public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg) + { + // Check each vector component against expected result. + Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on x component"); + Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on y component"); + Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY, + "TestllSetPrimitiveParams " + msg + " vector check fail on z component"); + } + + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index e97ae06..7e3726a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -47,9 +47,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests [TestFixture, LongRunning] public class LSL_ApiTest { - private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; - private const float FLOAT_ACCURACY = 0.00005f; + private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; private LSL_Api m_lslApi; [SetUp] @@ -255,241 +254,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests } [Test] - // llSetPrimitiveParams and llGetPrimitiveParams test. - public void TestllSetPrimitiveParams() - { - TestHelpers.InMethod(); - - // Create Prim1. - Scene scene = new SceneHelpers().SetupScene(); - string obj1Name = "Prim1"; - UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); - SceneObjectPart part1 = - new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, - Vector3.Zero, Quaternion.Identity, - Vector3.Zero) { Name = obj1Name, UUID = objUuid }; - Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part1), false), Is.True); - - // Note that prim hollow check is passed with the other prim params in order to allow the - // specification of a different check value from the prim param. A cylinder, prism, sphere, - // torus or ring, with a hole shape of square, is limited to a hollow of 70%. Test 5 below - // specifies a value of 95% and checks to see if 70% was properly returned. - - // Test a sphere. - CheckllSetPrimitiveParams( - "test 1", // Prim test identification string - new LSL_Types.Vector3(6.0d, 9.9d, 9.9d), // Prim size - ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type - ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type - new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut - 0.80f, // Prim hollow - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple - 0.80f); // Prim hollow check - - // Test a prism. - CheckllSetPrimitiveParams( - "test 2", // Prim test identification string - new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size - ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type - ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.90f, // Prim hollow - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.90f); // Prim hollow check - - // Test a box. - CheckllSetPrimitiveParams( - "test 3", // Prim test identification string - new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size - ScriptBaseClass.PRIM_TYPE_BOX, // Prim type - ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.95f, // Prim hollow - new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.95f); // Prim hollow check - - // Test a tube. - CheckllSetPrimitiveParams( - "test 4", // Prim test identification string - new LSL_Types.Vector3(4.2d, 4.2d, 4.2d), // Prim size - ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type - ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.00f, // Prim hollow - new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size - // Expression for y selected to test precision problems during byte - // cast in SetPrimitiveShapeParams. - new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut - // Expression for y selected to test precision problems during sbyte - // cast in SetPrimitiveShapeParams. - new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper - 1.11f, // Prim revolutions - 0.88f, // Prim radius - 0.95f, // Prim skew - 0.00f); // Prim hollow check - - // Test a prism. - CheckllSetPrimitiveParams( - "test 5", // Prim test identification string - new LSL_Types.Vector3(3.5d, 3.5d, 3.5d), // Prim size - ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type - ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type - new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.95f, // Prim hollow - // Expression for x selected to test precision problems during sbyte - // cast in SetPrimitiveShapeBlockParams. - new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist - // Expression for y selected to test precision problems during sbyte - // cast in SetPrimitiveShapeParams. - new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.70f); // Prim hollow check - - // Test a sculpted prim. - CheckllSetPrimitiveParams( - "test 6", // Prim test identification string - new LSL_Types.Vector3(2.0d, 2.0d, 2.0d), // Prim size - ScriptBaseClass.PRIM_TYPE_SCULPT, // Prim type - "be293869-d0d9-0a69-5989-ad27f1946fd4", // Prim map - ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE); // Prim sculpt type - } - - // Set prim params for a box, cylinder or prism and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, - float primHollowCheck) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primHoleType, - primCut, primHollow, primTwist, primTaper, primShear)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Validate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); - CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); - Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); - CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); - CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 6), primTest + " prim taper"); - CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear"); - } - - // Set prim params for a sphere and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primHoleType, - primCut, primHollow, primTwist, primDimple)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Validate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); - CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); - Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); - CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); - CheckllSetPrimitiveParamsVector(primDimple, m_lslApi.llList2Vector(primParams, 6), primTest + " prim dimple"); - } - - // Set prim params for a torus, tube or ring and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, - LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, - float primRev, float primRadius, float primSkew, float primHollowCheck) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primHoleType, - primCut, primHollow, primTwist, primHoleSize, primShear, primProfCut, - primTaper, primRev, primRadius, primSkew)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Valdate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primHoleType, m_lslApi.llList2Integer(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim hole default check fail"); - CheckllSetPrimitiveParamsVector(primCut, m_lslApi.llList2Vector(primParams, 3), primTest + " prim cut"); - Assert.AreEqual(primHollowCheck, m_lslApi.llList2Float(primParams, 4), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim hollow check fail"); - CheckllSetPrimitiveParamsVector(primTwist, m_lslApi.llList2Vector(primParams, 5), primTest + " prim twist"); - CheckllSetPrimitiveParamsVector(primHoleSize, m_lslApi.llList2Vector(primParams, 6), primTest + " prim hole size"); - CheckllSetPrimitiveParamsVector(primShear, m_lslApi.llList2Vector(primParams, 7), primTest + " prim shear"); - CheckllSetPrimitiveParamsVector(primProfCut, m_lslApi.llList2Vector(primParams, 8), primTest + " prim profile cut"); - CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 9), primTest + " prim taper"); - Assert.AreEqual(primRev, m_lslApi.llList2Float(primParams, 10), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim revolutions fail"); - Assert.AreEqual(primRadius, m_lslApi.llList2Float(primParams, 11), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim radius fail"); - Assert.AreEqual(primSkew, m_lslApi.llList2Float(primParams, 12), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim skew fail"); - } - - // Set prim params for a sculpted prim and check results. - public void CheckllSetPrimitiveParams(string primTest, - LSL_Types.Vector3 primSize, int primType, string primMap, int primSculptType) - { - // Set the prim params. - m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, - ScriptBaseClass.PRIM_TYPE, primType, primMap, primSculptType)); - - // Get params for prim to validate settings. - LSL_Types.list primParams = - m_lslApi.llGetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, ScriptBaseClass.PRIM_TYPE)); - - // Validate settings. - CheckllSetPrimitiveParamsVector(primSize, m_lslApi.llList2Vector(primParams, 0), primTest + " prim size"); - Assert.AreEqual(primType, m_lslApi.llList2Integer(primParams, 1), - "TestllSetPrimitiveParams " + primTest + " prim type check fail"); - Assert.AreEqual(primMap, (string)m_lslApi.llList2String(primParams, 2), - "TestllSetPrimitiveParams " + primTest + " prim map check fail"); - Assert.AreEqual(primSculptType, m_lslApi.llList2Integer(primParams, 3), - "TestllSetPrimitiveParams " + primTest + " prim type scuplt check fail"); - } - - public void CheckllSetPrimitiveParamsVector(LSL_Types.Vector3 vecCheck, LSL_Types.Vector3 vecReturned, string msg) - { - // Check each vector component against expected result. - Assert.AreEqual(vecCheck.x, vecReturned.x, VECTOR_COMPONENT_ACCURACY, - "TestllSetPrimitiveParams " + msg + " vector check fail on x component"); - Assert.AreEqual(vecCheck.y, vecReturned.y, VECTOR_COMPONENT_ACCURACY, - "TestllSetPrimitiveParams " + msg + " vector check fail on y component"); - Assert.AreEqual(vecCheck.z, vecReturned.z, VECTOR_COMPONENT_ACCURACY, - "TestllSetPrimitiveParams " + msg + " vector check fail on z component"); - } - - [Test] public void TestllVecNorm() { TestHelpers.InMethod(); -- cgit v1.1 From f99dae03cb1f5ab7215de1f7741befc3f0856840 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 16 Sep 2013 23:00:40 +0100 Subject: Fix bug where using PRIM_LINK_TARGET with only two remaining list items (e.g. link number then PRIM_ROTATION) would not return the parameter Extended regression test for this case --- .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 4 ++-- .../Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs | 14 ++++++++++++++ 2 files changed, 16 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 bd451a5..975bf2d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -8202,7 +8202,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else remaining = GetAgentParams((ScenePresence)entity, rules, ref result); - if (remaining == null || remaining.Length <= 2) + if (remaining == null || remaining.Length < 2) return result; int linknumber = remaining.GetLSLIntegerItem(0); @@ -8786,7 +8786,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case (int)ScriptBaseClass.PRIM_LINK_TARGET: // TODO: Should be issuing a runtime script warning in this case. - if (remain < 3) + if (remain < 2) return null; return rules.GetSublist(idx, -1); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs index ff87cc1..ed61dc0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiObjectTests.cs @@ -100,6 +100,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests Assert.That(resList.Length, Is.EqualTo(1)); } + // Check 2 prim case + { + LSL_List resList + = apiGrp1.llGetLinkPrimitiveParams( + 1, + new LSL_List( + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION), + new LSL_Integer(ScriptBaseClass.PRIM_LINK_TARGET), + new LSL_Integer(2), + new LSL_Integer(ScriptBaseClass.PRIM_ROTATION))); + + Assert.That(resList.Length, Is.EqualTo(2)); + } + // Check invalid parameters are ignored { LSL_List resList -- cgit v1.1 From 2603a2891bd6e4e20d9169c4a74eaabf9b44fba0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 16 Sep 2013 23:26:13 +0100 Subject: Reinsert comments about possible race conditions when sending bulk inventory updates on non-flag clothing editing --- OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index c4b07a5..69b5f43 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -512,6 +512,9 @@ namespace OpenSim.Region.Framework.Scenes // This MAY be problematic, if it is, another solution // needs to be found. If inventory item flags are updated // the viewer's notion of the item needs to be refreshed. + // + // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start + // failing frequently. Possibly this is a race with a separate transaction that uploads the asset. if (sendUpdate) remoteClient.SendBulkUpdateInventory(item); } -- cgit v1.1 From 69ec85f4911de3218e0efb910fdbb1725e81e4ae Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 17 Sep 2013 00:02:36 +0100 Subject: Fix issue in recent 3f0fa9f7 where the code start adding unknown user cache entries with no name --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 25e8d69..63f78ac 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -602,8 +602,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement user.LastName = "@unknown"; } } + if (parts.Length >= 2) user.FirstName = parts[1].Replace(' ', '.'); + + AddUserInternal(user); } // To avoid issues with clients, particularly Hypergrid ones, permanently caching @@ -618,8 +621,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // user.FirstName = "Unknown"; // user.LastName = "UserUMMAU4"; // } - - AddUserInternal(user); } } -- cgit v1.1 From 845d2b193a2e2058cfe89e06e0589f38c8103eb3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 17 Sep 2013 00:54:53 +0100 Subject: Comment out warning about no grid user found in UMM.TryGetUserNamesFromServices() for now --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 63f78ac..80b6ac1 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -388,10 +388,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); } - else - { - m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); - } +// else +// { +// m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); +// } names[0] = "Unknown"; names[1] = "UserUMMTGUN9"; -- cgit v1.1 From 1d2466889a3f184ff86d0d607ab3d2d10b1b4e16 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 17 Sep 2013 01:20:55 +0100 Subject: Reinstate insertion of "Unknown UserUMMAU4" now, as naive removing may be generating too many repeating user requests from other sources. Leaves in the dropping of the client GUN8 (now 9) uuid binding message, since this was the much more common case from the viewer-side and this can only affect viewers. --- .../UserManagement/UserManagementModule.cs | 66 ++++++++++------------ 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 80b6ac1..bb2bbe3 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -388,10 +388,10 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); } -// else -// { -// m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); -// } + else + { + m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); + } names[0] = "Unknown"; names[1] = "UserUMMTGUN9"; @@ -552,24 +552,24 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (oldUser != null) { -// if (creatorData == null || creatorData == String.Empty) -// { -// //ignore updates without creator data -// return; -// } -// -// //try update unknown users, but don't update anyone else -// if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) -// { -// lock (m_UserCache) -// m_UserCache.Remove(id); -// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); -// } -// else -// { + if (creatorData == null || creatorData == String.Empty) + { + //ignore updates without creator data + return; + } + + //try update unknown users, but don't update anyone else + if (oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) + { + lock (m_UserCache) + m_UserCache.Remove(id); + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); + } + else + { //we have already a valid user within the cache return; -// } + } } UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); @@ -605,22 +605,18 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement if (parts.Length >= 2) user.FirstName = parts[1].Replace(' ', '.'); - - AddUserInternal(user); } - - // To avoid issues with clients, particularly Hypergrid ones, permanently caching - // UUID -> "Unknown User" name bindings, elsewhere we will drop such requests rather than replying. - // This also means that we cannot add an unknown user binding to the cache here. -// else -// { -// // Temporarily add unknown user entries of this type into the cache so that we can distinguish -// // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding -// // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or -// // disappeared. -// user.FirstName = "Unknown"; -// user.LastName = "UserUMMAU4"; -// } + else + { + // Temporarily add unknown user entries of this type into the cache so that we can distinguish + // this source from other recent (hopefully resolved) bugs that fail to retrieve a user name binding + // TODO: Can be removed when GUN* unknown users have definitely dropped significantly or + // disappeared. + user.FirstName = "Unknown"; + user.LastName = "UserUMMAU4"; + } + + AddUserInternal(user); } } -- cgit v1.1 From 7dbc93c62a6803fbe201e933b8bc1374b48869ad Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 21:41:51 +0100 Subject: Change logging to provide more information on LLUDPServer.HandleCompleteMovementIntoRegion() Add more information on which endpoint sent the packet when we have to wait and if we end up dropping the packet Only check if the client is active - other checks are redundant since they can only failed if IsActve = false --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 49 +++++++++++++++++----- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 102e581..cdc1668 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1693,31 +1693,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; // Determine which agent this packet came from + // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination + // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode + // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these + // packets asynchronously, we need to account for this thread proceeding more quickly than the + // UseCircuitCode thread. int count = 20; - bool ready = false; - while (!ready && count-- > 0) + while (count-- > 0) { - if (m_scene.TryGetClient(endPoint, out client) && client.IsActive && client.SceneAgent != null) + if (m_scene.TryGetClient(endPoint, out client)) { - LLClientView llClientView = (LLClientView)client; - LLUDPClient udpClient = llClientView.UDPClient; - if (udpClient != null && udpClient.IsConnected) - ready = true; + if (client.IsActive) + { + break; + } else { - m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); - Thread.Sleep(200); + // This check exists to catch a condition where the client has been closed by another thread + // but has not yet been removed from the client manager (and possibly a new connection has + // not yet been established). + m_log.DebugFormat( + "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} for {1} in {2} but client is not active. Waiting.", + endPoint, client.Name, m_scene.Name); } } else { - m_log.Debug("[LLUDPSERVER]: Received a CompleteMovementIntoRegion in " + m_scene.RegionInfo.RegionName + " (not ready yet)"); + m_log.DebugFormat( + "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} in {1} but no client exists. Waiting.", + endPoint, m_scene.Name); + Thread.Sleep(200); } } if (client == null) + { + m_log.DebugFormat( + "[LLUDPSERVER]: No client found for CompleteMovementIntoRegion from {0} in {1} after wait. Dropping.", + endPoint, m_scene.Name); + return; + } + else if (!client.IsActive) + { + // This check exists to catch a condition where the client has been closed by another thread + // but has not yet been removed from the client manager. + // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging + // purposes. + m_log.DebugFormat( + "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} for {1} in {2} but client is not active after wait. Dropping.", + endPoint, client.Name, m_scene.Name); + + return; + } IncomingPacket incomingPacket1; -- cgit v1.1 From f4d82a56f4c13bd24305e008418819edcfdc549d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 22:09:46 +0100 Subject: Double the time spent waiting for a UseCircuitCode packet in LLUDPServer.HandleCompleteMovementIntoRegion() This is to deal with one aspect of http://opensimulator.org/mantis/view.php?id=6755 With the V2 teleport arrangements, viewers appear to send the single UseCircuitCode and CompleteAgentMovement packets immediately after each other Possibly, on occasion a poor network might drop the initial UseCircuitCode packet and by the time it retries, the CompleteAgementMovement has timed out and the teleport fails. There's no apparant harm in doubling the wait time (most times only one wait will be performed) so trying this. --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index cdc1668..b1752c1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1698,7 +1698,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these // packets asynchronously, we need to account for this thread proceeding more quickly than the // UseCircuitCode thread. - int count = 20; + int count = 40; while (count-- > 0) { if (m_scene.TryGetClient(endPoint, out client)) -- cgit v1.1 From 3ce46adb2a614dda85b8207bb327dae6024824d8 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 22:56:00 +0100 Subject: minor: Make log message when Scene.IncomingChildAgentDateUpdate() more explicit that there is a problem if it still finds the agent to be a child if the sender wanted to wait till it became root Add some comments about the mssage sequence, though much more data is at http://opensimulator.org/wiki/Teleports --- OpenSim/Region/Framework/Scenes/Scene.cs | 11 ++++++++--- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e00206f..6c9a8df 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4338,9 +4338,14 @@ namespace OpenSim.Region.Framework.Scenes while (sp.IsChildAgent && ntimes-- > 0) Thread.Sleep(1000); - m_log.DebugFormat( - "[SCENE]: Found presence {0} {1} {2} in {3} after {4} waits", - sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", Name, 20 - ntimes); + if (sp.IsChildAgent) + m_log.DebugFormat( + "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}", + sp.Name, sp.UUID, Name); + else + m_log.DebugFormat( + "[SCENE]: Found presence {0} {1} as root in {2} after {3} waits", + sp.Name, sp.UUID, Name, 20 - ntimes); if (sp.IsChildAgent) return false; diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index b4e8f09..d542e47 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1354,7 +1354,10 @@ namespace OpenSim.Region.Framework.Scenes private bool WaitForUpdateAgent(IClientAPI client) { - // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero + // Before the source region executes UpdateAgent + // (which triggers Scene.IncomingChildAgentDataUpdate(AgentData cAgentData) here in the destination, + // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the + // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero int count = 50; while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) { -- cgit v1.1 From ddcbd4bb7d1518d0607d43e9d687faee186e9409 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 23:09:38 +0100 Subject: refactor: rename *ChildAgentDataUpdate() methods to *UpdateChildAgent() verb-noun is consistent with other similar methods --- .../ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | 6 +++--- OpenSim/Region/Framework/Scenes/Scene.cs | 8 ++++---- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index e86d186..8ec943d 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -235,7 +235,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // destination.RegionName, destination.RegionID); - return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); + return m_scenes[destination.RegionID].IncomingUpdateChildAgent(cAgentData); } // m_log.DebugFormat( @@ -245,7 +245,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData) + public bool UpdateAgent(GridRegion destination, AgentPosition agentPosition) { if (destination == null) return false; @@ -257,7 +257,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation foreach (Scene s in m_scenes.Values) { // m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); - s.IncomingChildAgentDataUpdate(cAgentData); + s.IncomingUpdateChildAgent(agentPosition); } //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate"); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 6c9a8df..758a012 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4296,7 +4296,7 @@ namespace OpenSim.Region.Framework.Scenes /// Agent that contains all of the relevant things about an agent. /// Appearance, animations, position, etc. /// true if we handled it. - public virtual bool IncomingChildAgentDataUpdate(AgentData cAgentData) + public virtual bool IncomingUpdateChildAgent(AgentData cAgentData) { m_log.DebugFormat( "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); @@ -4330,7 +4330,7 @@ namespace OpenSim.Region.Framework.Scenes sp.UUID, sp.ControllingClient.SessionId, cAgentData.SessionID)); } - sp.ChildAgentDataUpdate(cAgentData); + sp.UpdateChildAgent(cAgentData); int ntimes = 20; if (cAgentData.SenderWantsToWaitForRoot) @@ -4363,7 +4363,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// AgentPosition that contains agent positional data so we can know what to send /// true if we handled it. - public virtual bool IncomingChildAgentDataUpdate(AgentPosition cAgentData) + public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData) { //m_log.Debug(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName); ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); @@ -4383,7 +4383,7 @@ namespace OpenSim.Region.Framework.Scenes uint tRegionX = RegionInfo.RegionLocX; uint tRegionY = RegionInfo.RegionLocY; //Send Data to ScenePresence - childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); + childAgentUpdate.UpdateChildAgent(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY); // Not Implemented: //TODO: Do we need to pass the message on to one of our neighbors? } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d542e47..3e61713 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3341,7 +3341,7 @@ namespace OpenSim.Region.Framework.Scenes #region Child Agent Updates - public void ChildAgentDataUpdate(AgentData cAgentData) + public void UpdateChildAgent(AgentData cAgentData) { // m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); if (!IsChildAgent) @@ -3351,11 +3351,12 @@ namespace OpenSim.Region.Framework.Scenes } private static Vector3 marker = new Vector3(-1f, -1f, -1f); + /// /// This updates important decision making data about a child agent /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region /// - public void ChildAgentDataUpdate(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY) + public void UpdateChildAgent(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY) { if (!IsChildAgent) return; -- cgit v1.1 From 8999f0602535ee7066caee5774a6dae72a12a45b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 23:13:31 +0100 Subject: minor: correct method name in comment --- 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 3e61713..52ea8fe 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1355,7 +1355,7 @@ namespace OpenSim.Region.Framework.Scenes private bool WaitForUpdateAgent(IClientAPI client) { // Before the source region executes UpdateAgent - // (which triggers Scene.IncomingChildAgentDataUpdate(AgentData cAgentData) here in the destination, + // (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination, // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero int count = 50; -- cgit v1.1 From ac0a527976cda9d138d1b8967e81be4767e9f332 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 23:27:37 +0100 Subject: Add [SimulationService] section to GridHypergrid.ini and StandaloneHypergrid.ini This was already in Grid.ini and Standalone.ini Default settings are same as previously, just introduce a debug ConnectorProtocolVersion parameter --- bin/config-include/GridHypergrid.ini | 11 +++++++++++ bin/config-include/StandaloneHypergrid.ini | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/bin/config-include/GridHypergrid.ini b/bin/config-include/GridHypergrid.ini index 7edcafb..d416ee9 100644 --- a/bin/config-include/GridHypergrid.ini +++ b/bin/config-include/GridHypergrid.ini @@ -35,6 +35,17 @@ SimulationServiceInConnector = true LibraryModule = true +[SimulationService] + ; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport + ; It is used to control the teleport handoff process. + ; Valid values are + ; "SIMULATION/0.2" + ; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol + ; - this protocol is more efficient than "SIMULATION/0.1" + ; "SIMULATION/0.1" + ; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. + ConnectorProtocolVersion = "SIMULATION/0.2" + [Profile] Module = "BasicProfileModule" diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index 3abf49b..4dd35c0 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -38,6 +38,16 @@ SimulationServiceInConnector = true MapImageServiceInConnector = true +[SimulationService] + ; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport + ; It is used to control the teleport handoff process. + ; Valid values are + ; "SIMULATION/0.2" + ; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol + ; - this protocol is more efficient than "SIMULATION/0.1" + ; "SIMULATION/0.1" + ; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. + ConnectorProtocolVersion = "SIMULATION/0.2" [Messaging] MessageTransferModule = HGMessageTransferModule -- cgit v1.1 From 997700c4aae2c0498e86c955cd158e89ae2d2489 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 18 Sep 2013 23:49:27 +0100 Subject: minor: Make config-include .ini files more consistent Chiefly tabs to spaces. No actual setting changes --- bin/config-include/Grid.ini | 7 +- bin/config-include/GridCommon.ini.example | 83 +++++++++--------- bin/config-include/GridHypergrid.ini | 25 +++--- bin/config-include/HyperSimianGrid.ini | 7 +- bin/config-include/Standalone.ini | 9 +- bin/config-include/StandaloneCommon.ini.example | 109 ++++++++++++------------ bin/config-include/StandaloneHypergrid.ini | 58 ++++++------- 7 files changed, 149 insertions(+), 149 deletions(-) diff --git a/bin/config-include/Grid.ini b/bin/config-include/Grid.ini index 1837bdd..69a209a 100644 --- a/bin/config-include/Grid.ini +++ b/bin/config-include/Grid.ini @@ -22,8 +22,8 @@ EntityTransferModule = "BasicEntityTransferModule" InventoryAccessModule = "BasicInventoryAccessModule" LandServices = "RemoteLandServicesConnector" - MapImageService = "MapImageServiceModule" - SearchModule = "BasicSearchModule" + MapImageService = "MapImageServiceModule" + SearchModule = "BasicSearchModule" LandServiceInConnector = true NeighbourServiceInConnector = true @@ -52,7 +52,7 @@ ; for the LocalGridServicesConnector which is used by the Remote one StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" - NetworkConnector = "OpenSim.Services.Connectors.dll:GridServicesConnector" + NetworkConnector = "OpenSim.Services.Connectors.dll:GridServicesConnector" [LibraryService] LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" @@ -64,5 +64,6 @@ [MapImageService] LocalServiceModule = "OpenSim.Services.Connectors.dll:MapImageServicesConnector" + ; in minutes RefreshTime = 60 diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example index 920a691..0a69dbf 100644 --- a/bin/config-include/GridCommon.ini.example +++ b/bin/config-include/GridCommon.ini.example @@ -27,24 +27,24 @@ ;ConnectionString = "Server=localhost\SQLEXPRESS;Database=opensim;User Id=opensim; password=***;" [Hypergrid] - ; Uncomment the variables in this section only if you are in - ; Hypergrid configuration. Otherwise, ignore. + ; Uncomment the variables in this section only if you are in + ; Hypergrid configuration. Otherwise, ignore. ;# {HomeURI} {Hypergrid} {The Home URL of this world} {} - ;; If this is a standalone world, this is the address of this instance. - ;; If this is a grided simulator, this is the address of the external robust server that - ;; runs the UserAgentsService. - ;; For example http://myworld.com:9000 or http://myworld.com:8002 - ;; This is a default that can be overwritten in some sections. - ; HomeURI = "http://127.0.0.1:9000" + ;; If this is a standalone world, this is the address of this instance. + ;; If this is a grided simulator, this is the address of the external robust server that + ;; runs the UserAgentsService. + ;; For example http://myworld.com:9000 or http://myworld.com:8002 + ;; This is a default that can be overwritten in some sections. + ; HomeURI = "http://127.0.0.1:9000" ;# {GatekeeperURI} {Hypergrid} {The URL of the gatekeeper of this world} {} - ;; If this is a standalone world, this is the address of this instance. - ;; If this is a grided simulator, this is the address of the external robust server - ;; that runs the Gatekeeper service. - ;; For example http://myworld.com:9000 or http://myworld.com:8002 - ;; This is a default that can be overwritten in some sections. - ; GatekeeperURI = "http://127.0.0.1:9000" + ;; If this is a standalone world, this is the address of this instance. + ;; If this is a grided simulator, this is the address of the external robust server + ;; that runs the Gatekeeper service. + ;; For example http://myworld.com:9000 or http://myworld.com:8002 + ;; This is a default that can be overwritten in some sections. + ; GatekeeperURI = "http://127.0.0.1:9000" [Modules] ;; Choose one cache module and the corresponding config file, if it exists. @@ -81,10 +81,10 @@ InventoryServerURI = "http://mygridserver.com:8003" [GridInfo] - ; - ; Change this to your grid info service - ; - GridInfoURI = "http://mygridserver.com:8002" + ; + ; Change this to your grid info service + ; + GridInfoURI = "http://mygridserver.com:8002" [GridService] ; @@ -157,9 +157,9 @@ ;; uncomment the next line. You may want to do this on sims that have licensed content. ; OutboundPermission = False - ;; Send visual reminder to local users that their inventories are unavailable while they are traveling - ;; and available when they return. True by default. - ;RestrictInventoryAccessAbroad = True + ;; Send visual reminder to local users that their inventories are unavailable while they are traveling + ;; and available when they return. True by default. + ;RestrictInventoryAccessAbroad = True [HGAssetService] @@ -171,14 +171,14 @@ HomeURI = "http://mygridserver.com:8002" ;; The asset types that this grid can export to / import from other grids. - ;; Comma separated. - ;; Valid values are all the asset types in OpenMetaverse.AssetType, namely: - ;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText, - ;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh - ;; - ;; Leave blank or commented if you don't want to apply any restrictions. - ;; A more strict, but still reasonable, policy may be to disallow the exchange - ;; of scripts, like so: + ;; Comma separated. + ;; Valid values are all the asset types in OpenMetaverse.AssetType, namely: + ;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText, + ;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh + ;; + ;; Leave blank or commented if you don't want to apply any restrictions. + ;; A more strict, but still reasonable, policy may be to disallow the exchange + ;; of scripts, like so: ; DisallowExport ="LSLText" ; DisallowImport ="LSLBytecode" @@ -197,20 +197,19 @@ MapImageServerURI = "http://mygridserver.com:8003" [AuthorizationService] - ; If you have regions with access restrictions - ; specify them here using the convention - ; Region_ = - ; Valid flags are: - ; DisallowForeigners -- HG visitors not allowed - ; DisallowResidents -- only Admins and Managers allowed - ; Example: - ; Region_Test_1 = "DisallowForeigners" - + ; If you have regions with access restrictions + ; specify them here using the convention + ; Region_ = + ; Valid flags are: + ; DisallowForeigners -- HG visitors not allowed + ; DisallowResidents -- only Admins and Managers allowed + ; Example: + ; Region_Test_1 = "DisallowForeigners" ;; Uncomment if you are using SimianGrid for grid services [SimianGrid] - ;; SimianGrid services URL - ;; SimianServiceURL = "http://grid.sciencesim.com/Grid/" + ;; SimianGrid services URL + ;; SimianServiceURL = "http://grid.sciencesim.com/Grid/" - ;; Capability assigned by the grid administrator for the simulator - ;; SimulatorCapability = "00000000-0000-0000-0000-000000000000" \ No newline at end of file + ;; Capability assigned by the grid administrator for the simulator + ;; SimulatorCapability = "00000000-0000-0000-0000-000000000000" diff --git a/bin/config-include/GridHypergrid.ini b/bin/config-include/GridHypergrid.ini index d416ee9..2a66b4c 100644 --- a/bin/config-include/GridHypergrid.ini +++ b/bin/config-include/GridHypergrid.ini @@ -25,10 +25,10 @@ EntityTransferModule = "HGEntityTransferModule" InventoryAccessModule = "HGInventoryAccessModule" LandServices = "RemoteLandServicesConnector" - FriendsModule = "HGFriendsModule" - MapImageService = "MapImageServiceModule" - UserManagementModule = "HGUserManagementModule" - SearchModule = "BasicSearchModule" + FriendsModule = "HGFriendsModule" + MapImageService = "MapImageServiceModule" + UserManagementModule = "HGUserManagementModule" + SearchModule = "BasicSearchModule" LandServiceInConnector = true NeighbourServiceInConnector = true @@ -73,7 +73,7 @@ ; Needed to display non-default map tile images for linked regions AssetService = "OpenSim.Services.Connectors.dll:AssetServicesConnector" - HypergridLinker = true + HypergridLinker = true AllowHypergridMapSearch = true [LibraryService] @@ -89,12 +89,13 @@ LureModule = HGLureModule [HGInstantMessageService] - LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInstantMessageService" - GridService = "OpenSim.Services.Connectors.dll:GridServicesConnector" - PresenceService = "OpenSim.Services.Connectors.dll:PresenceServicesConnector" - UserAgentService = "OpenSim.Services.Connectors.dll:UserAgentServiceConnector" + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInstantMessageService" + GridService = "OpenSim.Services.Connectors.dll:GridServicesConnector" + PresenceService = "OpenSim.Services.Connectors.dll:PresenceServicesConnector" + UserAgentService = "OpenSim.Services.Connectors.dll:UserAgentServiceConnector" [MapImageService] - LocalServiceModule = "OpenSim.Services.Connectors.dll:MapImageServicesConnector" - ; in minutes - RefreshTime = 60 + LocalServiceModule = "OpenSim.Services.Connectors.dll:MapImageServicesConnector" + + ; in minutes + RefreshTime = 60 diff --git a/bin/config-include/HyperSimianGrid.ini b/bin/config-include/HyperSimianGrid.ini index 99a589c..f561dd5 100644 --- a/bin/config-include/HyperSimianGrid.ini +++ b/bin/config-include/HyperSimianGrid.ini @@ -91,6 +91,7 @@ ; accessible from other grids ; ProfileServerURI = "http://mygridserver.com:8002/user" - ;; If you want to protect your assets from being copied by foreign visitors - ;; uncomment the next line. You may want to do this on sims that have licensed content. - ; OutboundPermission = False + + ;; If you want to protect your assets from being copied by foreign visitors + ;; uncomment the next line. You may want to do this on sims that have licensed content. + ; OutboundPermission = False diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index 7b7beb2..424d8c8 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -19,7 +19,7 @@ EntityTransferModule = "BasicEntityTransferModule" InventoryAccessModule = "BasicInventoryAccessModule" MapImageService = "MapImageServiceModule" - SearchModule = "BasicSearchModule" + SearchModule = "BasicSearchModule" LibraryModule = true LLLoginServiceInConnector = true @@ -117,9 +117,10 @@ DSTZone = "America/Los_Angeles;Pacific Standard Time" [MapImageService] - LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" - ; in minutes - RefreshTime = 60 + LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" + + ; in minutes + RefreshTime = 60 ;; This should always be the very last thing on this file [Includes] diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index f7545d4..12c5b95 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -28,25 +28,24 @@ ;ConnectionString = "Server=localhost\SQLEXPRESS;Database=opensim;User Id=opensim; password=***;" [Hypergrid] - ; Uncomment the variables in this section only if you are in - ; Hypergrid configuration. Otherwise, ignore. + ; Uncomment the variables in this section only if you are in + ; Hypergrid configuration. Otherwise, ignore. ;# {HomeURI} {Hypergrid} {The Home URL of this world} {} - ;; If this is a standalone world, this is the address of this instance. - ;; If this is a grided simulator, this is the address of the external robust server that - ;; runs the UserAgentsService. - ;; For example http://myworld.com:9000 or http://myworld.com:8002 - ;; This is a default that can be overwritten in some sections. - ; HomeURI = "http://127.0.0.1:9000" + ;; If this is a standalone world, this is the address of this instance. + ;; If this is a grided simulator, this is the address of the external robust server that + ;; runs the UserAgentsService. + ;; For example http://myworld.com:9000 or http://myworld.com:8002 + ;; This is a default that can be overwritten in some sections. + ; HomeURI = "http://127.0.0.1:9000" ;# {GatekeeperURI} {Hypergrid} {The URL of the gatekeeper of this world} {} - ;; If this is a standalone world, this is the address of this instance. - ;; If this is a grided simulator, this is the address of the external robust server - ;; that runs the Gatekeeper service. - ;; For example http://myworld.com:9000 or http://myworld.com:8002 - ;; This is a default that can be overwritten in some sections. - ; GatekeeperURI = "http://127.0.0.1:9000" - + ;; If this is a standalone world, this is the address of this instance. + ;; If this is a grided simulator, this is the address of the external robust server + ;; that runs the Gatekeeper service. + ;; For example http://myworld.com:9000 or http://myworld.com:8002 + ;; This is a default that can be overwritten in some sections. + ; GatekeeperURI = "http://127.0.0.1:9000" [Modules] ;; Choose one cache module and the corresponding config file, if it exists. @@ -266,20 +265,20 @@ ; If false, HG TPs happen only to the Default regions specified in [GridService] section AllowTeleportsToAnyRegion = true - ;; Regular expressions for controlling which client versions are accepted/denied. - ;; An empty string means nothing is checked. - ;; - ;; Example 1: allow only these 3 types of clients (any version of them) - ;; AllowedClients = "Imprudence|Hippo|Second Life" - ;; - ;; Example 2: allow all clients except these - ;; DeniedClients = "Twisted|Crawler|Cryolife|FuckLife|StreetLife|GreenLife|AntiLife|KORE-Phaze|Synlyfe|Purple Second Life|SecondLi |Emerald" - ;; - ;; Note that these are regular expressions, so every character counts. - ;; Also note that this is very weak security and should not be trusted as a reliable means - ;; for keeping bad clients out; modified clients can fake their identifiers. - ;; - ;; + ;; Regular expressions for controlling which client versions are accepted/denied. + ;; An empty string means nothing is checked. + ;; + ;; Example 1: allow only these 3 types of clients (any version of them) + ;; AllowedClients = "Imprudence|Hippo|Second Life" + ;; + ;; Example 2: allow all clients except these + ;; DeniedClients = "Twisted|Crawler|Cryolife|FuckLife|StreetLife|GreenLife|AntiLife|KORE-Phaze|Synlyfe|Purple Second Life|SecondLi |Emerald" + ;; + ;; Note that these are regular expressions, so every character counts. + ;; Also note that this is very weak security and should not be trusted as a reliable means + ;; for keeping bad clients out; modified clients can fake their identifiers. + ;; + ;; ;AllowedClients = "" ;DeniedClients = "" @@ -302,7 +301,7 @@ ;; Are local users allowed to visit other grids? ;; What user level? Use variables of this forrm: ;; ForeignTripsAllowed_Level_ = true | false - ;; (the default is true) + ;; (the default is true) ;; For example: ; ForeignTripsAllowed_Level_0 = false ; ForeignTripsAllowed_Level_200 = true ; true is default, no need to say it @@ -310,45 +309,45 @@ ;; If ForeignTripsAllowed is false, make exceptions using DisallowExcept ;; Leave blank or commented for no exceptions. ; DisallowExcept_Level_0 = "http://myothergrid.com:8002, http://boss.com:8002" - ;; + ;; ;; If ForeignTripsAllowed is true, make exceptions using AllowExcept. ;; Leave blank or commented for no exceptions. ; AllowExcept_Level_200 = "http://griefer.com:8002, http://enemy.com:8002" [HGInventoryService] - ;; If you have this set under [Hypergrid], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; HomeURI = "http://127.0.0.1:9000" [HGAssetService] - ;; If you have this set under [Hypergrid], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; HomeURI = "http://127.0.0.1:9000" ;; The asset types that this grid can export to / import from other grids. - ;; Comma separated. - ;; Valid values are all the asset types in OpenMetaverse.AssetType, namely: - ;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText, - ;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh - ;; - ;; Leave blank or commented if you don't want to apply any restrictions. - ;; A more strict, but still reasonable, policy may be to disallow the exchange - ;; of scripts, like so: + ;; Comma separated. + ;; Valid values are all the asset types in OpenMetaverse.AssetType, namely: + ;; Unknown, Texture, Sound, CallingCard, Landmark, Clothing, Object, Notecard, LSLText, + ;; LSLBytecode, TextureTGA, Bodypart, SoundWAV, ImageTGA, ImageJPEG, Animation, Gesture, Mesh + ;; + ;; Leave blank or commented if you don't want to apply any restrictions. + ;; A more strict, but still reasonable, policy may be to disallow the exchange + ;; of scripts, like so: ; DisallowExport ="LSLText" ; DisallowImport ="LSLBytecode" [HGInventoryAccessModule] - ;; If you have these set under [Hypergrid], no need to set it here, leave it commented + ;; If you have these set under [Hypergrid], no need to set it here, leave it commented ; HomeURI = "http://127.0.0.1:9000" - ; GatekeeperURI = "http://127.0.0.1:9000" + ; GatekeeperURI = "http://127.0.0.1:9000" ;; If you want to protect your assets from being copied by foreign visitors ;; uncomment the next line. You may want to do this on sims that have licensed content. - ;; true = allow exports, false = disallow exports. True by default. + ;; true = allow exports, false = disallow exports. True by default. ; OutboundPermission = True - ;; Send visual reminder to local users that their inventories are unavailable while they are traveling - ;; and available when they return. True by default. - ;RestrictInventoryAccessAbroad = True + ;; Send visual reminder to local users that their inventories are unavailable while they are traveling + ;; and available when they return. True by default. + ;RestrictInventoryAccessAbroad = True [HGFriendsModule] ; User level required to be able to send friendship invitations to foreign users @@ -356,20 +355,20 @@ [Messaging] ; === HG ONLY === - ;; If you have this set under [Hypergrid], no need to set it here, leave it commented + ;; If you have this set under [Hypergrid], no need to set it here, leave it commented ; GatekeeperURI = "http://127.0.0.1:9000" [EntityTransfer] - ;; User level from which local users are allowed to HG teleport. Default 0 (all users) - ;LevelHGTeleport = 0 + ;; User level from which local users are allowed to HG teleport. Default 0 (all users) + ;LevelHGTeleport = 0 - ;; Are local users restricted from taking their appearance abroad? - ;; Default is no restrictions + ;; Are local users restricted from taking their appearance abroad? + ;; Default is no restrictions ;RestrictAppearanceAbroad = false - ;; If appearance is restricted, which accounts' appearances are allowed to be exported? - ;; Comma-separated list of account names + ;; If appearance is restricted, which accounts' appearances are allowed to be exported? + ;; Comma-separated list of account names AccountForAppearance = "Test User, Astronaut Smith" ;; UserProfiles Service @@ -385,5 +384,3 @@ UserAccountService = OpenSim.Services.UserAccountService.dll:UserAccountService AuthenticationServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" - - diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index 4dd35c0..370ab90 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -5,7 +5,7 @@ ;; [Startup] - WorldMapModule = "HGWorldMap" + WorldMapModule = "HGWorldMap" [Modules] AssetServices = "HGAssetBroker" @@ -20,12 +20,12 @@ SimulationServices = "RemoteSimulationConnectorModule" AvatarServices = "LocalAvatarServicesConnector" UserProfilesServices = "LocalUserProfilesServicesConnector" - MapImageService = "MapImageServiceModule" + MapImageService = "MapImageServiceModule" EntityTransferModule = "HGEntityTransferModule" InventoryAccessModule = "HGInventoryAccessModule" FriendsModule = "HGFriendsModule" - UserManagementModule = "HGUserManagementModule" - SearchModule = "BasicSearchModule" + UserManagementModule = "HGUserManagementModule" + SearchModule = "BasicSearchModule" InventoryServiceInConnector = true AssetServiceInConnector = true @@ -33,10 +33,10 @@ NeighbourServiceInConnector = true LibraryModule = true LLLoginServiceInConnector = true - GridInfoServiceInConnector = true + GridInfoServiceInConnector = true AuthenticationServiceInConnector = true SimulationServiceInConnector = true - MapImageServiceInConnector = true + MapImageServiceInConnector = true [SimulationService] ; This is the protocol version which the simulator advertises to the source destination when acting as a target destination for a teleport @@ -74,9 +74,9 @@ LocalServiceModule = "OpenSim.Services.AvatarService.dll:AvatarService" [LibraryService] - LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" - LibraryName = "OpenSim Library" - DefaultLibrary = "./inventory/Libraries.xml" + LocalServiceModule = "OpenSim.Services.InventoryService.dll:LibraryService" + LibraryName = "OpenSim Library" + DefaultLibrary = "./inventory/Libraries.xml" [AuthenticationService] LocalServiceModule = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" @@ -123,7 +123,7 @@ LocalServiceModule = "OpenSim.Services.LLLoginService.dll:LLLoginService" UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" GridUserService = "OpenSim.Services.UserAccountService.dll:GridUserService" - UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" + UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" AuthenticationService = "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService" InventoryService = "OpenSim.Services.InventoryService.dll:XInventoryService" PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" @@ -132,9 +132,9 @@ FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" [MapImageService] - LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" - ; in minutes - RefreshTime = 60 + LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" + ; in minutes + RefreshTime = 60 [GatekeeperService] LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService" @@ -148,8 +148,8 @@ SimulationService ="OpenSim.Services.Connectors.dll:SimulationServiceConnector" [UserAgentService] - LocalServiceModule = "OpenSim.Services.HypergridService.dll:UserAgentService" - ;; for the service + LocalServiceModule = "OpenSim.Services.HypergridService.dll:UserAgentService" + ;; for the service GridUserService = "OpenSim.Services.UserAccountService.dll:GridUserService" GridService = "OpenSim.Services.GridService.dll:GridService" GatekeeperService = "OpenSim.Services.HypergridService.dll:GatekeeperService" @@ -166,10 +166,10 @@ [HGInventoryService] ; For the InventoryServiceInConnector LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGSuitcaseInventoryService" - ;; alternatives: - ;; HG1.5, more permissive, not recommended, but still supported + ;; alternatives: + ;; HG1.5, more permissive, not recommended, but still supported ;LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInventoryService" - ;; HG1.0, totally permissive, not recommended, but OK for grids with 100% trust + ;; HG1.0, totally permissive, not recommended, but OK for grids with 100% trust ;LocalServiceModule = "OpenSim.Services.InventoryService.dll:XInventoryService" UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" @@ -182,19 +182,19 @@ UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" [HGFriendsService] - LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGFriendsService" - UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" - FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" - UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" - GridService = "OpenSim.Services.GridService.dll:GridService" - PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGFriendsService" + UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" + FriendsService = "OpenSim.Services.FriendsService.dll:FriendsService" + UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService" + GridService = "OpenSim.Services.GridService.dll:GridService" + PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" [HGInstantMessageService] - LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInstantMessageService" - GridService = "OpenSim.Services.GridService.dll:GridService" - PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" - UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" - InGatekeeper = True + LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGInstantMessageService" + GridService = "OpenSim.Services.GridService.dll:GridService" + PresenceService = "OpenSim.Services.PresenceService.dll:PresenceService" + UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" + InGatekeeper = True ;; This should always be the very last thing on this file [Includes] -- cgit v1.1 From 83c113896ec518cef98880195f81bc6fe2d6a63f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 19 Sep 2013 20:24:08 +0100 Subject: Create regression TestCrossOnSameSimulatorNoRootDestPerm() to check that avatars are not allowed to cross into a neighbour where they are not authorized, even if a child agent was allowed. --- OpenSim/Region/Framework/Scenes/Scene.cs | 3 +- .../Scenes/Tests/ScenePresenceCrossingTests.cs | 86 ++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 758a012..4357b91 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -731,6 +731,7 @@ namespace OpenSim.Region.Framework.Scenes m_config = config; MinFrameTime = 0.089f; MinMaintenanceTime = 1; + SeeIntoRegion = true; Random random = new Random(); @@ -841,7 +842,7 @@ namespace OpenSim.Region.Framework.Scenes //Animation states m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); - SeeIntoRegion = startupConfig.GetBoolean("see_into_region", true); + SeeIntoRegion = startupConfig.GetBoolean("see_into_region", SeeIntoRegion); MaxUndoCount = startupConfig.GetInt("MaxPrimUndos", 20); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 12a778b..cf211a1 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs @@ -38,6 +38,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.CoreModules.Framework; using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Permissions; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -159,5 +160,90 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(agentMovementCompleteReceived, Is.EqualTo(1)); Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False); } + + /// + /// Test a cross attempt where the user can see into the neighbour but does not have permission to become + /// root there. + /// + [Test] + public void TestCrossOnSameSimulatorNoRootDestPerm() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + + // We need to set up the permisions module on scene B so that our later use of agent limit to deny + // QueryAccess won't succeed anyway because administrators are always allowed in and the default + // IsAdministrator if no permissions module is present is true. + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), new PermissionsModule(), etmB); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + TestClient tc = new TestClient(acd, sceneA); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + // Make sure sceneB will not accept this avatar. + sceneB.RegionInfo.EstateSettings.PublicAccess = false; + + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); + originalSp.AbsolutePosition = new Vector3(128, 32, 10); + + AgentUpdateArgs moveArgs = new AgentUpdateArgs(); + //moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero); + moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2))); + moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; + moveArgs.SessionID = acd.SessionID; + + originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs); + + sceneA.Update(1); + +// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition); + + // FIXME: This is a sufficient number of updates to for the presence to reach the northern border. + // But really we want to do this in a more robust way. + for (int i = 0; i < 100; i++) + { + sceneA.Update(1); +// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition); + } + + // sceneA agent should still be root + ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID); + Assert.That(spAfterCrossSceneA.IsChildAgent, Is.False); + + ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID); + + // sceneB agent should also still be root + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); + + // sceneB should ignore unauthorized attempt to upgrade agent to root + TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient); + + int agentMovementCompleteReceived = 0; + sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++; + + sceneBTc.CompleteMovement(); + + Assert.That(agentMovementCompleteReceived, Is.EqualTo(0)); + Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True); + } } } \ No newline at end of file -- cgit v1.1 From 3a9a8d2113cc6cc333edf7e813f881111f301378 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 19 Sep 2013 20:26:26 +0100 Subject: Revert "Also check user authorization if looking to upgrade from a child to a root agent." This reverts commit c7ded0618c303f8c24a91c83c2129292beebe466. This proves not to be necessary - the necessary checks are already being done via QueryAccess() before cross or teleport --- OpenSim/Region/Framework/Scenes/Scene.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 4357b91..495491c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3861,19 +3861,6 @@ namespace OpenSim.Region.Framework.Scenes // Let the SP know how we got here. This has a lot of interesting // uses down the line. sp.TeleportFlags = (TPFlags)teleportFlags; - - // We must carry out a further authorization check if there's an - // attempt to make a child agent into a root agent, since SeeIntoRegion may have allowed a child - // agent to login to a region where a full avatar would not be allowed. - // - // We determine whether this is a CreateAgent for a future non-child agent by inspecting - // TeleportFlags, which will be default for a child connection. This relies on input from the source - // region. - if (sp.TeleportFlags != TPFlags.Default) - { - if (!AuthorizeUser(acd, false, out reason)) - return false; - } if (sp.IsChildAgent) { -- cgit v1.1 From 6bdef1f70b782b69090e5846f9463942857d97cd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 19 Sep 2013 20:49:55 +0100 Subject: minor: Stop debug logging whenever an npc is moved, other npc log related formatting cleanups --- .../Region/OptionalModules/World/NPC/NPCModule.cs | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index c26fdfc..b863370 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -146,9 +146,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC int.MaxValue); m_log.DebugFormat( - "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", - firstname, lastname, npcAvatar.AgentId, owner, - senseAsAgent, position, scene.RegionInfo.RegionName); + "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", + firstname, lastname, npcAvatar.AgentId, owner, + senseAsAgent, position, scene.RegionInfo.RegionName); AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = npcAvatar.AgentId; @@ -188,16 +188,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC sp.CompleteMovement(npcAvatar, false); m_avatars.Add(npcAvatar.AgentId, npcAvatar); - m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", - npcAvatar.AgentId, sp.Name); + m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name); return npcAvatar.AgentId; } else { m_log.WarnFormat( - "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", - sp.Name, sp.UUID); + "[NPC MODULE]: Could not find scene presence for NPC {0} {1}", + sp.Name, sp.UUID); + return UUID.Zero; } } @@ -213,10 +213,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; if (scene.TryGetScenePresence(agentID, out sp)) { - m_log.DebugFormat( - "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", - sp.Name, pos, scene.RegionInfo.RegionName, - noFly, landAtTarget); +// m_log.DebugFormat( +// "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", +// sp.Name, pos, scene.RegionInfo.RegionName, +// noFly, landAtTarget); sp.MoveToTarget(pos, noFly, landAtTarget); sp.SetAlwaysRun = running; @@ -293,9 +293,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; if (scene.TryGetScenePresence(agentID, out sp)) { - sp.HandleAgentRequestSit(m_avatars[agentID], agentID, - partID, Vector3.Zero); - //sp.HandleAgentSit(m_avatars[agentID], agentID); + sp.HandleAgentRequestSit(m_avatars[agentID], agentID, partID, Vector3.Zero); return true; } @@ -387,8 +385,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC */ scene.IncomingCloseAgent(agentID, false); -// scene.RemoveClient(agentID, false); + m_avatars.Remove(agentID); + /* m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}", agentID, av.Name); @@ -427,4 +426,4 @@ namespace OpenSim.Region.OptionalModules.World.NPC av.OwnerID == callerID; } } -} +} \ No newline at end of file -- cgit v1.1 From 03b2b5b77bef684536143ed509df444b859c26c0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 19 Sep 2013 20:59:27 +0100 Subject: minor: Make log message at top of ScenePresence.CompleteMovement info level and comment out later log message in ScenePresence.MakeRootAgent() Need an info message since this is currently important in detecting teleport issue when not at debug log level. CompleteMovement message occurs before MakeRootAgent() one did --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 52ea8fe..e247875 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -900,9 +900,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void MakeRootAgent(Vector3 pos, bool isFlying) { - m_log.InfoFormat( - "[SCENE]: Upgrading child to root agent for {0} in {1}", - Name, m_scene.RegionInfo.RegionName); +// m_log.InfoFormat( +// "[SCENE]: Upgrading child to root agent for {0} in {1}", +// Name, m_scene.RegionInfo.RegionName); //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); @@ -1388,9 +1388,9 @@ namespace OpenSim.Region.Framework.Scenes { // DateTime startTime = DateTime.Now; - m_log.DebugFormat( + m_log.InfoFormat( "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", - client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); + client.Name, Scene.Name, AbsolutePosition); // Make sure it's not a login agent. We don't want to wait for updates during login if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0) -- cgit v1.1 From b6f10780c25007032835c4247fbd51d695d348df Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 19 Sep 2013 21:44:30 +0100 Subject: minor: Make SP.MakeRootAgent() private - no external code has any business calling this method --- 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 e247875..f12d629 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -898,7 +898,7 @@ namespace OpenSim.Region.Framework.Scenes /// This method is on the critical path for transferring an avatar from one region to another. Delay here /// delays that crossing. /// - public void MakeRootAgent(Vector3 pos, bool isFlying) + private void MakeRootAgent(Vector3 pos, bool isFlying) { // m_log.InfoFormat( // "[SCENE]: Upgrading child to root agent for {0} in {1}", -- cgit v1.1 From 979b17165b7e504385187ab082ef0a8cd50605bd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 19 Sep 2013 22:45:50 +0100 Subject: For debug purposes, allow simulators to force use of earlier SIMULATION/0.1 teleport protocol even if SIMULATION/0.2 is available. This is specified in the MaxOutgoingTransferVersion attribute of [EntityTransfer] in OpenSim.ini, see OpenSimDefaults.ini for more details. Default remains "SIMULATION/0.2" Primarily for http://opensimulator.org/mantis/view.php?id=6755 --- .../EntityTransfer/EntityTransferModule.cs | 53 ++++++++++++++++++++-- .../Scenes/Tests/ScenePresenceTeleportTests.cs | 2 +- bin/OpenSimDefaults.ini | 10 +++- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 9302784..c1c8672 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -56,6 +56,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public const int DefaultMaxTransferDistance = 4095; public const bool WaitForAgentArrivedAtDestinationDefault = true; + public string OutgoingTransferVersionName { get; set; } + + /// + /// Determine the maximum entity transfer version we will use for teleports. + /// + public float MaxOutgoingTransferVersion { get; set; } + /// /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. /// @@ -151,9 +158,35 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// protected virtual void InitialiseCommon(IConfigSource source) { + string transferVersionName = "SIMULATION"; + float maxTransferVersion = 0.2f; + IConfig transferConfig = source.Configs["EntityTransfer"]; if (transferConfig != null) { + string rawVersion + = transferConfig.GetString( + "MaxOutgoingTransferVersion", + string.Format("{0}/{1}", transferVersionName, maxTransferVersion)); + + string[] rawVersionComponents = rawVersion.Split(new char[] { '/' }); + + bool versionValid = false; + + if (rawVersionComponents.Length >= 2) + versionValid = float.TryParse(rawVersionComponents[1], out maxTransferVersion); + + if (!versionValid) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: MaxOutgoingTransferVersion {0} is invalid, using {1}", + rawVersion, string.Format("{0}/{1}", transferVersionName, maxTransferVersion)); + } + else + { + transferVersionName = rawVersionComponents[0]; + } + DisableInterRegionTeleportCancellation = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); @@ -167,6 +200,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer MaxTransferDistance = DefaultMaxTransferDistance; } + OutgoingTransferVersionName = transferVersionName; + MaxOutgoingTransferVersion = maxTransferVersion; + m_entityTransferStateMachine = new EntityTransferStateMachine(this); m_Enabled = true; @@ -623,7 +659,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!sp.ValidateAttachments()) m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", - sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); + sp.Name, sp.Scene.Name, finalDestination.RegionName); string reason; string version; @@ -634,7 +670,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", - sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); + sp.Name, sp.Scene.Name, finalDestination.RegionName, reason); return; } @@ -644,7 +680,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // as server attempts. m_interRegionTeleportAttempts.Value++; - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: {0} max transfer version is {1}/{2}, {3} max version is {4}", + sp.Scene.Name, OutgoingTransferVersionName, MaxOutgoingTransferVersion, finalDestination.RegionName, version); // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions @@ -689,7 +727,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } - if (version.Equals("SIMULATION/0.2")) + // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 or we're forcing + // use of the earlier protocol + float versionNumber = 0.1f; + string[] versionComponents = version.Split(new char[] { '/' }); + if (versionComponents.Length >= 2) + float.TryParse(versionComponents[1], out versionNumber); + + if (versionNumber == 0.2f && MaxOutgoingTransferVersion >= versionNumber) TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); else TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, version, out reason); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index 8c25dbc..3ba34dd 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -185,7 +185,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestSameSimulatorIsolatedRegionsV2() { TestHelpers.InMethod(); -// TestHelpers.EnableLogging(); + TestHelpers.EnableLogging(); UUID userId = TestHelpers.ParseTail(0x1); diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 7954a14..8da4daf 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -636,7 +636,6 @@ Cap_AvatarPickerSearch = "localhost" - [Chat] ; Controls whether the chat module is enabled. Default is true. enabled = true; @@ -652,6 +651,15 @@ [EntityTransfer] + ; The maximum protocol version that we will use for outgoing transfers + ; Valid values are + ; "SIMULATION/0.2" + ; - this is the default. A source simulator which only implements "SIMULATION/0.1" can still teleport with that protocol + ; - this protocol is more efficient than "SIMULATION/0.1" + ; "SIMULATION/0.1" + ; - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. + MaxOutgoingTransferVersion = "SIMULATION/0.2" + ; The maximum distance in regions that an agent is allowed to teleport ; along the x or y axis. This is set to 16383 because current viewers ; can't handle teleports that are greater than this distance -- cgit v1.1 From f1267730ef7c4c91e189ad98eeda1bfa80aa106c Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Wed, 24 Apr 2013 11:42:27 +0300 Subject: UUID Gatherer: find assets used in Light Projection, Particle Systems, and Collision Sounds. --- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 8f69ce3..502c748 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -172,7 +172,20 @@ namespace OpenSim.Region.Framework.Scenes // If the prim is a sculpt then preserve this information too if (part.Shape.SculptTexture != UUID.Zero) assetUuids[part.Shape.SculptTexture] = AssetType.Texture; - + + if (part.Shape.ProjectionTextureUUID != UUID.Zero) + assetUuids[part.Shape.ProjectionTextureUUID] = AssetType.Texture; + + if (part.CollisionSound != UUID.Zero) + assetUuids[part.CollisionSound] = AssetType.Sound; + + if (part.ParticleSystem.Length > 0) + { + Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); + if (ps.Texture != UUID.Zero) + assetUuids[ps.Texture] = AssetType.Texture; + } + TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); // Now analyze this prim's inventory items to preserve all the uuids that they reference -- cgit v1.1 From c06a9ffe5c639ae50bdb129882b5689443cce654 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 20 Sep 2013 00:04:33 +0100 Subject: Make new regions PG by default instead of Mature. This makes scripted object sounds and a few other things play by default instead of having to switch the viewer to adult This reduces the support burden --- OpenSim/Framework/RegionSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs index 47dbcec..db8c53e 100644 --- a/OpenSim/Framework/RegionSettings.cs +++ b/OpenSim/Framework/RegionSettings.cs @@ -200,7 +200,7 @@ namespace OpenSim.Framework set { m_ObjectBonus = value; } } - private int m_Maturity = 1; + private int m_Maturity = 0; public int Maturity { -- cgit v1.1 From 07d7a5fd76460a16b97d285a1b2c4a101e5543b6 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 20 Sep 2013 09:36:19 -0700 Subject: BulletSim: zero velocity when avatar not moving. This fixes a movement jitter that happens when an avatar is standing on a tilted surface. --- OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 04a4a32..8ca55e5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -278,6 +278,7 @@ public class BSActorAvatarMove : BSActor if (m_controllingPrim.IsStationary) { entprop.Position = m_controllingPrim.RawPosition; + entprop.Velocity = OMV.Vector3.Zero; m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); } -- cgit v1.1 From 35a6361b2431abf9d49b4413c5b9eaac51934134 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 20 Sep 2013 09:23:12 -0700 Subject: BulletSim: reduce avatar walking stopped threshold. Add parameter for setting the walking stopped threshold. This fixes the slight jump when an avatar stops walking. --- OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | 1 + OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs index 8ca55e5..1bcf879 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs @@ -128,6 +128,7 @@ public class BSActorAvatarMove : BSActor BSMotor.Infinite, // decay time scale 1f // efficiency ); + m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold; // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 2f1799b..43aa63e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -134,6 +134,7 @@ public static class BSParam public static float AvatarHeightMidFudge { get; private set; } public static float AvatarHeightHighFudge { get; private set; } public static float AvatarContactProcessingThreshold { get; private set; } + public static float AvatarStopZeroThreshold { get; private set; } public static int AvatarJumpFrames { get; private set; } public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } public static float AvatarStepHeight { get; private set; } @@ -575,6 +576,8 @@ public static class BSParam 0.1f ), new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 0.1f ), + new ParameterDefn("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped", + 0.1f ), new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", 1.0f ), new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", -- cgit v1.1 From c6dea6ee783b0d2f300ef34fb432fb7197a5dabb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 20 Sep 2013 20:19:44 +0100 Subject: Change some message log levels in Scene.IncomingUpdateChildAgent() for debugging purposes --- OpenSim/Region/Framework/Scenes/Scene.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 495491c..bc5a67f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4293,7 +4293,7 @@ namespace OpenSim.Region.Framework.Scenes ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); if (nearestParcel == null) { - m_log.DebugFormat( + m_log.InfoFormat( "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel", cAgentData.AgentID, RegionInfo.RegionName); @@ -4327,11 +4327,11 @@ namespace OpenSim.Region.Framework.Scenes Thread.Sleep(1000); if (sp.IsChildAgent) - m_log.DebugFormat( + m_log.WarnFormat( "[SCENE]: Found presence {0} {1} unexpectedly still child in {2}", sp.Name, sp.UUID, Name); else - m_log.DebugFormat( + m_log.InfoFormat( "[SCENE]: Found presence {0} {1} as root in {2} after {3} waits", sp.Name, sp.UUID, Name, 20 - ntimes); -- cgit v1.1 From c01db5fbdd982a9613d1d64e2ac54f1b5c73b63c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 20 Sep 2013 22:41:53 +0100 Subject: Lock around read/write of ScenePresence.m_originRegionID to make sure that all threads are seeing the latest value and not a cached one. There is a possibilty that some V2 teleport failures are due to the viewer triggered CompleteMovement thread not seeing the change of m_originRegionID by the UpdateAgent thread. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 38 ++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f12d629..8d72e18 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -311,7 +311,21 @@ namespace OpenSim.Region.Framework.Scenes /// private string m_callbackURI; - public UUID m_originRegionID; + /// + /// Records the region from which this presence originated, if not from login. + /// + /// + /// Also acts as a signal in the teleport V2 process to release UpdateAgent after a viewer has triggered + /// CompleteMovement and made the previous child agent a root agent. + /// + private UUID m_originRegionID; + + /// + /// This object is used as a lock before accessing m_originRegionID to make sure that every thread is seeing + /// the very latest value and not using some cached version. Cannot make m_originRegionID itself volatite as + /// it is a value type. + /// + private object m_originRegionIDAccessLock = new object(); /// /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent @@ -1359,13 +1373,21 @@ namespace OpenSim.Region.Framework.Scenes // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero int count = 50; - while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) + UUID originID; + + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + + while (originID.Equals(UUID.Zero) && count-- > 0) { + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); Thread.Sleep(200); } - if (m_originRegionID.Equals(UUID.Zero)) + if (originID.Equals(UUID.Zero)) { // Movement into region will fail m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name); @@ -1444,7 +1466,12 @@ namespace OpenSim.Region.Framework.Scenes "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", client.Name, client.AgentId, m_callbackURI); - Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); + UUID originID; + + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + + Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); m_callbackURI = null; } // else @@ -3461,7 +3488,8 @@ namespace OpenSim.Region.Framework.Scenes private void CopyFrom(AgentData cAgent) { - m_originRegionID = cAgent.RegionID; + lock (m_originRegionIDAccessLock) + m_originRegionID = cAgent.RegionID; m_callbackURI = cAgent.CallbackURI; // m_log.DebugFormat( -- cgit v1.1 From 8502517d8081366dfc63756ae07cfe64a27a1eb0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 20 Sep 2013 23:07:24 +0100 Subject: Make UUID.Zero resolve to "Unknown User" in user cache. This is to avoid massive numbers of 'no user found' logs when user IDs are missing for some reason. UUID.Zero should not be used for any user ID. --- .../Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index bb2bbe3..96eb63f 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -73,6 +73,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement Init(); m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); } + + AddUser(UUID.Zero, "Unknown", "User"); } public bool IsSharedModule -- cgit v1.1 From e2b3b7a2ae01a82e7ca1ed7efd6237a5bf1c9811 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 20 Sep 2013 23:42:55 +0100 Subject: minor: Correct minor spelling mistake Reseting -> Resetting in HG Map module log message --- OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs index 97227b3..79a409d 100644 --- a/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs +++ b/OpenSim/Region/CoreModules/Hypergrid/HGWorldMapModule.cs @@ -129,7 +129,7 @@ namespace OpenSim.Region.CoreModules.Hypergrid b.Access = 254; // means 'simulator is offline'. We need this because the viewer ignores 255's } - m_log.DebugFormat("[HG MAP]: Reseting {0} blocks", mapBlocks.Count); + m_log.DebugFormat("[HG MAP]: Resetting {0} blocks", mapBlocks.Count); sp.ControllingClient.SendMapBlock(mapBlocks, 0); m_SeenMapBlocks.Remove(clientID); } -- cgit v1.1 From 4c0ec861769497b64b5ad71f712fb792564ebe4a Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 21 Sep 2013 00:14:57 +0100 Subject: minor: Add prefix to log message in LureModule --- OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs index 7f4606b..465ffbc 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs @@ -165,7 +165,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure (uint)presence.AbsolutePosition.Y, (uint)Math.Ceiling(presence.AbsolutePosition.Z)); - m_log.DebugFormat("TP invite with message {0}, type {1}", message, lureType); + m_log.DebugFormat("[LURE MODULE]: TP invite with message {0}, type {1}", message, lureType); GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, client.FirstName+" "+client.LastName, targetid, -- cgit v1.1 From cbdfe96905da9d1386b572f89e8372bbdb3345e6 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Mon, 15 Jul 2013 15:26:18 +0300 Subject: When giving items between avatars in different simulators, only add the item to the receiving avatar's inventory once. When a user gives an item, the user's client sends an InventoryOffered IM message to its simulator. This adds the item to the receiver's inventory. If the receiver isn't in the same simulator then XMLRPC is used to forward the IM to the correct simulator. The bug was that the receiving simulator handled the message by calling OnInstantMessage() again, which added a second copy of the item to the inventory. Instead, the receiving simulator should only notify the avatar that the item was offered. --- .../Inventory/Transfer/InventoryTransferModule.cs | 53 ++++++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index 1417a19..f52654f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -148,9 +148,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer private void OnInstantMessage(IClientAPI client, GridInstantMessage im) { -// m_log.DebugFormat( -// "[INVENTORY TRANSFER]: {0} IM type received from {1}", -// (InstantMessageDialog)im.dialog, client.Name); + m_log.DebugFormat( + "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}", + (InstantMessageDialog)im.dialog, client.Name, + im.fromAgentID, im.fromAgentName, im.toAgentID); Scene scene = FindClientScene(client.AgentId); @@ -450,23 +451,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer /// /// /// - /// - private void OnGridInstantMessage(GridInstantMessage msg) + /// + private void OnGridInstantMessage(GridInstantMessage im) { + // Check if it's a type of message that we should handle + if (!((im.dialog == (byte) InstantMessageDialog.InventoryOffered) + || (im.dialog == (byte) InstantMessageDialog.InventoryAccepted) + || (im.dialog == (byte) InstantMessageDialog.InventoryDeclined) + || (im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined))) + return; + + m_log.DebugFormat( + "[INVENTORY TRANSFER]: {0} IM type received from grid. From={1} ({2}), To={3}", + (InstantMessageDialog)im.dialog, im.fromAgentID, im.fromAgentName, im.toAgentID); + // Check if this is ours to handle // - Scene scene = FindClientScene(new UUID(msg.toAgentID)); + Scene scene = FindClientScene(new UUID(im.toAgentID)); if (scene == null) return; // Find agent to deliver to // - ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); + ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID)); - // Just forward to local handling - OnInstantMessage(user.ControllingClient, msg); + if (user != null) + { + user.ControllingClient.SendInstantMessage(im); + if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) + { + AssetType assetType = (AssetType)im.binaryBucket[0]; + UUID inventoryID = new UUID(im.binaryBucket, 1); + + IInventoryService invService = scene.InventoryService; + InventoryNodeBase node = null; + if (AssetType.Folder == assetType) + { + InventoryFolderBase folder = new InventoryFolderBase(inventoryID, new UUID(im.toAgentID)); + node = invService.GetFolder(folder); + } + else + { + InventoryItemBase item = new InventoryItemBase(inventoryID, new UUID(im.toAgentID)); + node = invService.GetItem(item); + } + + if (node != null) + user.ControllingClient.SendBulkUpdateInventory(node); + } + } } } } -- cgit v1.1 From a37c59b43e34e1b3f279f7684a42a2c4a25f18c7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 21 Sep 2013 00:40:23 +0100 Subject: minor: Recomment out log message uncommented in previous cbdfe969 --- .../Avatar/Inventory/Transfer/InventoryTransferModule.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index f52654f..0b10dd8 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs @@ -148,10 +148,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer private void OnInstantMessage(IClientAPI client, GridInstantMessage im) { - m_log.DebugFormat( - "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}", - (InstantMessageDialog)im.dialog, client.Name, - im.fromAgentID, im.fromAgentName, im.toAgentID); +// m_log.DebugFormat( +// "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}", +// (InstantMessageDialog)im.dialog, client.Name, +// im.fromAgentID, im.fromAgentName, im.toAgentID); Scene scene = FindClientScene(client.AgentId); -- cgit v1.1 From 2dc92e7de11086c7649d3ee0f8adc974efce6805 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 4 Aug 2013 19:19:11 +0200 Subject: Preserve attachment point & position when attachment is rezzed in world Patch taken from http://opensimulator.org/mantis/view.php?id=4905 originally by Greg C. Fixed to apply to r/23314 commit ba9daf849e7c8db48e7c03e7cdedb77776b2052f (cherry picked from commit 4ff9fbca441110cc2b93edc7286e0e9339e61cbe) --- OpenSim/Data/MSSQL/MSSQLSimulationData.cs | 17 ++++++++++--- .../Data/MSSQL/Resources/RegionStore.migrations | 12 +++++++++ OpenSim/Data/MySQL/MySQLSimulationData.cs | 29 ++++++++++++++++++---- .../Data/MySQL/Resources/RegionStore.migrations | 10 ++++++++ .../Data/SQLite/Resources/RegionStore.migrations | 12 +++++++++ OpenSim/Data/SQLite/SQLiteSimulationData.cs | 16 ++++++++++++ OpenSim/Framework/PrimitiveBaseShape.cs | 11 ++++++++ .../Linden/Caps/ObjectCaps/ObjectAdd.cs | 4 +++ .../Caps/ObjectCaps/UploadObjectAssetModule.cs | 1 + .../Region/ClientStack/Linden/UDP/LLClientView.cs | 1 + .../Avatar/Attachments/AttachmentsModule.cs | 18 +++++++++++++- .../InventoryAccess/InventoryAccessModule.cs | 8 ++++++ OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | 7 ++++++ .../Scenes/Serialization/SceneObjectSerializer.cs | 14 +++++++++++ 14 files changed, 150 insertions(+), 10 deletions(-) diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs index 5135050..f41f60c 100644 --- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs +++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs @@ -351,7 +351,7 @@ IF EXISTS (SELECT UUID FROM prims WHERE UUID = @UUID) 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, + LinkNumber = @LinkNumber, MediaURL = @MediaURL, AttachedPosX = @AttachedPosX, AttachedPosY = @AttachedPosY, AttachedPosZ = @AttachedPosZ, DynAttrs = @DynAttrs, PhysicsShapeType = @PhysicsShapeType, Density = @Density, GravityModifier = @GravityModifier, Friction = @Friction, Restitution = @Restitution WHERE UUID = @UUID END @@ -367,7 +367,7 @@ ELSE 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, + ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, AttachedPosX, AttachedPosY, AttachedPosZ, DynAttrs, PhysicsShapeType, Density, GravityModifier, Friction, Restitution ) VALUES ( @UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask, @@ -378,7 +378,7 @@ ELSE @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, + @ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @AttachedPosX, @AttachedPosY, @AttachedPosZ, @DynAttrs, @PhysicsShapeType, @Density, @GravityModifier, @Friction, @Restitution ) END"; @@ -1695,6 +1695,12 @@ VALUES if (!(primRow["MediaURL"] is System.DBNull)) prim.MediaUrl = (string)primRow["MediaURL"]; + if (!(primRow["AttachedPosX"] is System.DBNull)) + prim.AttachedPos = new Vector3( + Convert.ToSingle(primRow["AttachedPosX"]), + Convert.ToSingle(primRow["AttachedPosY"]), + Convert.ToSingle(primRow["AttachedPosZ"])); + if (!(primRow["DynAttrs"] is System.DBNull)) prim.DynAttrs = DAMap.FromXml((string)primRow["DynAttrs"]); else @@ -2099,7 +2105,10 @@ VALUES parameters.Add(_Database.CreateParameter("PassTouches", 0)); parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum)); parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl)); - + parameters.Add(_Database.CreateParameter("AttachedPosX", prim.AttachedPos.X)); + parameters.Add(_Database.CreateParameter("AttachedPosY", prim.AttachedPos.Y)); + parameters.Add(_Database.CreateParameter("AttachedPosZ", prim.AttachedPos.Z)); + if (prim.DynAttrs.CountNamespaces > 0) parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml())); else diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations index 4549801..bb89884 100644 --- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations @@ -1168,3 +1168,15 @@ ALTER TABLE prims ADD `Friction` double NOT NULL default '0.6'; ALTER TABLE prims ADD `Restitution` double NOT NULL default '0.5'; COMMIT + +:VERSION 40 #---------------- Save Attachment info + +BEGIN TRANSACTION + +ALTER TABLE prims ADD AttachedPosX float(53) default 0.0; +ALTER TABLE prims ADD AttachedPosY float(53) default 0.0; +ALTER TABLE prims ADD AttachedPosZ float(53) default 0.0; +ALTER TABLE primshapes ADD LastAttachPoint int not null default 0; + +COMMIT + diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index cf367ef..b03a904 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -173,7 +173,8 @@ namespace OpenSim.Data.MySQL "ParticleSystem, ClickAction, Material, " + "CollisionSound, CollisionSoundVolume, " + "PassTouches, " + - "LinkNumber, MediaURL, KeyframeMotion, " + + "LinkNumber, MediaURL, AttachedPosX, " + + "AttachedPosY, AttachedPosZ, KeyframeMotion, " + "PhysicsShapeType, Density, GravityModifier, " + "Friction, Restitution, DynAttrs " + ") values (" + "?UUID, " + @@ -208,7 +209,8 @@ namespace OpenSim.Data.MySQL "?ColorB, ?ColorA, ?ParticleSystem, " + "?ClickAction, ?Material, ?CollisionSound, " + "?CollisionSoundVolume, ?PassTouches, " + - "?LinkNumber, ?MediaURL, ?KeyframeMotion, " + + "?LinkNumber, ?MediaURL, ?AttachedPosX, " + + "?AttachedPosY, ?AttachedPosZ, ?KeyframeMotion, " + "?PhysicsShapeType, ?Density, ?GravityModifier, " + "?Friction, ?Restitution, ?DynAttrs)"; @@ -227,7 +229,7 @@ namespace OpenSim.Data.MySQL "PathTaperX, PathTaperY, PathTwist, " + "PathTwistBegin, ProfileBegin, ProfileEnd, " + "ProfileCurve, ProfileHollow, Texture, " + - "ExtraParams, State, Media) " + + "ExtraParams, State, LastAttachPoint, Media) " + "values (?UUID, " + "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " + "?PCode, ?PathBegin, ?PathEnd, " + @@ -239,7 +241,7 @@ namespace OpenSim.Data.MySQL "?PathTwistBegin, ?ProfileBegin, " + "?ProfileEnd, ?ProfileCurve, " + "?ProfileHollow, ?Texture, ?ExtraParams, " + - "?State, ?Media)"; + "?State, ?LastAttachPoint, ?Media)"; FillShapeCommand(cmd, prim); @@ -1303,7 +1305,16 @@ namespace OpenSim.Data.MySQL if (!(row["MediaURL"] is System.DBNull)) prim.MediaUrl = (string)row["MediaURL"]; - + + if (!(row["AttachedPosX"] is System.DBNull)) + { + prim.AttachedPos = new Vector3( + (float)(double)row["AttachedPosX"], + (float)(double)row["AttachedPosY"], + (float)(double)row["AttachedPosZ"] + ); + } + if (!(row["DynAttrs"] is System.DBNull)) prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]); else @@ -1673,6 +1684,12 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum); cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl); + if (prim.AttachedPos != null) + { + cmd.Parameters.AddWithValue("AttachedPosX", (double)prim.AttachedPos.X); + cmd.Parameters.AddWithValue("AttachedPosY", (double)prim.AttachedPos.Y); + cmd.Parameters.AddWithValue("AttachedPosZ", (double)prim.AttachedPos.Z); + } if (prim.KeyframeMotion != null) cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize()); @@ -1879,6 +1896,7 @@ namespace OpenSim.Data.MySQL s.ExtraParams = (byte[])row["ExtraParams"]; 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"]); @@ -1925,6 +1943,7 @@ namespace OpenSim.Data.MySQL cmd.Parameters.AddWithValue("Texture", s.TextureEntry); cmd.Parameters.AddWithValue("ExtraParams", s.ExtraParams); cmd.Parameters.AddWithValue("State", s.State); + cmd.Parameters.AddWithValue("LastAttachPoint", s.LastAttachPoint); cmd.Parameters.AddWithValue("Media", null == s.Media ? null : s.Media.ToXml()); } diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index 70b9558..a77e44d 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -930,3 +930,13 @@ BEGIN; ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob; COMMIT; + +:VERSION 49 #--------------------- Save attachment info + +BEGIN; +ALTER TABLE prims ADD COLUMN AttachedPosX double default 0; +ALTER TABLE prims ADD COLUMN AttachedPosY double default 0; +ALTER TABLE prims ADD COLUMN AttachedPosZ double default 0; +ALTER TABLE primshapes ADD COLUMN LastAttachPoint int(4) not null default '0'; +COMMIT; + diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations index bff039d..901068f 100644 --- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations +++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations @@ -600,3 +600,15 @@ BEGIN; ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob; COMMIT; + +:VERSION 30 #---------------- Save Attachment info + +BEGIN; + +ALTER TABLE prims ADD COLUMN AttachedPosX double default '0'; +ALTER TABLE prims ADD COLUMN AttachedPosY double default '0'; +ALTER TABLE prims ADD COLUMN AttachedPosZ double default '0'; +ALTER TABLE primshapes ADD COLUMN LastAttachPoint int not null default '0'; + +COMMIT; + diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index eba6612..d938b6b 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -1236,6 +1236,10 @@ namespace OpenSim.Data.SQLite createCol(prims, "MediaURL", typeof(String)); + createCol(prims, "AttachedPosX", typeof(Double)); + createCol(prims, "AttachedPosY", typeof(Double)); + createCol(prims, "AttachedPosZ", typeof(Double)); + createCol(prims, "DynAttrs", typeof(String)); createCol(prims, "PhysicsShapeType", typeof(Byte)); @@ -1724,6 +1728,12 @@ namespace OpenSim.Data.SQLite prim.MediaUrl = (string)row["MediaURL"]; } + prim.AttachedPos = new Vector3( + Convert.ToSingle(row["AttachedPosX"]), + Convert.ToSingle(row["AttachedPosY"]), + Convert.ToSingle(row["AttachedPosZ"]) + ); + if (!(row["DynAttrs"] is System.DBNull)) { //m_log.DebugFormat("[SQLITE]: DynAttrs type [{0}]", row["DynAttrs"].GetType()); @@ -2176,6 +2186,10 @@ namespace OpenSim.Data.SQLite row["MediaURL"] = prim.MediaUrl; + row["AttachedPosX"] = prim.AttachedPos.X; + row["AttachedPosY"] = prim.AttachedPos.Y; + row["AttachedPosZ"] = prim.AttachedPos.Z; + if (prim.DynAttrs.CountNamespaces > 0) row["DynAttrs"] = prim.DynAttrs.ToXml(); else @@ -2444,6 +2458,7 @@ namespace OpenSim.Data.SQLite s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]); s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]); s.State = Convert.ToByte(row["State"]); + s.LastAttachPoint = Convert.ToByte(row["LastAttachPoint"]); byte[] textureEntry = (byte[])row["Texture"]; s.TextureEntry = textureEntry; @@ -2493,6 +2508,7 @@ namespace OpenSim.Data.SQLite row["ProfileCurve"] = s.ProfileCurve; row["ProfileHollow"] = s.ProfileHollow; row["State"] = s.State; + row["LastAttachPoint"] = s.LastAttachPoint; row["Texture"] = s.TextureEntry; row["ExtraParams"] = s.ExtraParams; diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index c1e1a4f..c8a5376 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -105,6 +105,7 @@ namespace OpenSim.Framework private ushort _profileHollow; private Vector3 _scale; private byte _state; + private byte _lastattach; private ProfileShape _profileShape; private HollowShape _hollowShape; @@ -207,6 +208,7 @@ namespace OpenSim.Framework PCode = (byte)prim.PrimData.PCode; State = prim.PrimData.State; + LastAttachPoint = prim.PrimData.State; PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd); PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX); @@ -583,6 +585,15 @@ namespace OpenSim.Framework } } + public byte LastAttachPoint { + get { + return _lastattach; + } + set { + _lastattach = value; + } + } + public ProfileShape ProfileShape { get { return _profileShape; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs index 92805e2..94f8bc1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs @@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.Linden Quaternion rotation = Quaternion.Identity; Vector3 scale = Vector3.Zero; int state = 0; + int lastattach = 0; if (r.Type != OSDType.Map) // not a proper req return responsedata; @@ -224,6 +225,7 @@ namespace OpenSim.Region.ClientStack.Linden ray_target_id = ObjMap["RayTargetId"].AsUUID(); state = ObjMap["State"].AsInteger(); + lastattach = ObjMap["LastAttachPoint"].AsInteger(); try { ray_end = ((OSDArray)ObjMap["RayEnd"]).AsVector3(); @@ -290,6 +292,7 @@ namespace OpenSim.Region.ClientStack.Linden //session_id = rm["session_id"].AsUUID(); state = rm["state"].AsInteger(); + lastattach = rm["last_attach_point"].AsInteger(); try { ray_end = ((OSDArray)rm["ray_end"]).AsVector3(); @@ -331,6 +334,7 @@ namespace OpenSim.Region.ClientStack.Linden pbs.ProfileEnd = (ushort)profile_end; pbs.Scale = scale; pbs.State = (byte)state; + pbs.LastAttachPoint = (byte)lastattach; SceneObjectGroup obj = null; ; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 55a503e..769fe28 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs @@ -277,6 +277,7 @@ namespace OpenSim.Region.ClientStack.Linden pbs.ProfileEnd = (ushort) obj.ProfileEnd; pbs.Scale = obj.Scale; pbs.State = (byte) 0; + pbs.LastAttachPoint = (byte) 0; SceneObjectPart prim = new SceneObjectPart(); prim.UUID = UUID.Random(); prim.CreatorID = AgentId; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 1b091bf..3609ec1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -12188,6 +12188,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP shape.PCode = addPacket.ObjectData.PCode; shape.State = addPacket.ObjectData.State; + shape.LastAttachPoint = addPacket.ObjectData.State; shape.PathBegin = addPacket.ObjectData.PathBegin; shape.PathEnd = addPacket.ObjectData.PathEnd; shape.PathScaleX = addPacket.ObjectData.PathScaleX; diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 2818712..d0e0b35 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -422,6 +422,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments attachPos = Vector3.Zero; } + // if the attachment point is the same as previous, make sure we get the saved + // position info. + if (attachmentPt != 0 && attachmentPt == group.RootPart.Shape.LastAttachPoint) + { + attachPos = group.RootPart.AttachedPos; + } + // AttachmentPt 0 means the client chose to 'wear' the attachment. if (attachmentPt == (uint)AttachmentPoint.Default) { @@ -429,6 +436,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments attachmentPt = group.AttachmentPoint; } + // if we didn't find an attach point, look for where it was last attached + if (attachmentPt == 0) + { + attachmentPt = (uint)group.RootPart.Shape.LastAttachPoint; + attachPos = group.RootPart.AttachedPos; + group.HasGroupChanged = true; + } + // if we still didn't find a suitable attachment point....... if (attachmentPt == 0) { @@ -619,6 +634,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments so.ClearPartAttachmentData(); rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive); so.HasGroupChanged = true; + so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint; rootPart.Rezzed = DateTime.Now; rootPart.RemFlag(PrimFlags.TemporaryOnRez); so.AttachToBackup(); @@ -1210,4 +1226,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 68e4e26..0ec9575 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -836,6 +836,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); } + // if this was previously an attachment and is now being rezzed, + // save the old attachment info. + if (group.IsAttachment == false && group.RootPart.Shape.State != 0) + { + group.RootPart.AttachedPos = group.AbsolutePosition; + group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; + } + foreach (SceneObjectPart part in group.Parts) { // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 69b5f43..4bebbe8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -2230,6 +2230,13 @@ namespace OpenSim.Region.Framework.Scenes sourcePart.Inventory.RemoveInventoryItem(item.ItemID); } + + if (group.IsAttachment == false && group.RootPart.Shape.State != 0) + { + group.RootPart.AttachedPos = group.AbsolutePosition; + group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; + } + group.FromPartID = sourcePart.UUID; AddNewSceneObject(group, true, pos, rot, vel); diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 945745e..3ea936c 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -365,6 +365,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("CollisionSound", ProcessCollisionSound); m_SOPXmlProcessors.Add("CollisionSoundVolume", ProcessCollisionSoundVolume); m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); + m_SOPXmlProcessors.Add("AttachedPos", ProcessAttachedPos); m_SOPXmlProcessors.Add("DynAttrs", ProcessDynAttrs); m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); @@ -433,6 +434,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_ShapeXmlProcessors.Add("ProfileEnd", ProcessShpProfileEnd); m_ShapeXmlProcessors.Add("ProfileHollow", ProcessShpProfileHollow); m_ShapeXmlProcessors.Add("Scale", ProcessShpScale); + m_ShapeXmlProcessors.Add("LastAttachPoint", ProcessShpLastAttach); m_ShapeXmlProcessors.Add("State", ProcessShpState); m_ShapeXmlProcessors.Add("ProfileShape", ProcessShpProfileShape); m_ShapeXmlProcessors.Add("HollowShape", ProcessShpHollowShape); @@ -761,6 +763,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.MediaUrl = reader.ReadElementContentAsString("MediaUrl", String.Empty); } + private static void ProcessAttachedPos(SceneObjectPart obj, XmlTextReader reader) + { + obj.AttachedPos = Util.ReadVector(reader, "AttachedPos"); + } + private static void ProcessDynAttrs(SceneObjectPart obj, XmlTextReader reader) { obj.DynAttrs.ReadXml(reader); @@ -1043,6 +1050,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization shp.State = (byte)reader.ReadElementContentAsInt("State", String.Empty); } + private static void ProcessShpLastAttach(PrimitiveBaseShape shp, XmlTextReader reader) + { + shp.LastAttachPoint = (byte)reader.ReadElementContentAsInt("LastAttachPoint", String.Empty); + } + private static void ProcessShpProfileShape(PrimitiveBaseShape shp, XmlTextReader reader) { shp.ProfileShape = Util.ReadEnum(reader, "ProfileShape"); @@ -1289,6 +1301,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); if (sop.MediaUrl != null) writer.WriteElementString("MediaUrl", sop.MediaUrl.ToString()); + WriteVector(writer, "AttachedPos", sop.AttachedPos); if (sop.DynAttrs.CountNamespaces > 0) { @@ -1471,6 +1484,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("ProfileEnd", shp.ProfileEnd.ToString()); writer.WriteElementString("ProfileHollow", shp.ProfileHollow.ToString()); writer.WriteElementString("State", shp.State.ToString()); + writer.WriteElementString("LastAttachPoint", shp.LastAttachPoint.ToString()); WriteFlags(writer, "ProfileShape", shp.ProfileShape.ToString(), options); WriteFlags(writer, "HollowShape", shp.HollowShape.ToString(), options); -- cgit v1.1 From 7889e7757a7a3266c70bf0763f92c53b33d86b60 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 4 Aug 2013 19:20:10 +0200 Subject: Don't use 'Indented' formatting for RpcXml responses. (cherry picked from commit 93abcde69043b175071e0bb752538d9730433f1d) --- OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index c4e569d..76b4257 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -1056,7 +1056,21 @@ namespace OpenSim.Framework.Servers.HttpServer } response.ContentType = "text/xml"; - responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); + using (MemoryStream outs = new MemoryStream()) + { + using (XmlTextWriter writer = new XmlTextWriter(outs, Encoding.UTF8)) + { + writer.Formatting = Formatting.None; + XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); + writer.Flush(); + outs.Flush(); + outs.Position = 0; + using (StreamReader sr = new StreamReader(outs)) + { + responseString = sr.ReadToEnd(); + } + } + } } else { -- cgit v1.1 From 8de5c29e2cc75598f5a00e1a557bd925129e506e Mon Sep 17 00:00:00 2001 From: teravus Date: Sun, 22 Sep 2013 21:34:55 -0500 Subject: * The last two are the the patch that Aleric wanted pulled from his repo. * Added GregC to CONTRIBUTORS.txt, Aleric was already in there. * There's some controversy, Some people have suggested that this could be stored in dynamic attributes instead of the database.. Melanie was wanting to pull from the avination repo but was asked to wait on committing anything new until the release. The cherry-pick doesn't answer those questions. --- CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 8181483..a4bcb91 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -87,6 +87,7 @@ what it is today. * Garmin Kawaguichi * Gerhard * Godfrey +* Greg C. * Grumly57 * GuduleLapointe * Ewe Loon -- cgit v1.1 From f384a6291e6b03b451dd3e3fec7667bc8f53c296 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 25 Sep 2013 00:02:17 +0100 Subject: Instead of swallowing any socket begin/end receive exceptions, log them for debugging purposes. This may reveal why on some teleports with current code, the UseCircuitCode message gets through but CompleteMovement disappears into the ether. --- .../ClientStack/Linden/UDP/OpenSimUDPBase.cs | 39 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index d0ed7e8..88494be 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -295,7 +295,16 @@ namespace OpenMetaverse m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); } } - catch (ObjectDisposedException) { } + catch (ObjectDisposedException e) + { + m_log.Error( + string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); + } + catch (Exception e) + { + m_log.Error( + string.Format("[UDPBASE]: Error processing UDP begin receive {0}. Exception ", UdpReceives), e); + } } } @@ -312,12 +321,12 @@ namespace OpenMetaverse if (m_asyncPacketHandling) AsyncBeginReceive(); - // get the buffer that was created in AsyncBeginReceive - // this is the received data - UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; - try { + // get the buffer that was created in AsyncBeginReceive + // this is the received data + UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; + int startTick = Util.EnvironmentTickCount(); // get the length of data actually read from the socket, store it with the @@ -345,8 +354,24 @@ namespace OpenMetaverse m_currentReceiveTimeSamples++; } } - catch (SocketException) { } - catch (ObjectDisposedException) { } + catch (SocketException se) + { + m_log.Error( + string.Format( + "[UDPBASE]: Error processing UDP end receive {0}, socket error code {1}. Exception ", + UdpReceives, se.ErrorCode), + se); + } + catch (ObjectDisposedException e) + { + m_log.Error( + string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); + } + catch (Exception e) + { + m_log.Error( + string.Format("[UDPBASE]: Error processing UDP end receive {0}. Exception ", UdpReceives), e); + } finally { // if (UsePools) -- cgit v1.1 From 732554be0451b9e7fa5f96ffb8f9f347b964dd88 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 25 Sep 2013 18:29:14 +0100 Subject: Reinsert 200ms sleep accidentally removed in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100) --- OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index b1752c1..a130ffe 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1722,9 +1722,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.DebugFormat( "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} in {1} but no client exists. Waiting.", endPoint, m_scene.Name); - - Thread.Sleep(200); } + + Thread.Sleep(200); } if (client == null) -- cgit v1.1 From 32ddfc274056e68bfd9e7e6d3e7921c8062a59d1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 25 Sep 2013 18:45:56 +0100 Subject: Reinsert client.SceneAgent checks into LLUDPServer.HandleCompleteMovementIntoRegion() to fix race condition regression in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100) This check is necessary to close a race condition where the CompleteAgentMovement processing could proceed when the UseCircuitCode thread had added the client to the client manager but before the ScenePresence had registered to process the CompleteAgentMovement message. This is most probably why the message appeared to get lost on a proportion of entity transfers. A better long term solution may be to set the IClientAPI.SceneAgent property before the client is added to the manager. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 37 +++++++++++++++------- OpenSim/Region/Framework/Scenes/Scene.cs | 3 ++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index a130ffe..9504f15 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -1692,6 +1692,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP endPoint = (IPEndPoint)array[0]; CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; + m_log.DebugFormat( + "[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name); + // Determine which agent this packet came from // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode @@ -1703,24 +1706,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (m_scene.TryGetClient(endPoint, out client)) { - if (client.IsActive) - { - break; - } - else + if (!client.IsActive) { // This check exists to catch a condition where the client has been closed by another thread // but has not yet been removed from the client manager (and possibly a new connection has // not yet been established). m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} for {1} in {2} but client is not active. Waiting.", + "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.", + endPoint, client.Name, m_scene.Name); + } + else if (client.SceneAgent == null) + { + // This check exists to catch a condition where the new client has been added to the client + // manager but the SceneAgent has not yet been set in Scene.AddNewClient(). If we are too + // eager, then the new ScenePresence may not have registered a listener for this messsage + // before we try to process it. + // XXX: A better long term fix may be to add the SceneAgent before the client is added to + // the client manager + m_log.DebugFormat( + "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", endPoint, client.Name, m_scene.Name); } + else + { + break; + } } else { m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} in {1} but no client exists. Waiting.", + "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", endPoint, m_scene.Name); } @@ -1730,19 +1745,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (client == null) { m_log.DebugFormat( - "[LLUDPSERVER]: No client found for CompleteMovementIntoRegion from {0} in {1} after wait. Dropping.", + "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.", endPoint, m_scene.Name); return; } - else if (!client.IsActive) + else if (!client.IsActive || client.SceneAgent == null) { // This check exists to catch a condition where the client has been closed by another thread // but has not yet been removed from the client manager. // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging // purposes. m_log.DebugFormat( - "[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} for {1} in {2} but client is not active after wait. Dropping.", + "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.", endPoint, client.Name, m_scene.Name); return; @@ -1767,7 +1782,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP catch (Exception e) { m_log.ErrorFormat( - "[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", + "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", endPoint != null ? endPoint.ToString() : "n/a", client != null ? client.Name : "unknown", client != null ? client.AgentId.ToString() : "unknown", diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index bc5a67f..3dc509b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2863,6 +2863,9 @@ namespace OpenSim.Region.Framework.Scenes // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the // client is for a root or child agent. + // XXX: This may be better set for a new client before that client is added to the client manager. + // But need to know what happens in the case where a ScenePresence is already present (and if this + // actually occurs). client.SceneAgent = sp; // This is currently also being done earlier in NewUserConnection for real users to see if this -- cgit v1.1 From b22c92368f8991c174897306334c523bac8a4099 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 25 Sep 2013 21:53:38 +0100 Subject: Move adding UUID.Zero -> Unknown User binding to UMM.Init() so that it's also called by HGUserManagementModule --- .../CoreModules/Framework/UserManagement/UserManagementModule.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 96eb63f..d3926cc 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -73,8 +73,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement Init(); m_log.DebugFormat("[USER MANAGEMENT MODULE]: {0} is enabled", Name); } - - AddUser(UUID.Zero, "Unknown", "User"); } public bool IsSharedModule @@ -645,6 +643,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement protected void Init() { + AddUser(UUID.Zero, "Unknown", "User"); RegisterConsoleCmds(); } -- cgit v1.1 From 4664090b34dfa2e944204fb7b616a19fcb3eeddf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 25 Sep 2013 22:59:57 +0100 Subject: minor: correct spelling of Initialized in LSC connector version message --- .../ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 8ec943d..5c098a8 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -94,7 +94,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation throw new Exception(string.Format("Invalid ConnectorProtocolVersion {0}", ServiceVersion)); m_log.InfoFormat( - "[LOCAL SIMULATION CONNECTOR]: Initialzied with connector protocol version {0}", ServiceVersion); + "[LOCAL SIMULATION CONNECTOR]: Initialized with connector protocol version {0}", ServiceVersion); } } -- cgit v1.1 From babfbe8d6d29380e42242008b6a743bc895ddb96 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 26 Sep 2013 00:31:33 +0100 Subject: minor: log MaxOutgoingTransferVersion at EntityTransferModule startup --- .../CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index c1c8672..8ae81ac 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -185,6 +185,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer else { transferVersionName = rawVersionComponents[0]; + + m_log.InfoFormat( + "[ENTITY TRANSFER MODULE]: MaxOutgoingTransferVersion set to {0}", + string.Format("{0}/{1}", transferVersionName, maxTransferVersion)); } DisableInterRegionTeleportCancellation -- cgit v1.1 From 253f8de8cddfc195c2e54ef328ac0c4cb371d199 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 26 Sep 2013 00:33:50 +0100 Subject: minor: Add scene name to baked textures in cache log message --- 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 8d72e18..7243db1 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2909,7 +2909,7 @@ namespace OpenSim.Region.Framework.Scenes // If we are using the the cached appearance then send it out to everyone if (cachedappearance) { - m_log.DebugFormat("[SCENE PRESENCE]: baked textures are in the cache for {0}", Name); + m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name); // If the avatars baked textures are all in the cache, then we have a // complete appearance... send it out, if not, then we'll send it when -- cgit v1.1 From e24edada2435f942575a5a7acb4568fe6c0e4e30 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 26 Sep 2013 00:39:32 +0100 Subject: minor: Comment out windlight log message about sending scene data for now. --- OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs index 89f3280..0a4e83e 100644 --- a/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs +++ b/OpenSim/Region/CoreModules/World/LightShare/LightShareModule.cs @@ -207,7 +207,8 @@ namespace OpenSim.Region.CoreModules.World.LightShare private void EventManager_OnMakeRootAgent(ScenePresence presence) { - m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); +// m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client {0}", presence.Name); + SendProfileToClient(presence.ControllingClient); } -- cgit v1.1 From d6d82dbd3c9d081209914351ff3cc18c349e362b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 26 Sep 2013 20:13:29 +0100 Subject: minor: correct attachment spelling mistake in log message in HGEntityTransferModule.OnIncomingSceneObject() --- .../CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 76dbc72..04a0db6 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) { string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url); Dictionary ids = new Dictionary(); HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url); uuidGatherer.GatherAssetUuids(so, ids); -- cgit v1.1 From 70b51f12cd0b4f2c11cefa4a2c47b91fe2fde53e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 27 Sep 2013 00:01:18 +0100 Subject: minor: Clean up tabbing and spacing issues in OpenSim.ini.example --- bin/OpenSim.ini.example | 51 +++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index d6de777..b78e3b7 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -418,8 +418,8 @@ ;# {SMTP_SERVER_PASSWORD} {[Startup]emailmodule:DefaultEmailModule enabled:true} {SMTP server password} {} ; SMTP_SERVER_PASSWORD = "" -[Network] +[Network] ;# {ConsoleUser} {} {User name for console account} {} ;; Configure the remote console user here. This will not actually be used ;; unless you use -console=rest at startup. @@ -456,6 +456,7 @@ ;; web server ; user_agent = "OpenSim LSL (Mozilla Compatible)" + [XMLRPC] ;# {XmlRpcRouterModule} {} {Module used to route incoming llRemoteData calls} {XmlRpcRouterModule XmlRpcGridRouterModule} XmlRpcRouterModule ;; If enabled and set to XmlRpcRouterModule, this will post an event, @@ -470,9 +471,6 @@ ;# {XmlRpcPort} {} {Port for incoming llRemoteData xmlrpc calls} {} 20800 ;XmlRpcPort = 20800 - -;; {option} {depends on} {question to ask} {choices} default value - ;# {XmlRpcHubURI} {XmlRpcRouterModule} {URI for external service used to register xmlrpc channels created in the simulator. This depends on XmlRpcRouterModule being set to XmlRpcGridRouterModule} {} http://example.com ;; If XmlRpcRouterModule is set to XmlRpcGridRouterModule, the simulator ;; will use this address to register xmlrpc channels on the external @@ -508,7 +506,7 @@ ; These are enabled by default to localhost. Change if you see fit. Cap_GetTexture = "localhost" Cap_GetMesh = "localhost" - Cap_AvatarPickerSearch = "localhost" + Cap_AvatarPickerSearch = "localhost" ; This is disabled by default. Change if you see fit. Note that ; serving this cap from the simulators may lead to poor performace. @@ -516,7 +514,6 @@ [SimulatorFeatures] - ;# {MapImageServerURI} {} {URL for the map server} {} ; Experimental new information sent in SimulatorFeatures cap for Kokua ; viewers @@ -554,7 +551,7 @@ ;; Module to handle offline messaging. The core module requires an external ;; web service to do this. See OpenSim wiki. ; OfflineMessageModule = OfflineMessageModule - ;; Or, alternatively, use this one, which works for both standalones and grids + ;; Or, alternatively, use this one, which works for both standalones and grids ; OfflineMessageModule = "Offline Message Module V2" ;# {OfflineMessageURL} {OfflineMessageModule:OfflineMessageModule Offline Message Module V2:Offline Message Module V2} {URL of offline messaging service} {} @@ -562,8 +559,8 @@ ; OfflineMessageURL = http://yourserver/Offline.php or http://yourrobustserver:8003 ;# {StorageProvider} {Offline Message Module V2:Offline Message Module V2} {DLL that provides the storage interface} {OpenSim.Data.MySQL.dll} - ;; For standalones, this is the storage dll. - ; StorageProvider = OpenSim.Data.MySQL.dll + ;; For standalones, this is the storage dll. + ; StorageProvider = OpenSim.Data.MySQL.dll ;# {MuteListModule} {OfflineMessageModule:OfflineMessageModule} {} {} MuteListModule ;; Mute list handler (not yet implemented). MUST BE SET to allow offline @@ -960,38 +957,38 @@ ;; http://code.google.com/p/flotsam/ ;; or from the SimianGrid project at http://code.google.com/p/openmetaverse ; Module = Default - ;; or... use Groups Module V2, which works for standalones and robust grids - ; Module = "Groups Module V2" + ;; or... use Groups Module V2, which works for standalones and robust grids + ; Module = "Groups Module V2" ;# {StorageProvider} {Module:Groups Module V2} {The DLL that provides the storage for V2} {OpenSim.Data.MySQL.dll} ; StorageProvider = OpenSim.Data.MySQL.dll ;# {ServicesConnectorModule} {Module:GroupsModule Module:Groups Module V2} {Service connector to use for groups} {XmlRpcGroupsServicesConnector SimianGroupsServicesConnector "Groups Local Service Connector" "Groups Remote Service Connector" "Groups HG Service Connector"} XmlRpcGroupsServicesConnector ;; Service connectors to the Groups Service as used in the GroupsModule. Select one as follows: - ;; -- for Flotsam Groups use XmlRpcGroupsServicesConnector - ;; -- for Simian Groups use SimianGroupsServicesConnector - ;; -- for V2 Groups, standalone, non-HG use "Groups Local Service Connector" - ;; -- for V2 Groups, grided sim, non-HG use "Groups Remote Service Connector" - ;; -- for V2 Groups, HG, both standalone and grided sim, use "Groups HG Service Connector" - ;; Note that the quotes "" around the words are important! + ;; -- for Flotsam Groups use XmlRpcGroupsServicesConnector + ;; -- for Simian Groups use SimianGroupsServicesConnector + ;; -- for V2 Groups, standalone, non-HG use "Groups Local Service Connector" + ;; -- for V2 Groups, grided sim, non-HG use "Groups Remote Service Connector" + ;; -- for V2 Groups, HG, both standalone and grided sim, use "Groups HG Service Connector" + ;; Note that the quotes "" around the words are important! ; ServicesConnectorModule = XmlRpcGroupsServicesConnector ;# {LocalService} {ServicesConnectorModule:Groups HG Service Connector} {Is the group service in this process or elsewhere?} {local remote} local - ;; Used for V2 in HG only. If standalone, set this to local; if grided sim, set this to remote + ;; Used for V2 in HG only. If standalone, set this to local; if grided sim, set this to remote ; LocalService = local ;# {GroupsServerURI} {Module:GroupsModule (ServicesConnectorModule:Groups Remote Service Connector or (ServicesConnectorModule:Groups HG Service Connector and LocalService:remote))} {Groups Server URI} {} ;; URI for the groups services of this grid ;; e.g. http://yourxmlrpcserver.com/xmlrpc.php for Flotsam XmlRpc ;; or http://mygridserver.com:82/Grid/ for SimianGrid - ;; or http:://mygridserver.com:8003 for robust, V2 - ;; Leave it commented for standalones, V2 + ;; or http:://mygridserver.com:8003 for robust, V2 + ;; Leave it commented for standalones, V2 ; GroupsServerURI = "" ;# {HomeURI} {ServicesConnectorModule:Groups HG Service Connector} {What's the home address of this world?} {} - ;; Used for V2 in HG only. For example - ;; http://mygridserver.com:9000 or http://mygridserver.com:8002 - ;; If you have this set under [Startup], no need to set it here, leave it commented + ;; Used for V2 in HG only. For example + ;; http://mygridserver.com:9000 or http://mygridserver.com:8002 + ;; If you have this set under [Startup], no need to set it here, leave it commented ; HomeURI = "" ;# {MessagingEnabled} {Module:GroupsModule Module:Groups Module V2} {Is groups messaging enabled?} {true false} true @@ -999,8 +996,8 @@ ;# {MessagingModule} {MessagingEnabled:true} {Module to use for groups messaging} {GroupsMessagingModule "Groups Messaging Module V2"} GroupsMessagingModule ; MessagingModule = GroupsMessagingModule - ;; or use V2 for Groups V2 - ; MessagingModule = "Groups Messaging Module V2" + ;; or use V2 for Groups V2 + ; MessagingModule = "Groups Messaging Module V2" ;# {NoticesEnabled} {Module:GroupsModule Module:Groups Module V2} {Enable group notices?} {true false} true ;; Enable Group Notices @@ -1020,6 +1017,7 @@ ; XmlRpcServiceReadKey = 1234 ; XmlRpcServiceWriteKey = 1234 + [InterestManagement] ;# {UpdatePrioritizationScheme} {} {Update prioritization scheme?} {BestAvatarResponsiveness Time Distance SimpleAngularDistance FrontBack} BestAvatarResponsiveness ;; This section controls how state updates are prioritized for each client @@ -1038,16 +1036,19 @@ ;# {Enabled} {} {Enable Non Player Character (NPC) facilities} {true false} false ; Enabled = false + [Terrain] ;# {InitialTerrain} {} {Initial terrain type} {pinhead-island flat} pinhead-island ; InitialTerrain = "pinhead-island" + [UserProfiles] ;# {ProfileURL} {} {Set url to UserProfilesService} {} ;; Set the value of the url to your UserProfilesService ;; If un-set / "" the module is disabled ;; ProfileServiceURL = http://127.0.0.1:8002 + [Architecture] ;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini config-include/SimianGrid.ini config-include/HyperSimianGrid.ini} config-include/Standalone.ini ;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim, -- cgit v1.1 From 585d0800dd61798ec2640e3f42f7d41fb9fa5b33 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 27 Sep 2013 00:14:40 +0100 Subject: minor: Make OpenSimDefaults.ini consistent (spacing and tabs to spaces) --- bin/OpenSimDefaults.ini | 51 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 8da4daf..c090306 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -399,7 +399,6 @@ ; ProfileURL = http://127.0.0.1:9000 - [SMTP] enabled = false @@ -461,6 +460,7 @@ ; many simultaneous requests, default is 30 and is currently applied only to assets ;MaxRequestConcurrency = 30 + [ClientStack.LindenUDP] ; Set this to true to process incoming packets asynchronously. Networking is ; already separated from packet handling with a queue, so this will only @@ -560,6 +560,7 @@ ; ;PausedAckTimeout = 300 + [ClientStack.LindenCaps] ;; Long list of capabilities taken from ;; http://wiki.secondlife.com/wiki/Current_Sim_Capabilities @@ -632,8 +633,8 @@ Cap_FetchInventoryDescendents2 = "localhost" Cap_FetchInventory2 = "localhost" - ; Capability for searching for people - Cap_AvatarPickerSearch = "localhost" + ; Capability for searching for people + Cap_AvatarPickerSearch = "localhost" [Chat] @@ -964,6 +965,7 @@ ; Default is false. ;force_simple_prim_meshing = true + [BulletSim] ; All the BulletSim parameters can be displayed with the console command ; "physics get all" and all are defined in the source file @@ -1279,6 +1281,7 @@ ; Maximum number of external urls that scripts can set up in this simulator (e.g. via llRequestURL()) max_external_urls_per_simulator = 100 + [DataSnapshot] ; The following set of configs pertains to search. ; Set index_sims to true to enable search engines to index your searchable data @@ -1683,31 +1686,36 @@ RootReprioritizationDistance = 10.0 ChildReprioritizationDistance = 20.0 + [Monitoring] ; Enable region monitoring ; If true, this will print out an error if more than a minute has passed since the last simulator frame ; Also is another source of region statistics provided via the regionstats URL Enabled = true -; View region statistics via a web page -; See http://opensimulator.org/wiki/FAQ#Region_Statistics_on_a_Web_Page -; Use a web browser and type in the "Login URI" + "/SStats/" -; For example- http://127.0.0.1:9000/SStats/ + [WebStats] -; enabled=false + ; View region statistics via a web page + ; See http://opensimulator.org/wiki/FAQ#Region_Statistics_on_a_Web_Page + ; Use a web browser and type in the "Login URI" + "/SStats/" + ; For example- http://127.0.0.1:9000/SStats/ + ; enabled=false [MediaOnAPrim] ; Enable media on a prim facilities Enabled = true; + [NPC] ;; Enable Non Player Character (NPC) facilities Enabled = false + [Terrain] InitialTerrain = "pinhead-island" + ;; ;; If you are using a simian grid frontend you can enable ;; this module to upload tile images for the mapping fn @@ -1717,15 +1725,17 @@ MaptileURL = "http://www.mygrid.com/Grid/" RefreshTime = 3600 + ;; ;; JsonStore module provides structured store for scripts ;; [JsonStore] -Enabled = False + Enabled = False + + ;; Enable direct access to the SOP dynamic attributes + EnableObjectStore = False + MaxStringSpace = 0 -;; Enable direct access to the SOP dynamic attributes -EnableObjectStore = False -MaxStringSpace = 0 ;; ;; These are defaults that are overwritten below in [Architecture]. @@ -1740,24 +1750,29 @@ MaxStringSpace = 0 ; asset store each time the region starts AssetLoaderEnabled = true + [GridService] ;; default standalone, overridable in StandaloneCommon.ini StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" + [AutoBackupModule] - ;; default is module is disabled at the top level - AutoBackupModuleEnabled = false + ;; default is module is disabled at the top level + AutoBackupModuleEnabled = false + [Sounds] - ;; {Module} {} {Implementation of ISoundModule to use.} {OpenSim.Region.CoreModules.dll:SoundModule} - Module = OpenSim.Region.CoreModules.dll:SoundModule + ;; {Module} {} {Implementation of ISoundModule to use.} {OpenSim.Region.CoreModules.dll:SoundModule} + Module = OpenSim.Region.CoreModules.dll:SoundModule + + ;; {MaxDistance} {} {Cut-off distance at which sounds will not be sent to users} {100.0} + MaxDistance = 100.0 - ;; {MaxDistance} {} {Cut-off distance at which sounds will not be sent to users} {100.0} - MaxDistance = 100.0 [ServiceThrottle] ;; Default time interval (in ms) for the throttle service thread to wake up Interval = 5000 + [Modules] Include-modules = "addon-modules/*/config/*.ini" -- cgit v1.1 From b704de9bf82782c3e8e5ebbdf88d8dfcb26c1750 Mon Sep 17 00:00:00 2001 From: dahlia Date: Thu, 26 Sep 2013 16:27:11 -0700 Subject: minor code formatting for the sake of consistency and readability --- OpenSim/Region/Application/OpenSim.cs | 54 +++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 1cdd868..a7fe226 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -237,27 +237,33 @@ namespace OpenSim m_console.Commands.AddCommand("General", false, "change region", "change region ", - "Change current console region", ChangeSelectedRegion); + "Change current console region", + ChangeSelectedRegion); m_console.Commands.AddCommand("Archiving", false, "save xml", "save xml", - "Save a region's data in XML format", SaveXml); + "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", SaveXml2); + "Save a region's data in XML2 format", + SaveXml2); m_console.Commands.AddCommand("Archiving", false, "load xml", "load xml [-newIDs [ ]]", - "Load a region's data from XML format", LoadXml); + "Load a region's data from XML format", + LoadXml); m_console.Commands.AddCommand("Archiving", false, "load xml2", "load xml2", - "Load a region's data from XML2 format", LoadXml2); + "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", SavePrimsXml2); + "Save named prim to XML2", + SavePrimsXml2); m_console.Commands.AddCommand("Archiving", false, "load oar", "load oar [--merge] [--skip-assets] []", @@ -287,7 +293,8 @@ namespace OpenSim m_console.Commands.AddCommand("Objects", false, "edit scale", "edit scale ", - "Change the scale of a named prim", HandleEditScale); + "Change the scale of a named prim", + HandleEditScale); m_console.Commands.AddCommand("Users", false, "kick user", "kick user [--force] [message]", @@ -305,31 +312,38 @@ namespace OpenSim m_console.Commands.AddCommand("Comms", false, "show connections", "show connections", - "Show connection data", HandleShow); + "Show connection data", + HandleShow); m_console.Commands.AddCommand("Comms", false, "show circuits", "show circuits", - "Show agent circuit data", HandleShow); + "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", HandleShow); + "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", HandleShow); + "Show module data", + HandleShow); m_console.Commands.AddCommand("Regions", false, "show regions", "show regions", - "Show region data", HandleShow); + "Show region data", + HandleShow); m_console.Commands.AddCommand("Regions", false, "show ratings", "show ratings", - "Show rating data", HandleShow); + "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.", RunCommand); + "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", + RunCommand); m_console.Commands.AddCommand("Regions", false, "create region", "create region [\"region name\"] ", @@ -342,19 +356,23 @@ namespace OpenSim m_console.Commands.AddCommand("Regions", false, "restart", "restart", - "Restart all sims in this instance", RunCommand); + "Restart all sims in this instance", + RunCommand); m_console.Commands.AddCommand("General", false, "command-script", "command-script