From 42f1b88eb2492f8d218526c1b30ac027a65d67f3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Sep 2011 18:13:36 +0100 Subject: [PATCH 01/64] If a prim inventory becomes empty through deletion, send an empty xfer file name rather than one that references a metadata file containing only the folder object. If we do this, then viewer 3 crashes when we try and rez a script directly in an attachment's prim inventory. Sending an empty file name was already being done if the prim's inventory had never been touched. Now we always do that if there are no items in that inventory. Hopefully addresses the remaining point in http://opensimulator.org/mantis/view.php?id=5644 --- .../Scenes/SceneObjectPartInventory.cs | 63 +++++++++++++------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 57adda7be4..59ac30da69 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -784,6 +784,10 @@ namespace OpenSim.Region.Framework.Scenes private bool CreateInventoryFile() { +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}", +// m_part.Name, m_part.UUID, m_part.LocalId, m_inventorySerial); + if (m_inventoryFileName == String.Empty || m_inventoryFileNameSerial < m_inventorySerial) { @@ -797,6 +801,10 @@ namespace OpenSim.Region.Framework.Scenes { foreach (TaskInventoryItem item in m_items.Values) { +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}", +// item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId); + UUID ownerID = item.OwnerID; uint everyoneMask = 0; uint baseMask = item.BasePermissions; @@ -856,28 +864,43 @@ namespace OpenSim.Region.Framework.Scenes /// public void RequestInventoryFile(IClientAPI client, IXfer xferManager) { - CreateInventoryFile(); - - if (m_inventorySerial == 0) // No inventory + lock (m_items) { - client.SendTaskInventory(m_part.UUID, 0, new byte[0]); - return; + CreateInventoryFile(); + + // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing + // a new script if any previous deletion has left the prim inventory empty. + if (m_items.Count == 0) // No inventory + { +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items", +// m_part.Name, m_part.LocalId, m_part.UUID, client.Name); + + client.SendTaskInventory(m_part.UUID, 0, new byte[0]); + return; + } + + // In principle, we should only do the rest if the inventory changed; + // by sending m_inventorySerial to the client, it ought to know + // that nothing changed and that it doesn't need to request the file. + // Unfortunately, it doesn't look like the client optimizes this; + // the client seems to always come back and request the Xfer, + // no matter what value m_inventorySerial has. + // FIXME: Could probably be > 0 here rather than > 2 + if (m_inventoryFileData.Length > 2) + { + // Add the file for Xfer + // m_log.DebugFormat( + // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}", + // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId); + + xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); + } + + // Tell the client we're ready to Xfer the file + client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial, + Util.StringToBytes256(m_inventoryFileName)); } - - // In principle, we should only do the rest if the inventory changed; - // by sending m_inventorySerial to the client, it ought to know - // that nothing changed and that it doesn't need to request the file. - // Unfortunately, it doesn't look like the client optimizes this; - // the client seems to always come back and request the Xfer, - // no matter what value m_inventorySerial has. - - if (m_inventoryFileData.Length > 2) - // Add the file for Xfer - xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); - - // Tell the client we're ready to Xfer the file - client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial, - Util.StringToBytes256(m_inventoryFileName)); } /// From 8fb3e71b14e28bf8a4ddb72e3d1b529128f090ce Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Sep 2011 18:36:22 +0100 Subject: [PATCH 02/64] Shuffle order of code in invnetory connector GetFolderContent() calls to avoid a possible race condition --- .../Inventory/LocalInventoryServiceConnector.cs | 15 +++++++++------ .../Inventory/RemoteXInventoryServiceConnector.cs | 15 +++++++++------ .../Framework/Scenes/SceneObjectPartInventory.cs | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index 1c83f8eb49..097ff1aded 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -185,15 +185,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory public InventoryCollection GetFolderContent(UUID userID, UUID folderID) { InventoryCollection invCol = m_InventoryService.GetFolderContent(userID, folderID); - Util.FireAndForget(delegate + + if (UserManager != null) { - if (UserManager != null) + // Protect ourselves against the caller subsequently modifying the items list + List items = new List(invCol.Items); + + Util.FireAndForget(delegate { - // Protect ourselves against the caller subsequently modifying the items list - foreach (InventoryItemBase item in new List(invCol.Items)) + foreach (InventoryItemBase item in items) UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); - } - }); + }); + } return invCol; } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index c9c716cec7..73ab4e31cc 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -193,15 +193,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory public InventoryCollection GetFolderContent(UUID userID, UUID folderID) { InventoryCollection invCol = m_RemoteConnector.GetFolderContent(userID, folderID); - Util.FireAndForget(delegate + + if (UserManager != null) { - if (UserManager != null) + // Protect ourselves against the caller subsequently modifying the items list + List items = new List(invCol.Items); + + Util.FireAndForget(delegate { - // Protect ourselves against the caller subsequently modifying the items list - foreach (InventoryItemBase item in new List(invCol.Items)) + foreach (InventoryItemBase item in items) UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); - } - }); + }); + } return invCol; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 59ac30da69..6085f1e451 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -875,7 +875,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items", // m_part.Name, m_part.LocalId, m_part.UUID, client.Name); - + client.SendTaskInventory(m_part.UUID, 0, new byte[0]); return; } From a4cc5f628f053ad1f9f849addf79551cd58e9337 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Sep 2011 18:42:10 +0100 Subject: [PATCH 03/64] Only bother to create an inventory xfer file if there are any items in a prim inventory --- OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 6085f1e451..d63b411185 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -866,8 +866,6 @@ namespace OpenSim.Region.Framework.Scenes { lock (m_items) { - CreateInventoryFile(); - // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing // a new script if any previous deletion has left the prim inventory empty. if (m_items.Count == 0) // No inventory @@ -879,6 +877,8 @@ namespace OpenSim.Region.Framework.Scenes client.SendTaskInventory(m_part.UUID, 0, new byte[0]); return; } + + CreateInventoryFile(); // In principle, we should only do the rest if the inventory changed; // by sending m_inventorySerial to the client, it ought to know From de19dc3024e5359f594d0a32c593d905163c24ea Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Sep 2011 18:58:58 +0100 Subject: [PATCH 04/64] refactor: rename SOG/SOP.GetProperties() to SendPropertiesToClient() to reflect what it actually does This also makes it consistent with some other methods that send data to the client. --- .../ClientStack/Linden/UDP/LLClientView.cs | 4 +-- .../World/Objects/BuySell/BuySellModule.cs | 4 +-- .../Framework/Scenes/Scene.Inventory.cs | 18 +++++------ .../Framework/Scenes/Scene.PacketHandlers.cs | 4 +-- .../Framework/Scenes/SceneObjectGroup.cs | 20 +++++------- .../Framework/Scenes/SceneObjectPart.cs | 32 +++++++++++-------- .../Scenes/SceneObjectPartInventory.cs | 2 +- .../Shared/Api/Implementation/LSL_Api.cs | 2 +- 8 files changed, 43 insertions(+), 43 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index e9ee7be57f..b5c6742631 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -4119,8 +4119,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP while (updatesThisCall < m_maxUpdates) { lock (m_entityProps.SyncRoot) - if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) - break; + if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) + break; ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; if (update.SendFamilyProps) diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index 8b78701537..1e4f0a4e93 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell part.ParentGroup.HasGroupChanged = true; - part.GetProperties(client); + part.SendPropertiesToClient(client); } public bool BuyObject(IClientAPI remoteClient, UUID categoryID, uint localID, byte saleType, int salePrice) @@ -142,7 +142,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell part.SalePrice = 10; group.HasGroupChanged = true; - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); part.TriggerScriptChangedEvent(Changed.OWNER); group.ResumeScripts(); part.ScheduleFullUpdate(); diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 9dcd10a3e5..f9dba2d24c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -274,7 +274,7 @@ namespace OpenSim.Region.Framework.Scenes if (group.UpdateInventoryItem(item)) remoteClient.SendAgentAlertMessage("Script saved", false); - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); // Trigger rerunning of script (use TriggerRezScript event, see RezScript) ArrayList errors = new ArrayList(); @@ -999,7 +999,7 @@ namespace OpenSim.Region.Framework.Scenes } group.RemoveInventoryItem(localID, itemID); - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); } private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId) @@ -1272,7 +1272,7 @@ namespace OpenSim.Region.Framework.Scenes if (TryGetScenePresence(srcTaskItem.OwnerID, out avatar)) { - destPart.GetProperties(avatar.ControllingClient); + destPart.SendPropertiesToClient(avatar.ControllingClient); } } @@ -1427,7 +1427,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.InfoFormat( "[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}", item.Name, primLocalID, remoteClient.Name); - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); if (!Permissions.BypassPermissions()) { if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) @@ -1522,7 +1522,7 @@ namespace OpenSim.Region.Framework.Scenes if (part.Inventory.UpdateInventoryItem(itemInfo)) { - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); } } } @@ -1574,7 +1574,7 @@ namespace OpenSim.Region.Framework.Scenes // m_log.InfoFormat("[PRIMINVENTORY]: " + // "Rezzed script {0} into prim local ID {1} for user {2}", // item.inventoryName, localID, remoteClient.Name); - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); part.ParentGroup.ResumeScripts(); } else @@ -1632,7 +1632,7 @@ namespace OpenSim.Region.Framework.Scenes taskItem.AssetID = asset.FullID; part.Inventory.AddInventoryItem(taskItem, false); - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0); part.ParentGroup.ResumeScripts(); @@ -1746,7 +1746,7 @@ namespace OpenSim.Region.Framework.Scenes if (TryGetScenePresence(srcTaskItem.OwnerID, out avatar)) { - destPart.GetProperties(avatar.ControllingClient); + destPart.SendPropertiesToClient(avatar.ControllingClient); } } @@ -2084,7 +2084,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart part = GetSceneObjectPart(localID); if (part == null) continue; - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 29d01d6366..270e582bd1 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -144,7 +144,7 @@ namespace OpenSim.Region.Framework.Scenes { if (((SceneObjectGroup) ent).LocalId == primLocalID) { - ((SceneObjectGroup) ent).GetProperties(remoteClient); + ((SceneObjectGroup) ent).SendPropertiesToClient(remoteClient); ((SceneObjectGroup) ent).IsSelected = true; // A prim is only tainted if it's allowed to be edited by the person clicking it. if (Permissions.CanEditObject(((SceneObjectGroup)ent).UUID, remoteClient.AgentId) @@ -167,7 +167,7 @@ namespace OpenSim.Region.Framework.Scenes { if (part.LocalId == primLocalID) { - part.GetProperties(remoteClient); + part.SendPropertiesToClient(remoteClient); foundPrim = true; break; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 2819545026..e7f2491813 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1728,8 +1728,6 @@ namespace OpenSim.Region.Framework.Scenes #endregion - #region Scheduling - public override void Update() { // Check that the group was not deleted before the scheduled update @@ -1880,7 +1878,14 @@ namespace OpenSim.Region.Framework.Scenes parts[i].SendTerseUpdateToAllClients(); } - #endregion + /// + /// Send metadata about the root prim (name, description, sale price, etc.) to a client. + /// + /// + public void SendPropertiesToClient(IClientAPI client) + { + m_rootPart.SendPropertiesToClient(client); + } #region SceneGroupPart Methods @@ -2369,15 +2374,6 @@ namespace OpenSim.Region.Framework.Scenes } } - /// - /// Return metadata about a prim (name, description, sale price, etc.) - /// - /// - public void GetProperties(IClientAPI client) - { - m_rootPart.GetProperties(client); - } - /// /// Set the name of a prim /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 04fef83961..72036635d1 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1305,8 +1305,6 @@ namespace OpenSim.Region.Framework.Scenes #endregion Public Properties with only Get - #region Private Methods - private uint ApplyMask(uint val, bool set, uint mask) { if (set) @@ -1327,14 +1325,27 @@ namespace OpenSim.Region.Framework.Scenes m_updateFlag = 0; } - private void SendObjectPropertiesToClient(UUID AgentID) + /// + /// Send this part's properties (name, description, inventory serial, base mask, etc.) to a client + /// + /// + public void SendPropertiesToClient(IClientAPI client) + { + client.SendObjectPropertiesReply(this); + } + + /// + /// For the scene object group to which this part belongs, send that scene object's root part properties to a client. + /// + /// + private void SendRootPartPropertiesToClient(UUID AgentID) { m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) { // Ugly reference :( if (avatar.UUID == AgentID) { - m_parentGroup.GetProperties(avatar.ControllingClient); + m_parentGroup.SendPropertiesToClient(avatar.ControllingClient); } }); } @@ -1363,8 +1374,6 @@ namespace OpenSim.Region.Framework.Scenes // } // } - #endregion Private Methods - #region Public Methods public void ResetExpire() @@ -2030,11 +2039,6 @@ namespace OpenSim.Region.Framework.Scenes return Vector3.Zero; } - public void GetProperties(IClientAPI client) - { - client.SendObjectPropertiesReply(this); - } - /// /// Method for a prim to get it's world position from the group. /// @@ -3453,7 +3457,7 @@ namespace OpenSim.Region.Framework.Scenes { _groupID = groupID; if (client != null) - GetProperties(client); + SendPropertiesToClient(client); m_updateFlag = 2; } @@ -4273,10 +4277,10 @@ namespace OpenSim.Region.Framework.Scenes break; } + SendFullUpdateToAllClients(); - SendObjectPropertiesToClient(AgentID); - + SendRootPartPropertiesToClient(AgentID); } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index d63b411185..94467414eb 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -878,7 +878,7 @@ namespace OpenSim.Region.Framework.Scenes return; } - CreateInventoryFile(); + CreateInventoryFile(); // In principle, we should only do the rest if the inventory changed; // by sending m_inventorySerial to the client, it ought to know diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index cf8517d8b0..070cdc04b9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3591,7 +3591,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parentPrim.ScheduleGroupForFullUpdate(); if (client != null) - parentPrim.GetProperties(client); + parentPrim.SendPropertiesToClient(client); ScriptSleep(1000); } From c4efb97d49dec736151dfa3fa102efe6a5f6fbab Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 15 Sep 2011 22:59:29 +0100 Subject: [PATCH 05/64] Write code to create minimum necessary body parts/clothing and avatar entries to make a newly created user appear as a non-cloud on viewer 2 Viewer 2 no longer contains the default avatar assets (i.e. "Ruth") that would appear if the user had insufficient body part/clothing entries. Instead, avatars always appear as a cloud, which is a very bad experience for out-of-the-box OpenSim. Default is currently off. My intention is to switch it on for standalone shortly. This is not particularly flexible as "Ruth" is hardcoded, but this can change in the future, in co-ordination with the existing RemoteAdmin capabilities. Need to fix creation of suitable entries for users created as estate owners on standalone. Avatars still appear with spooky empty eyes, need to see if we can address this. This commit adds a "Default Iris" to the library (thanks to Eirynne Sieyes from http://opensimulator.org/mantis/view.php?id=1461) which can be used. --- .../AvatarFactory/AvatarFactoryModule.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 1 + .../UserAccountService/UserAccountService.cs | 152 ++++++++++++- .../BodyPartsAssetSet/BodyPartsAssetSet.xml | 10 +- bin/assets/BodyPartsAssetSet/base_eyes.dat | 26 +++ bin/assets/BodyPartsAssetSet/base_hair.dat | 26 +++ bin/assets/BodyPartsAssetSet/base_shape.dat | 212 +++++++++++------- bin/assets/BodyPartsAssetSet/newhair.dat | 63 ------ .../TexturesAssetSet/TexturesAssetSet.xml | 7 + bin/assets/TexturesAssetSet/default_iris.jp2 | Bin 0 -> 15719 bytes bin/config-include/Standalone.ini | 1 + .../TexturesLibrary/TexturesLibraryItems.xml | 10 + 12 files changed, 362 insertions(+), 148 deletions(-) create mode 100644 bin/assets/BodyPartsAssetSet/base_eyes.dat create mode 100644 bin/assets/BodyPartsAssetSet/base_hair.dat delete mode 100644 bin/assets/BodyPartsAssetSet/newhair.dat create mode 100644 bin/assets/TexturesAssetSet/default_iris.jp2 diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index b6a156462e..c5a1828682 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -467,7 +467,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return; } - // m_log.WarnFormat("[AVFACTORY]: Received request for wearables of {0}", client.AgentId); +// m_log.DebugFormat("[AVFACTORY]: Received request for wearables of {0}", client.Name); client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++); } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index c5c926023b..f394a956cf 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1237,6 +1237,7 @@ namespace OpenSim.Region.Framework.Scenes first, last); + m_log.InfoFormat("[USER ACCOUNT SERVICE]: Account {0} {1} created successfully", first, last); m_regInfo.EstateSettings.EstateOwner = account.PrincipalID; diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index 8b8a8f9fe8..21ce86ceb0 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs @@ -28,15 +28,15 @@ using System; using System.Collections.Generic; using System.Reflection; +using log4net; using Nini.Config; +using OpenMetaverse; using OpenSim.Data; +using OpenSim.Framework; using OpenSim.Services.Interfaces; using OpenSim.Framework.Console; using GridRegion = OpenSim.Services.Interfaces.GridRegion; -using OpenMetaverse; -using log4net; - namespace OpenSim.Services.UserAccountService { public class UserAccountService : UserAccountServiceBase, IUserAccountService @@ -44,10 +44,16 @@ namespace OpenSim.Services.UserAccountService private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static UserAccountService m_RootInstance; + /// + /// Should we create default entries (minimum body parts/clothing, avatar wearable entries) for a new avatar? + /// + private bool m_CreateDefaultAvatarEntries; + protected IGridService m_GridService; protected IAuthenticationService m_AuthenticationService; protected IGridUserService m_GridUserService; protected IInventoryService m_InventoryService; + protected IAvatarService m_AvatarService; public UserAccountService(IConfigSource config) : base(config) @@ -77,6 +83,12 @@ namespace OpenSim.Services.UserAccountService if (invServiceDll != string.Empty) m_InventoryService = LoadPlugin(invServiceDll, new Object[] { config }); + string avatarServiceDll = userConfig.GetString("AvatarService", string.Empty); + if (avatarServiceDll != string.Empty) + m_AvatarService = LoadPlugin(avatarServiceDll, new Object[] { config }); + + m_CreateDefaultAvatarEntries = userConfig.GetBoolean("CreateDefaultAvatarEntries", false); + if (MainConsole.Instance != null) { MainConsole.Instance.Commands.AddCommand("UserService", false, @@ -102,9 +114,7 @@ namespace OpenSim.Services.UserAccountService "show account ", "Show account details for the given user", HandleShowAccount); } - } - } #region IUserAccountService @@ -493,12 +503,20 @@ namespace OpenSim.Services.UserAccountService { success = m_InventoryService.CreateUserInventory(account.PrincipalID); if (!success) + { m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to create inventory for account {0} {1}.", firstName, lastName); + } + else if (m_CreateDefaultAvatarEntries) + { + CreateDefaultAppearanceEntries(account.PrincipalID); + } } m_log.InfoFormat("[USER ACCOUNT SERVICE]: Account {0} {1} created successfully", firstName, lastName); - } else { + } + else + { m_log.ErrorFormat("[USER ACCOUNT SERVICE]: Account creation failed for account {0} {1}", firstName, lastName); } } @@ -507,5 +525,125 @@ namespace OpenSim.Services.UserAccountService m_log.ErrorFormat("[USER ACCOUNT SERVICE]: A user with the name {0} {1} already exists!", firstName, lastName); } } + + private void CreateDefaultAppearanceEntries(UUID principalID) + { + m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID); + + InventoryFolderBase bodyPartsFolder = m_InventoryService.GetFolderForType(principalID, AssetType.Bodypart); + + InventoryItemBase eyes = new InventoryItemBase(UUID.Random(), principalID); + eyes.AssetID = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7"); + eyes.Name = "Default Eyes"; + eyes.CreatorId = principalID.ToString(); + eyes.AssetType = (int)AssetType.Bodypart; + eyes.InvType = (int)InventoryType.Wearable; + eyes.Folder = bodyPartsFolder.ID; + eyes.BasePermissions = (uint)PermissionMask.All; + eyes.CurrentPermissions = (uint)PermissionMask.All; + eyes.EveryOnePermissions = (uint)PermissionMask.All; + eyes.GroupPermissions = (uint)PermissionMask.All; + eyes.NextPermissions = (uint)PermissionMask.All; + eyes.Flags = (uint)WearableType.Eyes; + m_InventoryService.AddItem(eyes); + + InventoryItemBase shape = new InventoryItemBase(UUID.Random(), principalID); + shape.AssetID = AvatarWearable.DEFAULT_BODY_ASSET; + shape.Name = "Default Shape"; + shape.CreatorId = principalID.ToString(); + shape.AssetType = (int)AssetType.Bodypart; + shape.InvType = (int)InventoryType.Wearable; + shape.Folder = bodyPartsFolder.ID; + shape.BasePermissions = (uint)PermissionMask.All; + shape.CurrentPermissions = (uint)PermissionMask.All; + shape.EveryOnePermissions = (uint)PermissionMask.All; + shape.GroupPermissions = (uint)PermissionMask.All; + shape.NextPermissions = (uint)PermissionMask.All; + shape.Flags = (uint)WearableType.Shape; + m_InventoryService.AddItem(shape); + + InventoryItemBase skin = new InventoryItemBase(UUID.Random(), principalID); + skin.AssetID = AvatarWearable.DEFAULT_SKIN_ASSET; + skin.Name = "Default Skin"; + skin.CreatorId = principalID.ToString(); + skin.AssetType = (int)AssetType.Bodypart; + skin.InvType = (int)InventoryType.Wearable; + skin.Folder = bodyPartsFolder.ID; + skin.BasePermissions = (uint)PermissionMask.All; + skin.CurrentPermissions = (uint)PermissionMask.All; + skin.EveryOnePermissions = (uint)PermissionMask.All; + skin.GroupPermissions = (uint)PermissionMask.All; + skin.NextPermissions = (uint)PermissionMask.All; + skin.Flags = (uint)WearableType.Skin; + m_InventoryService.AddItem(skin); + + InventoryItemBase hair = new InventoryItemBase(UUID.Random(), principalID); + hair.AssetID = AvatarWearable.DEFAULT_HAIR_ASSET; + hair.Name = "Default Hair"; + hair.CreatorId = principalID.ToString(); + hair.AssetType = (int)AssetType.Bodypart; + hair.InvType = (int)InventoryType.Wearable; + hair.Folder = bodyPartsFolder.ID; + hair.BasePermissions = (uint)PermissionMask.All; + hair.CurrentPermissions = (uint)PermissionMask.All; + hair.EveryOnePermissions = (uint)PermissionMask.All; + hair.GroupPermissions = (uint)PermissionMask.All; + hair.NextPermissions = (uint)PermissionMask.All; + hair.Flags = (uint)WearableType.Hair; + m_InventoryService.AddItem(hair); + + InventoryFolderBase clothingFolder = m_InventoryService.GetFolderForType(principalID, AssetType.Clothing); + + InventoryItemBase shirt = new InventoryItemBase(UUID.Random(), principalID); + shirt.AssetID = AvatarWearable.DEFAULT_SHIRT_ASSET; + shirt.Name = "Default Shirt"; + shirt.CreatorId = principalID.ToString(); + shirt.AssetType = (int)AssetType.Clothing; + shirt.InvType = (int)InventoryType.Wearable; + shirt.Folder = clothingFolder.ID; + shirt.BasePermissions = (uint)PermissionMask.All; + shirt.CurrentPermissions = (uint)PermissionMask.All; + shirt.EveryOnePermissions = (uint)PermissionMask.All; + shirt.GroupPermissions = (uint)PermissionMask.All; + shirt.NextPermissions = (uint)PermissionMask.All; + shirt.Flags = (uint)WearableType.Shirt; + m_InventoryService.AddItem(shirt); + + InventoryItemBase pants = new InventoryItemBase(UUID.Random(), principalID); + pants.AssetID = AvatarWearable.DEFAULT_PANTS_ASSET; + pants.Name = "Default Pants"; + pants.CreatorId = principalID.ToString(); + pants.AssetType = (int)AssetType.Clothing; + pants.InvType = (int)InventoryType.Wearable; + pants.Folder = clothingFolder.ID; + pants.BasePermissions = (uint)PermissionMask.All; + pants.CurrentPermissions = (uint)PermissionMask.All; + pants.EveryOnePermissions = (uint)PermissionMask.All; + pants.GroupPermissions = (uint)PermissionMask.All; + pants.NextPermissions = (uint)PermissionMask.All; + pants.Flags = (uint)WearableType.Pants; + m_InventoryService.AddItem(pants); + + if (m_AvatarService != null) + { + m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default avatar entries for {0}", principalID); + + AvatarWearable[] wearables = new AvatarWearable[6]; + wearables[AvatarWearable.EYES] = new AvatarWearable(eyes.ID, eyes.AssetID); + wearables[AvatarWearable.BODY] = new AvatarWearable(shape.ID, shape.AssetID); + wearables[AvatarWearable.SKIN] = new AvatarWearable(skin.ID, skin.AssetID); + wearables[AvatarWearable.HAIR] = new AvatarWearable(hair.ID, hair.AssetID); + wearables[AvatarWearable.SHIRT] = new AvatarWearable(shirt.ID, shirt.AssetID); + wearables[AvatarWearable.PANTS] = new AvatarWearable(pants.ID, pants.AssetID); + + AvatarAppearance ap = new AvatarAppearance(); + for (int i = 0; i < 6; i++) + { + ap.SetWearable(i, wearables[i]); + } + + m_AvatarService.SetAppearance(principalID, ap); + } + } } -} +} \ No newline at end of file diff --git a/bin/assets/BodyPartsAssetSet/BodyPartsAssetSet.xml b/bin/assets/BodyPartsAssetSet/BodyPartsAssetSet.xml index 8ef0fe72f7..a3d7ba3a07 100644 --- a/bin/assets/BodyPartsAssetSet/BodyPartsAssetSet.xml +++ b/bin/assets/BodyPartsAssetSet/BodyPartsAssetSet.xml @@ -4,7 +4,7 @@ - +
@@ -34,6 +34,14 @@
+ +
+ + + + +
+ {2}", nameA, nameB, - //needsCollision); - - - return needsCollision; - } - //added by jed zhu - //calculas the collision between the Prim and Actor - // - private int Collision(BulletXCharacter actorA, BulletXPrim primB) - { - int[] indexBase; - Vector3[] vertexBase; - Vector3 vNormal; - // Vector3 vP1; - // Vector3 vP2; - // Vector3 vP3; - IMesh mesh = primB.GetMesh(); - - float fdistance; - if (primB == null) - return 3; - if (mesh == null) - return 2; - if (actorA == null) - return 3; - - int iVertexCount = mesh.getVertexList().Count; - int iIndexCount = mesh.getIndexListAsInt().Length; - if (iVertexCount == 0) - return 3; - if (iIndexCount == 0) - return 3; - lock (BulletXScene.BulletXLock) - { - indexBase = mesh.getIndexListAsInt(); - vertexBase = new Vector3[iVertexCount]; - - for (int i = 0; i < iVertexCount; i++) - { - OpenMetaverse.Vector3 v = mesh.getVertexList()[i]; - if (v != null) // Note, null has special meaning. See meshing code for details - vertexBase[i] = BulletXMaths.PhysicsVectorToXnaVector3(v); - else - vertexBase[i] = Vector3.Zero; - } - - for (int ix = 0; ix < iIndexCount; ix += 3) - { - int ia = indexBase[ix + 0]; - int ib = indexBase[ix + 1]; - int ic = indexBase[ix + 2]; - // - Vector3 v1 = vertexBase[ib] - vertexBase[ia]; - Vector3 v2 = vertexBase[ic] - vertexBase[ia]; - - Vector3.Cross(ref v1, ref v2, out vNormal); - Vector3.Normalize(ref vNormal, out vNormal); - - fdistance = Vector3.Dot(vNormal, vertexBase[ia]) + 0.50f; - if (preCheckCollision(actorA, vNormal, fdistance) == 1) - { - if (CheckCollision(actorA, ia, ib, ic, vNormal, vertexBase) == 1) - { - //PhysicsVector v = actorA.Position; - //Vector3 v3 = BulletXMaths.PhysicsVectorToXnaVector3(v); - //Vector3 vp = vNormal * (fdistance - Vector3.Dot(vNormal, v3) + 0.2f); - //actorA.Position += BulletXMaths.XnaVector3ToPhysicsVector(vp); - return 1; - } - } - } - } - - - return 0; - } - //added by jed zhu - //return value 1: need second check - //return value 0: no need check - - private int preCheckCollision(BulletXActor actA, Vector3 vNormal, float fDist) - { - float fstartSide; - OpenMetaverse.Vector3 v = actA.Position; - Vector3 v3 = BulletXMaths.PhysicsVectorToXnaVector3(v); - - fstartSide = Vector3.Dot(vNormal, v3) - fDist; - if (fstartSide > 0) return 0; - else return 1; - } - //added by jed zhu - private int CheckCollision(BulletXActor actA, int ia, int ib, int ic, Vector3 vNormal, Vector3[] vertBase) - { - Vector3 perPlaneNormal; - float fPerPlaneDist; - OpenMetaverse.Vector3 v = actA.Position; - Vector3 v3 = BulletXMaths.PhysicsVectorToXnaVector3(v); - //check AB - Vector3 v1; - v1 = vertBase[ib] - vertBase[ia]; - Vector3.Cross(ref vNormal, ref v1, out perPlaneNormal); - Vector3.Normalize(ref perPlaneNormal, out perPlaneNormal); - - if (Vector3.Dot((vertBase[ic] - vertBase[ia]), perPlaneNormal) < 0) - perPlaneNormal = -perPlaneNormal; - fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ia]) - 0.50f; - - - - if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) < 0) - return 0; - fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ic]) + 0.50f; - if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) > 0) - return 0; - - //check BC - - v1 = vertBase[ic] - vertBase[ib]; - Vector3.Cross(ref vNormal, ref v1, out perPlaneNormal); - Vector3.Normalize(ref perPlaneNormal, out perPlaneNormal); - - if (Vector3.Dot((vertBase[ia] - vertBase[ib]), perPlaneNormal) < 0) - perPlaneNormal = -perPlaneNormal; - fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ib]) - 0.50f; - - - if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) < 0) - return 0; - fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ia]) + 0.50f; - if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) > 0) - return 0; - //check CA - v1 = vertBase[ia] - vertBase[ic]; - Vector3.Cross(ref vNormal, ref v1, out perPlaneNormal); - Vector3.Normalize(ref perPlaneNormal, out perPlaneNormal); - - if (Vector3.Dot((vertBase[ib] - vertBase[ic]), perPlaneNormal) < 0) - perPlaneNormal = -perPlaneNormal; - fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ic]) - 0.50f; - - - if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) < 0) - return 0; - fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ib]) + 0.50f; - if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) > 0) - return 0; - - return 1; - - } - } - - /// - /// PhysicsScene Class for BulletX - /// - public class BulletXScene : PhysicsScene - { - #region BulletXScene Fields - - public DiscreteDynamicsWorld ddWorld; - private CollisionDispatcher cDispatcher; - private OverlappingPairCache opCache; - private SequentialImpulseConstraintSolver sicSolver; - public static Object BulletXLock = new Object(); - - private const int minXY = 0; - private const int minZ = 0; - private const int maxXY = (int)Constants.RegionSize; - private const int maxZ = 4096; - private const int maxHandles = 32766; //Why? I don't know - private const float gravity = 9.8f; - private const float heightLevel0 = 77.0f; - private const float heightLevel1 = 200.0f; - private const float lowGravityFactor = 0.2f; - //OpenSim calls Simulate 10 times per seconds. So FPS = "Simulate Calls" * simulationSubSteps = 100 FPS - private const int simulationSubSteps = 10; - //private float[] _heightmap; - private BulletXPlanet _simFlatPlanet; - internal Dictionary _characters = new Dictionary(); - internal Dictionary _prims = new Dictionary(); - - public IMesher mesher; - // private IConfigSource m_config; - - // protected internal String identifier; - - public BulletXScene(String sceneIdentifier) - { - //identifier = sceneIdentifier; - cDispatcher = new CollisionDispatcherLocal(this); - Vector3 worldMinDim = new Vector3((float)minXY, (float)minXY, (float)minZ); - Vector3 worldMaxDim = new Vector3((float)maxXY, (float)maxXY, (float)maxZ); - opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles); - sicSolver = new SequentialImpulseConstraintSolver(); - - lock (BulletXLock) - { - ddWorld = new DiscreteDynamicsWorld(cDispatcher, opCache, sicSolver); - ddWorld.Gravity = new Vector3(0, 0, -gravity); - } - //this._heightmap = new float[65536]; - } - - public static float Gravity - { - get { return gravity; } - } - - public static float HeightLevel0 - { - get { return heightLevel0; } - } - - public static float HeightLevel1 - { - get { return heightLevel1; } - } - - public static float LowGravityFactor - { - get { return lowGravityFactor; } - } - - public static int MaxXY - { - get { return maxXY; } - } - - public static int MaxZ - { - get { return maxZ; } - } - - private List _forgottenRigidBodies = new List(); - internal string is_ex_message = "Can't remove rigidBody!: "; - - #endregion - - public BulletXScene() - { - cDispatcher = new CollisionDispatcherLocal(this); - Vector3 worldMinDim = new Vector3((float) minXY, (float) minXY, (float) minZ); - Vector3 worldMaxDim = new Vector3((float) maxXY, (float) maxXY, (float) maxZ); - opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles); - sicSolver = new SequentialImpulseConstraintSolver(); - - lock (BulletXLock) - { - ddWorld = new DiscreteDynamicsWorld(cDispatcher, opCache, sicSolver); - ddWorld.Gravity = new Vector3(0, 0, -gravity); - } - //this._heightmap = new float[65536]; - } - - public override void Initialise(IMesher meshmerizer, IConfigSource config) - { - mesher = meshmerizer; - // m_config = config; - } - - public override void Dispose() - { - - } - - public override Dictionary GetTopColliders() - { - Dictionary returncolliders = new Dictionary(); - return returncolliders; - } - - public override void SetWaterLevel(float baseheight) - { - - } - - public override PhysicsActor AddAvatar(string avName, OpenMetaverse.Vector3 position, OpenMetaverse.Vector3 size, bool isFlying) - { - OpenMetaverse.Vector3 pos = OpenMetaverse.Vector3.Zero; - pos.X = position.X; - pos.Y = position.Y; - pos.Z = position.Z + 20; - BulletXCharacter newAv = null; - lock (BulletXLock) - { - newAv = new BulletXCharacter(avName, this, pos); - _characters.Add(newAv.RigidBody, newAv); - } - newAv.Flying = isFlying; - return newAv; - } - - public override void RemoveAvatar(PhysicsActor actor) - { - if (actor is BulletXCharacter) - { - lock (BulletXLock) - { - try - { - ddWorld.RemoveRigidBody(((BulletXCharacter) actor).RigidBody); - } - catch (Exception ex) - { - BulletXMessage(is_ex_message + ex.Message, true); - ((BulletXCharacter) actor).RigidBody.ActivationState = ActivationState.DisableSimulation; - AddForgottenRigidBody(((BulletXCharacter) actor).RigidBody); - } - _characters.Remove(((BulletXCharacter) actor).RigidBody); - } - GC.Collect(); - } - } - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, OpenMetaverse.Vector3 position, - OpenMetaverse.Vector3 size, OpenMetaverse.Quaternion rotation, bool isPhysical, uint localid) - { - PhysicsActor result; - - switch (pbs.ProfileShape) - { - case ProfileShape.Square: - /// support simple box & hollow box now; later, more shapes - if (pbs.ProfileHollow == 0) - { - result = AddPrim(primName, position, size, rotation, null, null, isPhysical); - } - else - { - IMesh mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical); - result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical); - } - break; - - default: - result = AddPrim(primName, position, size, rotation, null, null, isPhysical); - break; - } - - return result; - } - - public PhysicsActor AddPrim(String name, OpenMetaverse.Vector3 position, OpenMetaverse.Vector3 size, OpenMetaverse.Quaternion rotation, - IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical) - { - BulletXPrim newPrim = null; - lock (BulletXLock) - { - newPrim = new BulletXPrim(name, this, position, size, rotation, mesh, pbs, isPhysical); - _prims.Add(newPrim.RigidBody, newPrim); - } - return newPrim; - } - - public override void RemovePrim(PhysicsActor prim) - { - if (prim is BulletXPrim) - { - lock (BulletXLock) - { - try - { - ddWorld.RemoveRigidBody(((BulletXPrim) prim).RigidBody); - } - catch (Exception ex) - { - BulletXMessage(is_ex_message + ex.Message, true); - ((BulletXPrim) prim).RigidBody.ActivationState = ActivationState.DisableSimulation; - AddForgottenRigidBody(((BulletXPrim) prim).RigidBody); - } - _prims.Remove(((BulletXPrim) prim).RigidBody); - } - GC.Collect(); - } - } - - public override void AddPhysicsActorTaint(PhysicsActor prim) - { - } - - public override float Simulate(float timeStep) - { - float fps = 0; - lock (BulletXLock) - { - //Try to remove garbage - RemoveForgottenRigidBodies(); - //End of remove - MoveAPrimitives(timeStep); - - - fps = (timeStep*simulationSubSteps); - - ddWorld.StepSimulation(timeStep, simulationSubSteps, timeStep); - //Extra Heightmap Validation: BulletX's HeightFieldTerrain somestimes doesn't work so fine. - ValidateHeightForAll(); - //End heightmap validation. - UpdateKineticsForAll(); - } - return fps; - } - - private void MoveAPrimitives(float timeStep) - { - foreach (BulletXCharacter actor in _characters.Values) - { - actor.Move(timeStep); - } - } - - private void ValidateHeightForAll() - { - float _height; - foreach (BulletXCharacter actor in _characters.Values) - { - //_height = HeightValue(actor.RigidBodyPosition); - _height = _simFlatPlanet.HeightValue(actor.RigidBodyPosition); - actor.ValidateHeight(_height); - //if (_simFlatPlanet.heightIsNotValid(actor.RigidBodyPosition, out _height)) actor.ValidateHeight(_height); - } - foreach (BulletXPrim prim in _prims.Values) - { - //_height = HeightValue(prim.RigidBodyPosition); - _height = _simFlatPlanet.HeightValue(prim.RigidBodyPosition); - prim.ValidateHeight(_height); - //if (_simFlatPlanet.heightIsNotValid(prim.RigidBodyPosition, out _height)) prim.ValidateHeight(_height); - } - //foreach (BulletXCharacter actor in _characters) - //{ - // actor.ValidateHeight(0); - //} - //foreach (BulletXPrim prim in _prims) - //{ - // prim.ValidateHeight(0); - //} - } - - private void UpdateKineticsForAll() - { - //UpdatePosition > UpdateKinetics. - //Not only position will be updated, also velocity cause acceleration. - foreach (BulletXCharacter actor in _characters.Values) - { - actor.UpdateKinetics(); - } - foreach (BulletXPrim prim in _prims.Values) - { - prim.UpdateKinetics(); - } - //if (this._simFlatPlanet!=null) this._simFlatPlanet.Restore(); - } - - public override void GetResults() - { - } - - public override bool IsThreaded - { - get - { - return (false); // for now we won't be multithreaded - } - } - - public override void SetTerrain(float[] heightMap) - { - ////As the same as ODE, heightmap (x,y) must be swapped for BulletX - //for (int i = 0; i < 65536; i++) - //{ - // // this._heightmap[i] = (double)heightMap[i]; - // // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...) - // int x = i & 0xff; - // int y = i >> 8; - // this._heightmap[i] = heightMap[x * 256 + y]; - //} - - //float[] swappedHeightMap = new float[65536]; - ////As the same as ODE, heightmap (x,y) must be swapped for BulletX - //for (int i = 0; i < 65536; i++) - //{ - // // this._heightmap[i] = (double)heightMap[i]; - // // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...) - // int x = i & 0xff; - // int y = i >> 8; - // swappedHeightMap[i] = heightMap[x * 256 + y]; - //} - DeleteTerrain(); - //There is a BulletXLock inside the constructor of BulletXPlanet - //this._simFlatPlanet = new BulletXPlanet(this, swappedHeightMap); - _simFlatPlanet = new BulletXPlanet(this, heightMap); - //this._heightmap = heightMap; - } - - public override void DeleteTerrain() - { - if (_simFlatPlanet != null) - { - lock (BulletXLock) - { - try - { - ddWorld.RemoveRigidBody(_simFlatPlanet.RigidBody); - } - catch (Exception ex) - { - BulletXMessage(is_ex_message + ex.Message, true); - _simFlatPlanet.RigidBody.ActivationState = ActivationState.DisableSimulation; - AddForgottenRigidBody(_simFlatPlanet.RigidBody); - } - } - _simFlatPlanet = null; - GC.Collect(); - BulletXMessage("Terrain erased!", false); - } - - - - //this._heightmap = null; - } - - - - internal void AddForgottenRigidBody(RigidBody forgottenRigidBody) - { - _forgottenRigidBodies.Add(forgottenRigidBody); - } - - private void RemoveForgottenRigidBodies() - { - RigidBody forgottenRigidBody; - int nRigidBodies = _forgottenRigidBodies.Count; - for (int i = nRigidBodies - 1; i >= 0; i--) - { - forgottenRigidBody = _forgottenRigidBodies[i]; - try - { - ddWorld.RemoveRigidBody(forgottenRigidBody); - _forgottenRigidBodies.Remove(forgottenRigidBody); - BulletXMessage("Forgotten Rigid Body Removed", false); - } - catch (Exception ex) - { - BulletXMessage("Can't remove forgottenRigidBody!: " + ex.Message, false); - } - } - GC.Collect(); - } - - internal static void BulletXMessage(string message, bool isWarning) - { - PhysicsPluginManager.PhysicsPluginMessage("[Modified BulletX]:\t" + message, isWarning); - } - - //temp - //private float HeightValue(MonoXnaCompactMaths.Vector3 position) - //{ - // int li_x, li_y; - // float height; - // li_x = (int)Math.Round(position.X); if (li_x < 0) li_x = 0; - // li_y = (int)Math.Round(position.Y); if (li_y < 0) li_y = 0; - - // height = this._heightmap[li_y * 256 + li_x]; - // if (height < 0) height = 0; - // else if (height > maxZ) height = maxZ; - - // return height; - //} - } - - /// - /// Generic Physics Actor for BulletX inherit from PhysicActor - /// - public class BulletXActor : PhysicsActor - { - protected bool flying = false; - protected bool _physical = false; - protected OpenMetaverse.Vector3 _position; - protected OpenMetaverse.Vector3 _velocity; - protected OpenMetaverse.Vector3 _size; - protected OpenMetaverse.Vector3 _acceleration; - protected OpenMetaverse.Quaternion _orientation; - protected OpenMetaverse.Vector3 m_rotationalVelocity; - protected RigidBody rigidBody; - protected int m_PhysicsActorType; - private Boolean iscolliding = false; - internal string _name; - - public BulletXActor(String name) - { - _name = name; - } - - public override bool Stopped - { - get { return false; } - } - - public override OpenMetaverse.Vector3 Position - { - get { return _position; } - set - { - lock (BulletXScene.BulletXLock) - { - _position = value; - Translate(); - } - } - } - - public override OpenMetaverse.Vector3 RotationalVelocity - { - get { return m_rotationalVelocity; } - set { m_rotationalVelocity = value; } - } - - public override OpenMetaverse.Vector3 Velocity - { - get { return _velocity; } - set - { - lock (BulletXScene.BulletXLock) - { - //Static objects don' have linear velocity - if (_physical) - { - _velocity = value; - Speed(); - } - else - { - _velocity = OpenMetaverse.Vector3.Zero; - } - } - } - } - public override float CollisionScore - { - get { return 0f; } - set { } - } - public override OpenMetaverse.Vector3 Size - { - get { return _size; } - set - { - lock (BulletXScene.BulletXLock) - { - _size = value; - } - } - } - - public override OpenMetaverse.Vector3 Force - { - get { return OpenMetaverse.Vector3.Zero; } - set { return; } - } - - public override int VehicleType - { - get { return 0; } - set { return; } - } - - public override void VehicleFloatParam(int param, float value) - { - - } - - public override void VehicleVectorParam(int param, OpenMetaverse.Vector3 value) - { - - } - - public override void VehicleRotationParam(int param, OpenMetaverse.Quaternion rotation) - { - - } - - public override void VehicleFlags(int param, bool remove) - { - - } - - public override void SetVolumeDetect(int param) - { - - } - - public override OpenMetaverse.Vector3 CenterOfMass - { - get { return OpenMetaverse.Vector3.Zero; } - } - - public override OpenMetaverse.Vector3 GeometricCenter - { - get { return OpenMetaverse.Vector3.Zero; } - } - - public override PrimitiveBaseShape Shape - { - set { return; } - } - - public override bool SetAlwaysRun - { - get { return false; } - set { return; } - } - - public override OpenMetaverse.Vector3 Acceleration - { - get { return _acceleration; } - } - - public override OpenMetaverse.Quaternion Orientation - { - get { return _orientation; } - set - { - lock (BulletXScene.BulletXLock) - { - _orientation = value; - ReOrient(); - } - } - } - public override void link(PhysicsActor obj) - { - - } - - public override void delink() - { - - } - - public override void LockAngularMotion(OpenMetaverse.Vector3 axis) - { - - } - - public override float Mass - { - get { return ActorMass; } - } - - public virtual float ActorMass - { - get { return 0; } - } - - public override int PhysicsActorType - { - get { return (int) m_PhysicsActorType; } - set { m_PhysicsActorType = value; } - } - - public RigidBody RigidBody - { - get { return rigidBody; } - } - - public Vector3 RigidBodyPosition - { - get { return rigidBody.CenterOfMassPosition; } - } - - public override bool IsPhysical - { - get { return _physical; } - set { _physical = value; } - } - - public override bool Flying - { - get { return flying; } - set { flying = value; } - } - - public override bool ThrottleUpdates - { - get { return false; } - set { return; } - } - - public override bool IsColliding - { - get { return iscolliding; } - set { iscolliding = value; } - } - - public override bool CollidingGround - { - get { return false; } - set { return; } - } - - public override bool CollidingObj - { - get { return false; } - set { return; } - } - - public override uint LocalID - { - set { return; } - } - - public override bool Grabbed - { - set { return; } - } - - public override bool Selected - { - set { return; } - } - - public override float Buoyancy - { - get { return 0f; } - set { return; } - } - - public override bool FloatOnWater - { - set { return; } - } - - public virtual void SetAcceleration(OpenMetaverse.Vector3 accel) - { - lock (BulletXScene.BulletXLock) - { - _acceleration = accel; - } - } - - public override bool Kinematic - { - get { return false; } - set { } - } - - public override void AddForce(OpenMetaverse.Vector3 force, bool pushforce) - { - } - public override OpenMetaverse.Vector3 Torque - { - get { return OpenMetaverse.Vector3.Zero; } - set { return; } - } - public override void AddAngularForce(OpenMetaverse.Vector3 force, bool pushforce) - { - } - - public override void SetMomentum(OpenMetaverse.Vector3 momentum) - { - } - - internal virtual void ValidateHeight(float heighmapPositionValue) - { - } - - internal virtual void UpdateKinetics() - { - } - - #region Methods for updating values of RigidBody - - protected internal void Translate() - { - Translate(_position); - } - - protected internal void Translate(OpenMetaverse.Vector3 _newPos) - { - Vector3 _translation; - _translation = BulletXMaths.PhysicsVectorToXnaVector3(_newPos) - rigidBody.CenterOfMassPosition; - rigidBody.Translate(_translation); - } - - protected internal void Speed() - { - Speed(_velocity); - } - - protected internal void Speed(OpenMetaverse.Vector3 _newSpeed) - { - Vector3 _speed; - _speed = BulletXMaths.PhysicsVectorToXnaVector3(_newSpeed); - rigidBody.LinearVelocity = _speed; - } - - protected internal void ReOrient() - { - ReOrient(_orientation); - } - - protected internal void ReOrient(OpenMetaverse.Quaternion _newOrient) - { - Quaternion _newOrientation; - _newOrientation = BulletXMaths.QuaternionToXnaQuaternion(_newOrient); - Matrix _comTransform = rigidBody.CenterOfMassTransform; - BulletXMaths.SetRotation(ref _comTransform, _newOrientation); - rigidBody.CenterOfMassTransform = _comTransform; - } - - protected internal void ReSize() - { - ReSize(_size); - } - - protected internal virtual void ReSize(OpenMetaverse.Vector3 _newSize) - { - } - - public virtual void ScheduleTerseUpdate() - { - base.RequestPhysicsterseUpdate(); - } - - #endregion - - public override void CrossingFailure() - { - - } - public override OpenMetaverse.Vector3 PIDTarget { set { return; } } - public override bool PIDActive { set { return; } } - public override float PIDTau { set { return; } } - - public override float PIDHoverHeight { set { return; } } - public override bool PIDHoverActive { set { return; } } - public override PIDHoverType PIDHoverType { set { return; } } - public override float PIDHoverTau { set { return; } } - - public override OpenMetaverse.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 SubscribeEvents(int ms) - { - - } - public override void UnSubscribeEvents() - { - - } - public override bool SubscribedEvents() - { - return false; - } - } - - /// - /// PhysicsActor Character Class for BulletX - /// - public class BulletXCharacter : BulletXActor - { - public BulletXCharacter(BulletXScene parent_scene, OpenMetaverse.Vector3 pos) - : this(String.Empty, parent_scene, pos) - { - } - - public BulletXCharacter(String avName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos) - : this(avName, parent_scene, pos, OpenMetaverse.Vector3.Zero, OpenMetaverse.Vector3.Zero, OpenMetaverse.Vector3.Zero, - OpenMetaverse.Quaternion.Identity) - { - } - - public BulletXCharacter(String avName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos, OpenMetaverse.Vector3 velocity, - OpenMetaverse.Vector3 size, OpenMetaverse.Vector3 acceleration, OpenMetaverse.Quaternion orientation) - : base(avName) - { - //This fields will be removed. They're temporal - float _sizeX = 0.5f; - float _sizeY = 0.5f; - float _sizeZ = 1.6f; - //. - _position = pos; - _velocity = velocity; - _size = size; - //--- - _size.X = _sizeX; - _size.Y = _sizeY; - _size.Z = _sizeZ; - //. - _acceleration = acceleration; - _orientation = orientation; - _physical = true; - - float _mass = 50.0f; //This depends of avatar's dimensions - //For RigidBody Constructor. The next values might change - float _linearDamping = 0.0f; - float _angularDamping = 0.0f; - float _friction = 0.5f; - float _restitution = 0.0f; - Matrix _startTransform = Matrix.Identity; - Matrix _centerOfMassOffset = Matrix.Identity; - lock (BulletXScene.BulletXLock) - { - _startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(pos); - //CollisionShape _collisionShape = new BoxShape(new MonoXnaCompactMaths.Vector3(1.0f, 1.0f, 1.60f)); - //For now, like ODE, collisionShape = sphere of radious = 1.0 - CollisionShape _collisionShape = new SphereShape(1.0f); - DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset); - Vector3 _localInertia = new Vector3(); - _collisionShape.CalculateLocalInertia(_mass, out _localInertia); //Always when mass > 0 - rigidBody = - new RigidBody(_mass, _motionState, _collisionShape, _localInertia, _linearDamping, _angularDamping, - _friction, _restitution); - //rigidBody.ActivationState = ActivationState.DisableDeactivation; - //It's seems that there are a bug with rigidBody constructor and its CenterOfMassPosition - Vector3 _vDebugTranslation; - _vDebugTranslation = _startTransform.Translation - rigidBody.CenterOfMassPosition; - rigidBody.Translate(_vDebugTranslation); - parent_scene.ddWorld.AddRigidBody(rigidBody); - } - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Agent; } - set { return; } - } - - public override OpenMetaverse.Vector3 Position - { - get { return base.Position; } - set { base.Position = value; } - } - - public override OpenMetaverse.Vector3 Velocity - { - get { return base.Velocity; } - set { base.Velocity = value; } - } - - public override OpenMetaverse.Vector3 Size - { - get { return base.Size; } - set { base.Size = value; } - } - - public override OpenMetaverse.Vector3 Acceleration - { - get { return base.Acceleration; } - } - - public override OpenMetaverse.Quaternion Orientation - { - get { return base.Orientation; } - set { base.Orientation = value; } - } - - public override bool Flying - { - get { return base.Flying; } - set { base.Flying = value; } - } - - public override bool IsColliding - { - get { return base.IsColliding; } - set { base.IsColliding = value; } - } - - public override bool Kinematic - { - get { return base.Kinematic; } - set { base.Kinematic = value; } - } - - public override void SetAcceleration(OpenMetaverse.Vector3 accel) - { - base.SetAcceleration(accel); - } - - public override void AddForce(OpenMetaverse.Vector3 force, bool pushforce) - { - base.AddForce(force, pushforce); - } - - public override void SetMomentum(OpenMetaverse.Vector3 momentum) - { - base.SetMomentum(momentum); - } - - internal void Move(float timeStep) - { - Vector3 vec = new Vector3(); - //At this point it's supossed that: - //_velocity == rigidBody.LinearVelocity - vec.X = _velocity.X; - vec.Y = _velocity.Y; - vec.Z = _velocity.Z; - if ((vec.X != 0.0f) || (vec.Y != 0.0f) || (vec.Z != 0.0f)) rigidBody.Activate(); - if (flying) - { - //Antigravity with movement - if (_position.Z <= BulletXScene.HeightLevel0) - { - vec.Z += BulletXScene.Gravity*timeStep; - } - //Lowgravity with movement - else if ((_position.Z > BulletXScene.HeightLevel0) - && (_position.Z <= BulletXScene.HeightLevel1)) - { - vec.Z += BulletXScene.Gravity*timeStep*(1.0f - BulletXScene.LowGravityFactor); - } - //Lowgravity with... - else if (_position.Z > BulletXScene.HeightLevel1) - { - if (vec.Z > 0) //no movement - vec.Z = BulletXScene.Gravity*timeStep*(1.0f - BulletXScene.LowGravityFactor); - else - vec.Z += BulletXScene.Gravity*timeStep*(1.0f - BulletXScene.LowGravityFactor); - } - } - rigidBody.LinearVelocity = vec; - } - - //This validation is very basic - internal override void ValidateHeight(float heighmapPositionValue) - { - if (rigidBody.CenterOfMassPosition.Z < heighmapPositionValue + _size.Z/2.0f) - { - Matrix m = rigidBody.WorldTransform; - Vector3 v3 = m.Translation; - v3.Z = heighmapPositionValue + _size.Z/2.0f; - m.Translation = v3; - rigidBody.WorldTransform = m; - //When an Avie touch the ground it's vertical velocity it's reduced to ZERO - Speed(new OpenMetaverse.Vector3(rigidBody.LinearVelocity.X, rigidBody.LinearVelocity.Y, 0.0f)); - } - } - - internal override void UpdateKinetics() - { - _position = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.CenterOfMassPosition); - _velocity = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.LinearVelocity); - //Orientation it seems that it will be the default. - ReOrient(); - } - } - - /// - /// PhysicsActor Prim Class for BulletX - /// - public class BulletXPrim : BulletXActor - { - //Density it will depends of material. - //For now all prims have the same density, all prims are made of water. Be water my friend! :D - private const float _density = 1000.0f; - private BulletXScene _parent_scene; - private OpenMetaverse.Vector3 m_prev_position; - private bool m_lastUpdateSent = false; - //added by jed zhu - private IMesh _mesh; - public IMesh GetMesh() { return _mesh; } - - - - public BulletXPrim(String primName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos, OpenMetaverse.Vector3 size, - OpenMetaverse.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical) - : this( - primName, parent_scene, pos, OpenMetaverse.Vector3.Zero, size, OpenMetaverse.Vector3.Zero, rotation, mesh, pbs, - isPhysical) - { - } - - public BulletXPrim(String primName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos, OpenMetaverse.Vector3 velocity, - OpenMetaverse.Vector3 size, - OpenMetaverse.Vector3 acceleration, OpenMetaverse.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, - bool isPhysical) - : base(primName) - { - if ((size.X == 0) || (size.Y == 0) || (size.Z == 0)) - throw new Exception("Size 0"); - if (OpenMetaverse.Quaternion.Normalize(rotation).Length() == 0f) - rotation = OpenMetaverse.Quaternion.Identity; - - _position = pos; - _physical = isPhysical; - _velocity = _physical ? velocity : OpenMetaverse.Vector3.Zero; - _size = size; - _acceleration = acceleration; - _orientation = rotation; - - _parent_scene = parent_scene; - - CreateRigidBody(parent_scene, mesh, pos, size); - } - - public override int PhysicsActorType - { - get { return (int) ActorTypes.Prim; } - set { return; } - } - - public override OpenMetaverse.Vector3 Position - { - get { return base.Position; } - set { base.Position = value; } - } - - public override OpenMetaverse.Vector3 Velocity - { - get { return base.Velocity; } - set { base.Velocity = value; } - } - - public override OpenMetaverse.Vector3 Size - { - get { return _size; } - set - { - lock (BulletXScene.BulletXLock) - { - _size = value; - ReSize(); - } - } - } - - public override OpenMetaverse.Vector3 Acceleration - { - get { return base.Acceleration; } - } - - public override OpenMetaverse.Quaternion Orientation - { - get { return base.Orientation; } - set { base.Orientation = value; } - } - - public override float ActorMass - { - get - { - //For now all prims are boxes - return (_physical ? 1 : 0)*_density*_size.X*_size.Y*_size.Z; - } - } - - public override bool IsPhysical - { - get { return base.IsPhysical; } - set - { - base.IsPhysical = value; - if (value) - { - //--- - PhysicsPluginManager.PhysicsPluginMessage("Physical - Recreate", true); - //--- - ReCreateRigidBody(_size); - } - else - { - //--- - PhysicsPluginManager.PhysicsPluginMessage("Physical - SetMassProps", true); - //--- - rigidBody.SetMassProps(Mass, new Vector3()); - } - } - } - - public override bool Flying - { - get { return base.Flying; } - set { base.Flying = value; } - } - - public override bool IsColliding - { - get { return base.IsColliding; } - set { base.IsColliding = value; } - } - - public override bool Kinematic - { - get { return base.Kinematic; } - set { base.Kinematic = value; } - } - - public override void SetAcceleration(OpenMetaverse.Vector3 accel) - { - lock (BulletXScene.BulletXLock) - { - _acceleration = accel; - } - } - - public override void AddForce(OpenMetaverse.Vector3 force, bool pushforce) - { - base.AddForce(force,pushforce); - } - - public override void SetMomentum(OpenMetaverse.Vector3 momentum) - { - base.SetMomentum(momentum); - } - - internal override void ValidateHeight(float heighmapPositionValue) - { - if (rigidBody.CenterOfMassPosition.Z < heighmapPositionValue + _size.Z/2.0f) - { - Matrix m = rigidBody.WorldTransform; - Vector3 v3 = m.Translation; - v3.Z = heighmapPositionValue + _size.Z/2.0f; - m.Translation = v3; - rigidBody.WorldTransform = m; - //When a Prim touch the ground it's vertical velocity it's reduced to ZERO - //Static objects don't have linear velocity - if (_physical) - Speed(new OpenMetaverse.Vector3(rigidBody.LinearVelocity.X, rigidBody.LinearVelocity.Y, 0.0f)); - } - } - - internal override void UpdateKinetics() - { - if (_physical) //Updates properties. Prim updates its properties physically - { - _position = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.CenterOfMassPosition); - - _velocity = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.LinearVelocity); - _orientation = BulletXMaths.XnaQuaternionToQuaternion(rigidBody.Orientation); - - if ((Math.Abs(m_prev_position.X - _position.X) < 0.03) - && (Math.Abs(m_prev_position.Y - _position.Y) < 0.03) - && (Math.Abs(m_prev_position.Z - _position.Z) < 0.03)) - { - if (!m_lastUpdateSent) - { - _velocity = OpenMetaverse.Vector3.Zero; - base.ScheduleTerseUpdate(); - m_lastUpdateSent = true; - } - } - else - { - m_lastUpdateSent = false; - base.ScheduleTerseUpdate(); - } - m_prev_position = _position; - } - else //Doesn't updates properties. That's a cancel - { - Translate(); - //Speed(); //<- Static objects don't have linear velocity - ReOrient(); - } - } - - #region Methods for updating values of RigidBody - - protected internal void CreateRigidBody(BulletXScene parent_scene, IMesh mesh, OpenMetaverse.Vector3 pos, - OpenMetaverse.Vector3 size) - { - //For RigidBody Constructor. The next values might change - float _linearDamping = 0.0f; - float _angularDamping = 0.0f; - float _friction = 1.0f; - float _restitution = 0.0f; - Matrix _startTransform = Matrix.Identity; - Matrix _centerOfMassOffset = Matrix.Identity; - //added by jed zhu - _mesh = mesh; - - lock (BulletXScene.BulletXLock) - { - _startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(pos); - //For now all prims are boxes - CollisionShape _collisionShape; - if (mesh == null) - { - _collisionShape = new BoxShape(BulletXMaths.PhysicsVectorToXnaVector3(size)/2.0f); - } - else - { - int iVertexCount = mesh.getVertexList().Count; - int[] indices = mesh.getIndexListAsInt(); - Vector3[] v3Vertices = new Vector3[iVertexCount]; - for (int i = 0; i < iVertexCount; i++) - { - OpenMetaverse.Vector3 v = mesh.getVertexList()[i]; - if (v != null) // Note, null has special meaning. See meshing code for details - v3Vertices[i] = BulletXMaths.PhysicsVectorToXnaVector3(v); - else - v3Vertices[i] = Vector3.Zero; - } - TriangleIndexVertexArray triMesh = new TriangleIndexVertexArray(indices, v3Vertices); - - _collisionShape = new TriangleMeshShape(triMesh); - } - DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset); - Vector3 _localInertia = new Vector3(); - if (_physical) _collisionShape.CalculateLocalInertia(Mass, out _localInertia); //Always when mass > 0 - rigidBody = - new RigidBody(Mass, _motionState, _collisionShape, _localInertia, _linearDamping, _angularDamping, - _friction, _restitution); - //rigidBody.ActivationState = ActivationState.DisableDeactivation; - //It's seems that there are a bug with rigidBody constructor and its CenterOfMassPosition - Vector3 _vDebugTranslation; - _vDebugTranslation = _startTransform.Translation - rigidBody.CenterOfMassPosition; - rigidBody.Translate(_vDebugTranslation); - //--- - parent_scene.ddWorld.AddRigidBody(rigidBody); - } - } - - protected internal void ReCreateRigidBody(OpenMetaverse.Vector3 size) - { - //There is a bug when trying to remove a rigidBody that is colliding with something.. - try - { - _parent_scene.ddWorld.RemoveRigidBody(rigidBody); - } - catch (Exception ex) - { - BulletXScene.BulletXMessage(_parent_scene.is_ex_message + ex.Message, true); - rigidBody.ActivationState = ActivationState.DisableSimulation; - _parent_scene.AddForgottenRigidBody(rigidBody); - } - CreateRigidBody(_parent_scene, null, _position, size); - // Note, null for the meshing definitely is wrong. It's here for the moment to apease the compiler - if (_physical) Speed(); //Static objects don't have linear velocity - ReOrient(); - GC.Collect(); - } - - protected internal override void ReSize(OpenMetaverse.Vector3 _newSize) - { - //I wonder to know how to resize with a simple instruction in BulletX. It seems that for now there isn't - //so i have to do it manually. That's recreating rigidbody - ReCreateRigidBody(_newSize); - } - - #endregion - } - - /// - /// This Class manage a HeighField as a RigidBody. This is for to be added in the BulletXScene - /// - internal class BulletXPlanet - { - private OpenMetaverse.Vector3 _staticPosition; -// private Vector3 _staticVelocity; -// private OpenMetaverse.Quaternion _staticOrientation; - private float _mass; - // private BulletXScene _parentscene; - internal float[] _heightField; - private RigidBody _flatPlanet; - - internal RigidBody RigidBody - { - get { return _flatPlanet; } - } - - internal BulletXPlanet(BulletXScene parent_scene, float[] heightField) - { - _staticPosition = new OpenMetaverse.Vector3(BulletXScene.MaxXY / 2, BulletXScene.MaxXY / 2, 0); -// _staticVelocity = new PhysicsVector(); -// _staticOrientation = OpenMetaverse.Quaternion.Identity; - _mass = 0; //No active - // _parentscene = parent_scene; - _heightField = heightField; - - float _linearDamping = 0.0f; - float _angularDamping = 0.0f; - float _friction = 0.5f; - float _restitution = 0.0f; - Matrix _startTransform = Matrix.Identity; - Matrix _centerOfMassOffset = Matrix.Identity; - - lock (BulletXScene.BulletXLock) - { - try - { - _startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(_staticPosition); - CollisionShape _collisionShape = - new HeightfieldTerrainShape(BulletXScene.MaxXY, BulletXScene.MaxXY, _heightField, - (float) BulletXScene.MaxZ, 2, true, false); - DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset); - Vector3 _localInertia = new Vector3(); - //_collisionShape.CalculateLocalInertia(_mass, out _localInertia); //Always when mass > 0 - _flatPlanet = - new RigidBody(_mass, _motionState, _collisionShape, _localInertia, _linearDamping, - _angularDamping, _friction, _restitution); - //It's seems that there are a bug with rigidBody constructor and its CenterOfMassPosition - Vector3 _vDebugTranslation; - _vDebugTranslation = _startTransform.Translation - _flatPlanet.CenterOfMassPosition; - _flatPlanet.Translate(_vDebugTranslation); - parent_scene.ddWorld.AddRigidBody(_flatPlanet); - } - catch (Exception ex) - { - BulletXScene.BulletXMessage(ex.Message, true); - } - } - BulletXScene.BulletXMessage("BulletXPlanet created.", false); - } - - internal float HeightValue(Vector3 position) - { - int li_x, li_y; - float height; - li_x = (int) Math.Round(position.X); - if (li_x < 0) li_x = 0; - if (li_x >= BulletXScene.MaxXY) li_x = BulletXScene.MaxXY - 1; - li_y = (int) Math.Round(position.Y); - if (li_y < 0) li_y = 0; - if (li_y >= BulletXScene.MaxXY) li_y = BulletXScene.MaxXY - 1; - - height = ((HeightfieldTerrainShape) _flatPlanet.CollisionShape).getHeightFieldValue(li_x, li_y); - if (height < 0) height = 0; - else if (height > BulletXScene.MaxZ) height = BulletXScene.MaxZ; - - return height; - } - } -} diff --git a/OpenSim/Region/Physics/BulletXPlugin/TriangleIndexVertexArray.cs b/OpenSim/Region/Physics/BulletXPlugin/TriangleIndexVertexArray.cs deleted file mode 100644 index 637cf6e20c..0000000000 --- a/OpenSim/Region/Physics/BulletXPlugin/TriangleIndexVertexArray.cs +++ /dev/null @@ -1,197 +0,0 @@ -/* - Bullet for XNA Copyright (c) 2003-2007 Vsevolod Klementjev http://www.codeplex.com/xnadevru - Bullet original C++ version Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* - This file contains a class TriangleIndexVertexArray. I tried using the class with the same name - from the BulletX implementation and found it unusable for the purpose of using triangle meshes - within BulletX as the implementation was painfully incomplete. - The attempt to derive from the original class failed as viable members were hidden. - Fiddling around with BulletX itself was not my intention. - So I copied the class to the BulletX-plugin and modified it. - If you want to fiddle around with it it's up to you to move all this to BulletX. - If someone someday implements the missing functionality in BulletX, feel free to remove this class. - It's just an ugly hack. -*/ - -using System; -using System.Collections.Generic; -using MonoXnaCompactMaths; -using XnaDevRu.BulletX; - -namespace OpenSim.Region.Physics.BulletXPlugin -{ - /// - /// IndexedMesh indexes into existing vertex and index arrays, in a similar way OpenGL glDrawElements - /// instead of the number of indices, we pass the number of triangles - /// - public struct IndexedMesh - { - private int _numTriangles; - private int[] _triangleIndexBase; - private int _triangleIndexStride; - private int _numVertices; - private Vector3[] _vertexBase; - private int _vertexStride; - - public IndexedMesh(int numTriangleIndices, int[] triangleIndexBase, int triangleIndexStride, int numVertices, - Vector3[] vertexBase, int vertexStride) - { - _numTriangles = numTriangleIndices; - _triangleIndexBase = triangleIndexBase; - _triangleIndexStride = triangleIndexStride; - _vertexBase = vertexBase; - _numVertices = numVertices; - _vertexStride = vertexStride; - } - - public IndexedMesh(int[] triangleIndexBase, Vector3[] vertexBase) - { - _numTriangles = triangleIndexBase.Length; - _triangleIndexBase = triangleIndexBase; - _triangleIndexStride = 32; - _vertexBase = vertexBase; - _numVertices = vertexBase.Length; - _vertexStride = 24; - } - - public int TriangleCount - { - get { return _numTriangles; } - set { _numTriangles = value; } - } - - public int[] TriangleIndexBase - { - get { return _triangleIndexBase; } - set { _triangleIndexBase = value; } - } - - public int TriangleIndexStride - { - get { return _triangleIndexStride; } - set { _triangleIndexStride = value; } - } - - public int VertexCount - { - get { return _numVertices; } - set { _numVertices = value; } - } - - public Vector3[] VertexBase - { - get { return _vertexBase; } - set { _vertexBase = value; } - } - - public int VertexStride - { - get { return _vertexStride; } - set { _vertexStride = value; } - } - } - - /// - /// TriangleIndexVertexArray allows to use multiple meshes, by indexing into existing triangle/index arrays. - /// Additional meshes can be added using addIndexedMesh - /// - public class TriangleIndexVertexArray : StridingMeshInterface - { - private List _indexedMeshes = new List(); - - public TriangleIndexVertexArray() - { - } - - public TriangleIndexVertexArray(int numTriangleIndices, int[] triangleIndexBase, int triangleIndexStride, - int numVertices, Vector3[] vertexBase, int vertexStride) - { - IndexedMesh mesh = new IndexedMesh(); - mesh.TriangleCount = numTriangleIndices; - mesh.TriangleIndexBase = triangleIndexBase; - mesh.TriangleIndexStride = triangleIndexStride; - mesh.VertexBase = vertexBase; - mesh.VertexCount = numVertices; - mesh.VertexStride = vertexStride; - - AddIndexedMesh(mesh); - } - - public TriangleIndexVertexArray(int[] triangleIndexBase, Vector3[] vertexBase) - : this(triangleIndexBase.Length, triangleIndexBase, 32, vertexBase.Length, vertexBase, 24) - { - } - - public void AddIndexedMesh(IndexedMesh indexedMesh) - { - _indexedMeshes.Add(indexedMesh); - } - - public override void GetLockedVertexIndexBase(out List verts, out List indicies, out int numfaces, - int subpart) - { - throw new Exception("The method or operation is not implemented."); - } - - public override void GetLockedReadOnlyVertexIndexBase(out List verts, out List indicies, - out int numfaces, int subpart) - { - IndexedMesh m = _indexedMeshes[0]; - Vector3[] vertexBase = m.VertexBase; - verts = new List(); - foreach (Vector3 v in vertexBase) - { - verts.Add(v); - } - int[] indexBase = m.TriangleIndexBase; - indicies = new List(); - foreach (int i in indexBase) - { - indicies.Add(i); - } - numfaces = vertexBase.GetLength(0); - } - - public override void UnLockVertexBase(int subpart) - { - throw new Exception("The method or operation is not implemented."); - } - - public override void UnLockReadOnlyVertexBase(int subpart) - { - } - - public override int SubPartsCount() - { - return _indexedMeshes.Count; - } - - public override void PreallocateVertices(int numverts) - { - throw new Exception("The method or operation is not implemented."); - } - - public override void PreallocateIndices(int numindices) - { - throw new Exception("The method or operation is not implemented."); - } - } -} diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index c36d2a4ea6..0ef6880d36 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -149,14 +149,11 @@ ;; Choose one of the physics engines below ;; OpenDynamicsEngine is by some distance the most developed physics engine - ;; basicphysics effectively does not model physics at all, making all - ;; objects phantom - ;; The Bullet plugins do not work properly right now. A better Bullet plugin is on the way. + ;; basicphysics effectively does not model physics at all, making all objects phantom ;; Default is OpenDynamicsEngine ; physics = OpenDynamicsEngine ; physics = basicphysics ; physics = POS - ; physics = modified_BulletX ;# {permissionmodules} {} {Permission modules to use (may specify multiple modules, separated by space} {} DefaultPermissionsModule ;; Permission modules to use, separated by space. diff --git a/prebuild.xml b/prebuild.xml index 3aca02d03b..690de5ae88 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -573,34 +573,6 @@ - - - - ../../../../bin/Physics/ - - - - - ../../../../bin/Physics/ - - - - ../../../../bin/ - - - - - - - - - - - - - - - @@ -690,34 +662,6 @@ - - - - ../../../../bin/Physics/ - - - - - ../../../../bin/Physics/ - - - - ../../../../bin/ - - - - - - - - - - - - - - - From 27af016381f2f4aaa8cda99ce7f029980bf8ea76 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 17 Sep 2011 01:13:07 +0100 Subject: [PATCH 23/64] Add BulletSim physics option details to OpenSim.ini.example. Marked as in development and experimental. --- bin/OpenSim.ini.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 0ef6880d36..925c343aa1 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -149,9 +149,11 @@ ;; Choose one of the physics engines below ;; OpenDynamicsEngine is by some distance the most developed physics engine + ;; BulletSim is incomplete and experimental but in active development ;; basicphysics effectively does not model physics at all, making all objects phantom ;; Default is OpenDynamicsEngine ; physics = OpenDynamicsEngine + ; physics = BulletSim ; physics = basicphysics ; physics = POS From 1e798136c3458b8255fcb6341713bf9dbb689f4b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 17 Sep 2011 01:33:55 +0100 Subject: [PATCH 24/64] adjust some whitespace to trigger another build, to check the last failure was just a glitch --- OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 924d7c2d77..ac92b8b963 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -1526,6 +1526,7 @@ Console.WriteLine("changeadd 1"); { if (Body == IntPtr.Zero) enableBody(); + //Prim auto disable after 20 frames, //if you move it, re-enable the prim manually. if (_parent != null) @@ -1536,6 +1537,7 @@ Console.WriteLine("changeadd 1"); m_linkJoint = IntPtr.Zero; } } + if (Body != IntPtr.Zero) { d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); @@ -1599,7 +1601,6 @@ Console.WriteLine(" JointCreateFixed"); float fy = 0; float fz = 0; - if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims. { if (m_vehicle.Type != Vehicle.TYPE_NONE) @@ -1818,7 +1819,6 @@ Console.WriteLine(" JointCreateFixed"); // 35x10 = 350n times the mass per second applied maximum. float nmax = 35f * m_mass; float nmin = -35f * m_mass; - if (fx > nmax) fx = nmax; From aadf7dd91cdeb98b48cd81c5db06481593aff993 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 20 Sep 2011 20:56:32 +0100 Subject: [PATCH 25/64] Remove vestigal OpenSim.Data mono addins extension points that don't look like they've been active for at least 2 and a half years --- .../Resources/OpenSim.Data.MSSQL.addin.xml | 23 ------------------- .../Resources/OpenSim.Data.MySQL.addin.xml | 23 ------------------- .../Resources/OpenSim.Data.SQLite.addin.xml | 20 ---------------- 3 files changed, 66 deletions(-) delete mode 100644 OpenSim/Data/MSSQL/Resources/OpenSim.Data.MSSQL.addin.xml delete mode 100644 OpenSim/Data/MySQL/Resources/OpenSim.Data.MySQL.addin.xml delete mode 100644 OpenSim/Data/SQLite/Resources/OpenSim.Data.SQLite.addin.xml diff --git a/OpenSim/Data/MSSQL/Resources/OpenSim.Data.MSSQL.addin.xml b/OpenSim/Data/MSSQL/Resources/OpenSim.Data.MSSQL.addin.xml deleted file mode 100644 index 15fd29e57c..0000000000 --- a/OpenSim/Data/MSSQL/Resources/OpenSim.Data.MSSQL.addin.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSim/Data/MySQL/Resources/OpenSim.Data.MySQL.addin.xml b/OpenSim/Data/MySQL/Resources/OpenSim.Data.MySQL.addin.xml deleted file mode 100644 index 9e995479d0..0000000000 --- a/OpenSim/Data/MySQL/Resources/OpenSim.Data.MySQL.addin.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/OpenSim/Data/SQLite/Resources/OpenSim.Data.SQLite.addin.xml b/OpenSim/Data/SQLite/Resources/OpenSim.Data.SQLite.addin.xml deleted file mode 100644 index e6764facbd..0000000000 --- a/OpenSim/Data/SQLite/Resources/OpenSim.Data.SQLite.addin.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - From fa9291512aabbe72cb6b1b0b7a9af79d9b05d253 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Tue, 20 Sep 2011 14:07:10 -0700 Subject: [PATCH 26/64] Make debug statements in ScenePresence consistent and add a few more --- .../Region/Framework/Scenes/ScenePresence.cs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9358a4aba1..b1094cc32e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -70,7 +70,7 @@ namespace OpenSim.Region.Framework.Scenes { // ~ScenePresence() // { -// m_log.Debug("[ScenePresence] Destructor called"); +// m_log.Debug("[SCENE PRESENCE] Destructor called"); // } private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -517,7 +517,7 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception e) { - m_log.Error("[SCENEPRESENCE]: ABSOLUTE POSITION " + e.Message); + m_log.Error("[SCENE PRESENCE]: ABSOLUTE POSITION " + e.Message); } } @@ -570,7 +570,7 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception e) { - m_log.Error("[SCENEPRESENCE]: VELOCITY " + e.Message); + m_log.Error("[SCENE PRESENCE]: VELOCITY " + e.Message); } } @@ -1008,7 +1008,7 @@ namespace OpenSim.Region.Framework.Scenes Animator.ResetAnimations(); // m_log.DebugFormat( -// "[SCENEPRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", +// "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", // Name, UUID, m_scene.RegionInfo.RegionName); // Don't zero out the velocity since this can cause problems when an avatar is making a region crossing, @@ -1175,7 +1175,7 @@ namespace OpenSim.Region.Framework.Scenes m_callbackURI = null; } - //m_log.DebugFormat("Completed movement"); + m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); m_controllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); SendInitialData(); @@ -2416,7 +2416,7 @@ namespace OpenSim.Region.Framework.Scenes Vector3 pos = m_pos; pos.Z += m_appearance.HipOffset; - //m_log.DebugFormat("[SCENEPRESENCE]: TerseUpdate: Pos={0} Rot={1} Vel={2}", m_pos, m_bodyRot, m_velocity); + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, m_bodyRot, m_velocity); remoteClient.SendPrimUpdate( this, @@ -2503,6 +2503,7 @@ namespace OpenSim.Region.Framework.Scenes ///
private void SendInitialData() { + m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID); // Moved this into CompleteMovement to ensure that m_appearance is initialized before // the inventory arrives // m_scene.GetAvatarAppearance(m_controllingClient, out m_appearance); @@ -2547,10 +2548,11 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendAvatarDataToAllAgents() { + m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" if (IsChildAgent) { - m_log.Warn("[SCENEPRESENCE] attempt to send avatar data from a child agent"); + m_log.Warn("[SCENE PRESENCE] attempt to send avatar data from a child agent"); return; } @@ -2600,7 +2602,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendAvatarDataToAgent(ScenePresence avatar) { -// m_log.WarnFormat("[SP] Send avatar data from {0} to {1}",m_uuid,avatar.ControllingClient.AgentId); + m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); avatar.ControllingClient.SendAvatarDataImmediate(this); if (Animator != null) @@ -2613,10 +2615,11 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendAppearanceToAllOtherAgents() { + m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} ({1})", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" if (IsChildAgent) { - m_log.Warn("[SCENEPRESENCE] attempt to send avatar data from a child agent"); + m_log.Warn("[SCENE PRESENCE] attempt to send avatar data from a child agent"); return; } @@ -2642,6 +2645,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendOtherAgentsAppearanceToMe() { + m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} ({1})", Name, UUID); m_perfMonMS = Util.EnvironmentTickCount(); int count = 0; @@ -3826,4 +3830,4 @@ namespace OpenSim.Region.Framework.Scenes } } } -} \ No newline at end of file +} From 7ec7a3cf33b3a67cb10df14bad04cf6f09262822 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Tue, 20 Sep 2011 15:31:43 -0700 Subject: [PATCH 27/64] Null simulation data must return a non-null region settings or other parts of the simulator expect --- OpenSim/Data/Null/NullSimulationData.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs index c33a6f2c43..b7889767da 100644 --- a/OpenSim/Data/Null/NullSimulationData.cs +++ b/OpenSim/Data/Null/NullSimulationData.cs @@ -77,8 +77,10 @@ namespace OpenSim.Data.Null } public RegionSettings LoadRegionSettings(UUID regionUUID) - { - return null; + { + RegionSettings rs = new RegionSettings(); + rs.RegionUUID = regionUUID; + return rs; } public void StoreObject(SceneObjectGroup obj, UUID regionUUID) From 8159fd7110459246ff61a41800899f5d854eceee Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 21 Sep 2011 19:28:41 +0100 Subject: [PATCH 28/64] When calling osNpcMoveTo(), rotate the avatar in the direction of travel. This stops the npc walking backwards if the target is directly behind. This means that the npc no longer returns to its original rotation once movement has finished. If you want this behaviour, please store and reset the original rotation after movement. This is somewhat to address http://opensimulator.org/mantis/view.php?id=5678 --- .../Region/Framework/Scenes/ScenePresence.cs | 23 +++++- .../World/NPC/Tests/NPCModuleTests.cs | 16 +++- .../Common/QuaternionToleranceConstraint.cs | 82 +++++++++++++++++++ 3 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 OpenSim/Tests/Common/QuaternionToleranceConstraint.cs diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9358a4aba1..cd3cb60ddd 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -585,7 +585,11 @@ namespace OpenSim.Region.Framework.Scenes public Quaternion Rotation { get { return m_bodyRot; } - set { m_bodyRot = value; } + set + { + m_bodyRot = value; + m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); + } } public Quaternion PreviousRotation @@ -1711,7 +1715,7 @@ namespace OpenSim.Region.Framework.Scenes // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is // always slightly higher than the actual terrain height. - // FIXME: This constrains NOC movements as well, so should be somewhere else. + // FIXME: This constrains NPC movements as well, so should be somewhere else. if (pos.Z - terrainHeight < 0.2) pos.Z = terrainHeight; @@ -1727,6 +1731,21 @@ namespace OpenSim.Region.Framework.Scenes MovingToTarget = true; MoveToPositionTarget = pos; + // Rotate presence around the z-axis to point in same direction as movement. + // Ignore z component of vector + Vector3 localVectorToTarget3D = pos - AbsolutePosition; + Vector3 localVectorToTarget2D = new Vector3((float)(localVectorToTarget3D.X), (float)(localVectorToTarget3D.Y), 0f); + +// m_log.DebugFormat("[SCENE PRESENCE]: Local vector to target is {0}", localVectorToTarget2D); + + // Calculate the yaw. + Vector3 angle = new Vector3(0, 0, (float)(Math.Atan2(localVectorToTarget2D.Y, localVectorToTarget2D.X))); + +// m_log.DebugFormat("[SCENE PRESENCE]: Angle is {0}", angle); + + Rotation = Quaternion.CreateFromEulers(angle); +// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, Rotation); + Vector3 agent_control_v3 = new Vector3(); HandleMoveToTargetUpdate(ref agent_control_v3); AddNewMovement(agent_control_v3); diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 246bc34219..1a0d0c742d 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -182,18 +182,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests scene.Update(); Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); - Vector3 targetPos = startPos + new Vector3(0, 0, 10); + Vector3 targetPos = startPos + new Vector3(0, 10, 0); npcModule.MoveToTarget(npc.UUID, scene, targetPos, false, false); Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); + //Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0.7071068f, 0.7071068f))); + Assert.That( + npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001)); scene.Update(); // We should really check the exact figure. Assert.That(npc.AbsolutePosition.X, Is.EqualTo(startPos.X)); - Assert.That(npc.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); - Assert.That(npc.AbsolutePosition.Z, Is.GreaterThan(startPos.Z)); - Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.Z)); + Assert.That(npc.AbsolutePosition.Y, Is.GreaterThan(startPos.Y)); + Assert.That(npc.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + Assert.That(npc.AbsolutePosition.Z, Is.LessThan(targetPos.X)); for (int i = 0; i < 10; i++) scene.Update(); @@ -208,6 +211,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests targetPos = startPos + new Vector3(10, 0, 0); npcModule.MoveToTarget(npc.UUID, scene, targetPos, false, false); + Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); +// Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0, 1))); + Assert.That( + npc.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0, 1), 0.000001)); + scene.Update(); // We should really check the exact figure. diff --git a/OpenSim/Tests/Common/QuaternionToleranceConstraint.cs b/OpenSim/Tests/Common/QuaternionToleranceConstraint.cs new file mode 100644 index 0000000000..b38c382f53 --- /dev/null +++ b/OpenSim/Tests/Common/QuaternionToleranceConstraint.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 OpenMetaverse; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace OpenSim.Tests.Common +{ + public class QuaternionToleranceConstraint : ANumericalToleranceConstraint + { + private Quaternion _baseValue; + private Quaternion _valueToBeTested; + + public QuaternionToleranceConstraint(Quaternion baseValue, double tolerance) : base(tolerance) + { + _baseValue = baseValue; + } + + /// + /// Test whether the constraint is satisfied by a given value + /// + /// The value to be tested + /// + /// True for success, false for failure + /// + public override bool Matches(object valueToBeTested) + { + if (valueToBeTested == null) + { + throw new ArgumentException("Constraint cannot be used upon null values."); + } + if (valueToBeTested.GetType() != typeof (Quaternion)) + { + throw new ArgumentException("Constraint cannot be used upon non quaternion values."); + } + + _valueToBeTested = (Quaternion)valueToBeTested; + + return (IsWithinDoubleConstraint(_valueToBeTested.X, _baseValue.X) && + IsWithinDoubleConstraint(_valueToBeTested.Y, _baseValue.Y) && + IsWithinDoubleConstraint(_valueToBeTested.Z, _baseValue.Z) && + IsWithinDoubleConstraint(_valueToBeTested.W, _baseValue.W)); + } + + public override void WriteDescriptionTo(MessageWriter writer) + { + writer.WriteExpectedValue( + string.Format("A value {0} within tolerance of plus or minus {1}", _baseValue, _tolerance)); + } + + public override void WriteActualValueTo(MessageWriter writer) + { + writer.WriteActualValue(_valueToBeTested); + } + } +} \ No newline at end of file From 572b680cb01a856f860b1e3fb40a7153a36113f2 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 21 Sep 2011 20:15:06 +0100 Subject: [PATCH 29/64] get rid of an incredibly noisy logging message from the last commit --- 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 5a3e587750..affb844fca 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -588,7 +588,7 @@ namespace OpenSim.Region.Framework.Scenes set { m_bodyRot = value; - m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); +// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); } } From f9438e7147bbb347a45b14126fa7181307f8ef43 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 21 Sep 2011 22:01:57 +0100 Subject: [PATCH 30/64] Remove unused and never set SP.PreviousRotation --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index affb844fca..82d9abf6d6 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -178,8 +178,6 @@ namespace OpenSim.Region.Framework.Scenes private Quaternion m_bodyRot = Quaternion.Identity; - private Quaternion m_bodyRotPrevious = Quaternion.Identity; - private const int LAND_VELOCITYMAG_MAX = 12; public bool IsRestrictedToRegion; @@ -592,12 +590,6 @@ namespace OpenSim.Region.Framework.Scenes } } - public Quaternion PreviousRotation - { - get { return m_bodyRotPrevious; } - set { m_bodyRotPrevious = value; } - } - /// /// If this is true, agent doesn't have a representation in this scene. /// this is an agent 'looking into' this scene from a nearby scene(region) From 241e07d006fad1b54e088d8a9ddede0b98a1e800 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 21 Sep 2011 23:56:11 +0100 Subject: [PATCH 31/64] Move code which handles NPC movement into Scene so that this can also be used by Autopilot coming from the client side. I thought that I had implemented this but must have accidentally removed it. Adds a regression test to detect if this happens again. Temporarily disables automatic landing of NPC at a target. Will be fixed presently. --- OpenSim/Region/Framework/Scenes/Scene.cs | 67 +++++++++ .../Tests/ScenePresenceAutopilotTests.cs | 135 ++++++++++++++++++ .../OptionalModules/World/NPC/NPCModule.cs | 2 +- 3 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 976e001a60..000a6ed6ab 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -870,6 +870,8 @@ namespace OpenSim.Region.Framework.Scenes if (dm != null) m_eventManager.OnPermissionError += dm.SendAlertToUser; + + m_eventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; } public override string GetSimulatorVersion() @@ -5138,5 +5140,70 @@ namespace OpenSim.Region.Framework.Scenes reason = String.Empty; return true; } + + /// + /// This method deals with movement when an avatar is automatically moving (but this is distinct from the + /// autopilot that moves an avatar to a sit target!. + /// + /// + /// This is not intended as a permament location for this method. + /// + /// + private void HandleOnSignificantClientMovement(ScenePresence presence) + { + if (presence.MovingToTarget) + { + double distanceToTarget = Util.GetDistanceTo(presence.AbsolutePosition, presence.MoveToPositionTarget); +// m_log.DebugFormat( +// "[SCENE]: Abs pos of {0} is {1}, target {2}, distance {3}", +// presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget, distanceToTarget); + + // Check the error term of the current position in relation to the target position + if (distanceToTarget <= ScenePresence.SIGNIFICANT_MOVEMENT) + { + // We are close enough to the target +// m_log.DebugFormat("[SCENEE]: Stopping autopilot of {0}", presence.Name); + + presence.Velocity = Vector3.Zero; + presence.AbsolutePosition = presence.MoveToPositionTarget; + presence.ResetMoveToTarget(); + + if (presence.PhysicsActor.Flying) + { + // A horrible hack to stop the avatar dead in its tracks rather than having them overshoot + // the target if flying. + // We really need to be more subtle (slow the avatar as it approaches the target) or at + // least be able to set collision status once, rather than 5 times to give it enough + // weighting so that that PhysicsActor thinks it really is colliding. + for (int i = 0; i < 5; i++) + presence.PhysicsActor.IsColliding = true; + +// Vector3 targetPos = presence.MoveToPositionTarget; +// if (m_avatars[presence.UUID].LandAtTarget) +// presence.PhysicsActor.Flying = false; + +// float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; +// if (targetPos.Z - terrainHeight < 0.2) +// { +// presence.PhysicsActor.Flying = false; +// } + } + +// m_log.DebugFormat( +// "[SCENE]: AgentControlFlags {0}, MovementFlag {1} for {2}", +// presence.AgentControlFlags, presence.MovementFlag, presence.Name); + } + else + { +// m_log.DebugFormat( +// "[SCENE]: Updating npc {0} at {1} for next movement to {2}", +// presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget); + + Vector3 agent_control_v3 = new Vector3(); + presence.HandleMoveToTargetUpdate(ref agent_control_v3); + presence.AddNewMovement(agent_control_v3); + } + } + } } } diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs new file mode 100644 index 0000000000..5a85d7f9da --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs @@ -0,0 +1,135 @@ +/* + * 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; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + [TestFixture] + public class ScenePresenceAutopilotTests + { + private TestScene m_scene; + + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + + [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 void Init() + { + m_scene = SceneHelpers.SetupScene(); + } + + [Test] + public void TestMove() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); + + Vector3 startPos = sp.AbsolutePosition; +// Vector3 startPos = new Vector3(128, 128, 30); + + // For now, we'll make the scene presence fly to simplify this test, but this needs to change. + sp.PhysicsActor.Flying = true; + + m_scene.Update(); + Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); + + Vector3 targetPos = startPos + new Vector3(0, 10, 0); + sp.MoveToTarget(targetPos, false); + + Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0.7071068f, 0.7071068f), 0.000001)); + + m_scene.Update(); + + // We should really check the exact figure. + Assert.That(sp.AbsolutePosition.X, Is.EqualTo(startPos.X)); + Assert.That(sp.AbsolutePosition.Y, Is.GreaterThan(startPos.Y)); + Assert.That(sp.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + Assert.That(sp.AbsolutePosition.Z, Is.LessThan(targetPos.X)); + + for (int i = 0; i < 10; i++) + m_scene.Update(); + + double distanceToTarget = Util.GetDistanceTo(sp.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "Avatar not within 1 unit of target position on first move"); + Assert.That(sp.AbsolutePosition, Is.EqualTo(targetPos)); + Assert.That(sp.AgentControlFlags, Is.EqualTo((uint)AgentManager.ControlFlags.NONE)); + + // Try a second movement + startPos = sp.AbsolutePosition; + targetPos = startPos + new Vector3(10, 0, 0); + sp.MoveToTarget(targetPos, false); + + Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); + Assert.That( + sp.Rotation, new QuaternionToleranceConstraint(new Quaternion(0, 0, 0, 1), 0.000001)); + + m_scene.Update(); + + // We should really check the exact figure. + Assert.That(sp.AbsolutePosition.X, Is.GreaterThan(startPos.X)); + Assert.That(sp.AbsolutePosition.X, Is.LessThan(targetPos.X)); + Assert.That(sp.AbsolutePosition.Y, Is.EqualTo(startPos.Y)); + Assert.That(sp.AbsolutePosition.Z, Is.EqualTo(startPos.Z)); + + for (int i = 0; i < 10; i++) + m_scene.Update(); + + distanceToTarget = Util.GetDistanceTo(sp.AbsolutePosition, targetPos); + Assert.That(distanceToTarget, Is.LessThan(1), "Avatar not within 1 unit of target position on second move"); + Assert.That(sp.AbsolutePosition, Is.EqualTo(targetPos)); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 2fdeeabe69..62822459f6 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC if (config != null && config.GetBoolean("Enabled", false)) { scene.RegisterModuleInterface(this); - scene.EventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; +// scene.EventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; } } From d358125cac4e01194dae4b1f0bc9afc87e463f76 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 Sep 2011 00:16:05 +0100 Subject: [PATCH 32/64] Reinstate option to land an npc when it reaches a target. This is moved into ScenePresence for now as a general facility --- .../Rest/Inventory/tests/Remote.cs | 2 +- OpenSim/Framework/IClientAPI.cs | 2 +- .../ClientStack/Linden/UDP/LLClientView.cs | 6 +- .../Examples/SimpleModule/MyNpcCharacter.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 6 +- .../Framework/Scenes/SceneObjectGroup.cs | 2 +- .../Region/Framework/Scenes/ScenePresence.cs | 11 ++- .../Tests/ScenePresenceAutopilotTests.cs | 4 +- .../Server/IRCClientView.cs | 2 +- .../OptionalModules/World/NPC/NPCAvatar.cs | 7 +- .../OptionalModules/World/NPC/NPCModule.cs | 72 +------------------ OpenSim/Tests/Common/Mock/TestClient.cs | 2 +- 12 files changed, 28 insertions(+), 90 deletions(-) diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs index 1023108661..b53806c651 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs @@ -169,7 +169,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]); float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]); Vector3 vector = new Vector3(x, y, z); - presence.MoveToTarget(vector, false); + presence.MoveToTarget(vector, false, false); } catch (Exception e) { diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 150ff1bf3f..47e79d133e 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -935,7 +935,7 @@ namespace OpenSim.Framework event ScriptReset OnScriptReset; event GetScriptRunning OnGetScriptRunning; event SetScriptRunning OnSetScriptRunning; - event Action OnAutoPilotGo; + event Action OnAutoPilotGo; event TerrainUnacked OnUnackedTerrain; event ActivateGesture OnActivateGesture; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index b5c6742631..ce2ff86513 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -231,7 +231,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; - public event Action OnAutoPilotGo; + public event Action OnAutoPilotGo; public event TerrainUnacked OnUnackedTerrain; public event ActivateGesture OnActivateGesture; public event DeactivateGesture OnDeactivateGesture; @@ -11640,9 +11640,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP locy = Convert.ToSingle(args[1]) - (float)regionY; locz = Convert.ToSingle(args[2]); - Action handlerAutoPilotGo = OnAutoPilotGo; + Action handlerAutoPilotGo = OnAutoPilotGo; if (handlerAutoPilotGo != null) - handlerAutoPilotGo(new Vector3(locx, locy, locz), false); + handlerAutoPilotGo(new Vector3(locx, locy, locz), false, false); } /// diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index c87790f9f8..b0266c53bf 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -222,7 +222,7 @@ namespace OpenSim.Region.Examples.SimpleModule public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; - public event Action OnAutoPilotGo; + public event Action OnAutoPilotGo; public event TerrainUnacked OnUnackedTerrain; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 000a6ed6ab..eadec09df3 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -5178,10 +5178,10 @@ namespace OpenSim.Region.Framework.Scenes for (int i = 0; i < 5; i++) presence.PhysicsActor.IsColliding = true; -// Vector3 targetPos = presence.MoveToPositionTarget; -// if (m_avatars[presence.UUID].LandAtTarget) -// presence.PhysicsActor.Flying = false; + if (presence.LandAtTarget) + presence.PhysicsActor.Flying = false; +// Vector3 targetPos = presence.MoveToPositionTarget; // float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; // if (targetPos.Z - terrainHeight < 0.2) // { diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index e7f2491813..980b01fda0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1599,7 +1599,7 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); if (avatar != null) { - avatar.MoveToTarget(target, false); + avatar.MoveToTarget(target, false, false); } } else diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 82d9abf6d6..a7b189b47b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -220,6 +220,11 @@ namespace OpenSim.Region.Framework.Scenes public bool MovingToTarget { get; private set; } public Vector3 MoveToPositionTarget { get; private set; } + /// + /// Controls whether an avatar automatically moving to a target will land when it gets there (if flying). + /// + public bool LandAtTarget { get; private set; } + private bool m_followCamAuto; private int m_movementUpdateCount; @@ -1681,7 +1686,10 @@ namespace OpenSim.Region.Framework.Scenes /// This is to allow movement to targets that are known to be on an elevated platform with a continuous path /// from start to finish. /// - public void MoveToTarget(Vector3 pos, bool noFly) + /// + /// If true and the avatar starts flying during the move then land at the target. + /// + public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget) { m_log.DebugFormat( "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}", @@ -1720,6 +1728,7 @@ namespace OpenSim.Region.Framework.Scenes else if (pos.Z > terrainHeight) PhysicsActor.Flying = true; + LandAtTarget = landAtTarget; MovingToTarget = true; MoveToPositionTarget = pos; diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs index 5a85d7f9da..64c36ffaef 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs @@ -85,7 +85,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); Vector3 targetPos = startPos + new Vector3(0, 10, 0); - sp.MoveToTarget(targetPos, false); + sp.MoveToTarget(targetPos, false, false); Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); Assert.That( @@ -110,7 +110,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Try a second movement startPos = sp.AbsolutePosition; targetPos = startPos + new Vector3(10, 0, 0); - sp.MoveToTarget(targetPos, false); + sp.MoveToTarget(targetPos, false, false); Assert.That(sp.AbsolutePosition, Is.EqualTo(startPos)); Assert.That( diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index c413634c61..f6656c2564 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -806,7 +806,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; - public event Action OnAutoPilotGo; + public event Action OnAutoPilotGo; public event TerrainUnacked OnUnackedTerrain; public event ActivateGesture OnActivateGesture; public event DeactivateGesture OnDeactivateGesture; diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 31e79fa449..edb618e773 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -37,11 +37,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC { public class NPCAvatar : IClientAPI { - /// - /// Signal whether the avatar should land when it reaches a move target - /// - public bool LandAtTarget { get; set; } - private readonly string m_firstname; private readonly string m_lastname; private readonly Vector3 m_startPos; @@ -333,7 +328,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; - public event Action OnAutoPilotGo; + public event Action OnAutoPilotGo; public event TerrainUnacked OnUnackedTerrain; diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 62822459f6..bcd9e943ee 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -53,78 +53,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC if (config != null && config.GetBoolean("Enabled", false)) { scene.RegisterModuleInterface(this); -// scene.EventManager.OnSignificantClientMovement += HandleOnSignificantClientMovement; - } - } - - public void HandleOnSignificantClientMovement(ScenePresence presence) - { - lock (m_avatars) - { - if (m_avatars.ContainsKey(presence.UUID) && presence.MovingToTarget) - { - double distanceToTarget = Util.GetDistanceTo(presence.AbsolutePosition, presence.MoveToPositionTarget); -// m_log.DebugFormat( -// "[NPC MODULE]: Abs pos of {0} is {1}, target {2}, distance {3}", -// presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget, distanceToTarget); - - // Check the error term of the current position in relation to the target position - if (distanceToTarget <= ScenePresence.SIGNIFICANT_MOVEMENT) - { - // We are close enough to the target - m_log.DebugFormat("[NPC MODULE]: Stopping movement of npc {0}", presence.Name); - - presence.Velocity = Vector3.Zero; - presence.AbsolutePosition = presence.MoveToPositionTarget; - presence.ResetMoveToTarget(); - - if (presence.PhysicsActor.Flying) - { - // A horrible hack to stop the NPC dead in its tracks rather than having them overshoot - // the target if flying. - // We really need to be more subtle (slow the avatar as it approaches the target) or at - // least be able to set collision status once, rather than 5 times to give it enough - // weighting so that that PhysicsActor thinks it really is colliding. - for (int i = 0; i < 5; i++) - presence.PhysicsActor.IsColliding = true; - -// Vector3 targetPos = presence.MoveToPositionTarget; - if (m_avatars[presence.UUID].LandAtTarget) - presence.PhysicsActor.Flying = false; - -// float terrainHeight = (float)presence.Scene.Heightmap[(int)targetPos.X, (int)targetPos.Y]; -// if (targetPos.Z - terrainHeight < 0.2) -// { -// presence.PhysicsActor.Flying = false; -// } - } - -// m_log.DebugFormat( -// "[NPC MODULE]: AgentControlFlags {0}, MovementFlag {1} for {2}", -// presence.AgentControlFlags, presence.MovementFlag, presence.Name); - } - else - { -// m_log.DebugFormat( -// "[NPC MODULE]: Updating npc {0} at {1} for next movement to {2}", -// presence.Name, presence.AbsolutePosition, presence.MoveToPositionTarget); - - Vector3 agent_control_v3 = new Vector3(); - presence.HandleMoveToTargetUpdate(ref agent_control_v3); - presence.AddNewMovement(agent_control_v3); - } -// -//// presence.DoMoveToPositionUpdate((0, presence.MoveToPositionTarget, null); - -// -// - - } } } public bool IsNPC(UUID agentId, Scene scene) { + // FIXME: This implementation could not just use the ScenePresence.PresenceType (and callers could inspect + // that directly). ScenePresence sp = scene.GetScenePresence(agentId); if (sp == null || sp.IsChildAgent) return false; @@ -218,8 +153,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC "[NPC MODULE]: Moving {0} to {1} in {2}, noFly {3}, landAtTarget {4}", sp.Name, pos, scene.RegionInfo.RegionName, noFly, landAtTarget); - m_avatars[agentID].LandAtTarget = landAtTarget; - sp.MoveToTarget(pos, noFly); + sp.MoveToTarget(pos, noFly, landAtTarget); return true; } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index b7cefeb9b5..71f2bf4582 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -234,7 +234,7 @@ namespace OpenSim.Tests.Common.Mock public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; - public event Action OnAutoPilotGo; + public event Action OnAutoPilotGo; public event TerrainUnacked OnUnackedTerrain; From 2c0bb8118db0b91c14783c2e2a401725e88aa650 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Wed, 21 Sep 2011 16:24:19 -0700 Subject: [PATCH 33/64] Commented out new debug statements in ScenePresence --- 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 82d9abf6d6..b1c2eeae9e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1171,7 +1171,7 @@ namespace OpenSim.Region.Framework.Scenes m_callbackURI = null; } - m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); + //m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); m_controllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); SendInitialData(); @@ -2514,7 +2514,7 @@ namespace OpenSim.Region.Framework.Scenes /// private void SendInitialData() { - m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID); + //m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID); // Moved this into CompleteMovement to ensure that m_appearance is initialized before // the inventory arrives // m_scene.GetAvatarAppearance(m_controllingClient, out m_appearance); @@ -2559,7 +2559,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendAvatarDataToAllAgents() { - m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); + //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" if (IsChildAgent) { @@ -2613,7 +2613,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendAvatarDataToAgent(ScenePresence avatar) { - m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); + //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); avatar.ControllingClient.SendAvatarDataImmediate(this); if (Animator != null) @@ -2656,7 +2656,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendOtherAgentsAppearanceToMe() { - m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} ({1})", Name, UUID); + //m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} ({1})", Name, UUID); m_perfMonMS = Util.EnvironmentTickCount(); int count = 0; From 3ccb58c05c0a11fb4cff0f3adf90ca29d67b0c8b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 Sep 2011 01:08:38 +0100 Subject: [PATCH 34/64] Fix failure to teleport when an agent is lured on the same sim (and probably in neighbouring sims) with HG lure active It turns out that the HG lure module was setting up a pending lure when it intercepted the instant message on its way out to the target avatar. However, an IM would only be sent if the user was remote, so it would not be set up for users on the same sim or in an immediate neighbour. We fix this by adding the pending lure when the message goes out and ignoring a duplicate pending lure add if it goes to out via IM. Hopefully addresses http://opensimulator.org/mantis/view.php?id=5690 --- .../InstantMessage/HGMessageTransferModule.cs | 11 ++++++----- .../CoreModules/Avatar/Lure/HGLureModule.cs | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs index 7753c259b3..d2946922cd 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/HGMessageTransferModule.cs @@ -24,6 +24,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + using System; using System.Collections; using System.Collections.Generic; @@ -145,14 +146,14 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage scene.Entities[toAgentID] is ScenePresence) { // m_log.DebugFormat( -// "[INSTANT MESSAGE]: Looking for root agent {0} in {1}", +// "[HG INSTANT MESSAGE]: Looking for root agent {0} in {1}", // toAgentID.ToString(), scene.RegionInfo.RegionName); ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; if (!user.IsChildAgent) { // Local message -// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID); +// m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID); user.ControllingClient.SendInstantMessage(im); // Message sent @@ -166,7 +167,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage foreach (Scene scene in m_Scenes) { // m_log.DebugFormat( -// "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); +// "[HG INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); if (scene.Entities.ContainsKey(toAgentID) && scene.Entities[toAgentID] is ScenePresence) @@ -174,7 +175,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage // Local message ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; -// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); +// m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); user.ControllingClient.SendInstantMessage(im); // Message sent @@ -183,7 +184,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage } } -// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); +// m_log.DebugFormat("[HG INSTANT MESSAGE]: Delivering IM to {0} via XMLRPC", im.toAgentID); // Is the user a local user? UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, toAgentID); string url = string.Empty; diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index d687e6aa01..bc5c1ff2c2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -154,14 +154,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure if (im.dialog == (byte)InstantMessageDialog.RequestTeleport) { UUID sessionID = new UUID(im.imSessionID); - m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", im.imSessionID, im.RegionID, im.message); - m_PendingLures.Add(sessionID, im, 7200); // 2 hours + + if (!m_PendingLures.Contains(sessionID)) + { + m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", im.imSessionID, im.RegionID, im.message); + m_PendingLures.Add(sessionID, im, 7200); // 2 hours + } // Forward. We do this, because the IM module explicitly rejects // IMs of this type if (m_TransferModule != null) m_TransferModule.SendInstantMessage(im, delegate(bool success) { }); - } } @@ -177,12 +180,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure m_log.DebugFormat("[HG LURE MODULE]: TP invite with message {0}", message); + UUID sessionID = UUID.Random(); + GridInstantMessage m = new GridInstantMessage(scene, client.AgentId, client.FirstName+" "+client.LastName, targetid, (byte)InstantMessageDialog.RequestTeleport, false, - message, UUID.Random(), false, presence.AbsolutePosition, + message, sessionID, false, presence.AbsolutePosition, new Byte[0]); m.RegionID = client.Scene.RegionInfo.RegionID.Guid; + + m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message); + m_PendingLures.Add(sessionID, m, 7200); // 2 hours if (m_TransferModule != null) { From c8304b7f84b1a8d9fb978cae510f684e36419deb Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 Sep 2011 02:59:33 +0100 Subject: [PATCH 35/64] Fix avatar parameter updating for viewer 3 and maybe 2. When a slider parameter is changed, the viewer uploads a new shape (or other asset) and the item is updated to point to it. Viewer 1 uploaded the data in the initial request itself, so the asset references was almost always correctly updated. However, viewer 3/2 always uploads data in a subsequent xfer, which exposed a race condition where the viewer would make the item update before the asset had uploaded. This commit shuffles the order of operations to avoid this race, the item is updated with the new asset id instead of the old one while the upload was still taking place. A second race had to be fixed where avatar appearance would also be updated with the old asset id rather than the new one. This was fixed by updating the avatar appearance ids when the appearance was actually saved, rather than when the wearables update was made. --- OpenSim/Framework/AssetBase.cs | 1 + OpenSim/Framework/AvatarAppearance.cs | 2 + .../AgentAssetsTransactions.cs | 170 +++++++++++++----- .../AssetTransactionModule.cs | 25 ++- .../AssetTransaction/AssetXferUploader.cs | 127 ++++++++++--- .../AvatarFactory/AvatarFactoryModule.cs | 19 +- .../Framework/Scenes/Scene.Inventory.cs | 7 +- .../InventoryService/XInventoryService.cs | 14 +- 8 files changed, 271 insertions(+), 94 deletions(-) diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index e8c85c9f0c..d2c6c57ac3 100644 --- a/OpenSim/Framework/AssetBase.cs +++ b/OpenSim/Framework/AssetBase.cs @@ -167,6 +167,7 @@ namespace OpenSim.Framework get { return m_metadata.FullID; } set { m_metadata.FullID = value; } } + /// /// Asset MetaData ID (transferring from UUID to string ID) /// diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index c69dde35c7..72b580bc43 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -225,6 +225,8 @@ namespace OpenSim.Framework /// public virtual void ResetAppearance() { +// m_log.WarnFormat("[AVATAR APPEARANCE]: Reset appearance"); + m_serial = 0; SetDefaultTexture(); diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs index 9d8082bd33..eed7cd590a 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs @@ -41,14 +41,13 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// public class AgentAssetTransactions { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // Fields private bool m_dumpAssetsToFile; private Scene m_Scene; - public UUID UserID; - public Dictionary XferUploaders = - new Dictionary(); + private UUID UserID; + private Dictionary XferUploaders = new Dictionary(); // Methods public AgentAssetTransactions(UUID agentID, Scene scene, @@ -59,36 +58,94 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction m_dumpAssetsToFile = dumpAssetsToFile; } - public AssetXferUploader RequestXferUploader(UUID transactionID) + /// + /// Return a xfer uploader if one does not already exist. + /// + /// + /// + /// We must transfer the new asset ID into the uploader on creation, otherwise + /// we can see race conditions with other threads which can retrieve an item before it is updated with the new + /// asset id. + /// + /// + /// The xfer uploader requested. Null if one is already in existence. + /// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple + /// transfers are made. Needs to be corrected. + /// + public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID) { - if (!XferUploaders.ContainsKey(transactionID)) + lock (XferUploaders) { - AssetXferUploader uploader = new AssetXferUploader(m_Scene, - m_dumpAssetsToFile); - - lock (XferUploaders) + if (!XferUploaders.ContainsKey(transactionID)) { - XferUploaders.Add(transactionID, uploader); - } + AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile); - return uploader; +// m_log.DebugFormat( +// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID); + + XferUploaders.Add(transactionID, uploader); + + return uploader; + } } + + m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID); + return null; } public void HandleXfer(ulong xferID, uint packetID, byte[] data) { + AssetXferUploader foundUploader = null; + lock (XferUploaders) { foreach (AssetXferUploader uploader in XferUploaders.Values) { +// m_log.DebugFormat( +// "[AGENT ASSETS TRANSACTIONS]: In HandleXfer, inspect xfer upload with xfer id {0}", +// uploader.XferID); + if (uploader.XferID == xferID) { - uploader.HandleXferPacket(xferID, packetID, data); + foundUploader = uploader; break; } } } + + if (foundUploader != null) + { +// m_log.DebugFormat( +// "[AGENT ASSETS TRANSACTIONS]: Found xfer uploader for xfer id {0}, packet id {1}, data length {2}", +// xferID, packetID, data.Length); + + foundUploader.HandleXferPacket(xferID, packetID, data); + } + else + { + m_log.ErrorFormat( + "[AGENT ASSET TRANSACTIONS]: Could not find uploader for xfer id {0}, packet id {1}, data length {2}", + xferID, packetID, data.Length); + } + } + + public bool RemoveXferUploader(UUID transactionID) + { + lock (XferUploaders) + { + bool removed = XferUploaders.Remove(transactionID); + + if (!removed) + m_log.WarnFormat( + "[AGENT ASSET TRANSACTIONS]: Received request to remove xfer uploader with transaction ID {0} but none found", + transactionID); +// else +// m_log.DebugFormat( +// "[AGENT ASSET TRANSACTIONS]: Removed xfer uploader with transaction ID {0}", transactionID); + + return removed; + } } public void RequestCreateInventoryItem(IClientAPI remoteClient, @@ -96,36 +153,43 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction string description, string name, sbyte invType, sbyte type, byte wearableType, uint nextOwnerMask) { - if (XferUploaders.ContainsKey(transactionID)) + AssetXferUploader uploader = null; + + lock (XferUploaders) { - XferUploaders[transactionID].RequestCreateInventoryItem( - remoteClient, transactionID, folderID, - callbackID, description, name, invType, type, - wearableType, nextOwnerMask); + if (XferUploaders.ContainsKey(transactionID)) + uploader = XferUploaders[transactionID]; } + + if (uploader != null) + uploader.RequestCreateInventoryItem( + remoteClient, transactionID, folderID, + callbackID, description, name, invType, type, + wearableType, nextOwnerMask); + else + m_log.ErrorFormat( + "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to create inventory item {1} from {2}", + transactionID, name, remoteClient.Name); } - - /// /// Get an uploaded asset. If the data is successfully retrieved, /// the transaction will be removed. /// /// /// The asset if the upload has completed, null if it has not. - public AssetBase GetTransactionAsset(UUID transactionID) + private AssetBase GetTransactionAsset(UUID transactionID) { - if (XferUploaders.ContainsKey(transactionID)) + lock (XferUploaders) { - AssetXferUploader uploader = XferUploaders[transactionID]; - AssetBase asset = uploader.GetAssetData(); - - lock (XferUploaders) + if (XferUploaders.ContainsKey(transactionID)) { - XferUploaders.Remove(transactionID); - } + AssetXferUploader uploader = XferUploaders[transactionID]; + AssetBase asset = uploader.GetAssetData(); + RemoveXferUploader(transactionID); - return asset; + return asset; + } } return null; @@ -135,7 +199,15 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction SceneObjectPart part, UUID transactionID, TaskInventoryItem item) { - if (XferUploaders.ContainsKey(transactionID)) + AssetXferUploader uploader = null; + + lock (XferUploaders) + { + if (XferUploaders.ContainsKey(transactionID)) + uploader = XferUploaders[transactionID]; + } + + if (uploader != null) { AssetBase asset = GetTransactionAsset(transactionID); @@ -161,28 +233,34 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction m_Scene.AssetService.Store(asset); } } + else + { + m_log.ErrorFormat( + "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}", + transactionID, item.Name, part.Name); + } } public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) { - if (XferUploaders.ContainsKey(transactionID)) + AssetXferUploader uploader = null; + + lock (XferUploaders) { - AssetBase asset = GetTransactionAsset(transactionID); + if (XferUploaders.ContainsKey(transactionID)) + uploader = XferUploaders[transactionID]; + } - if (asset != null) - { - asset.FullID = UUID.Random(); - asset.Name = item.Name; - asset.Description = item.Description; - asset.Type = (sbyte)item.AssetType; - item.AssetID = asset.FullID; - - m_Scene.AssetService.Store(asset); - - IInventoryService invService = m_Scene.InventoryService; - invService.UpdateItem(item); - } + if (uploader != null) + { + uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item); + } + else + { + m_log.ErrorFormat( + "[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}", + transactionID, item.Name, remoteClient.Name); } } } diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs index 82558de8a3..a28d5d7611 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs @@ -172,11 +172,12 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// /// Update an inventory item with data that has been received through a /// transaction. - /// + /// + /// /// This is called when clothing or body parts are updated (for /// instance, with new textures or colours). It may also be called in /// other situations. - /// + /// /// /// /// @@ -184,14 +185,12 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction UUID transactionID, InventoryItemBase item) { // m_log.DebugFormat( -// "[TRANSACTIONS MANAGER] Called HandleItemUpdateFromTransaction with item {0}", +// "[ASSET TRANSACTION MODULE]: Called HandleItemUpdateFromTransaction with item {0}", // item.Name); - AgentAssetTransactions transactions = - GetUserTransactions(remoteClient.AgentId); + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); - transactions.RequestUpdateInventoryItem(remoteClient, - transactionID, item); + transactions.RequestUpdateInventoryItem(remoteClient, transactionID, item); } /// @@ -255,11 +254,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction } } - AgentAssetTransactions transactions = - GetUserTransactions(remoteClient.AgentId); - - AssetXferUploader uploader = - transactions.RequestXferUploader(transaction); + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); + AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID); if (uploader != null) { @@ -279,9 +275,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction public void HandleXfer(IClientAPI remoteClient, ulong xferID, uint packetID, byte[] data) { - //m_log.Debug("xferID: " + xferID + " packetID: " + packetID + " data!"); - AgentAssetTransactions transactions = - GetUserTransactions(remoteClient.AgentId); +// m_log.Debug("xferID: " + xferID + " packetID: " + packetID + " data length " + data.Length); + AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); transactions.HandleXfer(xferID, packetID, data); } diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs index a7929ba75a..ec4dfd0bbb 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs @@ -40,11 +40,21 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we + /// are performing a delayed update. + /// + AgentAssetTransactions m_transactions; + private AssetBase m_asset; private UUID InventFolder = UUID.Zero; private sbyte invType = 0; + private bool m_createItem = false; private uint m_createItemCallback = 0; + private bool m_updateItem = false; + private InventoryItemBase m_updateItemData; + private string m_description = String.Empty; private bool m_dumpAssetToFile; private bool m_finished = false; @@ -58,9 +68,11 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction public ulong XferID; private Scene m_Scene; - public AssetXferUploader(Scene scene, bool dumpAssetToFile) + public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile) { + m_transactions = transactions; m_Scene = scene; + m_asset = new AssetBase() { FullID = assetID }; m_dumpAssetToFile = dumpAssetToFile; } @@ -73,6 +85,10 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// True if the transfer is complete, false otherwise or if the xferID was not valid public bool HandleXferPacket(ulong xferID, uint packetID, byte[] data) { +// m_log.DebugFormat( +// "[ASSET XFER UPLOADER]: Received packet {0} for xfer {1} (data length {2})", +// packetID, xferID, data.Length); + if (XferID == xferID) { if (m_asset.Data.Length > 1) @@ -107,16 +123,20 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// /// /// - /// True if the transfer is complete, false otherwise - public bool Initialise(IClientAPI remoteClient, UUID assetID, + public void Initialise(IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal, bool tempFile) { +// m_log.DebugFormat( +// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}", +// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length); + ourClient = remoteClient; - m_asset = new AssetBase(assetID, "blank", type, - remoteClient.AgentId.ToString()); - m_asset.Data = data; + m_asset.Name = "blank"; m_asset.Description = "empty"; + m_asset.Type = type; + m_asset.CreatorID = remoteClient.AgentId.ToString(); + m_asset.Data = data; m_asset.Local = storeLocal; m_asset.Temporary = tempFile; @@ -126,21 +146,22 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction if (m_asset.Data.Length > 2) { SendCompleteMessage(); - return true; } else { RequestStartXfer(); } - - return false; } protected void RequestStartXfer() { XferID = Util.GetNextXferID(); - ourClient.SendXferRequest(XferID, m_asset.Type, m_asset.FullID, - 0, new byte[0]); + +// m_log.DebugFormat( +// "[ASSET XFER UPLOADER]: Requesting Xfer of asset {0}, type {1}, transfer id {2} from {3}", +// m_asset.FullID, m_asset.Type, XferID, ourClient.Name); + + ourClient.SendXferRequest(XferID, m_asset.Type, m_asset.FullID, 0, new byte[0]); } protected void SendCompleteMessage() @@ -148,18 +169,32 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID); - m_finished = true; - if (m_createItem) + // We must lock in order to avoid a race with a separate thread dealing with an inventory item or create + // message from other client UDP. + lock (this) { - DoCreateItem(m_createItemCallback); - } - else if (m_storeLocal) - { - m_Scene.AssetService.Store(m_asset); + m_finished = true; + if (m_createItem) + { + DoCreateItem(m_createItemCallback); + } + else if (m_updateItem) + { + StoreAssetForItemUpdate(m_updateItemData); + + // Remove ourselves from the list of transactions if completion was delayed until the transaction + // was complete. + // TODO: Should probably do the same for create item. + m_transactions.RemoveXferUploader(TransactionID); + } + else if (m_storeLocal) + { + m_Scene.AssetService.Store(m_asset); + } } m_log.DebugFormat( - "[ASSET TRANSACTIONS]: Uploaded asset {0} for transaction {1}", + "[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}", m_asset.FullID, TransactionID); if (m_dumpAssetToFile) @@ -205,18 +240,66 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction m_asset.Description = description; m_asset.Type = type; + // We must lock to avoid a race with a separate thread uploading the asset. + lock (this) + { + if (m_finished) + { + DoCreateItem(callbackID); + } + else + { + m_createItem = true; //set flag so the inventory item is created when upload is complete + m_createItemCallback = callbackID; + } + } + } + } + + public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item) + { + // We must lock to avoid a race with a separate thread uploading the asset. + lock (this) + { + m_asset.Name = item.Name; + m_asset.Description = item.Description; + m_asset.Type = (sbyte)item.AssetType; + + // We must always store the item at this point even if the asset hasn't finished uploading, in order + // to avoid a race condition when the appearance module retrieves the item to set the asset id in + // the AvatarAppearance structure. + item.AssetID = m_asset.FullID; + m_Scene.InventoryService.UpdateItem(item); + if (m_finished) { - DoCreateItem(callbackID); + StoreAssetForItemUpdate(item); } else { - m_createItem = true; //set flag so the inventory item is created when upload is complete - m_createItemCallback = callbackID; +// m_log.DebugFormat( +// "[ASSET XFER UPLOADER]: Holding update inventory item request {0} for {1} pending completion of asset xfer for transaction {2}", +// item.Name, remoteClient.Name, transactionID); + + m_updateItem = true; + m_updateItemData = item; } } } + /// + /// Store the asset for the given item. + /// + /// + private void StoreAssetForItemUpdate(InventoryItemBase item) + { +// m_log.DebugFormat( +// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}", +// m_asset.FullID, item.Name, ourClient.Name); + + m_Scene.AssetService.Store(m_asset); + } + private void DoCreateItem(uint callbackID) { m_Scene.AssetService.Store(m_asset); diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index bb63bcd188..0cadd83e62 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -211,6 +211,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Process the visual params, this may change height as well if (visualParams != null) { +// string[] visualParamsStrings = new string[visualParams.Length]; +// for (int i = 0; i < visualParams.Length; i++) +// visualParamsStrings[i] = visualParams[i].ToString(); +// m_log.DebugFormat( +// "[AVFACTORY]: Setting visual params for {0} to {1}", +// client.Name, string.Join(", ", visualParamsStrings)); + float oldHeight = sp.Appearance.AvatarHeight; changed = sp.Appearance.SetVisualParams(visualParams); @@ -418,6 +425,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",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 + // assets and item asset id changes to complete. + // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids + // multiple save requests. + SetAppearanceAssets(sp.UUID, sp.Appearance); + m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); } @@ -504,9 +518,6 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory avatAppearance.GetAssetsFrom(sp.Appearance); - // This could take awhile since it needs to pull inventory - SetAppearanceAssets(sp.UUID, ref avatAppearance); - lock (m_setAppearanceLock) { // Update only those fields that we have changed. This is important because the viewer @@ -540,7 +551,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return true; } - private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) + private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) { IInventoryService invService = m_scene.InventoryService; diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index f9dba2d24c..663aa22efb 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -334,6 +334,10 @@ namespace OpenSim.Region.Framework.Scenes public void UpdateInventoryItemAsset(IClientAPI remoteClient, UUID transactionID, UUID itemID, InventoryItemBase itemUpd) { +// m_log.DebugFormat( +// "[USER INVENTORY]: Updating asset for item {0} {1}, transaction ID {2} for {3}", +// itemID, itemUpd.Name, transactionID, remoteClient.Name); + // This one will let people set next perms on items in agent // inventory. Rut-Roh. Whatever. Make this secure. Yeah. // @@ -385,8 +389,7 @@ namespace OpenSim.Region.Framework.Scenes IAgentAssetTransactions agentTransactions = this.RequestModuleInterface(); if (agentTransactions != null) { - agentTransactions.HandleItemUpdateFromTransaction( - remoteClient, transactionID, item); + agentTransactions.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); } } } diff --git a/OpenSim/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs index eeab67a666..1648b51bd8 100644 --- a/OpenSim/Services/InventoryService/XInventoryService.cs +++ b/OpenSim/Services/InventoryService/XInventoryService.cs @@ -40,9 +40,9 @@ namespace OpenSim.Services.InventoryService { public class XInventoryService : ServiceBase, IInventoryService { - //private static readonly ILog m_log = - // LogManager.GetLogger( - // MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = +// LogManager.GetLogger( +// MethodBase.GetCurrentMethod().DeclaringType); protected IXInventoryData m_Database; protected bool m_AllowDelete = true; @@ -385,18 +385,22 @@ namespace OpenSim.Services.InventoryService public virtual bool AddItem(InventoryItemBase item) { - //m_log.DebugFormat( - // "[XINVENTORY SERVICE]: Adding item {0} to folder {1} for {2}", item.ID, item.Folder, item.Owner); +// m_log.DebugFormat( +// "[XINVENTORY SERVICE]: Adding item {0} to folder {1} for {2}", item.ID, item.Folder, item.Owner); return m_Database.StoreItem(ConvertFromOpenSim(item)); } public virtual bool UpdateItem(InventoryItemBase item) { +// throw new Exception("urrgh"); if (!m_AllowDelete) if (item.AssetType == (sbyte)AssetType.Link || item.AssetType == (sbyte)AssetType.LinkFolder) return false; +// m_log.InfoFormat( +// "[XINVENTORY SERVICE]: Updating item {0} {1} in folder {2}", item.Name, item.ID, item.Folder); + return m_Database.StoreItem(ConvertFromOpenSim(item)); } From ceb09cde4ddaff6b7e76ce18656f0c2049bcb8ec Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 Sep 2011 21:57:52 +0100 Subject: [PATCH 36/64] Correct asset id of library default iris texture. For this change to show up you will need to clear viewer cache. --- bin/inventory/TexturesLibrary/TexturesLibraryItems.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/inventory/TexturesLibrary/TexturesLibraryItems.xml b/bin/inventory/TexturesLibrary/TexturesLibraryItems.xml index e1452f60d4..9b5080d809 100644 --- a/bin/inventory/TexturesLibrary/TexturesLibraryItems.xml +++ b/bin/inventory/TexturesLibrary/TexturesLibraryItems.xml @@ -564,7 +564,7 @@
- + From bec0cbe82b0de1b5fa8e214a0cc59d0db1f25959 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 Sep 2011 22:20:15 +0100 Subject: [PATCH 37/64] remove unused SOP.Create() method --- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 72036635d1..632ac8fbf2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1714,20 +1714,6 @@ namespace OpenSim.Region.Framework.Scenes Name, LocalId, id); } - public static SceneObjectPart Create() - { - SceneObjectPart part = new SceneObjectPart(); - part.UUID = UUID.Random(); - - PrimitiveBaseShape shape = PrimitiveBaseShape.Create(); - part.Shape = shape; - - part.Name = "Primitive"; - part._ownerID = UUID.Random(); - - return part; - } - /// /// Do a physics property update for a NINJA joint. /// From def74404f1ea6b2a0f479c602fd67bcfced41426 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 24 Sep 2011 00:18:32 +0100 Subject: [PATCH 38/64] make distribution creating code to copy FlotsamCache.ini.example to FlotsamCache.ini --- .nant/local.include | 1 + 1 file changed, 1 insertion(+) diff --git a/.nant/local.include b/.nant/local.include index b11c1e58c8..e5efb67055 100644 --- a/.nant/local.include +++ b/.nant/local.include @@ -8,6 +8,7 @@ + From 53646070057c9355bba6df9e181253232d97d8e9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 24 Sep 2011 00:22:23 +0100 Subject: [PATCH 39/64] Clarify explanation of the "DeleteScriptsOnStartup" config switch and add this to OpenSim.ini.example since it's very useful if you're not updating OpenSim from source. On reflection, "DeleteScriptsOnStartup" isn't a great name since it suggests real script deletion rather than compiled versions. --- bin/OpenSim.ini.example | 7 +++++++ bin/OpenSimDefaults.ini | 11 ++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 925c343aa1..57a2e06165 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -218,6 +218,13 @@ ;; server to send mail through. ; emailmodule = DefaultEmailModule + ; Controls whether previously compiled scripts are deleted on sim restart. If you disable this + ; then startup will be faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ; by scripts have changed. + ; Default is false + ; DeleteScriptsOnStartup = true + [SMTP] ;; The SMTP server enabled the email module to send email to external diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index ca4fbfb5b3..f5d7f4ab3c 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1182,11 +1182,12 @@ ;; Path to script assemblies ; ScriptEnginesPath = "ScriptEngines" - ; Whether to delete previously compiled scripts when the sim starts. If you disable this - ; then startup will be faster. However, then it becomes your responsibility to delete the - ; compiled scripts if OpenSim has changed enough that previously compiled scripts are no - ; longer compatible. - DeleteScriptsOnStartup = true + ; Controls whether previously compiled scripts are deleted on sim restart. If you disable this + ; then startup will be faster since scripts won't need to be recompiled. However, then it becomes your responsibility to delete the + ; compiled scripts if you're recompiling OpenSim from source code and internal interfaces used + ; by scripts have changed. + ; Default is false + ; DeleteScriptsOnStartup = true [OpenGridProtocol] From 839c1cdcc4e9ce410636becb5b81190463dec5bf Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 24 Sep 2011 01:10:23 +0100 Subject: [PATCH 40/64] Improve locking when access queue in EventQueueGetModule --- .../Caps/EventQueue/EventQueueGetModule.cs | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 139d8b8902..8d0c7a153a 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -179,9 +179,10 @@ namespace OpenSim.Region.ClientStack.Linden { Queue queue = GetQueue(avatarID); if (queue != null) - queue.Enqueue(ev); + lock (queue) + queue.Enqueue(ev); } - catch(NullReferenceException e) + catch (NullReferenceException e) { m_log.Error("[EVENTQUEUE] Caught exception: " + e); return false; @@ -338,12 +339,8 @@ namespace OpenSim.Region.ClientStack.Linden Queue queue = GetQueue(agentID); if (queue != null) lock (queue) - { - if (queue.Count > 0) - return true; - else - return false; - } + return queue.Count > 0; + return false; } @@ -358,8 +355,6 @@ namespace OpenSim.Region.ClientStack.Linden element = queue.Dequeue(); // 15s timeout } - - int thisID = 0; lock (m_ids) thisID = m_ids[pAgentId]; @@ -431,7 +426,10 @@ namespace OpenSim.Region.ClientStack.Linden // } Queue queue = TryGetQueue(agentID); - OSD element = queue.Dequeue(); // 15s timeout + OSD element; + + lock (queue) + element = queue.Dequeue(); // 15s timeout Hashtable responsedata = new Hashtable(); @@ -470,10 +468,14 @@ namespace OpenSim.Region.ClientStack.Linden else { array.Add(element); - while (queue.Count > 0) + + lock (queue) { - array.Add(queue.Dequeue()); - thisID++; + while (queue.Count > 0) + { + array.Add(queue.Dequeue()); + thisID++; + } } } @@ -520,6 +522,7 @@ namespace OpenSim.Region.ClientStack.Linden AvatarID = m_QueueUUIDAvatarMapping[capUUID]; } } + if (AvatarID != UUID.Zero) { return ProcessQueue(request, AvatarID, m_scene.CapsModule.GetCapsForUser(AvatarID)); From c14c4bc1ec5f381aa754068caf460c95e4539b17 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 24 Sep 2011 01:39:37 +0100 Subject: [PATCH 41/64] Don't try and resolve user account for authorization if the agent has come in via hypergrid. If a user account isn't available, this just passes on the name given by the agent instead. I'm not sure this is particularly useful since I believe that agent names could be faked in this context - it might be no more useful than a viewer agent string. In fact, there might even be an argument that passing on this name provides a false expectation of authenticity. However, I will apply for now. Patch applied from http://opensimulator.org/mantis/view.php?id=5696 Thanks Michelle Argus. --- .../RemoteAuthorizationServiceConnector.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs index 003324fb14..86c0099c68 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/RemoteAuthorizationServiceConnector.cs @@ -141,11 +141,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization if (scene != null) { + string mail = String.Empty; + UserAccount account = scene.UserAccountService.GetUserAccount(UUID.Zero, new UUID(userID)); + //if account not found, we assume its a foreign visitor from HG, else use account data... + if (account != null) + { + mail = account.Email; + firstName = account.FirstName; + lastName = account.LastName; + } + isAuthorized = IsAuthorizedForRegion( - userID, firstName, lastName, account.Email, scene.RegionInfo.RegionName, regionID, out message); + userID, firstName, lastName, mail, scene.RegionInfo.RegionName, regionID, out message); } else { From 39d7945efc8daa6e5cd0f4728b499e7a624526cd Mon Sep 17 00:00:00 2001 From: Kevin Houlihan & Michelle Argus Date: Wed, 21 Sep 2011 22:46:14 +0100 Subject: [PATCH 42/64] Added a setting to [Startup] section of config that will allow the simulator to start up with no regions configured. I added the boolean config setting "allow_regionless", defaulting to false. If set to true, opensim will start up ok if no region configurations are found in the specified region_info_source. It will not ask the user to create a region. --- .../Filesystem/RegionLoaderFileSystem.cs | 4 +- .../RegionLoader/Web/RegionLoaderWebServer.cs | 80 +++++++++++++------ .../LoadImageURL/LoadImageURLModule.cs | 9 ++- .../Tools/Configger/ConfigurationLoader.cs | 1 + bin/OpenSim.ini.example | 5 ++ bin/OpenSimDefaults.ini | 4 + 6 files changed, 73 insertions(+), 30 deletions(-) diff --git a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs b/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs index 0aae4ff353..8332c14478 100644 --- a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs +++ b/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs @@ -48,11 +48,13 @@ namespace OpenSim.Framework.RegionLoader.Filesystem public RegionInfo[] LoadRegions() { string regionConfigPath = Path.Combine(Util.configDir(), "Regions"); + bool allowRegionless = false; try { IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"]; regionConfigPath = startupConfig.GetString("regionload_regionsdir", regionConfigPath).Trim(); + allowRegionless = startupConfig.GetBoolean("allow_regionless", false); } catch (Exception) { @@ -68,7 +70,7 @@ namespace OpenSim.Framework.RegionLoader.Filesystem string[] iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); // Create an empty Regions.ini if there are no existing config files. - if (configFiles.Length == 0 && iniFiles.Length == 0) + if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0) { new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource); iniFiles = Directory.GetFiles(regionConfigPath, "*.ini"); diff --git a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs index de4898a0d7..a2f5d9c5ba 100644 --- a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs +++ b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs @@ -57,6 +57,8 @@ namespace OpenSim.Framework.RegionLoader.Web { IConfig startupConfig = (IConfig) m_configSource.Configs["Startup"]; string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim(); + bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false); + if (url == String.Empty) { m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty."); @@ -64,37 +66,63 @@ namespace OpenSim.Framework.RegionLoader.Web } else { + RegionInfo[] regionInfos = new RegionInfo[] {}; + int regionCount = 0; HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url); webRequest.Timeout = 30000; //30 Second Timeout m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url); - HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse(); - m_log.Debug("[WEBLOADER]: Downloading region information..."); - StreamReader reader = new StreamReader(webResponse.GetResponseStream()); - string xmlSource = String.Empty; - string tempStr = reader.ReadLine(); - while (tempStr != null) - { - xmlSource = xmlSource + tempStr; - tempStr = reader.ReadLine(); - } - m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + - xmlSource.Length); - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(xmlSource); - if (xmlDoc.FirstChild.Name == "Regions") - { - RegionInfo[] regionInfos = new RegionInfo[xmlDoc.FirstChild.ChildNodes.Count]; - int i; - for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) - { - m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); - regionInfos[i] = - new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource); - } - return regionInfos; + try + { + HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse(); + m_log.Debug("[WEBLOADER]: Downloading region information..."); + StreamReader reader = new StreamReader(webResponse.GetResponseStream()); + string xmlSource = String.Empty; + string tempStr = reader.ReadLine(); + while (tempStr != null) + { + xmlSource = xmlSource + tempStr; + tempStr = reader.ReadLine(); + } + m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + + xmlSource.Length); + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlSource); + if (xmlDoc.FirstChild.Name == "Regions") + { + regionCount = xmlDoc.FirstChild.ChildNodes.Count; + + if (regionCount > 0) + { + regionInfos = new RegionInfo[regionCount]; + int i; + for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) + { + m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); + regionInfos[i] = + new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource); + } + } + } + } + catch (WebException ex) + { + if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound) + { + if (!allowRegionless) + throw ex; + } + else + throw ex; + } + + if (regionCount > 0 | allowRegionless) + return regionInfos; + else + { + m_log.Error("[WEBLOADER]: No region configs were available."); + return null; } - return null; } } } diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs index ed3e516631..6f839485ec 100644 --- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs @@ -112,10 +112,13 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL public void PostInitialise() { - m_textureManager = m_scene.RequestModuleInterface(); - if (m_textureManager != null) + if (m_scene != null) { - m_textureManager.RegisterRender(GetContentType(), this); + m_textureManager = m_scene.RequestModuleInterface(); + if (m_textureManager != null) + { + m_textureManager.RegisterRender(GetContentType(), this); + } } } diff --git a/OpenSim/Tools/Configger/ConfigurationLoader.cs b/OpenSim/Tools/Configger/ConfigurationLoader.cs index 39146527b8..28bcc99ff4 100644 --- a/OpenSim/Tools/Configger/ConfigurationLoader.cs +++ b/OpenSim/Tools/Configger/ConfigurationLoader.cs @@ -233,6 +233,7 @@ namespace OpenSim.Tools.Configger config = defaultConfig.AddConfig("Startup"); config.Set("region_info_source", "filesystem"); + config.Set("allow_regionless", false); config.Set("gridmode", false); config.Set("physics", "OpenDynamicsEngine"); diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 57a2e06165..ce86d5637d 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -71,6 +71,11 @@ ;; in a tag. ; regionload_webserver_url = "http://example.com/regions.xml"; + ;# {allow_regionless} {} {Allow simulator to start up with no regions configured.} {true false} false + ;; Allow the simulator to start up if there are no region configuration available + ;; from the selected region_info_source. + ; allow_regionless = false + ;# {NonPhysicalPrimMax} {} {Maximum size of nonphysical prims?} {} 256 ;; Maximum size for non-physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonphysicalPrimMax!). ; NonPhysicalPrimMax = 256 diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index f5d7f4ab3c..a456f4d30e 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -70,6 +70,10 @@ ; except that everything is also enclosed in a tag. ; regionload_webserver_url = "http://example.com/regions.xml"; + ;; Allow the simulator to start up if there are no region configuration available + ;; from the selected region_info_source. + allow_regionless = false + ; Maximum size of non physical prims. Affects resizing of existing prims. This can be overriden in the region config file (as NonphysicalPrimMax!). NonPhysicalPrimMax = 256 From e789ab659c8a35a32f4edfc8f79f367b9a993721 Mon Sep 17 00:00:00 2001 From: Kevin Houlihan Date: Thu, 22 Sep 2011 18:11:55 +0100 Subject: [PATCH 43/64] Removed uncalled region load method. The method LoadRegionsPlugin.LoadRegionFromConfig was no longer being referenced from anywhere, so I removed it. It's function has apparently been taken on by the PostInitialise of that module. --- .../LoadRegions/LoadRegionsPlugin.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index e26c1d23b4..6e28eba1f4 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs @@ -186,35 +186,5 @@ namespace OpenSim.ApplicationPlugins.LoadRegions return true; } - - public void LoadRegionFromConfig(OpenSimBase openSim, ulong regionhandle) - { - m_log.Info("[LOADREGIONS]: Load Regions addin being initialised"); - - IRegionLoader regionLoader; - if (openSim.ConfigSource.Source.Configs["Startup"].GetString("region_info_source", "filesystem") == "filesystem") - { - m_log.Info("[LOADREGIONS]: Loading Region Info from filesystem"); - regionLoader = new RegionLoaderFileSystem(); - } - else - { - m_log.Info("[LOADREGIONS]: Loading Region Info from web"); - regionLoader = new RegionLoaderWebServer(); - } - - regionLoader.SetIniConfigSource(openSim.ConfigSource.Source); - RegionInfo[] regionsToLoad = regionLoader.LoadRegions(); - for (int i = 0; i < regionsToLoad.Length; i++) - { - if (regionhandle == regionsToLoad[i].RegionHandle) - { - IScene scene; - m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + - Thread.CurrentThread.ManagedThreadId.ToString() + ")"); - openSim.CreateRegion(regionsToLoad[i], true, out scene); - } - } - } } } From 8caf3ed49ec3403843e25db018cc9db63e2ca643 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 24 Sep 2011 02:22:47 +0100 Subject: [PATCH 44/64] Remove the unimplented "clear assets" command. This was a bizarre relic of a bygone age that had no implementations. If you're using and want to clear the flotsam asset cache then please use the existing "fcache clear" command --- OpenSim/Region/Application/OpenSim.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index e5b9dcb4b3..09958b1181 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -210,10 +210,6 @@ namespace OpenSim ///
private void RegisterConsoleCommands() { - m_console.Commands.AddCommand("region", false, "clear assets", - "clear assets", - "Clear the asset cache", HandleClearAssets); - m_console.Commands.AddCommand("region", false, "force update", "force update", "Force the update of all objects on clients", @@ -509,11 +505,6 @@ namespace OpenSim } } - private void HandleClearAssets(string module, string[] args) - { - MainConsole.Instance.Output("Not implemented."); - } - /// /// Force resending of all updates to all clients in active region(s) /// From 2b2580e3a12d5c493f9a77bf9435ca32a0a0355c Mon Sep 17 00:00:00 2001 From: Snoopy Pfeffer Date: Sun, 25 Sep 2011 00:51:43 +0200 Subject: [PATCH 45/64] Fix for rezzing and derezzing HUDs (see Mantis #5406). From now on updates are only sent to affected clients. --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 6 +++++- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 980b01fda0..234eb7d2ea 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1174,7 +1174,11 @@ namespace OpenSim.Region.Framework.Scenes { part.UpdateFlag = 0; if (part == m_rootPart) - avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); + { + if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || + (AttachmentPoint < 31) || (AttachmentPoint > 38)) + avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); + } } }); } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 632ac8fbf2..d631c12bfc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2999,6 +2999,10 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.IsDeleted) return; + if (ParentGroup.IsAttachment && (ParentGroup.AttachedAvatar != remoteClient.AgentId) && + (ParentGroup.AttachmentPoint >= 31) && (ParentGroup.AttachmentPoint <= 38)) + return; + clientFlags &= ~(uint) PrimFlags.CreateSelected; if (remoteClient.AgentId == _ownerID) @@ -4786,7 +4790,8 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.IsDeleted) return; - if (ParentGroup.IsAttachment && ParentGroup.RootPart != this) + if (ParentGroup.IsAttachment && ((ParentGroup.RootPart != this) || + ((ParentGroup.AttachedAvatar != remoteClient.AgentId) && (ParentGroup.AttachmentPoint >= 31) && (ParentGroup.AttachmentPoint <= 38)))) return; // Causes this thread to dig into the Client Thread Data. From a3531dec1aaafdcd22a70764cc512dd5666c75fc Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 26 Sep 2011 23:00:16 +0100 Subject: [PATCH 46/64] Add en_US culture setting to the async delete to inventory thread, to avoid any issues with float serialization with machines set to non en_US locales. Doing this to see if addresses inventory object deserialization problems in http://opensimulator.org/mantis/view.php?id=5708, though if it does I'm really surprised not to have seen it before now. Really need to go through and systematically set the culture for every timer and change all BeginInvoke calls to FireAndForget instead. But don't want to do something like that this close to a release. --- .../Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 342354257d..0ac3899dd4 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -112,6 +112,11 @@ namespace OpenSim.Region.Framework.Scenes private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e) { m_log.Debug("[ASYNC DELETER]: Starting send to inventory loop"); + + // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved + // in a culture where decimal points are commas and then reloaded in a culture which just treats them as + // number seperators. + Culture.SetCurrentCulture(); while (InventoryDeQueueAndDelete()) { From 528fcede6c31c056c3863fd19528558fcbaf475f Mon Sep 17 00:00:00 2001 From: Pixel Tomsen Date: Mon, 26 Sep 2011 20:18:06 +0200 Subject: [PATCH 47/64] llAvatarOnLinkSitTarget Implementation http://wiki.secondlife.com/wiki/LlAvatarOnLinkSitTarget --- .../Shared/Api/Implementation/LSL_Api.cs | 14 ++++++++++++++ .../ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | 1 + .../ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 070cdc04b9..39da563a55 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6296,6 +6296,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_host.GetAvatarOnSitTarget().ToString(); } + // http://wiki.secondlife.com/wiki/LlAvatarOnLinkSitTarget + public LSL_String llAvatarOnLinkSitTarget(int linknum) + { + m_host.AddScriptLPS(1); + if(linknum == ScriptBaseClass.LINK_SET || + linknum == ScriptBaseClass.LINK_ALL_CHILDREN || + linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString(); + + List parts = GetLinkParts(linknum); + if (parts.Count == 0) return UUID.Zero.ToString(); + return parts[0].SitTargetAvatar.ToString(); + } + + public void llAddToLandPassList(string avatar, double hours) { 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 4d7d60d6f6..62e2854998 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -54,6 +54,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Float llAtan2(double x, double y); void llAttachToAvatar(int attachment); LSL_Key llAvatarOnSitTarget(); + LSL_Key llAvatarOnLinkSitTarget(int linknum); LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up); LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle); LSL_Integer llBase64ToInteger(string str); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 96e46fdb60..508f33b13f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -129,6 +129,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llAvatarOnSitTarget(); } + public LSL_Key llAvatarOnLinkSitTarget(int linknum) + { + return m_LSL_Functions.llAvatarOnLinkSitTarget(linknum); + } + public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up) { return m_LSL_Functions.llAxes2Rot(fwd, left, up); From e742cffe15d3e50841908d7babc2e4c4a7630635 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 30 Sep 2011 01:19:22 +0100 Subject: [PATCH 48/64] Add Enabled switch in new [Attachments] section in OpenSimDefaults.ini to allow attachments to be temporarily turned off. This is for debugging purposes. Defaults to Attachments Enabled --- CONTRIBUTORS.txt | 4 +- .../Servers/HttpServer/BaseHttpServer.cs | 2 +- .../Avatar/Attachments/AttachmentsModule.cs | 56 ++++++++++++++++++- .../InventoryAccess/InventoryAccessModule.cs | 1 - bin/OpenSimDefaults.ini | 8 +++ 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 239b884363..2620a20075 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -5,7 +5,7 @@ for your effort!) These folks represent the current core team for OpenSim, and are the people that make the day to day of OpenSim happen. -* justincc +* justincc (OSVW Consulting, justincc.org) * chi11ken (Genkii) * dahlia * Melanie Thielker @@ -15,6 +15,7 @@ people that make the day to day of OpenSim happen. * Mic Bowman (Intel) * BlueWall (James Hughes) * Snoopy Pfeffer +* Richard Adams (Intel) = Core Developers Following the White Rabbit = Core developers who have temporarily (we hope) gone chasing the white rabbit. @@ -119,6 +120,7 @@ what it is today. * openlifegrid.com * Oren Hurvitz (Kitely) * otakup0pe +* Pixel Tomsen * ralphos * RemedyTomm * Revolution diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index af9b62f138..fefa242a18 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -442,7 +442,7 @@ namespace OpenSim.Framework.Servers.HttpServer string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); - //m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); +// m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); if (TryGetStreamHandler(handlerKey, out requestHandler)) { diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index b965d75443..8757251379 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -48,25 +48,42 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private Scene m_scene; private IDialogModule m_dialogModule; + + /// + /// Are attachments enabled? + /// + public bool Enabled { get; private set; } public string Name { get { return "Attachments Module"; } } public Type ReplaceableInterface { get { return null; } } - public void Initialise(IConfigSource source) {} + public void Initialise(IConfigSource source) + { + IConfig config = source.Configs["Attachments"]; + if (config != null) + Enabled = config.GetBoolean("Enabled", true); + else + Enabled = true; + } public void AddRegion(Scene scene) { m_scene = scene; m_dialogModule = m_scene.RequestModuleInterface(); m_scene.RegisterModuleInterface(this); - m_scene.EventManager.OnNewClient += SubscribeToClientEvents; + + if (Enabled) + m_scene.EventManager.OnNewClient += SubscribeToClientEvents; + // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI } public void RemoveRegion(Scene scene) { m_scene.UnregisterModuleInterface(this); - m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; + + if (Enabled) + m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; } public void RegionLoaded(Scene scene) {} @@ -102,6 +119,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// public void RezAttachments(IScenePresence sp) { + if (!Enabled) + return; + if (null == sp.Appearance) { m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID); @@ -145,6 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); + if (!Enabled) + return; + foreach (SceneObjectGroup grp in sp.GetAttachments()) { // if (grp.HasGroupChanged) // Resizer scripts? @@ -163,6 +186,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", // m_scene.RegionInfo.RegionName, sp.Name, silent); + if (!Enabled) + return; + foreach (SceneObjectGroup sop in sp.GetAttachments()) { sop.Scene.DeleteSceneObject(sop, silent); @@ -184,6 +210,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", // objectLocalID, remoteClient.Name, AttachmentPt, silent); + if (!Enabled) + return; + try { ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); @@ -232,6 +261,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) { + if (!Enabled) + return false; + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); if (sp == null) @@ -331,6 +363,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) { + if (!Enabled) + return; + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); if (sp == null) @@ -354,6 +389,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { + if (!Enabled) + return null; + // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); @@ -373,6 +411,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt) { + if (!Enabled) + return null; + // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", // (AttachmentPoint)AttachmentPt, itemID, sp.Name); @@ -535,6 +576,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) { + if (!Enabled) + return; + ScenePresence presence; if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) { @@ -554,6 +598,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient) { + if (!Enabled) + return; + // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", // remoteClient.Name, soLocalId); @@ -669,6 +716,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos) { + if (!Enabled) + return; + // First we save the // attachment point information, then we update the relative // positioning. Then we have to mark the object as NOT an diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 03238d94c2..54b422b37a 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -150,7 +150,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { if (!m_Enabled) return; - } #endregion diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index a456f4d30e..245f087812 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -515,6 +515,7 @@ ; so it is disabled by default. Cap_WebFetchInventoryDescendents = "" + [Chat] ; Controls whether the chat module is enabled. Default is true. enabled = true; @@ -528,6 +529,7 @@ ; Distance in meters that shouts should travel. Default is 100m shout_distance = 100 + [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 @@ -554,6 +556,12 @@ CoalesceMultipleObjectsToInventory = true +[Attachments] + ; Controls whether avatar attachments are enabled. + ; Defaults to true - only set to false for debugging purposes + Enabled = true + + [Mesh] ; enable / disable Collada mesh support ; default is true From 6d0978594d1eca9ae56584afe38215f4262256e7 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 30 Sep 2011 18:58:26 +0100 Subject: [PATCH 49/64] remove unused postgresql dll --- bin/Npgsql.dll | Bin 267264 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 bin/Npgsql.dll diff --git a/bin/Npgsql.dll b/bin/Npgsql.dll deleted file mode 100755 index 33fe6d3cc18c30064aa17545730d54ef1e4df5e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267264 zcmdqK378yJwFh2P)l=PFJ(Hv}lkQoP%p@?OXdsLz&@+K#!V)2DDu|OHWMK_UDs(3( zX?h$%Kp=^LA{v8A-1WKPz96{b`b2P-QCz@%dF~H2{C~f5ZY|x@6L|0M`@aA8@2{)s z-gD1A_uO;OJ$J2Jr>(u!axBYA;d=5(%lasu{Ef+d|F=m5&l>pnEbD{WuPyp$+o@k$ zbk-%Cs)Ji9!NrvgR}7xNVe{r->)^%<2P@k)4{q8#c)}TH4qg#laN*LJt%bFwq_-VWn zW?4OhmURZ*p!-RUU_#7eeah-+gghDCKhycPZ}9{5F=Uwf$&LHAPzp+7e zt~F2kPKTTMY5iMwd{8;z^2<-#uxYb(MfLoka^ZzbFSz`2E2O0Pwyk#SqkXnjo^4xg zhEVx?ZPw&U%lgB?DQmJd@qa6HxjoQbN8+CCL(*PpZKL0I>QDf$WG%F7;^-gFTIYZR zM9DjaV{&j-;NDV&SiS8A-45DGQDQ6~28!*uK6KYB<7U}@Ito?H6~BD)$tR}(wOk(x z;yqHbR?gSrIs(8&xX#2y1pfMm=UJQa1jG4|vh8OPF;_kw@O0q8-7(kp!Jg;%D1UF{ z07gjrop9qZ3lBx>oa^|r;p<9G^-EmT4KJ4-{YVo_-KBi0WJP>YkJsYb$T+z8>mQzP z?ZOj+n#R{N0dL7y7XljjnmSEz4IdAH58Ka!slsxfxN{vR<m#nW#0XnZmdEmK z6lVk96CiT~)4;{wsO@)yl3l2y*pSIlyBN$vS=fF7;1cqcvVb5zyC6YA-S&$Jf20(a z6%kn1c!jjRV#(sQ*wBOsts`uw;OyGOLU8H-iCtsDBcenQJ(9e@+puF=i7UBfwR3{R+EzBL&q=mj+==)--@CePgo_S$kzy5I&VaL5lXW#uX* zJ1TrY09&fKfsZgTtplkN@?s=~V3WV|oYbt;toC*vdh11;x0kwxGuBe@hYaT1C27w| zxrHXY={cleR!dEB?ZHV9U_C^R`>IF)fnCGx)-wR+&-Rfw*Y4X1J#MR`9;6ac?13>! zwvJpudZ!}YJ>nBJX zc8NSw6FhsUM!FD&&@XhgmzN>3pS<)dM{X?OJ~M&`BWymA-yiUVessaJn)Ngw+M``R6aG(u@SfK3)a(<1}K}( zY{;k9Wi|}{V9Vfv<8BWSJF^4%joE?O7p(6@O5>dwpl-;nOK%wb-GAQu>2bFgI31aR z!p6*icftCOOm@5@!P0wYU-Or7w{JfzmA-J}v&Y^3r)H^Z)$rTL-TC`vsqKzc{~C7} z?3bnQzGiaMxVvyaEWP({C)_gb4rHI2r}v-pz!@Zn#o z3PY#5p;H~9PDMPOJLm9ktHR90)0y2T*hq?{@)S(H^zpmDYh(srCFRc>10lT&y)~KRn%hYH24Dq!PDeYQx}hBTt~hu(rcWL!st3DAb0*m;Uw2 z8#PzLPmby|uUVZo3@+Yq*A+;}DAOD$)0{?S+A!ErevGw+;s!58s8Y5;l{O5X@T*U~ zIaKaeyu9P()v0BDj{|{)ykB1ae$Czi z;L*O!B$x}&{*TY8_BAt;PhFH*4+C_<;)78Yv`L!}ed&wzC3{hNJ?zh&PnM2X=?gO+ z6{e6-n9N1_)Owhow;k}RcYzyY5@$nW@{z`*FUqcG`#JK)SE4ddIl<06XiP5Dn2?>% zt~uvIllNS@B|o=+wc{090{iEu{^#E(T8`HIeB<1gU9So{6F+B6ygdlpvX<;T`uL&y zOd;%_pYG$^-W0X2t=YLdpE(`0sH8LTbM3^Le+!%Ymi!#~$I*L1gB5rG{Cwh}@06kr zNNav>d-#T5gBCTli67H(dIdXZL#L$2&oUh-1IUDc9s|gRfL;SYN9U{(``@nh6LjX# z<;xG0FKxfnmcHKR@qw{R&t0=Amo6TIA%~Sl=P%cu9$z@F-B@&1(Ra4ojFU-?-=@9O z_7%Tnm$ZFw5+Qrg&+902bn9jcCOkd9;`h?$^U#~z+vCFGzU5dCoV_1$f%7_UwgGVPg#WvTXF@r9Y4S-hw`WXmv=Z!IN0^NGAWcw2!o73@PhwWnk29db_0Fq1x?}cyl6e7Q~%}Qko znO&O#jPtym7;Lt6#=vYLI2_<5>EQi{k*#7j1QQQ$gF79(19$%wuH|;6r$|b1GGWLr z4dEzn3i-0AmB8d|$P@;F7Q5pCLcM%@71Jah!dT=}xU75{LRk4MIxXvYxVGVX02gKz ztUOr6BZ7YiZW6>OvaNr3jzwPh(>xE12bjFT{164u=O2LVt2+RBZ;Aq2B54}vk&RF- zl86@wLwHz$C!=DFCA`3Cp_Jqb;a!+(0yQhQ|1xaTGE7SmDif|h2sWt)C`K0kynSsP zBXw9S0YeSQV?4(a_vTvuQDAt4wF2&=;VvURlXp?IY8k+xoRClF=C%nEX?I~>1Tz&D z=9EGmv*$K&<6=H7)LSRT!guS>L9(1vnQwg_ac41ZjWFAvgn(I~?ntv18tDr=eQR=Q zsmzg1rbQ=Xo!hS>x(P*eMG@VEBDzzJ>gMi8-Q0w_iL66?y8`)QS-u)qQr|-OTLBOC z?Rm+}7sn<0D%(zry24))MG!_QbuDSV8^M@T=bR8}@HZ{4$aY>CWtJ@CzBPzIePj0d zGgD$}TNaEjJVz%{o{NIQ`~)8bePAAo7J=z)R*19koZG~RISbFlB*6LW3Q)eT;k0#_ zP!4H3Ju9I6R;o|94$T_sYASS}2{-B9WBY%GYG88pED5bYpO5zX*?i1O)n6db_B!S) z1RwKML@eP+Og<%OF(@Q(7#(w2j?iH`z#}Pvi36~%;f2-}m~5L3J?)$LJ8Yd24=_*X z!R{Ln(+NR6m<1v2U7LE=qB+1kFo})464Wqd!pTRsFNCIdk8A=Uj8GgyeK5Yl?Zsu( zk|=E1P~=PBUK}gJ2a`_P>D^mBSn*w(#=SC(nB^L-Oc-iYn=zJmWJ5~X0-OOUH43$ijFzd{PC>)~p-|}(IW?jpv{6)wC!(T0VqV(l{W(A_ zS*r);Os;`zaB1P8)Z|)$u^+^?gg(05IkX=`Mp(|Cs4~%1yVRy&Gmr=PY+Yq6rxRcG|P$9F|e?8)6 zoWMuqYJfz#+`JoXfulITdLv=hHzI4kuU&^ub>^V7VA<1!S}zsicE# zaB4DlBAEcv@~T(iww*Cw1jiJL)0$d>+Y-h5I`E23>?j@WW~4AHh;B)~eFcj>EmQdE z;Kd*{ItVICwK@CTRTN|mz~CC(V)(NOuM-Xf zm4Kf__)7?%#I4NEmtk;h9^9J2!`)Dt%Yn4r$!DrBWt7tq*+~b_!9x)*1Y)trl&YJocwD8`hJ0(7S^GjA=~*Edzbv&+kS+T-)8?}B1%mqIA5JQZR1(UQUr zSoh;%8TNr79`ZX4ddZ7D`!6)XpAR_66Q2#)s6BBl*zfN4Plmdd(1&u8?o%qS5zYNZviSyu=o74j(UB83~PW=KtQuPgd)OeSEn4JnfhlJ}J z39e!}&8=TdXR&?}AMHMBA^M=u9L}R>tjnK*2iw0MoK%m&ZE_tbJT0Ciag$<#2dtJ} z2oj}<%H7ECBs1sV0K&nI4N0KQ^+Ca9+sjOX&vt9X@Tuun?gatI--~h#B_U#0*>u-0 zMKrs+eiWAr-gyRgF<@dBwJee6dDb0a*$63Tj0#z@ zYcK(+k!5h3Vjrf{hw{23Ly=*D$3+2vFiG!YYjq2JHdHX>RZw+~9sL-Dt__h81^d#Sx1|61*Hr z(NSIqf|=kZxVIuLJLghkFr>a2kf0B8T#^Z(XWr;{&|poGt<1Iq!Q{|kZI1*{aPJZ6 z%ZF>)CjsG^xR98PW$>`VvOhBx7V0?0dPayZ3gOl7LXuohADH7`N)~SceUAP5tq*}t zS1k8C!zgnd9nEIFFj6iZ>_D`R%)Dib5UJIGm6fWH8JB@7b~gkIkZf0KZpw#r&CoXG z?}A(RU({Iob>7m!D*zqcO;L1$NLofmX_doFDb0flMf(X3fEy-C_C1gSe;8BvXp2OS z8;wjp5@ygYL}C4~-4nn^4>i<3qB%Pt^fv#^)IzP)hXBdc>Gy!{NI(3}z?}61KU(M6 zu87vDVwB?MriO{?2q-s2=ClEI1_sv+436buLid6YnpFTSnJbx3m$ri}bJPZls>C+2 ze|WL=Ww>F9FwRF;&(w}!Eow#ZRpFD?LHtHvzaB$30Skj5C_rjdjGLGeJ2(n(2ewM0 z5~)x{OYC+`tw&n652+&m476)-r`Sma%Dq4dRy0Q~ny92NB^g#+(demJ0OzpFWIIS` zry+wvWSzAUQpU9f*V}Q0WeBJIK8`ytQea)~8a~Q80{Vvj0_H7f@`44ZR3q(xCH&IG zL8gUq(06l~dHg77C{8BGAX4yq=H;!J=IUFa6oMTMIs7kT6N>LVxPrc8DmEacEs`HNQ>j!ZAzf@yVA|Q>*cfRUoE*u>bVNQSQ_4GiDm+GMZg~tD#4yJV z-hh;4pvCFjkp%?nv~945dMp+u-=24icZsc~vv3!@;~cmdx-0I1{>U7A(IjD4eu_c~ zGb*haYn6m{V|o`YkSjgGDKu49SH{j~OkIZUM4PPQVjehD07x~Z!JK1H9a<^=UW@B+ z6u}p9&4HWsItl+Se58vGN1Kf&@y7xCFI=Hs5l)+t!^O5Sgm(?kw$6p0KV$kIi}mdV z$j1niG?n6+;CM9d;LXl9cJQP_7!awrj0shq4TS1)R0^5n|F}uO_QFn!Xo`P3E0gq= ze6Z+Z3V0hIn9I6O_KfzT(EK~02t8xu#ZVcHsX$IC7%%pX`^G*@c57F_J$kipz6Qj^ z=oOX^5McXP0y0Vo*p-t=r2_vUZG}1p>?zx>oE^gIU?=4Uu$o@wQUHTj!Zpg4#{fSK zp(;?=FV@l6aNNVxjmTI7N6=%lDw{#U^;d#~CyP3j9SH!5Y7Pcz1OfS13+z*HeX<@W|gm(5Ok$Hv|VulD=$skwGg zWNq97SSI)b3brV-2kPz}dkNs_jI=hHfXzTb8j)ZKy=#90u%6@Jo_fzDQ!eJ&dW~;11B%G8S@W+U7LszxX11kY4exeV8^0HUQfz z{}VWFg_Km{g|1Bboq%as<+ah|RENnUHO_c?$5;vBk<6SyLS0_}PV}@fjg3zq+CBIVIYc4hLW1()iv;slsE zS8zn9McG_8KwIe**A#<08P63Vg&H1vLypaGRG}nxwYm|2Tw;{aS;nZ@%EqIFj#g@emfcDl`kw>+U=6CCs!{MJs>O$R+l||f zLCCrCJ{H`uNJ}vu{l^lWiJih`x8J+IO|<_@}rNwh1LRu=K8AHz={uz{Ky&_B$jE(@c0GpYiVlD8BAzsnowU?ho(tiU%PgzJ3 zr_EKUu8GMQO%rHGzvlT6O7$e%q(P)vtn8hINuUMQ??cl94|Q@0T1N@M8xdOux~2yd zq$j8~AowR0R3j7xjs;GErA9`X&y?s+VL7W`NchV$5bjX|7&|M`%fa5&Cqufc(0pop z`4rvvy!4S_NU2Ik;eySxSRYxM{PhoSvtEM0esJ^uCq?@{MEZZEXz!Zy|4z|hVN{=f zk#E)~6EIx^O~7;w)Bx2$NA*NOs(eYMRJhTp{V1hLYr0ZuKyQOmW`cxLrl+KZ%Sgus zxjY-y_>rfns2Bux8lyVwxoli zn|_hjurr&L%HCrdiq34@P;_SF_d^DdCavRkTyee@S?_{>0rDkX5YI^%t6X{@A7H%T zc9fOjJ}@k-WeP!=hHE`|tsE0V(L=ZufYFD^Fq_?81e)FAJlp2;Mb(r1a%6R}qfyjsxd9hnMKsNsn<0LUfSf zV~Wr#RbCze2K*gtdi>V|uBw1F&37On?R=y~akY1G7NBlrw?t(p(uA>h(SRKHGaA6s zi( zS6hceu+X7UcJB#gS3v)t!vOSNbr`^QGTq#Dp9NsiOUHe-T;CPCRVWy8Te&{ zOh;=K9%wt@WDTG3t;B!$bHiu0df+Vj3re zcVS^OWHx0(6(dIHU|Jv!Vm9J1yu~yQ?(?o}YM5AuDpj$&QPLP^;AKxXY*n=WSOqPC zm2e%0{ddeuSdcN-yX4n3?8*K@dbEQuQlQg}`9Q>#b<{E&UM|PvF#x=J5Jj?D7l8rh z8aT>YekR`c5Kq}UDq>5P>&Xw+Z#RKs*<&RRz!uxx{sba1ob(P9YUJrZkPob8yqgal zn7tHu#(5p1oc$nrdA2{uTpxqmyRpNiyQB4pmK$G+%Qt|9EXJyrA#Pzg`#F`%AuA8C zB;ckP&&0QuRWb%>x6@hGk}?gjkoOkhi+D0+lxk8s$W`{YS&3n7MGTmLU$DFOuDGtmn ze*lE$b_5?lFKraPXiNg2a=AjYvZw%KpP80mWewr!A=veF+z#YBWL`Wu?)QK}+mu^T zrxD^H1=H?ndFZHzg%{S_`{3pa=Ffm`5tY9qZ2yB`a4ULWQpb;iHh(AqK=_9fUW?%$ zNdOT3(S%pRKb8P+Pl=CoP;c^%tRj1EYU1O-2tGkHn1eR|7RV-e8*jfsD_ENFKZ&5q z6%azWT}t;{?Dg+OK2BNJ=VBD%R=zH3oIa`Tm*XRx~O^?`%v2pZMOboo!jvP#3;pZr|he-|c^tM+HE23u98q$v$uny3X~Y@H0@*Euvw2EwKhu5WE!=0fwE9ZKovhMg zbqyD-3lKJhbO(JDxFbtTPH-@6t`n4Sm%0|;s-K63dk8xXVY=Vy0YDsG`*CD3cAz`> zIz*#5vda&u@JnDJy|jgT!F^JBCwKu#px+YF3s%5GUXRcXOa5z&zYF{0QJ@xjn3#L~ z3?$Gqu@xDRTjfrON*1msu3`}dpGCOmj^+`;cB)gLQHP;VN&m!lgCB(e+kXg77BVQh z)vvISUj#%#K*OzmosbtB$kz#}gLEC0SaAN6kQyOZ8_0u%yo3;dQ$_!CaN2hD2;{v! z35e>56X{6hUa&sNoID6_lMTu?z^b1|^hxH4@is#3UJAG4e-YrVHv_*;e`DB}T82T{ z!g#kZ9{piF4U>4&!mf+sEkpII(;vpuFo`!U>}7F0G>>g{`onk{Ch?|)T_4ATUbNNe z594W=#A^tHUZYC5r6cSbOF8%gB)~YVi>KiUn*yErCQwvoDnEkEb<@uON?%AjOzUwb zobdmm$^XYD|KFPYSif(G|F5R--!%ENP58~}J0^U>_P>Rwb`82{cK3->R`p5+ydUAC z1K}3e6~|n#UzFAE0`~ga{=-qc;AEi&yZr&cf(MLT8*#W2UBbFRG9K%-Z2T>4HzIHA z;Rcg6wBWMA#PL4{k|nER!Vf~YPM!>MKFNf#3_a^)Fvwp5HAyO&aJ+Mk)u(bYsIm$5 zj5T+vPtXW~R@d+%>oK9qT9?p`Xy>phQz0lKFWTi5k~fAV3;rC0RKE=BII4n**QdCL zfvf^x24{-hmyA6zh1hm*HR#n@URr8)jixA=4`>LWB?=Z2;G?(b%C=t(3oro*=+_8^ z{E(+_!0CSl+y&2y@;qDSA`h1OK=m*Zy^n<>l)Qr~rDMU>^Aj(1^R}dl&0<R#Qv>Oqm*$9qA z4zLApG9eog#Xv$fBCG{1Wpgp0Dq|z838Hn2ticTSmC*oK4vHA??<2oAYaKG7&kjSS zDYRt)M&E6^n3=%Ou3ZB%qvycs$X+QE^ZYQTil%%hai#i=EP_+zS_M*1LH6&+=5wPH zFC(W8%hiMQNS|qDuVn z16vgA1pX>oJ|uuJHV-C@PJ}(EVHi_UTe;Vk>L1zP-%)s=#j`fhSF{cxpK6+O$PU)3 zWBd6BgL|_<_y_!EbzE$D8zL0;*;v&tMKU0r8sYAB7i-EYD>s;n zjOotxv@Uwy&z?P#PB$%jMrQ?~lVPpKMI|L7f7}mvnL3RQi(!#UVU7fLGp4g45^&GpViLHpb%S0^4w~&p5G1j#NCd>Me!*w(+HbxkeV82^R{P51mlQ1$5 z2r8zwz9#zTX@zXgOsUVu31%pbCD>mdd{>o;?E!2x_i^PNY`;Z23-gJl(DTp(J_w}8 zz?NlVx|K5`$h|_#t!#=QpEHm<0FnJOZsi?eVD%J`+zyhTC!~kDi|cOn6Ns4#?lbYf zH#5rp2Ic27qkP(+{B35G&lnV^AG{P>^72`t7^aUfHVHH4qRUIgAKXOmQEI83u(5$3 zjVc<0K1JS~^ke_~&D0Qw#*1?$hgjD_-uyi{7ZULY0oG}imjkc*ZFnbdf@^}eg3Rm% z-vLnk#X-(@?m(Qj7}!(Tf%e0W0liJJ`kMUxP5$|X9Va(XTu|K6-9T{wN8mK2I-s+T zajFBkViTExj_I*Fi_LUq4RkkyW;Zi5FlRbaej3u;X^^gIknRKohLkqyOq9jps0-Cc zP!CXyk&)_5kXp25$Z=;lT zZ`0Lut}Z>uhv5+ojDq2m#L^EzfLda(kp2>u#?BRF+cZ0NzDq*dBXgPmf?6lbCbN zVo;f&`c@7Ct{A>{^E${~NUFX1RVL`BmdA+aMu;gXeOajs5t&Zbx*b%XDfyHJ!W}^? z3CaHmv~uZ@3*kwN)yiQ>=anG0Y!N|~JLxQl^KLq6Zqt>wz&Yl?iNn;=m3PPJ?~l>% zjnO|%bQ|b}2ASFZqevZkL;jF8>sjE>*=G1djg9%+0#6fvH2#J^WmWi7R>_}X^#P{+ zzhc!9ozdcTLRL8+d<)8^G>U!k?8iHPj~FVzcMyKMT~xRhgajgNr-t>IFe;cvMA$B+ z*V{mkGC2xaJd$Nrdp%G_4usc7v*Te8J>Tc>iaUEzkFfjbg}VEwxV!!eAlfzFA=gn` zM+*raZ`HK=8`1&~w-J82J>T$03l{MQ)nV8I6DE~P^3_+F4e84JNv|Z%^X!4FK^lw* zfN9Ww6~l3MrI$-m6V`#|(7uG~t~ygrjFGe9f96{Iw>0_6+IoHsNz- zi2phho}VH99uq!yhH$98@Ygj%I18R~?QRv`HN3$37TQ1P3Es!~F*U;-xd(u_1M-cq zCb*R!gf#&@Vz=_k(1$AQR{j+FdgyDPZ>o=5DZ(k$hp!@47BE11Tb0AmIvLCR#+EB`AXW7`J5a z=%O9@2?}0HA64EuLb^6~@KXTk=Un=1SSY_+%oJ>b`cpm!*d+<49rM4h5g1N?%Gfow zkt|!3dR}9~`bZkCq~Z4h8F7A=NKfcJrU1^rvQJP({FLswc7g)pEGe_;jYy`15O#Ra z2Na8}q+$ENg8DFjuKzg5=^+prmJ$fpu@+kIM%ywX{4tj2bY@RP$BsvM%4@Q0mXW+n z2d%~PGF;c-f=!lY@tt^n0vFmp{*|;p8(KQmybvQXrarC6ab;Rb(-cfGDf10 z5eer!8c802ZHu8$&j>omk=NGxKKmbZ*v7y&|$CbxXQ0)%VY*z$V`uzeXe zFNa$3ybSRvU3oboC4H1SZEpD`LZBgO+S>BPN?1~&aV?*%07;3~RF5$*ywH5gj@FPl z+RO3*2^utza#n*46zG&&r%7aST2mjzEhl}c4u_i)ifc}s0}#voa9k%OuD*nu;S3{; z?(hozqL^ACgRnw&$O@$b-yH*~W(xdu3w&Q zvUc$;xRPrZ^izIZ*U&JeZPqoCVc(A9p{m+-`onk{Ch?|)eJ75$3`J3=Ka8hg5^q}A zcjI`+FdqG3JPnh0)55+N$2*qs=nvy*n8a%c<9WcWru^Cd`LKHpM?6RCu?)|di+aW% z=DS#Q0c@&_$3s8#Q~b2~hbb!NP>9+q^U-F0P2xi9T-{`@w4hoIw3_|Uo`�Hu?YD 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�SCx-$MMxi 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 Date: Fri, 30 Sep 2011 23:55:02 +0100 Subject: [PATCH 50/64] copy config information on allow/disallow individual os functions into OpenSim.ini.example I this is generally useful rather than a 'default' setting --- bin/OpenSim.ini.example | 19 +++++++++++++++++++ bin/OpenSimDefaults.ini | 38 +++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index ce86d5637d..c3d32165e6 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -600,6 +600,25 @@ ;; VeryHigh, Severe OSFunctionThreatLevel = VeryLow + ; OS Functions enable/disable + ; For each function, you can add one line, as shown + ; The default for all functions allows them if below threat level + + ; true allows the use of the function unconditionally + ; Allow_osSetRegionWaterHeight = true + + ; false disables the function completely + ; Allow_osSetRegionWaterHeight = false + + ; Comma separated list of UUIDS allows the function for that list of UUIDS + ; Allow_osSetRegionWaterHeight = 888760cb-a3cf-43ac-8ea4-8732fd3ee2bb + + ; You can also use script creators as the uuid + ; Creators_osSetRegionWaterHeight = , ... + + ; If both Allow_ and Creators_ are given, effective permissions + ; are the union of the two. + ;; Time a script can spend in an event handler before it is interrupted ; EventLimit = 30 diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 245f087812..cd69e2a16a 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -1136,6 +1136,25 @@ ; Threat level to allow, one of None, VeryLow, Low, Moderate, High, VeryHigh, Severe OSFunctionThreatLevel = VeryLow + ; OS Functions enable/disable + ; For each function, you can add one line, as shown + ; The default for all functions allows them if below threat level + + ; true allows the use of the function unconditionally + ; Allow_osSetRegionWaterHeight = true + + ; false disables the function completely + ; Allow_osSetRegionWaterHeight = false + + ; Comma separated list of UUIDS allows the function for that list of UUIDS + ; Allow_osSetRegionWaterHeight = 888760cb-a3cf-43ac-8ea4-8732fd3ee2bb + + ; You can also use script creators as the uuid + ; Creators_osSetRegionWaterHeight = , ... + + ; If both Allow_ and Creators_ are given, effective permissions + ; are the union of the two. + ; Interval (s) between background save of script states SaveInterval = 120 @@ -1163,25 +1182,6 @@ SensorMaxRange = 96.0 SensorMaxResults = 16 - ; OS Functions enable/disable - ; For each function, you can add one line, as shown - ; The default for all functions allows them if below threat level - - ; true allows the use of the function unconditionally - ; Allow_osSetRegionWaterHeight = true - - ; false disables the function completely - ; Allow_osSetRegionWaterHeight = false - - ; Comma separated list of UUIDS allows the function for that list of UUIDS - ; Allow_osSetRegionWaterHeight = 888760cb-a3cf-43ac-8ea4-8732fd3ee2bb - - ; You can also use script creators as the uuid - ; Creators_osSetRegionWaterHeight = , ... - - ; If both Allow_ and Creators_ are given, effective permissions - ; are the union of the two. - ; Allow for llCreateLink and llBreakLink to work without asking for permission ; only enable this in a trusted environment otherwise you may be subject to hijacking ; AutomaticLinkPermission = false From 246443773ae52420092b483603d0e1daf9b87f00 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 1 Oct 2011 00:15:30 +0100 Subject: [PATCH 51/64] minor: remove clutter null check from pass in config to AvatarFactoryModule.Initialize() This is never null --- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 13 +++++-------- .../Region/Framework/Interfaces/IRegionModule.cs | 9 +++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 0cadd83e62..d4e173663b 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -64,15 +64,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += NewClient; - if (config != null) + IConfig sconfig = config.Configs["Startup"]; + if (sconfig != null) { - IConfig sconfig = config.Configs["Startup"]; - if (sconfig != null) - { - m_savetime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); - m_sendtime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); - // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); - } + m_savetime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); + m_sendtime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); + // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); } if (m_scene == null) diff --git a/OpenSim/Region/Framework/Interfaces/IRegionModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionModule.cs index e25a6e86dd..2bb0c75b99 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionModule.cs @@ -35,7 +35,16 @@ namespace OpenSim.Region.Framework.Interfaces /// public interface IRegionModule { + /// + /// Initialize the module. + /// + /// + /// For a shared module this can be called multiple times - once per scene. + /// + /// + /// Configuration information. For a shared module this will be identical on every scene call void Initialise(Scene scene, IConfigSource source); + void PostInitialise(); void Close(); string Name { get; } From a1875ec7600758087f6c06ccaf625507362e215c Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 1 Oct 2011 00:19:09 +0100 Subject: [PATCH 52/64] Add ability to pass in the permissions option (perm) to save oar via RemoteAdmin Applies patch in http://opensimulator.org/mantis/view.php?id=5686 Thanks Michelle Argus! --- .../RemoteController/RemoteAdminPlugin.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index e20b487cc6..08f3dc7e9e 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -2340,10 +2340,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController /// UUID of the region /// region_name /// region name - /// profile + /// profile /// profile url /// noassets /// true if no assets should be saved + /// perm + /// C and/or T /// /// /// region_uuid takes precedence over @@ -2418,6 +2420,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController options["noassets"] = (string)requestData["noassets"] ; } + if (requestData.Contains("perm")) + { + options["checkPermissions"] = (string)requestData["perm"]; + } + IRegionArchiverModule archiver = scene.RequestModuleInterface(); if (archiver != null) From c7db3df3442657cda398ff2f90d387bce98c718a Mon Sep 17 00:00:00 2001 From: Pixel Tomsen Date: Thu, 29 Sep 2011 21:57:08 +0200 Subject: [PATCH 53/64] llGetLinkKey, llGetLinkName Fix for sitting Avatar when an avatar sits on a prim, we get now his key & name ;-) http://opensimulator.org/mantis/view.php?id=4476 --- .../Shared/Api/Implementation/LSL_Api.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 39da563a55..9a26f4b79a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3704,6 +3704,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetLinkKey(int linknum) { m_host.AddScriptLPS(1); + List keytable = new List(); + // parse for sitting avatare-uuids + World.ForEachScenePresence(delegate(ScenePresence presence) + { + if (!presence.IsChildAgent && presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID)) + keytable.Add(presence.UUID); + }); + + int totalprims = m_host.ParentGroup.PrimCount + keytable.Count; + if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims) + { + return keytable[totalprims - linknum].ToString(); + } + + if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && keytable.Count == 1) + { + return m_host.UUID.ToString(); + } + SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum); if (part != null) { @@ -3747,6 +3766,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetLinkName(int linknum) { m_host.AddScriptLPS(1); + // parse for sitting avatare-names + List nametable = new List(); + World.ForEachScenePresence(delegate(ScenePresence presence) + { + if (!presence.IsChildAgent && presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID)) + nametable.Add(presence.ControllingClient.Name); + }); + + int totalprims = m_host.ParentGroup.PrimCount + nametable.Count; + if (totalprims > m_host.ParentGroup.PrimCount) + { + // sitting Avatar-Name with negativ linknum / SinglePrim + if (linknum < 0 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1) + return nametable[0]; + // Prim-Name / SinglePrim Sitting Avatar + if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && nametable.Count == 1) + return m_host.Name; + // LinkNumber > of Real PrimSet = AvatarName + if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims) + return nametable[totalprims - linknum]; + } // simplest case, this prims link number if (m_host.LinkNum == linknum) @@ -3760,6 +3800,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api else return UUID.Zero.ToString(); } + // Link set SceneObjectPart part = null; if (m_host.LinkNum == 1) // this is the Root prim From 42fe774ad10d469c11fe58731fcab0e4df760871 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 1 Oct 2011 01:21:20 +0100 Subject: [PATCH 54/64] Remove OpenSim.Region.Examples.SimpleModule This module is more than 2 years old and at least some of the 'example' code it gives is now misleading. Even the logs say it say some bits were broken where it was put in! --- .../Examples/SimpleModule/ComplexObject.cs | 130 -- .../Examples/SimpleModule/CpuCounterObject.cs | 68 - .../Examples/SimpleModule/FileSystemObject.cs | 51 - .../Examples/SimpleModule/MyNpcCharacter.cs | 1167 ----------------- .../SimpleModule/Properties/AssemblyInfo.cs | 62 - .../Region/Examples/SimpleModule/README.txt | 9 - .../Examples/SimpleModule/RegionModule.cs | 147 --- prebuild.xml | 28 - 8 files changed, 1662 deletions(-) delete mode 100644 OpenSim/Region/Examples/SimpleModule/ComplexObject.cs delete mode 100644 OpenSim/Region/Examples/SimpleModule/CpuCounterObject.cs delete mode 100644 OpenSim/Region/Examples/SimpleModule/FileSystemObject.cs delete mode 100644 OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs delete mode 100644 OpenSim/Region/Examples/SimpleModule/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Region/Examples/SimpleModule/README.txt delete mode 100644 OpenSim/Region/Examples/SimpleModule/RegionModule.cs diff --git a/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs b/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs deleted file mode 100644 index e951befdc5..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs +++ /dev/null @@ -1,130 +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 OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.Examples.SimpleModule -{ - public class ComplexObject : SceneObjectGroup - { - private readonly Quaternion m_rotationDirection; - - protected override bool InSceneBackup - { - get - { - return false; - } - } - - private class RotatingWheel : SceneObjectPart - { - private readonly Quaternion m_rotationDirection; - - public RotatingWheel() - { - } - - public RotatingWheel( - UUID ownerID, Vector3 groupPosition, Vector3 offsetPosition, Quaternion rotationDirection) - : base(ownerID, PrimitiveBaseShape.Default, groupPosition, Quaternion.Identity, offsetPosition) - { - m_rotationDirection = rotationDirection; - - Flags |= PrimFlags.Touch; - } - - public override void UpdateMovement() - { - UpdateRotation(RotationOffset * m_rotationDirection); - } - } - - public override void UpdateMovement() - { - UpdateGroupRotationR(GroupRotation * m_rotationDirection); - - base.UpdateMovement(); - } - - public ComplexObject() - { - } - - public ComplexObject(Scene scene, ulong regionHandle, UUID ownerID, uint localID, Vector3 pos) - : base(ownerID, pos, PrimitiveBaseShape.Default) - { - m_rotationDirection = new Quaternion(0.05f, 0.1f, 0.15f); - - AddPart( - new RotatingWheel(ownerID, pos, new Vector3(0, 0, 0.75f), - new Quaternion(0.05f, 0, 0))); - AddPart( - new RotatingWheel(ownerID, pos, new Vector3(0, 0, -0.75f), - new Quaternion(-0.05f, 0, 0))); - - AddPart( - new RotatingWheel(ownerID, pos, new Vector3(0, 0.75f, 0), - new Quaternion(0.5f, 0, 0.05f))); - AddPart( - new RotatingWheel(ownerID, pos, new Vector3(0, -0.75f, 0), - new Quaternion(-0.5f, 0, -0.05f))); - - AddPart( - new RotatingWheel(ownerID, pos, new Vector3(0.75f, 0, 0), - new Quaternion(0, 0.5f, 0.05f))); - AddPart( - new RotatingWheel(ownerID, pos, new Vector3(-0.75f, 0, 0), - new Quaternion(0, -0.5f, -0.05f))); - - RootPart.Flags |= PrimFlags.Touch; - } - - public override void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) - { - m_parts.Remove(part.UUID); - - remoteClient.SendKillObject(m_regionHandle, part.LocalId); - remoteClient.AddMoney(1); - remoteClient.SendChatMessage("Poof!", 1, AbsolutePosition, "Party Party", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); - } - - public override void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient) - { - if (m_parts.Count == 1) - { - m_parts.Remove(m_rootPart.UUID); - m_scene.DeleteSceneObject(this, false); - remoteClient.SendKillObject(m_regionHandle, m_rootPart.LocalId); - remoteClient.AddMoney(50); - remoteClient.SendChatMessage("KABLAM!!!", 1, AbsolutePosition, "Groupie Groupie", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); - } - } - } -} diff --git a/OpenSim/Region/Examples/SimpleModule/CpuCounterObject.cs b/OpenSim/Region/Examples/SimpleModule/CpuCounterObject.cs deleted file mode 100644 index 8669139279..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/CpuCounterObject.cs +++ /dev/null @@ -1,68 +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.Diagnostics; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.Examples.SimpleModule -{ - public class CpuCounterObject : SceneObjectGroup - { - protected override bool InSceneBackup - { - get - { - return false; - } - } - - private PerformanceCounter m_counter; - - public CpuCounterObject(UUID ownerID, Vector3 pos) - : base(ownerID, pos, PrimitiveBaseShape.Default) - { - String objectName = "Processor"; - String counterName = "% Processor Time"; - String instanceName = "_Total"; - - m_counter = new PerformanceCounter(objectName, counterName, instanceName); - } - - public override void UpdateMovement() - { - float cpu = m_counter.NextValue()/40f; - Vector3 size = new Vector3(cpu, cpu, cpu); - - RootPart.Resize(size); - - base.UpdateMovement(); - } - } -} diff --git a/OpenSim/Region/Examples/SimpleModule/FileSystemObject.cs b/OpenSim/Region/Examples/SimpleModule/FileSystemObject.cs deleted file mode 100644 index f0f684c479..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/FileSystemObject.cs +++ /dev/null @@ -1,51 +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.IO; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.Examples.SimpleModule -{ - public class FileSystemObject : SceneObjectGroup - { - public FileSystemObject(FileInfo fileInfo, Vector3 pos) - : base(UUID.Zero, pos, PrimitiveBaseShape.Default) - { - Text = fileInfo.Name; - } - - protected override bool InSceneBackup - { - get - { - return false; - } - } - } -} diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs deleted file mode 100644 index b0266c53bf..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ /dev/null @@ -1,1167 +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.Net; -using OpenMetaverse; -using OpenMetaverse.Packets; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.Examples.SimpleModule -{ - public class MyNpcCharacter : IClientAPI - { - private uint movementFlag = 0; - private short flyState = 0; - private Quaternion bodyDirection = Quaternion.Identity; - private short count = 0; - private short frame = 0; - private Scene m_scene; - -// disable warning: public events, part of the public API -#pragma warning disable 67 - - public event Action OnLogout; - public event ObjectPermissions OnObjectPermissions; - - public event MoneyTransferRequest OnMoneyTransferRequest; - public event ParcelBuy OnParcelBuy; - public event Action OnConnectionClosed; - - public event ImprovedInstantMessage OnInstantMessage; - public event ChatMessage OnChatFromClient; - public event TextureRequest OnRequestTexture; - public event RezObject OnRezObject; - public event ModifyTerrain OnModifyTerrain; - public event BakeTerrain OnBakeTerrain; - public event SetAppearance OnSetAppearance; - public event AvatarNowWearing OnAvatarNowWearing; - public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; - public event RezMultipleAttachmentsFromInv OnRezMultipleAttachmentsFromInv; - public event UUIDNameRequest OnDetachAttachmentIntoInv; - public event ObjectAttach OnObjectAttach; - public event ObjectDeselect OnObjectDetach; - public event ObjectDrop OnObjectDrop; - public event StartAnim OnStartAnim; - public event StopAnim OnStopAnim; - public event LinkObjects OnLinkObjects; - public event DelinkObjects OnDelinkObjects; - public event RequestMapBlocks OnRequestMapBlocks; - public event RequestMapName OnMapNameRequest; - public event TeleportLocationRequest OnTeleportLocationRequest; - public event TeleportLandmarkRequest OnTeleportLandmarkRequest; - public event DisconnectUser OnDisconnectUser; - public event RequestAvatarProperties OnRequestAvatarProperties; - public event SetAlwaysRun OnSetAlwaysRun; - - public event DeRezObject OnDeRezObject; - public event Action OnRegionHandShakeReply; - public event GenericCall1 OnRequestWearables; - public event Action OnCompleteMovementToRegion; - public event UpdateAgent OnPreAgentUpdate; - public event UpdateAgent OnAgentUpdate; - public event AgentRequestSit OnAgentRequestSit; - public event AgentSit OnAgentSit; - public event AvatarPickerRequest OnAvatarPickerRequest; - public event Action OnRequestAvatarsData; - public event AddNewPrim OnAddPrim; - public event RequestGodlikePowers OnRequestGodlikePowers; - public event GodKickUser OnGodKickUser; - public event ObjectDuplicate OnObjectDuplicate; - public event GrabObject OnGrabObject; - public event DeGrabObject OnDeGrabObject; - public event MoveObject OnGrabUpdate; - public event SpinStart OnSpinStart; - public event SpinObject OnSpinUpdate; - public event SpinStop OnSpinStop; - public event ViewerEffectEventHandler OnViewerEffect; - - public event FetchInventory OnAgentDataUpdateRequest; - public event TeleportLocationRequest OnSetStartLocationRequest; - - public event UpdateShape OnUpdatePrimShape; - public event ObjectExtraParams OnUpdateExtraParams; - public event RequestObjectPropertiesFamily OnRequestObjectPropertiesFamily; - public event ObjectRequest OnObjectRequest; - public event ObjectSelect OnObjectSelect; - public event GenericCall7 OnObjectDescription; - public event GenericCall7 OnObjectName; - public event GenericCall7 OnObjectClickAction; - public event GenericCall7 OnObjectMaterial; - public event UpdatePrimFlags OnUpdatePrimFlags; - public event UpdatePrimTexture OnUpdatePrimTexture; - public event UpdateVector OnUpdatePrimGroupPosition; - public event UpdateVector OnUpdatePrimSinglePosition; - public event UpdatePrimRotation OnUpdatePrimGroupRotation; - public event UpdatePrimSingleRotationPosition OnUpdatePrimSingleRotationPosition; - public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation; - public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation; - public event UpdateVector OnUpdatePrimScale; - public event UpdateVector OnUpdatePrimGroupScale; - public event StatusChange OnChildAgentStatus; - public event GenericCall2 OnStopMovement; - public event Action OnRemoveAvatar; - - public event CreateNewInventoryItem OnCreateNewInventoryItem; - public event LinkInventoryItem OnLinkInventoryItem; - public event CreateInventoryFolder OnCreateNewInventoryFolder; - public event UpdateInventoryFolder OnUpdateInventoryFolder; - public event MoveInventoryFolder OnMoveInventoryFolder; - public event RemoveInventoryFolder OnRemoveInventoryFolder; - public event RemoveInventoryItem OnRemoveInventoryItem; - public event FetchInventoryDescendents OnFetchInventoryDescendents; - public event PurgeInventoryDescendents OnPurgeInventoryDescendents; - public event FetchInventory OnFetchInventory; - public event RequestTaskInventory OnRequestTaskInventory; - public event UpdateInventoryItem OnUpdateInventoryItem; - public event CopyInventoryItem OnCopyInventoryItem; - public event MoveInventoryItem OnMoveInventoryItem; - public event UDPAssetUploadRequest OnAssetUploadRequest; - public event RequestTerrain OnRequestTerrain; - public event RequestTerrain OnUploadTerrain; - public event XferReceive OnXferReceive; - public event RequestXfer OnRequestXfer; - public event ConfirmXfer OnConfirmXfer; - public event AbortXfer OnAbortXfer; - public event RezScript OnRezScript; - public event UpdateTaskInventory OnUpdateTaskInventory; - public event MoveTaskInventory OnMoveTaskItem; - public event RemoveTaskInventory OnRemoveTaskItem; - public event RequestAsset OnRequestAsset; - public event GenericMessage OnGenericMessage; - public event UUIDNameRequest OnNameFromUUIDRequest; - public event UUIDNameRequest OnUUIDGroupNameRequest; - - public event ParcelPropertiesRequest OnParcelPropertiesRequest; - public event ParcelDivideRequest OnParcelDivideRequest; - public event ParcelJoinRequest OnParcelJoinRequest; - public event ParcelPropertiesUpdateRequest OnParcelPropertiesUpdateRequest; - public event ParcelAbandonRequest OnParcelAbandonRequest; - public event ParcelGodForceOwner OnParcelGodForceOwner; - public event ParcelReclaim OnParcelReclaim; - public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest; - public event ParcelAccessListRequest OnParcelAccessListRequest; - public event ParcelAccessListUpdateRequest OnParcelAccessListUpdateRequest; - public event ParcelSelectObjects OnParcelSelectObjects; - public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest; - public event ParcelDeedToGroup OnParcelDeedToGroup; - public event ObjectDeselect OnObjectDeselect; - public event RegionInfoRequest OnRegionInfoRequest; - public event EstateCovenantRequest OnEstateCovenantRequest; - public event EstateChangeInfo OnEstateChangeInfo; - - public event ObjectDuplicateOnRay OnObjectDuplicateOnRay; - - public event FriendActionDelegate OnApproveFriendRequest; - public event FriendActionDelegate OnDenyFriendRequest; - public event FriendshipTermination OnTerminateFriendship; - public event GrantUserFriendRights OnGrantUserRights; - - public event EconomyDataRequest OnEconomyDataRequest; - public event MoneyBalanceRequest OnMoneyBalanceRequest; - public event UpdateAvatarProperties OnUpdateAvatarProperties; - - public event ObjectIncludeInSearch OnObjectIncludeInSearch; - public event UUIDNameRequest OnTeleportHomeRequest; - - public event ScriptAnswer OnScriptAnswer; - public event RequestPayPrice OnRequestPayPrice; - public event ObjectSaleInfo OnObjectSaleInfo; - public event ObjectBuy OnObjectBuy; - public event BuyObjectInventory OnBuyObjectInventory; - public event AgentSit OnUndo; - public event AgentSit OnRedo; - public event LandUndo OnLandUndo; - - public event ForceReleaseControls OnForceReleaseControls; - - public event GodLandStatRequest OnLandStatRequest; - public event RequestObjectPropertiesFamily OnObjectGroupRequest; - - public event DetailedEstateDataRequest OnDetailedEstateDataRequest; - public event SetEstateFlagsRequest OnSetEstateFlagsRequest; - public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture; - public event SetEstateTerrainDetailTexture OnSetEstateTerrainDetailTexture; - public event SetEstateTerrainTextureHeights OnSetEstateTerrainTextureHeights; - public event CommitEstateTerrainTextureRequest OnCommitEstateTerrainTextureRequest; - public event SetRegionTerrainSettings OnSetRegionTerrainSettings; - public event EstateRestartSimRequest OnEstateRestartSimRequest; - public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest; - public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest; - public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest; - public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; - public event EstateDebugRegionRequest OnEstateDebugRegionRequest; - public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; - public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; - public event ScriptReset OnScriptReset; - public event GetScriptRunning OnGetScriptRunning; - public event SetScriptRunning OnSetScriptRunning; - public event Action OnAutoPilotGo; - - public event TerrainUnacked OnUnackedTerrain; - - public event RegionHandleRequest OnRegionHandleRequest; - public event ParcelInfoRequest OnParcelInfoRequest; - - public event ActivateGesture OnActivateGesture; - public event DeactivateGesture OnDeactivateGesture; - public event ObjectOwner OnObjectOwner; - - public event DirPlacesQuery OnDirPlacesQuery; - public event DirFindQuery OnDirFindQuery; - public event DirLandQuery OnDirLandQuery; - public event DirPopularQuery OnDirPopularQuery; - public event DirClassifiedQuery OnDirClassifiedQuery; - public event EventInfoRequest OnEventInfoRequest; - public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime; - - public event MapItemRequest OnMapItemRequest; - - public event OfferCallingCard OnOfferCallingCard; - public event AcceptCallingCard OnAcceptCallingCard; - public event DeclineCallingCard OnDeclineCallingCard; - public event SoundTrigger OnSoundTrigger; - - public event StartLure OnStartLure; - public event TeleportLureRequest OnTeleportLureRequest; - public event NetworkStats OnNetworkStatsUpdate; - - public event ClassifiedInfoRequest OnClassifiedInfoRequest; - public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; - public event ClassifiedDelete OnClassifiedDelete; - public event ClassifiedDelete OnClassifiedGodDelete; - - public event EventNotificationAddRequest OnEventNotificationAddRequest; - public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; - public event EventGodDelete OnEventGodDelete; - - public event ParcelDwellRequest OnParcelDwellRequest; - public event UserInfoRequest OnUserInfoRequest; - public event UpdateUserInfo OnUpdateUserInfo; - - public event RetrieveInstantMessages OnRetrieveInstantMessages; - - public event PickDelete OnPickDelete; - public event PickGodDelete OnPickGodDelete; - public event PickInfoUpdate OnPickInfoUpdate; - public event AvatarNotesUpdate OnAvatarNotesUpdate; - - public event MuteListRequest OnMuteListRequest; - - public event AvatarInterestUpdate OnAvatarInterestUpdate; - - public event PlacesQuery OnPlacesQuery; - - public event FindAgentUpdate OnFindAgent; - public event TrackAgentUpdate OnTrackAgent; - public event NewUserReport OnUserReport; - public event SaveStateHandler OnSaveState; - public event GroupAccountSummaryRequest OnGroupAccountSummaryRequest; - public event GroupAccountDetailsRequest OnGroupAccountDetailsRequest; - public event GroupAccountTransactionsRequest OnGroupAccountTransactionsRequest; - public event FreezeUserUpdate OnParcelFreezeUser; - public event EjectUserUpdate OnParcelEjectUser; - public event ParcelBuyPass OnParcelBuyPass; - public event ParcelGodMark OnParcelGodMark; - public event GroupActiveProposalsRequest OnGroupActiveProposalsRequest; - public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; - public event SimWideDeletesDelegate OnSimWideDeletes; - public event SendPostcard OnSendPostcard; - public event MuteListEntryUpdate OnUpdateMuteListEntry; - public event MuteListEntryRemove OnRemoveMuteListEntry; - public event GodlikeMessage onGodlikeMessage; - public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate; - -#pragma warning restore 67 - - private UUID myID = UUID.Random(); - - public MyNpcCharacter(Scene scene) - { - - // startPos = new Vector3(128, (float)(Util.RandomClass.NextDouble()*100), 2); - m_scene = scene; - m_scene.EventManager.OnFrame += Update; - } - - private Vector3 startPos = new Vector3(128, 128, 30); - - public virtual Vector3 StartPos - { - get { return startPos; } - set { } - } - - public virtual UUID AgentId - { - get { return myID; } - } - - public UUID SessionId - { - get { return UUID.Zero; } - } - - public UUID SecureSessionId - { - get { return UUID.Zero; } - } - - public virtual string FirstName - { - get { return "Only"; } - } - - private string lastName = "Today" + Util.RandomClass.Next(1, 1000); - - public virtual string LastName - { - get { return lastName; } - } - - public virtual String Name - { - get { return FirstName + LastName; } - } - - public bool IsActive - { - get { return true; } - set { } - } - public bool IsLoggingOut - { - get { return false; } - set { } - } - public UUID ActiveGroupId - { - get { return UUID.Zero; } - } - - public string ActiveGroupName - { - get { return String.Empty; } - } - - public ulong ActiveGroupPowers - { - get { return 0; } - } - - public bool IsGroupMember(UUID groupID) - { - return false; - } - - public ulong GetGroupPowers(UUID groupID) - { - return 0; - } - - public virtual int NextAnimationSequenceNumber - { - get { return 1; } - } - - public IScene Scene - { - get { return m_scene; } - } - - public bool SendLogoutPacketWhenClosing - { - set { } - } - - public virtual void ActivateGesture(UUID assetId, UUID gestureId) - { - } - - public virtual void SendWearables(AvatarWearable[] wearables, int serial) - { - } - - public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) - { - } - - public virtual void Kick(string message) - { - } - - public virtual void SendStartPingCheck(byte seq) - { - } - - public virtual void SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData, List Data) - { - } - - public virtual void SendAgentDataUpdate(UUID agentid, UUID activegroupid, string firstname, string lastname, ulong grouppowers, string groupname, string grouptitle) - { - - } - - public virtual void SendKillObject(ulong regionHandle, uint localID) - { - } - - public virtual void SetChildAgentThrottle(byte[] throttle) - { - } - public byte[] GetThrottlesPacked(float multiplier) - { - return new byte[0]; - } - - - public virtual void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) - { - } - - public virtual void SendChatMessage(string message, byte type, Vector3 fromPos, string fromName, - UUID fromAgentID, byte source, byte audible) - { - } - - public virtual void SendChatMessage(byte[] message, byte type, Vector3 fromPos, string fromName, - UUID fromAgentID, byte source, byte audible) - { - } - - public void SendInstantMessage(GridInstantMessage im) - { - - } - - public void SendGenericMessage(string method, List message) - { - } - - public void SendGenericMessage(string method, List message) - { - - } - - public virtual void SendLayerData(float[] map) - { - } - - public virtual void SendLayerData(int px, int py, float[] map) - { - } - public virtual void SendLayerData(int px, int py, float[] map, bool track) - { - } - - public virtual void SendWindData(Vector2[] windSpeeds) { } - - public virtual void SendCloudData(float[] cloudCover) { } - - public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) - { - } - - public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) - { - } - - public virtual AgentCircuitData RequestClientInfo() - { - return new AgentCircuitData(); - } - - public virtual void CrossRegion(ulong newRegionHandle, Vector3 pos, Vector3 lookAt, - IPEndPoint newRegionExternalEndPoint, string capsURL) - { - } - - public virtual void SendMapBlock(List mapBlocks, uint flag) - { - } - - public virtual void SendLocalTeleport(Vector3 position, Vector3 lookAt, uint flags) - { - } - - public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, - uint locationID, uint flags, string capsURL) - { - } - - public virtual void SendTeleportFailed(string reason) - { - } - - public virtual void SendTeleportStart(uint flags) - { - } - - public virtual void SendTeleportProgress(uint flags, string message) - { - } - - public virtual void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance) - { - } - - public virtual void SendPayPrice(UUID objectID, int[] payPrice) - { - } - - public virtual void SendCoarseLocationUpdate(List users, List CoarseLocations) - { - } - - public virtual void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, string[] buttonlabels) - { - } - - public void SendAvatarDataImmediate(ISceneEntity avatar) - { - } - - public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) - { - } - - public void ReprioritizeUpdates() - { - } - - public void FlushPrimUpdates() - { - } - - public virtual void SendInventoryFolderDetails(UUID ownerID, UUID folderID, - List items, - List folders, - int version, - bool fetchFolders, - bool fetchItems) - { - } - - public virtual void SendInventoryItemDetails(UUID ownerID, InventoryItemBase item) - { - } - - public virtual void SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackID) - { - } - - public virtual void SendRemoveInventoryItem(UUID itemID) - { - } - - public virtual void SendBulkUpdateInventory(InventoryNodeBase node) - { - } - - public UUID GetDefaultAnimation(string name) - { - return UUID.Zero; - } - - public void SendTakeControls(int controls, bool passToAgent, bool TakeControls) - { - } - - public virtual void SendTaskInventory(UUID taskID, short serial, byte[] fileName) - { - } - - public virtual void SendXferPacket(ulong xferID, uint packet, byte[] data) - { - } - - public virtual void SendAbortXferPacket(ulong xferID) - { - - } - - - public virtual void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, - int PriceGroupCreate, int PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor, - int PriceParcelClaim, float PriceParcelClaimFactor, int PriceParcelRent, int PricePublicObjectDecay, - int PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int TeleportMinPrice, float TeleportPriceExponent) - { - - } - public virtual void SendNameReply(UUID profileId, string firstname, string lastname) - { - } - - public virtual void SendPreLoadSound(UUID objectID, UUID ownerID, UUID soundID) - { - } - - public virtual void SendPlayAttachedSound(UUID soundID, UUID objectID, UUID ownerID, float gain, - byte flags) - { - } - - public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) - { - } - - public void SendAttachedSoundGainChange(UUID objectID, float gain) - { - - } - - public void SendAlertMessage(string message) - { - } - - public void SendAgentAlertMessage(string message, bool modal) - { - } - - public void SendSystemAlertMessage(string message) - { - } - - public void SendLoadURL(string objectname, UUID objectID, UUID ownerID, bool groupOwned, string message, - string url) - { - } - - public virtual void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args) - { - if (OnRegionHandShakeReply != null) - { - OnRegionHandShakeReply(this); - } - - if (OnCompleteMovementToRegion != null) - { - OnCompleteMovementToRegion(this, true); - } - } - public void SendAssetUploadCompleteMessage(sbyte AssetType, bool Success, UUID AssetFullID) - { - } - - public void SendConfirmXfer(ulong xferID, uint PacketID) - { - } - - public void SendXferRequest(ulong XferID, short AssetType, UUID vFileID, byte FilePath, byte[] FileName) - { - } - - public void SendInitiateDownload(string simFileName, string clientFileName) - { - } - - public void SendImageFirstPart(ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) - { - } - - public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) - { - } - - public void SendImageNotFound(UUID imageid) - { - } - - public void SendShutdownConnectionNotice() - { - } - - public void SendSimStats(SimStats stats) - { - } - - public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) - { - - } - - public void SendObjectPropertiesReply(ISceneEntity entity) - { - } - - public void SendAgentOffline(UUID[] agentIDs) - { - - } - - public void SendAgentOnline(UUID[] agentIDs) - { - - } - - public void SendSitResponse(UUID TargetID, Vector3 OffsetPos, Quaternion SitOrientation, bool autopilot, - Vector3 CameraAtOffset, Vector3 CameraEyeOffset, bool ForceMouseLook) - { - } - - public void SendAdminResponse(UUID Token, uint AdminLevel) - { - - } - - public void SendGroupMembership(GroupMembershipData[] GroupMembership) - { - - } - - private void Update() - { - frame++; - if (frame > 20) - { - frame = 0; - if (OnAgentUpdate != null) - { - AgentUpdateArgs pack = new AgentUpdateArgs(); - pack.ControlFlags = movementFlag; - pack.BodyRotation = bodyDirection; - - OnAgentUpdate(this, pack); - } - if (flyState == 0) - { - movementFlag = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY | - (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG; - flyState = 1; - } - else if (flyState == 1) - { - movementFlag = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY | - (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; - flyState = 2; - } - else - { - movementFlag = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; - flyState = 0; - } - - if (count >= 10) - { - if (OnChatFromClient != null) - { - OSChatMessage args = new OSChatMessage(); - args.Message = "Hey You! Get out of my Home. This is my Region"; - args.Channel = 0; - args.From = FirstName + " " + LastName; - args.Scene = m_scene; - args.Position = new Vector3(128, 128, 26); - args.Sender = this; - args.Type = ChatTypeEnum.Shout; - - OnChatFromClient(this, args); - } - count = -1; - } - - count++; - } - } - - public bool AddMoney(int debit) - { - return false; - } - - public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong time, uint dlen, uint ylen, float phase) - { - } - - public void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks) - { - } - - public void SendViewerTime(int phase) - { - } - - public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, - string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, - UUID partnerID) - { - } - - public void SetDebugPacketLevel(int newDebug) - { - } - - public void InPacket(object NewPack) - { - } - - public void ProcessInPacket(Packet NewPack) - { - } - - public void Close() - { - } - - public void Start() - { - } - - public void Stop() - { - } - - private uint m_circuitCode; - - public uint CircuitCode - { - get { return m_circuitCode; } - set { m_circuitCode = value; } - } - - public IPEndPoint RemoteEndPoint - { - get { return new IPEndPoint(IPAddress.Loopback, (ushort)m_circuitCode); } - } - - public void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message) - { - - } - public void SendLogoutPacket() - { - } - - public void Terminate() - { - } - - public EndPoint GetClientEP() - { - return null; - } - - public ClientInfo GetClientInfo() - { - return null; - } - - public void SetClientInfo(ClientInfo info) - { - } - - public void SendScriptQuestion(UUID objectID, string taskName, string ownerName, UUID itemID, int question) - { - } - public void SendHealth(float health) - { - } - - public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID) - { - } - - public void SendBannedUserList(UUID invoice, EstateBan[] banlist, uint estateID) - { - } - - public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) - { - } - - public void SendEstateCovenantInformation(UUID covenant) - { - } - - public void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, UUID covenant, string abuseEmail, UUID estateOwner) - { - } - - public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, ILandObject lo, float simObjectBonusFactor, int parcelObjectCapacity, int simObjectCapacity, uint regionFlags) - { - } - - public void SendLandAccessListData(List avatars, uint accessFlag, int localLandID) - { - } - - public void SendForceClientSelectObjects(List objectIDs) - { - } - - public void SendLandObjectOwners(LandData land, List groups, Dictionary ownersAndCount) - { - } - - public void SendCameraConstraint(Vector4 ConstraintPlane) - { - - } - - public void SendLandParcelOverlay(byte[] data, int sequence_id) - { - } - - public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time) - { - } - - public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID, byte autoScale, string mediaType, - string mediaDesc, int mediaWidth, int mediaHeight, byte mediaLoop) - { - } - - public void SendGroupNameReply(UUID groupLLUID, string GroupName) - { - } - - public void SendLandStatReply(uint reportType, uint requestFlags, uint resultCount, LandStatReportItem[] lsrpia) - { - } - - public void SendScriptRunningReply(UUID objectID, UUID itemID, bool running) - { - } - - public void SendAsset(AssetRequestToClient req) - { - } - - public void SendTexture(AssetBase TextureAsset) - { - - } - - public void SendSetFollowCamProperties (UUID objectID, SortedDictionary parameters) - { - } - - public void SendClearFollowCamProperties (UUID objectID) - { - } - - public void SendRegionHandle (UUID regoinID, ulong handle) - { - } - - public void SendParcelInfo (RegionInfo info, LandData land, UUID parcelID, uint x, uint y) - { - } - - public void SetClientOption(string option, string value) - { - } - - public string GetClientOption(string option) - { - return string.Empty; - } - - public void SendScriptTeleportRequest(string objName, string simName, Vector3 pos, Vector3 lookAt) - { - } - - public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data) - { - } - - public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data) - { - } - - public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data) - { - } - - public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data) - { - } - - public void SendDirClassifiedReply(UUID queryID, DirClassifiedReplyData[] data) - { - } - - public void SendDirLandReply(UUID queryID, DirLandReplyData[] data) - { - } - - public void SendDirPopularReply(UUID queryID, DirPopularReplyData[] data) - { - } - - public void SendMapItemReply(mapItemReply[] replies, uint mapitemtype, uint flags) - { - } - - public void KillEndDone() - { - } - - public void SendEventInfoReply (EventData info) - { - } - - public void SendOfferCallingCard (UUID destID, UUID transactionID) - { - } - - public void SendAcceptCallingCard (UUID transactionID) - { - } - - public void SendDeclineCallingCard (UUID transactionID) - { - } - - public void SendAvatarGroupsReply(UUID avatarID, GroupMembershipData[] data) - { - } - - public void SendJoinGroupReply(UUID groupID, bool success) - { - } - - public void SendEjectGroupMemberReply(UUID agentID, UUID groupID, bool succss) - { - } - - public void SendLeaveGroupReply(UUID groupID, bool success) - { - } - - public void SendTerminateFriend(UUID exFriendID) - { - } - - #region IClientAPI Members - - - public bool AddGenericPacketHandler(string MethodName, GenericMessage handler) - { - return true; - } - - public void SendAvatarClassifiedReply(UUID targetID, UUID[] classifiedID, string[] name) - { - } - - public void SendClassifiedInfoReply(UUID classifiedID, UUID creatorID, uint creationDate, uint expirationDate, uint category, string name, string description, UUID parcelID, uint parentEstate, UUID snapshotID, string simName, Vector3 globalPos, string parcelName, byte classifiedFlags, int price) - { - } - - public void SendAgentDropGroup(UUID groupID) - { - } - - public void SendAvatarNotesReply(UUID targetID, string text) - { - } - - public void SendAvatarPicksReply(UUID targetID, Dictionary picks) - { - } - - public void SendAvatarClassifiedReply(UUID targetID, Dictionary classifieds) - { - } - - public void SendParcelDwellReply(int localID, UUID parcelID, float dwell) - { - } - - public void SendUserInfoReply(bool imViaEmail, bool visible, string email) - { - } - - public void SendCreateGroupReply(UUID groupID, bool success, string message) - { - } - - public void RefreshGroupMembership() - { - } - - public void SendUseCachedMuteList() - { - } - - public void SendMuteListUpdate(string filename) - { - } - - public void SendPickInfoReply(UUID pickID,UUID creatorID, bool topPick, UUID parcelID, string name, string desc, UUID snapshotID, string user, string originalName, string simName, Vector3 posGlobal, int sortOrder, bool enabled) - { - } - #endregion - - public void SendRebakeAvatarTextures(UUID textureID) - { - } - - public void SendAvatarInterestsReply(UUID avatarID, uint wantMask, string wantText, uint skillsMask, string skillsText, string languages) - { - } - - public void SendGroupAccountingDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID, int amt) - { - } - - public void SendGroupAccountingSummary(IClientAPI sender,UUID groupID, uint moneyAmt, int totalTier, int usedTier) - { - } - - public void SendGroupTransactionsSummaryDetails(IClientAPI sender,UUID groupID, UUID transactionID, UUID sessionID,int amt) - { - } - - public void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes) - { - } - - public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals) - { - } - - public void SendChangeUserRights(UUID agentID, UUID friendID, int rights) - { - } - - public void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId) - { - } - - public void StopFlying(ISceneEntity presence) - { - } - - public void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data) - { - } - } -} diff --git a/OpenSim/Region/Examples/SimpleModule/Properties/AssemblyInfo.cs b/OpenSim/Region/Examples/SimpleModule/Properties/AssemblyInfo.cs deleted file mode 100644 index 5e09adb007..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,62 +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.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("OpenSim.Region.Examples.SimpleModule")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("http://opensimulator.org")] -[assembly: AssemblyProduct("OpenSim.Region.Examples.SimpleModule")] -[assembly: AssemblyCopyright("Copyright (c) 2008")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f0caca77-7818-4a43-9200-0a8548009a05")] - -// 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 Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("0.6.5.*")] -[assembly: AssemblyVersion("0.6.5.*")] -[assembly: AssemblyFileVersion("0.6.5.0")] diff --git a/OpenSim/Region/Examples/SimpleModule/README.txt b/OpenSim/Region/Examples/SimpleModule/README.txt deleted file mode 100644 index 025e33dc7b..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -!!!IMPORTANT NOTE!!! - -This code snippet provided as an example of coding functional content with region modules. - -As of 13/3 2008 this module actually renders all regions within the instance unusable if enabled by dragging the dll from ./bin to global /bin. - -So, use at own peril and in dedicated instance. - -Peace. diff --git a/OpenSim/Region/Examples/SimpleModule/RegionModule.cs b/OpenSim/Region/Examples/SimpleModule/RegionModule.cs deleted file mode 100644 index 3b8ce379f0..0000000000 --- a/OpenSim/Region/Examples/SimpleModule/RegionModule.cs +++ /dev/null @@ -1,147 +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.Collections.Generic; -using Nini.Config; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.Examples.SimpleModule -{ - /// - /// Example region module. - /// - /// - /// This is an old and unmaintained region module which uses the old style module interface. It is not loaded into - /// OpenSim by default. If you want to try enabling it, look in the bin folder of this project. - /// Please see the README.txt in this project on the filesystem for some more information. - /// Nonetheless, it may contain some useful example code so has been left here for now. - /// - /// You can see bare bones examples of the more modern region module system in OpenSim/Region/OptionalModules/Example - /// - public class RegionModule : IRegionModule - { - #region IRegionModule Members - - private Scene m_scene; - - public void Initialise(Scene scene, IConfigSource source) - { - m_scene = scene; - } - - public void PostInitialise() - { - // RegionInfo regionInfo = m_scene.RegionInfo; - - // Vector3 pos = new Vector3(110, 129, 27); - - //AddCpuCounter(regionInfo, pos); - // AddComplexObjects(regionInfo, pos); - AddAvatars(); - // AddFileSystemObjects(); - } - - // private void AddFileSystemObjects() - // { - // DirectoryInfo dirInfo = new DirectoryInfo("."); - - // float x = 0; - // float z = 0; - - // foreach (FileInfo fileInfo in dirInfo.GetFiles()) - // { - // Vector3 filePos = new Vector3(100 + x, 129, 27 + z); - // x = x + 2; - // if (x > 50) - // { - // x = 0; - // z = z + 2; - // } - - // FileSystemObject fileObject = new FileSystemObject(m_scene, fileInfo, filePos); - // m_scene.AddNewSceneObject(fileObject, true); - // } - // } - - private void AddAvatars() - { - for (int i = 0; i < 1; i++) - { - MyNpcCharacter m_character = new MyNpcCharacter(m_scene); - m_scene.AddNewClient(m_character, PresenceType.Npc); - m_scene.AgentCrossing(m_character.AgentId, Vector3.Zero, false); - } - - m_scene.ForEachScenePresence(delegate(ScenePresence sp) - { - if (!sp.IsChildAgent) - sp.AbsolutePosition = - new Vector3((float)Util.RandomClass.Next(100, 200), (float)Util.RandomClass.Next(30, 200), 2); - }); - } - - // private void AddComplexObjects(RegionInfo regionInfo, Vector3 pos) - // { - // int objs = 3; - - // for (int i = 0; i < (objs*objs*objs); i++) - // { - // Vector3 posOffset = new Vector3((i % objs) * 4, ((i % (objs*objs)) / (objs)) * 4, (i / (objs*objs)) * 4); - // ComplexObject complexObject = - // new ComplexObject(m_scene, regionInfo.RegionHandle, UUID.Zero, pos + posOffset); - // m_scene.AddNewSceneObject(complexObject, true); - // } - // } - - // private void AddCpuCounter(RegionInfo regionInfo, Vector3 pos) - // { - // SceneObjectGroup sceneObject = - // new CpuCounterObject(m_scene, regionInfo.RegionHandle, UUID.Zero, pos + new Vector3(1f, 1f, 1f)); - // m_scene.AddNewSceneObject(sceneObject, true); - // } - - public void Close() - { - m_scene = null; - } - - public string Name - { - get { return GetType().AssemblyQualifiedName; } - } - - public bool IsSharedModule - { - get { return false; } - } - - #endregion - } -} diff --git a/prebuild.xml b/prebuild.xml index 690de5ae88..a204c0fa96 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2052,34 +2052,6 @@ - - - - bin/ - - - - - bin/ - - - - ../../../../bin/ - - - - - - - - - - - - - - - From 56dbab35e122e724c9277b05820417a05ad8a1be Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 1 Oct 2011 01:26:50 +0100 Subject: [PATCH 55/64] Remove unimplementated UpdateMovement() methods from SOG, SOP. SP still has an implementation but this is now just a public method on SP rather than an abstract one in EntityBase. No point making the code more complex until it actually needs to be, --- OpenSim/Region/Framework/Scenes/EntityBase.cs | 5 ----- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 7 ------- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 4 ---- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 4 files changed, 1 insertion(+), 17 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/EntityBase.cs b/OpenSim/Region/Framework/Scenes/EntityBase.cs index 320b904ff4..680a4a3214 100644 --- a/OpenSim/Region/Framework/Scenes/EntityBase.cs +++ b/OpenSim/Region/Framework/Scenes/EntityBase.cs @@ -114,11 +114,6 @@ namespace OpenSim.Region.Framework.Scenes m_name = "(basic entity)"; } - /// - /// - /// - public abstract void UpdateMovement(); - /// /// Performs any updates that need to be done at each frame, as opposed to immediately. /// These included scheduled updates and updates that occur due to physics processing. diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 234eb7d2ea..d983d7f79d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1005,13 +1005,6 @@ namespace OpenSim.Region.Framework.Scenes part.ClearUndoState(); } - public override void UpdateMovement() - { - SceneObjectPart[] parts = m_parts.GetArray(); - for (int i = 0; i < parts.Length; i++) - parts[i].UpdateMovement(); - } - public ushort GetTimeDilation() { return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index d631c12bfc..6fa82b8a88 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4189,10 +4189,6 @@ namespace OpenSim.Region.Framework.Scenes } } - public virtual void UpdateMovement() - { - } - /// /// /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 5b02c3bfc0..b3e04be98d 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3313,7 +3313,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Handles part of the PID controller function for moving an avatar. /// - public override void UpdateMovement() + public void UpdateMovement() { if (m_forceToApply.HasValue) { From 31125a5fd275a37261d87a336385f5447a62004e Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 3 Oct 2011 11:16:48 -0700 Subject: [PATCH 56/64] Add execute permission to runprebuild2010.bat --- runprebuild2010.bat | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 runprebuild2010.bat diff --git a/runprebuild2010.bat b/runprebuild2010.bat old mode 100644 new mode 100755 From e77c919290e166f19e77f3ef040418dd39f2f5bd Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 3 Oct 2011 11:55:54 -0700 Subject: [PATCH 57/64] Remove usage of Linden packet types from inside Attachments Module and interface --- OpenSim/Framework/IClientAPI.cs | 3 +-- OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 7 ++++--- .../CoreModules/Avatar/Attachments/AttachmentsModule.cs | 9 ++++----- .../Region/Framework/Interfaces/IAttachmentsModule.cs | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 47e79d133e..d8ccc89f98 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -53,8 +53,7 @@ namespace OpenSim.Framework public delegate ISceneEntity RezSingleAttachmentFromInv(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); - public delegate void RezMultipleAttachmentsFromInv(IClientAPI remoteClient, RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, - RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects); + public delegate void RezMultipleAttachmentsFromInv(IClientAPI remoteClient, List> rezlist ); public delegate void ObjectAttach( IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index ce2ff86513..29dce176d6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -6079,9 +6079,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP RezMultipleAttachmentsFromInv handlerRezMultipleAttachments = OnRezMultipleAttachmentsFromInv; if (handlerRezMultipleAttachments != null) { - RezMultipleAttachmentsFromInvPacket rez = (RezMultipleAttachmentsFromInvPacket)Pack; - handlerRezMultipleAttachments(this, rez.HeaderData, - rez.ObjectData); + List> rezlist = new List>(); + foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in ((RezMultipleAttachmentsFromInvPacket)Pack).ObjectData) + rezlist.Add(new KeyValuePair(obj.ItemID, obj.AttachmentPt)); + handlerRezMultipleAttachments(this, rezlist); } return true; diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 8757251379..48695a4585 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -360,8 +360,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void RezMultipleAttachmentsFromInventory( IClientAPI remoteClient, - RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, - RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) + List> rezlist) { if (!Enabled) return; @@ -380,9 +379,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); - foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) + foreach (KeyValuePair rez in rezlist) { - RezSingleAttachmentFromInventory(sp, obj.ItemID, obj.AttachmentPt); + RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); } } } @@ -941,4 +940,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return item; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 5ffbec873b..8d3366c062 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using OpenMetaverse; using OpenMetaverse.Packets; using OpenSim.Framework; @@ -104,8 +105,7 @@ namespace OpenSim.Region.Framework.Interfaces /// void RezMultipleAttachmentsFromInventory( IClientAPI remoteClient, - RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, - RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects); + List> rezlist); /// /// Detach an object from the avatar. From 37ae6451f9ddb2e07402a5e79a9ab58668781104 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 3 Oct 2011 23:25:09 +0100 Subject: [PATCH 58/64] Remove vestigal RegionStatus.SlaveScene. This appears to be code clutter since the code that uses this has long gone. --- OpenSim/Framework/IScene.cs | 3 - .../ClientStack/Linden/UDP/LLUDPServer.cs | 22 ++--- OpenSim/Region/Framework/Scenes/Scene.cs | 91 +++++++++---------- 3 files changed, 51 insertions(+), 65 deletions(-) diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index 8f7a2e5b4e..e0cb897e40 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -33,15 +33,12 @@ namespace OpenSim.Framework { public delegate void restart(RegionInfo thisRegion); - //public delegate void regionup (RegionInfo thisRegion); - public enum RegionStatus : int { Down = 0, Up = 1, Crashed = 2, Starting = 3, - SlaveScene = 4 }; /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index f2388cdf54..304efe6608 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -929,25 +929,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP UUID sessionID = useCircuitCode.CircuitCode.SessionID; uint circuitCode = useCircuitCode.CircuitCode.Code; - if (m_scene.RegionStatus != RegionStatus.SlaveScene) + AuthenticateResponse sessionInfo; + if (IsClientAuthorized(useCircuitCode, out sessionInfo)) { - AuthenticateResponse sessionInfo; - if (IsClientAuthorized(useCircuitCode, out sessionInfo)) - { - AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); - } - else - { - // Don't create circuits for unauthorized clients - m_log.WarnFormat( - "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", - useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); - } + AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo); } else { - // Slave regions don't accept new clients - m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet"); + // Don't create circuits for unauthorized clients + m_log.WarnFormat( + "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", + useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index eadec09df3..88b682bf8b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1278,56 +1278,53 @@ namespace OpenSim.Region.Framework.Scenes tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS); } - if (RegionStatus != RegionStatus.SlaveScene) + if (Frame % m_update_events == 0) { - if (Frame % m_update_events == 0) - { - int evMS = Util.EnvironmentTickCount(); - UpdateEvents(); - eventMS = Util.EnvironmentTickCountSubtract(evMS); ; - } - - if (Frame % m_update_backup == 0) - { - int backMS = Util.EnvironmentTickCount(); - UpdateStorageBackup(); - backupMS = Util.EnvironmentTickCountSubtract(backMS); - } - - if (Frame % m_update_terrain == 0) - { - int terMS = Util.EnvironmentTickCount(); - UpdateTerrain(); - terrainMS = Util.EnvironmentTickCountSubtract(terMS); - } - - //if (Frame % m_update_land == 0) - //{ - // int ldMS = Util.EnvironmentTickCount(); - // UpdateLand(); - // landMS = Util.EnvironmentTickCountSubtract(ldMS); - //} - - frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS); - otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; - lastCompletedFrame = Util.EnvironmentTickCount(); - - // if (Frame%m_update_avatars == 0) - // UpdateInWorldTime(); - StatsReporter.AddPhysicsFPS(physicsFPS); - StatsReporter.AddTimeDilation(TimeDilation); - StatsReporter.AddFPS(1); - StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount()); - StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount()); - StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount()); - StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount()); - StatsReporter.addFrameMS(frameMS); - StatsReporter.addPhysicsMS(physicsMS + physicsMS2); - StatsReporter.addOtherMS(otherMS); - StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount()); - StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); + int evMS = Util.EnvironmentTickCount(); + UpdateEvents(); + eventMS = Util.EnvironmentTickCountSubtract(evMS); ; } + if (Frame % m_update_backup == 0) + { + int backMS = Util.EnvironmentTickCount(); + UpdateStorageBackup(); + backupMS = Util.EnvironmentTickCountSubtract(backMS); + } + + if (Frame % m_update_terrain == 0) + { + int terMS = Util.EnvironmentTickCount(); + UpdateTerrain(); + terrainMS = Util.EnvironmentTickCountSubtract(terMS); + } + + //if (Frame % m_update_land == 0) + //{ + // int ldMS = Util.EnvironmentTickCount(); + // UpdateLand(); + // landMS = Util.EnvironmentTickCountSubtract(ldMS); + //} + + frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS); + otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; + lastCompletedFrame = Util.EnvironmentTickCount(); + + // if (Frame%m_update_avatars == 0) + // UpdateInWorldTime(); + StatsReporter.AddPhysicsFPS(physicsFPS); + StatsReporter.AddTimeDilation(TimeDilation); + StatsReporter.AddFPS(1); + StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount()); + StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount()); + StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount()); + StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount()); + StatsReporter.addFrameMS(frameMS); + StatsReporter.addPhysicsMS(physicsMS + physicsMS2); + StatsReporter.addOtherMS(otherMS); + StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount()); + StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); + if (LoginsDisabled && Frame == 20) { // In 99.9% of cases it is a bad idea to manually force garbage collection. However, From 8a6e6866d9c6c60e4a2e4b980ca2e35ae3963d0d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 4 Oct 2011 00:07:52 +0100 Subject: [PATCH 59/64] For llGetTexture(), if the face texture asset is in the inventory, return the inventory name rather than the asset UUID This is as per http://wiki.secondlife.com/wiki/LlGetTexture Applied patch in http://opensimulator.org/mantis/view.php?id=4552 with an additional break statement if an inventory item is found to exit early. Thanks Michelle Argus! --- .../Shared/Api/Implementation/LSL_Api.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 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 9a26f4b79a..8291105b0b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1912,11 +1912,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { face = 0; } + if (face >= 0 && face < GetNumberOfSides(part)) { Primitive.TextureEntryFace texface; texface = tex.GetFace((uint)face); - return texface.TextureID.ToString(); + string texture = texface.TextureID.ToString(); + + lock (part.TaskInventory) + { + foreach (KeyValuePair inv in part.TaskInventory) + { + if (inv.Value.AssetID == texface.TextureID) + { + texture = inv.Value.Name.ToString(); + break; + } + } + } + + return texture; } else { From a8af0a5ba873dbb8c447e16b142ba7f5af715bdb Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 4 Oct 2011 00:15:48 +0100 Subject: [PATCH 60/64] Return NULL_KEY from llGetTexture if a non-existent face is indicated, rather than "" As per http://wiki.secondlife.com/wiki/LlGetTexture --- .../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 8291105b0b..5ede801083 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1935,7 +1935,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } else { - return String.Empty; + return UUID.Zero.ToString(); } } From b98442dceccd416a493f19153f5daad2e173183e Mon Sep 17 00:00:00 2001 From: Pixel Tomsen Date: Sat, 1 Oct 2011 17:31:59 +0200 Subject: [PATCH 61/64] Animation-States Turning Left, Turning Right implemented/enabled http://opensimulator.org/mantis/view.php?id=3036 --- .../Framework/Scenes/Animation/ScenePresenceAnimator.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index e07d8b4308..e9e1845d4c 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -174,8 +174,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation bool heldBack = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG; bool heldLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS; bool heldRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG; - //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; - //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; + bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; + bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; bool heldDown = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG; //bool flying = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) == AgentManager.ControlFlags.AGENT_CONTROL_FLY; @@ -317,6 +317,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation // Not walking if (move.Z < 0) return "CROUCH"; + else if (heldTurnLeft) + return "TURNLEFT"; + else if (heldTurnRight) + return "TURNRIGHT"; else return "STAND"; } From c7d0d71666a92b201d639511d062a7c22726b3c9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 4 Oct 2011 00:37:02 +0100 Subject: [PATCH 62/64] trival tweak to trigger the continuous integration system --- .../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 5ede801083..f8327b93ba 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -4240,8 +4240,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llCollisionSound(string impact_sound, double impact_volume) { - m_host.AddScriptLPS(1); + // TODO: Parameter check logic required. UUID soundId = UUID.Zero; if (!UUID.TryParse(impact_sound, out soundId)) From 460946ad62b682c7a942751f192ca9e96b662f0e Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 3 Oct 2011 16:44:32 -0700 Subject: [PATCH 63/64] Removed redundant code in AttachmentsModule and simplified interfaces which converted back and forth between ScenePresence and IClientAPI. More to be done still. --- .../Avatar/Attachments/AttachmentsModule.cs | 156 ++++++++---------- .../Tests/AttachmentsModuleTests.cs | 10 +- .../Interfaces/IAttachmentsModule.cs | 35 +--- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- .../World/NPC/Tests/NPCModuleTests.cs | 6 +- .../Shared/Api/Implementation/LSL_Api.cs | 3 +- 6 files changed, 82 insertions(+), 130 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 48695a4585..78b9afcd8f 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -152,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (sp.PresenceType == PresenceType.Npc) RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p); else - RezSingleAttachmentFromInventory(sp.ControllingClient, attach.ItemID, p); + RezSingleAttachmentFromInventory(sp, attach.ItemID, p); } catch (Exception e) { @@ -204,7 +204,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// - public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) + private void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", @@ -258,25 +258,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); } } - - public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) - { - if (!Enabled) - return false; - - ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); - - if (sp == null) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); - return false; - } - - return AttachObject(sp, group, AttachmentPt, silent); - } - private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) + public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) { lock (sp.AttachmentsSyncLock) { @@ -356,29 +339,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } return true; + } + + private void RezMultipleAttachmentsFromInventory(IClientAPI remoteClient, List> rezlist) + { + if (!Enabled) + return; + + ScenePresence sp; + if (m_scene.TryGetScenePresence(remoteClient.AgentId, out sp)) + RezMultipleAttachmentsFromInventory(sp, rezlist); + else + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", + remoteClient.Name, remoteClient.AgentId); + return; } - public void RezMultipleAttachmentsFromInventory( - IClientAPI remoteClient, - List> rezlist) + public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List> rezlist) { if (!Enabled) - return; - - ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); - - if (sp == null) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", - remoteClient.Name, remoteClient.AgentId); - return; - } - + return; + +// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); lock (sp.AttachmentsSyncLock) { -// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); - foreach (KeyValuePair rez in rezlist) { RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); @@ -386,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } - public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + private ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { if (!Enabled) return null; @@ -408,7 +393,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); } - public ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt) + public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) { if (!Enabled) return null; @@ -593,23 +578,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments DetachSingleAttachmentToInv(itemID, presence); } } + } + + private void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient) + { + if (!Enabled) + return; + + ScenePresence sp; + if (m_scene.TryGetScenePresence(remoteClient.AgentId, out sp)) + DetachSingleAttachmentToGround(sp, soLocalId); } - public void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient) + public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) { if (!Enabled) return; // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", -// remoteClient.Name, soLocalId); +// sp.UUID, soLocalId); SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); if (so == null) return; - if (so.AttachedAvatar != remoteClient.AgentId) + if (so.AttachedAvatar != sp.UUID) return; UUID inventoryID = so.GetFromItemID(); @@ -618,57 +613,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}", // so.Name, so.LocalId, inventoryID); - ScenePresence presence; - if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) + lock (sp.AttachmentsSyncLock) { - lock (presence.AttachmentsSyncLock) - { - if (!m_scene.Permissions.CanRezObject( - so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) - return; + if (!m_scene.Permissions.CanRezObject( + so.PrimCount, sp.UUID, sp.AbsolutePosition)) + return; + + bool changed = sp.Appearance.DetachAttachment(inventoryID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); + + sp.RemoveAttachment(so); + + SceneObjectPart rootPart = so.RootPart; + rootPart.FromItemID = UUID.Zero; + so.AbsolutePosition = sp.AbsolutePosition; + so.AttachedAvatar = UUID.Zero; + rootPart.SetParentLocalId(0); + so.ClearPartAttachmentData(); + rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); + so.HasGroupChanged = true; + rootPart.Rezzed = DateTime.Now; + rootPart.RemFlag(PrimFlags.TemporaryOnRez); + so.AttachToBackup(); + m_scene.EventManager.TriggerParcelPrimCountTainted(); + rootPart.ScheduleFullUpdate(); + rootPart.ClearUndoState(); - bool changed = presence.Appearance.DetachAttachment(inventoryID); - if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); - - presence.RemoveAttachment(so); - DetachSceneObjectToGround(so, presence); - - List uuids = new List(); - uuids.Add(inventoryID); - m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids); - remoteClient.SendRemoveInventoryItem(inventoryID); - } - - m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); + List uuids = new List(); + uuids.Add(inventoryID); + m_scene.InventoryService.DeleteItems(sp.UUID, uuids); + sp.ControllingClient.SendRemoveInventoryItem(inventoryID); } - } - /// - /// Detach the given scene object to the ground. - /// - /// - /// The caller has to take care of all the other work in updating avatar appearance, inventory, etc. - /// - /// The scene object to detach. - /// The scene presence from which the scene object is being detached. - private void DetachSceneObjectToGround(SceneObjectGroup so, ScenePresence sp) - { - SceneObjectPart rootPart = so.RootPart; - - rootPart.FromItemID = UUID.Zero; - so.AbsolutePosition = sp.AbsolutePosition; - so.AttachedAvatar = UUID.Zero; - rootPart.SetParentLocalId(0); - so.ClearPartAttachmentData(); - rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); - so.HasGroupChanged = true; - rootPart.Rezzed = DateTime.Now; - rootPart.RemFlag(PrimFlags.TemporaryOnRez); - so.AttachToBackup(); - m_scene.EventManager.TriggerParcelPrimCountTainted(); - rootPart.ScheduleFullUpdate(); - rootPart.ClearUndoState(); + m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); } // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index ff3358f4fe..832c6eba7c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName).ParentGroup; - m_attMod.AttachObject(m_presence.ControllingClient, so, (uint)AttachmentPoint.Chest, false); + m_attMod.AttachObject(m_presence, so, (uint)AttachmentPoint.Chest, false); // Check status on scene presence Assert.That(m_presence.HasAttachments(), Is.True); @@ -140,7 +140,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); m_attMod.RezSingleAttachmentFromInventory( - m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); + m_presence, attItemId, (uint)AttachmentPoint.Chest); // Check scene presence status Assert.That(m_presence.HasAttachments(), Is.True); @@ -174,8 +174,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); ISceneEntity so = m_attMod.RezSingleAttachmentFromInventory( - m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); - m_attMod.DetachSingleAttachmentToGround(so.LocalId, m_presence.ControllingClient); + m_presence, attItemId, (uint)AttachmentPoint.Chest); + m_attMod.DetachSingleAttachmentToGround(m_presence, so.LocalId); // Check scene presence status Assert.That(m_presence.HasAttachments(), Is.False); @@ -208,7 +208,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); m_attMod.RezSingleAttachmentFromInventory( - m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); + m_presence, attItemId, (uint)AttachmentPoint.Chest); m_attMod.DetachSingleAttachmentToInv(attItemId, m_presence.ControllingClient); // Check status on scene presence diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 8d3366c062..1a0423f33d 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -57,17 +57,6 @@ namespace OpenSim.Region.Framework.Interfaces /// void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); - /// - /// Attach an object to an avatar from the world. - /// - /// - /// - /// - /// - /// - void AttachObject( - IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent); - /// /// Attach an object to an avatar /// @@ -76,17 +65,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// true if the object was successfully attached, false otherwise - bool AttachObject( - IClientAPI remoteClient, SceneObjectGroup grp, uint AttachmentPt, bool silent); - - /// - /// Rez an attachment from user inventory and change inventory status to match. - /// - /// - /// - /// - /// The scene object that was attached. Null if the scene object could not be found - ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); + bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent); /// /// Rez an attachment from user inventory and change inventory status to match. @@ -95,17 +74,15 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// The scene object that was attached. Null if the scene object could not be found - ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt); + ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt); /// /// Rez multiple attachments from a user's inventory /// - /// + /// /// /// - void RezMultipleAttachmentsFromInventory( - IClientAPI remoteClient, - List> rezlist); + void RezMultipleAttachmentsFromInventory(IScenePresence sp,List> rezlist); /// /// Detach an object from the avatar. @@ -121,9 +98,9 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Detach the given item to the ground. /// + /// /// - /// - void DetachSingleAttachmentToGround(uint objectLocalID, IClientAPI remoteClient); + void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID); /// /// Detach the given item so that it remains in the user's inventory. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index eadec09df3..0e5a7d25d2 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2451,7 +2451,7 @@ namespace OpenSim.Region.Framework.Scenes RootPrim.RemFlag(PrimFlags.TemporaryOnRez); if (AttachmentsModule != null) - AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false); + AttachmentsModule.AttachObject(sp, grp, 0, false); } else { diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 1a0d0c742d..49c06bcfcd 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -132,11 +132,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests UUID attAssetId = TestHelpers.ParseTail(0x3); string attName = "att"; - UserInventoryHelpers.CreateInventoryItem( - scene, attName, attItemId, attAssetId, sp.UUID, InventoryType.Object); + UserInventoryHelpers.CreateInventoryItem(scene, attName, attItemId, attAssetId, sp.UUID, InventoryType.Object); - am.RezSingleAttachmentFromInventory( - sp.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); + am.RezSingleAttachmentFromInventory(sp, attItemId, (uint)AttachmentPoint.Chest); INPCModule npcModule = scene.RequestModuleInterface(); UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, sp.Appearance); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 9a26f4b79a..4b2fb511bd 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2966,8 +2966,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; if (attachmentsModule != null) - attachmentsModule.AttachObject(presence.ControllingClient, - grp, (uint)attachment, false); + attachmentsModule.AttachObject(presence, grp, (uint)attachment, false); } } From 92c88121c72386f85472c6cf4891eca8b62b9867 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Tue, 4 Oct 2011 14:40:39 -0700 Subject: [PATCH 64/64] Removed all refs to IClientAPI from IAttachmentsModule. Separated client handlers for attachments to call public interface and rearranged module file into sections --- .../Avatar/Attachments/AttachmentsModule.cs | 734 +++++++++--------- .../Tests/AttachmentsModuleTests.cs | 2 +- .../Interfaces/IAttachmentsModule.cs | 31 +- .../Shared/Api/Implementation/LSL_Api.cs | 2 +- 4 files changed, 385 insertions(+), 384 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 78b9afcd8f..f893eb38ec 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -44,6 +44,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] public class AttachmentsModule : IAttachmentsModule, INonSharedRegionModule { + #region INonSharedRegionModule private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; @@ -92,26 +93,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { RemoveRegion(m_scene); } - - public void SubscribeToClientEvents(IClientAPI client) - { - client.OnRezSingleAttachmentFromInv += RezSingleAttachmentFromInventory; - client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; - client.OnObjectAttach += AttachObject; - client.OnObjectDetach += DetachObject; - client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv; - client.OnObjectDrop += DetachSingleAttachmentToGround; - } - - public void UnsubscribeFromClientEvents(IClientAPI client) - { - client.OnRezSingleAttachmentFromInv -= RezSingleAttachmentFromInventory; - client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; - client.OnObjectAttach -= AttachObject; - client.OnObjectDetach -= DetachObject; - client.OnDetachAttachmentIntoInv -= DetachSingleAttachmentToInv; - client.OnObjectDrop -= DetachSingleAttachmentToGround; - } + + #endregion + + #region IAttachmentsModule /// /// RezAttachments. This should only be called upon login on the first region. @@ -174,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // { grp.IsAttachment = false; grp.AbsolutePosition = grp.RootPart.AttachedPos; - UpdateKnownItem(sp.ControllingClient, grp); + UpdateKnownItem(sp, grp); grp.IsAttachment = true; // } } @@ -197,68 +182,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments sp.ClearAttachments(); } - /// - /// Called by client - /// - /// - /// - /// - /// - private void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) - { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", -// objectLocalID, remoteClient.Name, AttachmentPt, silent); - - if (!Enabled) - return; - - try - { - ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); - - if (sp == null) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); - return; - } - - // If we can't take it, we can't attach it! - SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); - if (part == null) - return; - - if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) - { - remoteClient.SendAgentAlertMessage( - "You don't have sufficient permissions to attach this object", false); - - return; - } - - // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should - // be removed when that functionality is implemented in opensim - AttachmentPt &= 0x7f; - - // Calls attach with a Zero position - if (AttachObject(sp, part.ParentGroup, AttachmentPt, false)) - { - m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); - - // Save avatar attachment information - m_log.Debug( - "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId - + ", AttachmentPoint: " + AttachmentPt); - - } - } - catch (Exception e) - { - m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); - } - } - public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) { lock (sp.AttachmentsSyncLock) @@ -320,7 +243,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments UUID oldAttachmentItemID = attachments[0].GetFromItemID(); if (oldAttachmentItemID != UUID.Zero) - DetachSingleAttachmentToInv(oldAttachmentItemID, sp); + DetachSingleAttachmentToInvInternal(sp, oldAttachmentItemID); else m_log.WarnFormat( "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!", @@ -330,7 +253,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Add the new attachment to inventory if we don't already have it. UUID newAttachmentItemID = group.GetFromItemID(); if (newAttachmentItemID == UUID.Zero) - newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; + newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); } @@ -339,58 +262,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } return true; - } - - private void RezMultipleAttachmentsFromInventory(IClientAPI remoteClient, List> rezlist) - { - if (!Enabled) - return; - - ScenePresence sp; - if (m_scene.TryGetScenePresence(remoteClient.AgentId, out sp)) - RezMultipleAttachmentsFromInventory(sp, rezlist); - else - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", - remoteClient.Name, remoteClient.AgentId); - return; - } - - public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List> rezlist) - { - if (!Enabled) - return; - -// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); - lock (sp.AttachmentsSyncLock) - { - foreach (KeyValuePair rez in rezlist) - { - RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); - } - } - } - - private ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) - { - if (!Enabled) - return null; - -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", -// (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); - - ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); - - if (sp == null) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", - remoteClient.Name, remoteClient.AgentId); - return null; - } - - return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); } public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) @@ -435,159 +306,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); if (att == null) - DetachSingleAttachmentToInv(itemID, sp.ControllingClient); + DetachSingleAttachmentToInv(sp, itemID); return att; } - private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( - IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) - { - IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); - if (invAccess != null) - { - lock (sp.AttachmentsSyncLock) - { - SceneObjectGroup objatt; - - if (itemID != UUID.Zero) - objatt = invAccess.RezObject(sp.ControllingClient, - itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, - false, false, sp.UUID, true); - else - objatt = invAccess.RezObject(sp.ControllingClient, - null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, - false, false, sp.UUID, true); - - // m_log.DebugFormat( - // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", - // objatt.Name, remoteClient.Name, AttachmentPt); - - if (objatt != null) - { - // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. - objatt.HasGroupChanged = false; - bool tainted = false; - if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) - tainted = true; - - // This will throw if the attachment fails - try - { - AttachObject(sp, objatt, attachmentPt, false); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", - objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); - - // Make sure the object doesn't stick around and bail - sp.RemoveAttachment(objatt); - m_scene.DeleteSceneObject(objatt, false); - return null; - } - - if (tainted) - objatt.HasGroupChanged = true; - - // Fire after attach, so we don't get messy perms dialogs - // 4 == AttachedRez - objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); - objatt.ResumeScripts(); - - // Do this last so that event listeners have access to all the effects of the attachment - m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); - - return objatt; - } - else - { - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", - itemID, sp.Name, attachmentPt); - } - } - } - - return null; - } - - /// - /// Update the user inventory to reflect an attachment - /// - /// - /// - /// - /// - private void ShowAttachInUserInventory( - IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) - { -// m_log.DebugFormat( -// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", -// att.Name, sp.Name, AttachmentPt, itemID); - - if (UUID.Zero == itemID) - { - m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID."); - return; - } - - if (0 == AttachmentPt) - { - m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point."); - return; - } - - InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); - item = m_scene.InventoryService.GetItem(item); - bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); - if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); - } - - public void DetachObject(uint objectLocalID, IClientAPI remoteClient) - { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: DetachObject() for object {0} on {1}", objectLocalID, remoteClient.Name); - - SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); - if (group != null) - { - DetachSingleAttachmentToInv(group.GetFromItemID(), remoteClient); - } - } - - public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) + public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List> rezlist) { if (!Enabled) return; - ScenePresence presence; - if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) + // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); + lock (sp.AttachmentsSyncLock) { - lock (presence.AttachmentsSyncLock) + foreach (KeyValuePair rez in rezlist) { - // Save avatar attachment information - m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); - - bool changed = presence.Appearance.DetachAttachment(itemID); - if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); - - DetachSingleAttachmentToInv(itemID, presence); + RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); } } - } - - private void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient) - { - if (!Enabled) - return; - - ScenePresence sp; - if (m_scene.TryGetScenePresence(remoteClient.AgentId, out sp)) - DetachSingleAttachmentToGround(sp, soLocalId); } public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) @@ -617,27 +353,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { if (!m_scene.Permissions.CanRezObject( so.PrimCount, sp.UUID, sp.AbsolutePosition)) - return; - + return; + bool changed = sp.Appearance.DetachAttachment(inventoryID); if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); - - sp.RemoveAttachment(so); - - SceneObjectPart rootPart = so.RootPart; - rootPart.FromItemID = UUID.Zero; - so.AbsolutePosition = sp.AbsolutePosition; - so.AttachedAvatar = UUID.Zero; - rootPart.SetParentLocalId(0); - so.ClearPartAttachmentData(); - rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); - so.HasGroupChanged = true; - rootPart.Rezzed = DateTime.Now; - rootPart.RemFlag(PrimFlags.TemporaryOnRez); - so.AttachToBackup(); - m_scene.EventManager.TriggerParcelPrimCountTainted(); - rootPart.ScheduleFullUpdate(); + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); + + sp.RemoveAttachment(so); + + SceneObjectPart rootPart = so.RootPart; + rootPart.FromItemID = UUID.Zero; + so.AbsolutePosition = sp.AbsolutePosition; + so.AttachedAvatar = UUID.Zero; + rootPart.SetParentLocalId(0); + so.ClearPartAttachmentData(); + rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); + so.HasGroupChanged = true; + rootPart.Rezzed = DateTime.Now; + rootPart.RemFlag(PrimFlags.TemporaryOnRez); + so.AttachToBackup(); + m_scene.EventManager.TriggerParcelPrimCountTainted(); + rootPart.ScheduleFullUpdate(); rootPart.ClearUndoState(); List uuids = new List(); @@ -648,46 +384,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); } - - // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. - // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? - private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp) + + public void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID) { -// m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); - - if (itemID == UUID.Zero) // If this happened, someone made a mistake.... - return; - - // We can NOT use the dictionries here, as we are looking - // for an entity by the fromAssetID, which is NOT the prim UUID - EntityBase[] detachEntities = m_scene.GetEntities(); - SceneObjectGroup group; - lock (sp.AttachmentsSyncLock) { - foreach (EntityBase entity in detachEntities) - { - if (entity is SceneObjectGroup) - { - group = (SceneObjectGroup)entity; - if (group.GetFromItemID() == itemID) - { - m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); - sp.RemoveAttachment(group); + // Save avatar attachment information + m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); - // Prepare sog for storage - group.AttachedAvatar = UUID.Zero; - group.RootPart.SetParentLocalId(0); - group.IsAttachment = false; - group.AbsolutePosition = group.RootPart.AttachedPos; + bool changed = sp.Appearance.DetachAttachment(itemID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); - UpdateKnownItem(sp.ControllingClient, group); - m_scene.DeleteSceneObject(group, false); - - return; - } - } - } + DetachSingleAttachmentToInvInternal(sp, itemID); } } @@ -709,7 +418,37 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments sog.AttachmentPoint = attachmentPoint; sog.HasGroupChanged = true; } - + + #endregion + + #region AttachmentModule private methods + + // This is public but is not part of the IAttachmentsModule interface. + // RegionCombiner module needs to poke at it to deliver client events. + // This breaks the encapsulation of the module and should get fixed somehow. + public void SubscribeToClientEvents(IClientAPI client) + { + client.OnRezSingleAttachmentFromInv += Client_OnRezSingleAttachmentFromInv; + client.OnRezMultipleAttachmentsFromInv += Client_OnRezMultipleAttachmentsFromInv; + client.OnObjectAttach += Client_OnObjectAttach; + client.OnObjectDetach += Client_OnObjectDetach; + client.OnDetachAttachmentIntoInv += Client_OnDetachAttachmentIntoInv; + client.OnObjectDrop += Client_OnObjectDrop; + } + + // This is public but is not part of the IAttachmentsModule interface. + // RegionCombiner module needs to poke at it to deliver client events. + // This breaks the encapsulation of the module and should get fixed somehow. + public void UnsubscribeFromClientEvents(IClientAPI client) + { + client.OnRezSingleAttachmentFromInv -= Client_OnRezSingleAttachmentFromInv; + client.OnRezMultipleAttachmentsFromInv -= Client_OnRezMultipleAttachmentsFromInv; + client.OnObjectAttach -= Client_OnObjectAttach; + client.OnObjectDetach -= Client_OnObjectDetach; + client.OnDetachAttachmentIntoInv -= Client_OnDetachAttachmentIntoInv; + client.OnObjectDrop -= Client_OnObjectDrop; + } + /// /// Update the attachment asset for the new sog details if they have changed. /// @@ -717,9 +456,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects, /// these details are not stored on the region. /// - /// + /// /// - private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp) + private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp) { if (grp.HasGroupChanged || grp.ContainsScripts()) { @@ -729,7 +468,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); - InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), remoteClient.AgentId); + InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), sp.UUID); item = m_scene.InventoryService.GetItem(item); if (item != null) @@ -739,7 +478,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments grp.GetPartDescription(grp.LocalId), (sbyte)AssetType.Object, Utils.StringToBytes(sceneObjectXml), - remoteClient.AgentId); + sp.UUID); m_scene.AssetService.Store(asset); item.AssetID = asset.FullID; @@ -751,8 +490,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.InventoryService.UpdateItem(item); // this gets called when the agent logs off! - if (remoteClient != null) - remoteClient.SendInventoryItemCreateUpdate(item, 0); + if (sp.ControllingClient != null) + sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); } } else @@ -761,8 +500,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", grp.UUID, grp.AttachmentPoint); } - } - + } + /// /// Attach this scene object to the given avatar. /// @@ -776,19 +515,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// private void AttachToAgent( - IScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) + IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", -// so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); - + // m_log.DebugFormat( + // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", + // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); + so.DetachFromBackup(); // Remove from database and parcel prim count m_scene.DeleteFromStorage(so.UUID); m_scene.EventManager.TriggerParcelPrimCountTainted(); - so.AttachedAvatar = avatar.UUID; + so.AttachedAvatar = sp.UUID; if (so.RootPart.PhysActor != null) { @@ -799,10 +538,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments so.AbsolutePosition = attachOffset; so.RootPart.AttachedPos = attachOffset; so.IsAttachment = true; - so.RootPart.SetParentLocalId(avatar.LocalId); + so.RootPart.SetParentLocalId(sp.LocalId); so.AttachmentPoint = attachmentpoint; - avatar.AddAttachment(so); + sp.AddAttachment(so); if (!silent) { @@ -818,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(); } - + // In case it is later dropped again, don't let // it get cleaned up so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); @@ -830,11 +569,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// The user inventory item created that holds the attachment. - private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IClientAPI remoteClient, SceneObjectGroup grp) + private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp) { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", -// grp.Name, grp.LocalId, remoteClient.Name); + // m_log.DebugFormat( + // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", + // grp.Name, grp.LocalId, remoteClient.Name); Vector3 inventoryStoredPosition = new Vector3 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) @@ -863,14 +602,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments grp.GetPartDescription(grp.LocalId), (sbyte)AssetType.Object, Utils.StringToBytes(sceneObjectXml), - remoteClient.AgentId); + sp.UUID); m_scene.AssetService.Store(asset); InventoryItemBase item = new InventoryItemBase(); item.CreatorId = grp.RootPart.CreatorID.ToString(); item.CreatorData = grp.RootPart.CreatorData; - item.Owner = remoteClient.AgentId; + item.Owner = sp.UUID; item.ID = UUID.Random(); item.AssetID = asset.FullID; item.Description = asset.Description; @@ -878,13 +617,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments item.AssetType = asset.Type; item.InvType = (int)InventoryType.Object; - InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object); + InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); if (folder != null) item.Folder = folder.ID; else // oopsies item.Folder = UUID.Zero; - if ((remoteClient.AgentId != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) + if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) { item.BasePermissions = grp.RootPart.NextOwnerMask; item.CurrentPermissions = grp.RootPart.NextOwnerMask; @@ -907,15 +646,290 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (m_scene.AddInventoryItem(item)) { - remoteClient.SendInventoryItemCreateUpdate(item, 0); + sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); } else { if (m_dialogModule != null) - m_dialogModule.SendAlertToUser(remoteClient, "Operation failed"); + m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed"); } return item; } + + // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. + // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? + private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID) + { + // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); + + if (itemID == UUID.Zero) // If this happened, someone made a mistake.... + return; + + // We can NOT use the dictionries here, as we are looking + // for an entity by the fromAssetID, which is NOT the prim UUID + EntityBase[] detachEntities = m_scene.GetEntities(); + SceneObjectGroup group; + + lock (sp.AttachmentsSyncLock) + { + foreach (EntityBase entity in detachEntities) + { + if (entity is SceneObjectGroup) + { + group = (SceneObjectGroup)entity; + if (group.GetFromItemID() == itemID) + { + m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); + sp.RemoveAttachment(group); + + // Prepare sog for storage + group.AttachedAvatar = UUID.Zero; + group.RootPart.SetParentLocalId(0); + group.IsAttachment = false; + group.AbsolutePosition = group.RootPart.AttachedPos; + + UpdateKnownItem(sp, group); + m_scene.DeleteSceneObject(group, false); + + return; + } + } + } + } + } + + private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( + IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) + { + IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); + if (invAccess != null) + { + lock (sp.AttachmentsSyncLock) + { + SceneObjectGroup objatt; + + if (itemID != UUID.Zero) + objatt = invAccess.RezObject(sp.ControllingClient, + itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + false, false, sp.UUID, true); + else + objatt = invAccess.RezObject(sp.ControllingClient, + null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + false, false, sp.UUID, true); + + // m_log.DebugFormat( + // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", + // objatt.Name, remoteClient.Name, AttachmentPt); + + if (objatt != null) + { + // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. + objatt.HasGroupChanged = false; + bool tainted = false; + if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) + tainted = true; + + // This will throw if the attachment fails + try + { + AttachObject(sp, objatt, attachmentPt, false); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", + objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); + + // Make sure the object doesn't stick around and bail + sp.RemoveAttachment(objatt); + m_scene.DeleteSceneObject(objatt, false); + return null; + } + + if (tainted) + objatt.HasGroupChanged = true; + + // Fire after attach, so we don't get messy perms dialogs + // 4 == AttachedRez + objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); + objatt.ResumeScripts(); + + // Do this last so that event listeners have access to all the effects of the attachment + m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); + + return objatt; + } + else + { + m_log.WarnFormat( + "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", + itemID, sp.Name, attachmentPt); + } + } + } + + return null; + } + + /// + /// Update the user inventory to reflect an attachment + /// + /// + /// + /// + /// + private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) + { + // m_log.DebugFormat( + // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", + // att.Name, sp.Name, AttachmentPt, itemID); + + if (UUID.Zero == itemID) + { + m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID."); + return; + } + + if (0 == AttachmentPt) + { + m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point."); + return; + } + + InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); + item = m_scene.InventoryService.GetItem(item); + bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); + } + + #endregion + + #region Client Event Handlers + + private ISceneEntity Client_OnRezSingleAttachmentFromInv(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + { + if (!Enabled) + return null; + + // m_log.DebugFormat( + // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", + // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); + + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + + if (sp == null) + { + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", + remoteClient.Name, remoteClient.AgentId); + return null; + } + + return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); + } + + private void Client_OnRezMultipleAttachmentsFromInv(IClientAPI remoteClient, List> rezlist) + { + if (!Enabled) + return; + + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + if (sp != null) + RezMultipleAttachmentsFromInventory(sp, rezlist); + else + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", + remoteClient.Name, remoteClient.AgentId); + } + + private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) + { + // m_log.DebugFormat( + // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", + // objectLocalID, remoteClient.Name, AttachmentPt, silent); + + if (!Enabled) + return; + + try + { + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + + if (sp == null) + { + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); + return; + } + + // If we can't take it, we can't attach it! + SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); + if (part == null) + return; + + if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) + { + remoteClient.SendAgentAlertMessage( + "You don't have sufficient permissions to attach this object", false); + + return; + } + + // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should + // be removed when that functionality is implemented in opensim + AttachmentPt &= 0x7f; + + // Calls attach with a Zero position + if (AttachObject(sp, part.ParentGroup, AttachmentPt, false)) + { + m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); + + // Save avatar attachment information + m_log.Debug( + "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + + ", AttachmentPoint: " + AttachmentPt); + + } + } + catch (Exception e) + { + m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); + } + } + + private void Client_OnObjectDetach(uint objectLocalID, IClientAPI remoteClient) + { + if (!Enabled) + return; + + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); + if (sp != null && group != null) + DetachSingleAttachmentToInv(sp, group.GetFromItemID()); + } + + private void Client_OnDetachAttachmentIntoInv(UUID itemID, IClientAPI remoteClient) + { + if (!Enabled) + return; + + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + if (sp != null) + DetachSingleAttachmentToInv(sp, itemID); + } + + private void Client_OnObjectDrop(uint soLocalId, IClientAPI remoteClient) + { + if (!Enabled) + return; + + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + if (sp != null) + DetachSingleAttachmentToGround(sp, soLocalId); + } + + #endregion } } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 832c6eba7c..86cfb324dc 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -209,7 +209,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests m_attMod.RezSingleAttachmentFromInventory( m_presence, attItemId, (uint)AttachmentPoint.Chest); - m_attMod.DetachSingleAttachmentToInv(attItemId, m_presence.ControllingClient); + m_attMod.DetachSingleAttachmentToInv(m_presence, attItemId); // Check status on scene presence Assert.That(m_presence.HasAttachments(), Is.False); diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 1a0423f33d..e668daebe8 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -28,7 +28,6 @@ using System; using System.Collections.Generic; using OpenMetaverse; -using OpenMetaverse.Packets; using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; @@ -40,6 +39,7 @@ namespace OpenSim.Region.Framework.Interfaces /// RezAttachments. This should only be called upon login on the first region. /// Attachment rezzings on crossings and TPs are done in a different way. /// + /// void RezAttachments(IScenePresence sp); /// @@ -50,17 +50,16 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Delete all the presence's attachments from the scene - /// - /// /// This is done when a root agent leaves/is demoted to child (for instance, on logout, teleport or region cross). - /// + /// + /// /// void DeleteAttachmentsFromScene(IScenePresence sp, bool silent); /// /// Attach an object to an avatar /// - /// + /// /// /// /// @@ -80,34 +79,22 @@ namespace OpenSim.Region.Framework.Interfaces /// Rez multiple attachments from a user's inventory /// /// - /// - /// + /// void RezMultipleAttachmentsFromInventory(IScenePresence sp,List> rezlist); - - /// - /// Detach an object from the avatar. - /// - /// - /// This method is called in response to a client's detach request, so we only update the information in - /// inventory - /// - /// - /// - void DetachObject(uint objectLocalID, IClientAPI remoteClient); /// /// Detach the given item to the ground. /// - /// + /// /// void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID); /// /// Detach the given item so that it remains in the user's inventory. /// - /// /param> - /// - void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient); + /// /param> + /// + void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID); /// /// Update the position of an attachment. diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 04762bea03..42e09fc358 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -3023,7 +3023,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; if (attachmentsModule != null) - attachmentsModule.DetachSingleAttachmentToInv(itemID, presence.ControllingClient); + attachmentsModule.DetachSingleAttachmentToInv(presence, itemID); } public void llTakeCamera(string avatar)