diff --git a/OpenSim/Framework/Console/ConsoleDisplayList.cs b/OpenSim/Framework/Console/ConsoleDisplayList.cs new file mode 100644 index 0000000000..68855091d4 --- /dev/null +++ b/OpenSim/Framework/Console/ConsoleDisplayList.cs @@ -0,0 +1,112 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenSim.Framework.Console +{ + /// + /// Used to generated a formatted table for the console. + /// + /// + /// Currently subject to change. If you use this, be prepared to change your code when this class changes. + /// + public class ConsoleDisplayList + { + /// + /// The default divider between key and value for a list item. + /// + public const string DefaultKeyValueDivider = " : "; + + /// + /// The divider used between key and value for a list item. + /// + public string KeyValueDivider { get; set; } + + /// + /// Table rows + /// + public List> Rows { get; private set; } + + /// + /// Number of spaces to indent the list. + /// + public int Indent { get; set; } + + public ConsoleDisplayList() + { + Rows = new List>(); + KeyValueDivider = DefaultKeyValueDivider; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + AddToStringBuilder(sb); + return sb.ToString(); + } + + public void AddToStringBuilder(StringBuilder sb) + { + string formatString = GetFormatString(); +// System.Console.WriteLine("FORMAT STRING [{0}]", formatString); + + // rows + foreach (KeyValuePair row in Rows) + sb.AppendFormat(formatString, row.Key, row.Value); + } + + /// + /// Gets the format string for the table. + /// + private string GetFormatString() + { + StringBuilder formatSb = new StringBuilder(); + + int longestKey = -1; + + foreach (KeyValuePair row in Rows) + if (row.Key.Length > longestKey) + longestKey = row.Key.Length; + + formatSb.Append(' ', Indent); + + // Can only do left formatting for now + formatSb.AppendFormat("{{0,-{0}}}{1}{{1}}\n", longestKey, KeyValueDivider); + + return formatSb.ToString(); + } + + public void AddRow(object key, object value) + { + Rows.Add(new KeyValuePair(key.ToString(), value.ToString())); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Console/ConsoleTable.cs b/OpenSim/Framework/Console/ConsoleDisplayTable.cs similarity index 86% rename from OpenSim/Framework/Console/ConsoleTable.cs rename to OpenSim/Framework/Console/ConsoleDisplayTable.cs index be3025be7f..e9d1628b1d 100644 --- a/OpenSim/Framework/Console/ConsoleTable.cs +++ b/OpenSim/Framework/Console/ConsoleDisplayTable.cs @@ -38,7 +38,7 @@ namespace OpenSim.Framework.Console /// /// Currently subject to change. If you use this, be prepared to change your code when this class changes. /// - public class ConsoleTable + public class ConsoleDisplayTable { /// /// Default number of spaces between table columns. @@ -48,12 +48,12 @@ namespace OpenSim.Framework.Console /// /// Table columns. /// - public List Columns { get; private set; } + public List Columns { get; private set; } /// /// Table rows /// - public List Rows { get; private set; } + public List Rows { get; private set; } /// /// Number of spaces to indent the table. @@ -65,11 +65,11 @@ namespace OpenSim.Framework.Console /// public int TableSpacing { get; set; } - public ConsoleTable() + public ConsoleDisplayTable() { TableSpacing = DefaultTableSpacing; - Columns = new List(); - Rows = new List(); + Columns = new List(); + Rows = new List(); } public override string ToString() @@ -88,7 +88,7 @@ namespace OpenSim.Framework.Console sb.AppendFormat(formatString, Columns.ConvertAll(c => c.Header).ToArray()); // rows - foreach (ConsoleTableRow row in Rows) + foreach (ConsoleDisplayTableRow row in Rows) sb.AppendFormat(formatString, row.Cells.ToArray()); } @@ -115,23 +115,23 @@ namespace OpenSim.Framework.Console } } - public struct ConsoleTableColumn + public struct ConsoleDisplayTableColumn { public string Header { get; set; } public int Width { get; set; } - public ConsoleTableColumn(string header, int width) : this() + public ConsoleDisplayTableColumn(string header, int width) : this() { Header = header; Width = width; } } - public struct ConsoleTableRow + public struct ConsoleDisplayTableRow { public List Cells { get; private set; } - public ConsoleTableRow(List cells) : this() + public ConsoleDisplayTableRow(List cells) : this() { Cells = cells; } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 2e1948d231..510b483ed1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -49,6 +49,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private Scene m_scene; private IDialogModule m_dialogModule; + private IInventoryAccessModule m_invAccessModule; /// /// Are attachments enabled? @@ -70,7 +71,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void AddRegion(Scene scene) { m_scene = scene; - m_dialogModule = m_scene.RequestModuleInterface(); m_scene.RegisterModuleInterface(this); if (Enabled) @@ -87,7 +87,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; } - public void RegionLoaded(Scene scene) {} + public void RegionLoaded(Scene scene) + { + m_dialogModule = m_scene.RequestModuleInterface(); + m_invAccessModule = m_scene.RequestModuleInterface(); + } public void Close() { @@ -578,90 +582,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// The user inventory item created that holds the attachment. private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp) { + if (m_invAccessModule == null) + return null; + // 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) - ? Constants.RegionSize - 6 - : grp.AbsolutePosition.X) - , - (grp.AbsolutePosition.Y > (int)Constants.RegionSize) - ? Constants.RegionSize - 6 - : grp.AbsolutePosition.Y, - grp.AbsolutePosition.Z); - - Vector3 originalPosition = grp.AbsolutePosition; - - grp.AbsolutePosition = inventoryStoredPosition; - - // If we're being called from a script, then trying to serialize that same script's state will not complete - // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if - // the client/server crashes rather than logging out normally, the attachment's scripts will resume - // without state on relog. Arguably, this is what we want anyway. - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false); - - grp.AbsolutePosition = originalPosition; - - AssetBase asset = m_scene.CreateAsset( - grp.GetPartName(grp.LocalId), - grp.GetPartDescription(grp.LocalId), - (sbyte)AssetType.Object, - Utils.StringToBytes(sceneObjectXml), - sp.UUID); - - m_scene.AssetService.Store(asset); - - InventoryItemBase item = new InventoryItemBase(); - item.CreatorId = grp.RootPart.CreatorID.ToString(); - item.CreatorData = grp.RootPart.CreatorData; - item.Owner = sp.UUID; - item.ID = UUID.Random(); - item.AssetID = asset.FullID; - item.Description = asset.Description; - item.Name = asset.Name; - item.AssetType = asset.Type; - item.InvType = (int)InventoryType.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 ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) - { - item.BasePermissions = grp.RootPart.NextOwnerMask; - item.CurrentPermissions = grp.RootPart.NextOwnerMask; - item.NextPermissions = grp.RootPart.NextOwnerMask; - item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; - item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; - } - else - { - item.BasePermissions = grp.RootPart.BaseMask; - item.CurrentPermissions = grp.RootPart.OwnerMask; - item.NextPermissions = grp.RootPart.NextOwnerMask; - item.EveryOnePermissions = grp.RootPart.EveryoneMask; - item.GroupPermissions = grp.RootPart.GroupMask; - } - item.CreationDate = Util.UnixTimeSinceEpoch(); + InventoryItemBase newItem = m_invAccessModule.CopyToInventory( + DeRezAction.TakeCopy, + m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID, + new List { grp }, + sp.ControllingClient, true)[0]; // sets itemID so client can show item as 'attached' in inventory - grp.FromItemID = item.ID; + grp.FromItemID = newItem.ID; - if (m_scene.AddInventoryItem(item)) - { - sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); - } - else - { - if (m_dialogModule != null) - m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed"); - } - - return item; + return newItem; } // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. @@ -709,70 +646,69 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) { - IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); - if (invAccess != null) + if (m_invAccessModule == null) + return null; + + lock (sp.AttachmentsSyncLock) { - lock (sp.AttachmentsSyncLock) + SceneObjectGroup objatt; + + if (itemID != UUID.Zero) + objatt = m_invAccessModule.RezObject(sp.ControllingClient, + itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + false, false, sp.UUID, true); + else + objatt = m_invAccessModule.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) { - SceneObjectGroup objatt; + // 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; - 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) + // This will throw if the attachment fails + try { - // 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; + AttachObject(sp, objatt, attachmentPt, false); } - else + catch (Exception e) { - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", - itemID, sp.Name, attachmentPt); + 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); } } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 42d07fd2d6..5e89eec25d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -99,12 +99,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests public void TestAddAttachmentFromGround() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); AddPresence(); string attName = "att"; - SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName).ParentGroup; + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, m_presence.UUID).ParentGroup; m_attMod.AttachObject(m_presence, so, (uint)AttachmentPoint.Chest, false); @@ -123,6 +123,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That( m_presence.Appearance.GetAttachpoint(attSo.FromItemID), Is.EqualTo((int)AttachmentPoint.Chest)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(attName)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(m_presence.UUID, AssetType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + +// TestHelpers.DisableLogging(); } [Test] diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 8171487545..69767c1b99 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -175,7 +175,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess sbyte assetType, byte wearableType, uint nextOwnerMask, int creationDate) { - m_log.DebugFormat("[AGENT INVENTORY]: Received request to create inventory item {0} in folder {1}", name, folderID); + m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}", name, folderID); if (!m_Scene.Permissions.CanCreateUserInventory(invType, remoteClient.AgentId)) return; @@ -210,7 +210,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.ErrorFormat( - "ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", + "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", remoteClient.AgentId); } } @@ -288,16 +288,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.ErrorFormat( - "[AGENT INVENTORY]: Could not find item {0} for caps inventory update", + "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update", itemID); } return UUID.Zero; } - public virtual UUID CopyToInventory(DeRezAction action, UUID folderID, - List objectGroups, IClientAPI remoteClient) + public virtual List CopyToInventory( + DeRezAction action, UUID folderID, + List objectGroups, IClientAPI remoteClient, bool asAttachment) { + List copiedItems = new List(); + Dictionary> bundlesToCopy = new Dictionary>(); if (CoalesceMultipleObjectsToInventory) @@ -324,16 +327,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - // This is method scoped and will be returned. It will be the - // last created asset id - UUID assetID = UUID.Zero; +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: Copying {0} object bundles to folder {1} action {2} for {3}", +// bundlesToCopy.Count, folderID, action, remoteClient.Name); // Each iteration is really a separate asset being created, // with distinct destinations as well. foreach (List bundle in bundlesToCopy.Values) - assetID = CopyBundleToInventory(action, folderID, bundle, remoteClient); + copiedItems.Add(CopyBundleToInventory(action, folderID, bundle, remoteClient, asAttachment)); - return assetID; + return copiedItems; } /// @@ -344,12 +347,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// /// - /// - protected UUID CopyBundleToInventory( - DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient) + /// Should be true if the bundle is being copied as an attachment. This prevents + /// attempted serialization of any script state which would abort any operating scripts. + /// The inventory item created by the copy + protected InventoryItemBase CopyBundleToInventory( + DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient, + bool asAttachment) { - UUID assetID = UUID.Zero; - CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); Dictionary originalPositions = new Dictionary(); @@ -385,18 +389,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess string itemXml; + // If we're being called from a script, then trying to serialize that same script's state will not complete + // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if + // the client/server crashes rather than logging out normally, the attachment's scripts will resume + // without state on relog. Arguably, this is what we want anyway. if (objlist.Count > 1) - itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); + itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment); else - itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); + itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); // Restore the position of each group now that it has been stored to inventory. foreach (SceneObjectGroup objectGroup in objlist) objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); + +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: Created item is {0}", +// item != null ? item.ID.ToString() : "NULL"); + if (item == null) - return UUID.Zero; + return null; // Can't know creator is the same, so null it in inventory if (objlist.Count > 1) @@ -406,7 +419,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else { - item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); + item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); + item.CreatorData = objlist[0].RootPart.CreatorData; item.SaleType = objlist[0].RootPart.ObjectSaleType; item.SalePrice = objlist[0].RootPart.SalePrice; } @@ -419,8 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess objlist[0].OwnerID.ToString()); m_Scene.AssetService.Store(asset); - item.AssetID = asset.FullID; - assetID = asset.FullID; + item.AssetID = asset.FullID; if (DeRezAction.SaveToExistingUserInventoryItem == action) { @@ -453,9 +466,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // This is a hook to do some per-asset post-processing for subclasses that need that if (remoteClient != null) - ExportAsset(remoteClient.AgentId, assetID); + ExportAsset(remoteClient.AgentId, asset.FullID); - return assetID; + return item; } protected virtual void ExportAsset(UUID agentID, UUID assetID) @@ -592,7 +605,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (null == item) { m_log.DebugFormat( - "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", + "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.", so.Name, so.UUID); return null; @@ -643,7 +656,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { // Catch all. Use lost & found // - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); } } @@ -694,7 +706,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (item == null) { m_log.WarnFormat( - "[InventoryAccessModule]: Could not find item {0} for {1} in RezObject()", + "[INVENTORY ACCESS MODULE]: Could not find item {0} for {1} in RezObject()", itemID, remoteClient.Name); return null; @@ -726,7 +738,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.WarnFormat( - "[InventoryAccessModule]: Could not find asset {0} for {1} in RezObject()", + "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()", assetID, remoteClient.Name); } @@ -803,7 +815,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess group = objlist[i]; // m_log.DebugFormat( -// "[InventoryAccessModule]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", +// "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", // group.Name, group.LocalId, group.UUID, // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask, // remoteClient.Name); @@ -811,7 +823,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Vector3 storedPosition = group.AbsolutePosition; if (group.UUID == UUID.Zero) { - m_log.Debug("[InventoryAccessModule]: Object has UUID.Zero! Position 3"); + m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); } foreach (SceneObjectPart part in group.Parts) @@ -874,7 +886,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } // m_log.DebugFormat( -// "[InventoryAccessModule]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", +// "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", // group.Name, group.LocalId, group.UUID, // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask, // remoteClient.Name); @@ -964,8 +976,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess so.FromFolderID = item.Folder; -// Console.WriteLine("rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", -// rootPart.OwnerID, item.Owner, item.CurrentPermissions); +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", +// rootPart.OwnerID, item.Owner, item.CurrentPermissions); if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0) @@ -1088,7 +1101,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (assetRequestItem.AssetID != requestID) { m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", + "[INVENTORY ACCESS MODULE]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", Name, requestID, itemID, assetRequestItem.AssetID); return false; diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs new file mode 100644 index 0000000000..2838e0c356 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs @@ -0,0 +1,155 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using log4net; +using Mono.Addins; +using NDesk.Options; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Statistics; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.World.Objects.Commands +{ + /// + /// A module that holds commands for manipulating objects in the scene. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionCommandsModule")] + public class RegionCommandsModule : INonSharedRegionModule + { + private Scene m_scene; + private ICommandConsole m_console; + + public string Name { get { return "Region Commands Module"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: INITIALIZED MODULE"); + } + + public void PostInitialise() + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: POST INITIALIZED MODULE"); + } + + public void Close() + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); + + m_scene = scene; + m_console = MainConsole.Instance; + + m_console.Commands.AddCommand( + "Regions", false, "show scene", + "show scene", + "Show live scene information for the currently selected region.", HandleShowScene); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); + } + + private void HandleShowScene(string module, string[] cmd) + { + if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) + return; + + SimStatsReporter r = m_scene.StatsReporter; + float[] stats = r.LastReportedSimStats; + + float timeDilation = stats[0]; + float simFps = stats[1]; + float physicsFps = stats[2]; + float agentUpdates = stats[3]; + float rootAgents = stats[4]; + float childAgents = stats[5]; + float totalPrims = stats[6]; + float activePrims = stats[7]; + float totalFrameTime = stats[8]; +// float netFrameTime = stats.StatsBlock[9].StatValue; // Ignored - not used by OpenSimulator + float physicsFrameTime = stats[10]; + float otherFrameTime = stats[11]; +// float imageFrameTime = stats.StatsBlock[12].StatValue; // Ignored + float inPacketsPerSecond = stats[13]; + float outPacketsPerSecond = stats[14]; + float unackedBytes = stats[15]; +// float agentFrameTime = stats.StatsBlock[16].StatValue; // Not really used + float pendingDownloads = stats[17]; + float pendingUploads = stats[18]; + float activeScripts = stats[19]; + float scriptLinesPerSecond = stats[20]; + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Scene statistics for {0}\n", m_scene.RegionInfo.RegionName); + + ConsoleDisplayList dispList = new ConsoleDisplayList(); + dispList.AddRow("Time Dilation", timeDilation); + dispList.AddRow("Sim FPS", simFps); + dispList.AddRow("Physics FPS", physicsFps); + dispList.AddRow("Avatars", rootAgents); + dispList.AddRow("Child agents", childAgents); + dispList.AddRow("Total prims", totalPrims); + dispList.AddRow("Scripts", activeScripts); + dispList.AddRow("Script lines processed per second", scriptLinesPerSecond); + dispList.AddRow("Physics enabled prims", activePrims); + dispList.AddRow("Total frame time", totalFrameTime); + dispList.AddRow("Physics frame time", physicsFrameTime); + dispList.AddRow("Other frame time", otherFrameTime); + dispList.AddRow("Agent Updates per second", agentUpdates); + dispList.AddRow("Packets processed from clients per second", inPacketsPerSecond); + dispList.AddRow("Packets sent to clients per second", outPacketsPerSecond); + dispList.AddRow("Bytes unacknowledged by clients", unackedBytes); + dispList.AddRow("Pending asset downloads to clients", pendingDownloads); + dispList.AddRow("Pending asset uploads from clients", pendingUploads); + + dispList.AddToStringBuilder(sb); + + MainConsole.Instance.Output(sb.ToString()); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 1904011b17..3576e35798 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs @@ -49,11 +49,15 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// + /// + /// Should be true if the object(s) are begin taken as attachments. False otherwise. + /// /// - /// Returns the UUID of the newly created item asset (not the item itself). - /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. + /// A list of the items created. If there was more than one object and objects are not being coaleseced in + /// inventory, then the order of items is in the same order as the input objects. /// - UUID CopyToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient); + List CopyToInventory( + DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient, bool asAttachment); /// /// Rez an object into the scene from the user's inventory diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 834464b2c8..f555b49f58 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -155,7 +155,7 @@ namespace OpenSim.Region.Framework.Scenes { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); if (invAccess != null) - invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); + invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient, false); if (x.permissionToDelete) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 5a0f56441f..fbe56f6b36 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -77,7 +77,12 @@ namespace OpenSim.Region.Framework.Scenes public bool DebugUpdates { get; private set; } public SynchronizeSceneHandler SynchronizeScene; - public SimStatsReporter StatsReporter; + + /// + /// Statistical information for this scene. + /// + public SimStatsReporter StatsReporter { get; private set; } + public List NorthBorders = new List(); public List EastBorders = new List(); public List SouthBorders = new List(); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 3734e03994..d27d9e1dad 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -1027,10 +1027,16 @@ namespace OpenSim.Region.Framework.Scenes public void ApplyNextOwnerPermissions() { + Util.PrintCallStack(); + lock (m_items) { foreach (TaskInventoryItem item in m_items.Values) { +// m_log.DebugFormat ( +// "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}", +// item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions); + if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) { if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) @@ -1040,6 +1046,7 @@ namespace OpenSim.Region.Framework.Scenes if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0) item.CurrentPermissions &= ~(uint)PermissionMask.Modify; } + item.CurrentPermissions &= item.NextPermissions; item.BasePermissions &= item.NextPermissions; item.EveryonePermissions &= item.NextPermissions; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index 55455cc434..a4f730d375 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -47,14 +47,30 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// public class CoalescedSceneObjectsSerializer { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Serialize coalesced objects to Xml /// /// + /// + /// If true then serialize script states. This will halt any running scripts + /// /// public static string ToXml(CoalescedSceneObjects coa) + { + return ToXml(coa, true); + } + + /// + /// Serialize coalesced objects to Xml + /// + /// + /// + /// If true then serialize script states. This will halt any running scripts + /// + /// + public static string ToXml(CoalescedSceneObjects coa, bool doScriptStates) { using (StringWriter sw = new StringWriter()) { @@ -91,7 +107,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteAttributeString("offsety", offsets[i].Y.ToString()); writer.WriteAttributeString("offsetz", offsets[i].Z.ToString()); - SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); + SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, doScriptStates); writer.WriteEndElement(); // SceneObjectGroup } diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs index a95514c642..1b9e3ace5c 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs @@ -145,12 +145,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments { sb.AppendFormat("Attachments for {0}\n", sp.Name); - ConsoleTable ct = new ConsoleTable() { Indent = 2 }; - ct.Columns.Add(new ConsoleTableColumn("Attachment Name", 36)); - ct.Columns.Add(new ConsoleTableColumn("Local ID", 10)); - ct.Columns.Add(new ConsoleTableColumn("Item ID", 36)); - ct.Columns.Add(new ConsoleTableColumn("Attach Point", 14)); - ct.Columns.Add(new ConsoleTableColumn("Position", 15)); + ConsoleDisplayTable ct = new ConsoleDisplayTable() { Indent = 2 }; + ct.Columns.Add(new ConsoleDisplayTableColumn("Attachment Name", 36)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Local ID", 10)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Item ID", 36)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Attach Point", 14)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Position", 15)); // sb.AppendFormat( // " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", @@ -176,7 +176,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments // attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, // (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); ct.Rows.Add( - new ConsoleTableRow( + new ConsoleDisplayTableRow( new List() { attachmentObject.Name, diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 3dc87bc5d5..8a60ca5467 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -509,19 +509,21 @@ namespace OpenSim.Services.GridService return; } - MainConsole.Instance.Output("Region Name Region UUID"); - MainConsole.Instance.Output("Location URI"); - MainConsole.Instance.Output("Owner ID Flags"); - MainConsole.Instance.Output("-------------------------------------------------------------------------------"); foreach (RegionData r in regions) { OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); - MainConsole.Instance.Output(String.Format("{0,-20} {1}\n{2,-20} {3}\n{4,-39} {5}\n\n", - r.RegionName, r.RegionID, - String.Format("{0},{1}", r.posX / Constants.RegionSize, r.posY / Constants.RegionSize), - r.Data["serverURI"], - r.Data["owner_uuid"], flags)); + + ConsoleDisplayList dispList = new ConsoleDisplayList(); + dispList.AddRow("Region Name", r.RegionName); + dispList.AddRow("Region ID", r.RegionID); + dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); + dispList.AddRow("URI", r.Data["serverURI"]); + dispList.AddRow("Owner ID", r.Data["owner_uuid"]); + dispList.AddRow("Flags", flags); + + MainConsole.Instance.Output(dispList.ToString()); } + return; } diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 59829d994f..239afc0aee 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -566,7 +566,7 @@ namespace OpenSim.Tests.Common /// public static SceneObjectPart AddSceneObject(Scene scene) { - return AddSceneObject(scene, "Test Object"); + return AddSceneObject(scene, "Test Object", UUID.Zero); } /// @@ -574,10 +574,11 @@ namespace OpenSim.Tests.Common /// /// /// + /// /// - public static SceneObjectPart AddSceneObject(Scene scene, string name) + public static SceneObjectPart AddSceneObject(Scene scene, string name, UUID ownerId) { - SceneObjectPart part = CreateSceneObjectPart(name, UUID.Random(), UUID.Zero); + SceneObjectPart part = CreateSceneObjectPart(name, UUID.Random(), ownerId); //part.UpdatePrimFlags(false, false, true); //part.ObjectFlags |= (uint)PrimFlags.Phantom;