From 69817b4d6a08d3f9866796c50a0d0fb0d28ded77 Mon Sep 17 00:00:00 2001 From: MW Date: Sat, 30 May 2009 12:51:28 +0000 Subject: Added a AvatarCreationModule to the user server. This handles the "cloning" of a existing avatar's inventory to another avatar's inventory (the base method will also create the inventory for a new avatar if the avatar doesn't alreayd have any inventory). The code also sets the target avatar as wearing whatever the template avatar was wearing (including attachments). The idea is to allow the use of this to give new avatars a more interesting avatar (and inventory set) than the current default. I have include a console command that will clone the inventory from one existing user (template avatar) to another existing avatar (target avatar). The format of the command is : "clone avatar " (to use this console command on new accounts, the "create user" command will need to be used first) While the code was designed for hooking up to a remote call from a web interface, I have left the hookup code out of this commit, as I believe most use cases will want to handle it differently. Also added a "trusted handler" to the inventory server to allow the user server to create new folders in a user's inventory. All this is in the old UGAIM servers so will need porting to the new servers. --- OpenSim/Grid/InventoryServer/Main.cs | 4 + .../UserServer.Modules/AvatarCreationModule.cs | 499 +++++++++++++++++++++ OpenSim/Grid/UserServer/Main.cs | 9 + 3 files changed, 512 insertions(+) create mode 100644 OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs diff --git a/OpenSim/Grid/InventoryServer/Main.cs b/OpenSim/Grid/InventoryServer/Main.cs index 7560383..537661e 100644 --- a/OpenSim/Grid/InventoryServer/Main.cs +++ b/OpenSim/Grid/InventoryServer/Main.cs @@ -136,6 +136,10 @@ namespace OpenSim.Grid.InventoryServer "POST", "/NewFolder/", m_inventoryService.AddFolder, m_inventoryService.CheckAuthSession)); m_httpServer.AddStreamHandler( + new RestDeserialiseTrustedHandler( + "POST", "/CreateFolder/", m_inventoryService.AddFolder, m_inventoryService.CheckTrustSource)); + + m_httpServer.AddStreamHandler( new RestDeserialiseSecureHandler( "POST", "/NewItem/", m_inventoryService.AddItem, m_inventoryService.CheckAuthSession)); diff --git a/OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs b/OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs new file mode 100644 index 0000000..5e6bc85 --- /dev/null +++ b/OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs @@ -0,0 +1,499 @@ +/* + * 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 OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using log4net; +using Nwc.XmlRpc; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Grid.Framework; + + +namespace OpenSim.Grid.UserServer.Modules +{ + public class AvatarCreationModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private UserDataBaseService m_userDataBaseService; + // private BaseHttpServer m_httpServer; + private UserConfig m_config; + + private string m_inventoryServerUrl; + private IInterServiceInventoryServices m_inventoryService; + + public AvatarCreationModule(UserDataBaseService userDataBaseService, UserConfig config, IInterServiceInventoryServices inventoryService) + { + m_config = config; + m_userDataBaseService = userDataBaseService; + m_inventoryService = inventoryService; + m_inventoryServerUrl = config.InventoryUrl.OriginalString; + } + + public void Initialise(IGridServiceCore core) + { + CommandConsole console; + if (core.TryGet(out console)) + { + console.Commands.AddCommand("userserver", false, "clone avatar", + "clone avatar ", + "Clone the template avatar inventory into a target avatar", RunCommand); + } + } + + public void PostInitialise() + { + + } + + public void RegisterHandlers(BaseHttpServer httpServer) + { + } + + public void RunCommand(string module, string[] cmd) + { + if ((cmd.Length == 6) && (cmd[0] == "clone") && (cmd[1] == "avatar")) + { + try + { + string tFirst = cmd[2]; + string tLast = cmd[3]; + + string nFirst = cmd[4]; + string nLast = cmd[5]; + + UserProfileData templateAvatar = m_userDataBaseService.GetUserProfile(tFirst, tLast); + UserProfileData newAvatar = m_userDataBaseService.GetUserProfile(nFirst, nLast); + + if (templateAvatar == null) + { + m_log.ErrorFormat("[AvatarAppearance] Clone Avatar: Could not find template avatar {0} , {1}", tFirst, tLast); + return; + } + + if (newAvatar == null) + { + m_log.ErrorFormat("[AvatarAppearance] Clone Avatar: Could not find target avatar {0} , {1}", nFirst, nLast); + return; + } + Guid avatar = newAvatar.ID.Guid; + Guid template = templateAvatar.ID.Guid; + CloneAvatar(avatar, template); + + } + catch (Exception e) + { + m_log.Error("Error: " + e.ToString()); + } + } + } + #region Avatar Appearance Creation + + public bool CloneAvatar(Guid avatarID, Guid templateID) + { + m_log.InfoFormat("[AvatarAppearance] Starting to create avatar's appearance for user {0}", avatarID.ToString()); + Guid bodyFolder = Guid.Empty; + Guid clothesFolder = Guid.Empty; + bool success = false; + + UUID avID = new UUID(avatarID); + List avatarInventory = m_inventoryService.GetInventorySkeleton(avID); + if ((avatarInventory == null) || (avatarInventory.Count == 0)) + { + m_log.InfoFormat("[AvatarAppearance] No inventory found for user {0} , so creating it", avID.ToString()); + m_inventoryService.CreateNewUserInventory(avID); + Thread.Sleep(5000); + avatarInventory = m_inventoryService.GetInventorySkeleton(avID); + } + + if ((avatarInventory != null) && (avatarInventory.Count > 0)) + { + UUID tempOwnID = new UUID(templateID); + AvatarAppearance appearance = m_userDataBaseService.GetUserAppearance(tempOwnID); + + List templateInventory = m_inventoryService.GetInventorySkeleton(tempOwnID); + if ((templateInventory != null) && (templateInventory.Count != 0)) + { + for (int i = 0; i < templateInventory.Count; i++) + { + if (templateInventory[i].ParentID == UUID.Zero) + { + success = CloneFolder(avatarInventory, avID, UUID.Zero, appearance, templateInventory[i], templateInventory); + break; + } + } + } + else + { + m_log.InfoFormat("[AvatarAppearance] Failed to find the template owner's {0} inventory", tempOwnID); + } + } + m_log.InfoFormat("[AvatarAppearance] finished cloning avatar with result: {0}", success); + return success; + } + + private void UpdateAvatarAppearance(UUID avatarID, int wearableType, UUID itemID, UUID assetID) + { + AvatarAppearance appearance = m_userDataBaseService.GetUserAppearance(avatarID); + if (appearance == null) + { + appearance = CreateDefaultAppearance(avatarID); + } + + appearance.Wearables[wearableType].AssetID = assetID; + appearance.Wearables[wearableType].ItemID = itemID; + + m_userDataBaseService.UpdateUserAppearance(avatarID, appearance); + + } + + private void UpdateAvatarAttachment(UUID avatarID, int attachmentPoint, UUID itemID, UUID assetID) + { + AvatarAppearance appearance = m_userDataBaseService.GetUserAppearance(avatarID); + if (appearance == null) + { + appearance = CreateDefaultAppearance(avatarID); + } + + appearance.SetAttachment(attachmentPoint, itemID, assetID); + + m_userDataBaseService.UpdateUserAppearance(avatarID, appearance); + + } + + private UUID FindFolderID(string name, List folders) + { + foreach (InventoryFolderBase folder in folders) + { + if (folder.Name == name) + { + return folder.ID; + } + } + return UUID.Zero; + } + + private InventoryFolderBase FindFolder(string name, List folders) + { + foreach (InventoryFolderBase folder in folders) + { + if (folder.Name == name) + { + return folder; + } + } + return null; + } + + private InventoryFolderBase FindFolder(string name, Guid parentFolderID, List folders) + { + foreach (InventoryFolderBase folder in folders) + { + if ((folder.Name == name) && (folder.ParentID.Guid == parentFolderID)) + { + return folder; + } + } + return null; + } + + private InventoryItemBase GetItem(string itemName, List items) + { + foreach (InventoryItemBase item in items) + { + if (item.Name.ToLower() == itemName.ToLower()) + { + return item; + } + } + return null; + } + + private List FindSubFolders(Guid parentFolderID, List folders) + { + List subFolders = new List(); + foreach (InventoryFolderBase folder in folders) + { + if (folder.ParentID.Guid == parentFolderID) + { + subFolders.Add(folder); + } + } + return subFolders; + } + + + private UUID CloneInventoryItem(UUID avatarID, UUID avatarFolder, InventoryItemBase item, bool modifyPerms) + { + if (avatarFolder != UUID.Zero) + { + InventoryItemBase clonedItem = new InventoryItemBase(); + clonedItem.Owner = avatarID; + clonedItem.AssetID = item.AssetID; + clonedItem.AssetType = item.AssetType; + clonedItem.BasePermissions = item.BasePermissions; + clonedItem.CreationDate = item.CreationDate; + clonedItem.CreatorId = item.CreatorId; + clonedItem.CreatorIdAsUuid = item.CreatorIdAsUuid; + clonedItem.CurrentPermissions = item.CurrentPermissions; + clonedItem.Description = item.Description; + clonedItem.EveryOnePermissions = item.EveryOnePermissions; + clonedItem.Flags = item.Flags; + clonedItem.Folder = avatarFolder; + clonedItem.GroupID = item.GroupID; + clonedItem.GroupOwned = item.GroupOwned; + clonedItem.GroupPermissions = item.GroupPermissions; + clonedItem.ID = UUID.Random(); + clonedItem.InvType = item.InvType; + clonedItem.Name = item.Name; + clonedItem.NextPermissions = item.NextPermissions; + clonedItem.SalePrice = item.SalePrice; + clonedItem.SaleType = item.SaleType; + + if (modifyPerms) + { + ModifyPermissions(clonedItem); + } + + SynchronousRestObjectRequester.MakeRequest( + "POST", m_inventoryServerUrl + "AddNewItem/", clonedItem); + + return clonedItem.ID; + } + + return UUID.Zero; + } + + private static void ModifyPermissions(InventoryItemBase clonedItem) + { + if ((clonedItem.CurrentPermissions & (uint)PermissionMask.Modify) == 0) + clonedItem.CurrentPermissions |= (uint)PermissionMask.Modify; + + if ((clonedItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0) + clonedItem.CurrentPermissions |= (uint)PermissionMask.Copy; + + if ((clonedItem.CurrentPermissions & (uint)PermissionMask.Transfer) != 0) + clonedItem.CurrentPermissions &= ~(uint)PermissionMask.Transfer; + + if ((clonedItem.NextPermissions & (uint)PermissionMask.Modify) == 0) + clonedItem.NextPermissions |= (uint)PermissionMask.Modify; + + if ((clonedItem.NextPermissions & (uint)PermissionMask.Copy) == 0) + clonedItem.NextPermissions |= (uint)PermissionMask.Copy; + + if ((clonedItem.NextPermissions & (uint)PermissionMask.Transfer) != 0) + clonedItem.NextPermissions &= ~(uint)PermissionMask.Transfer; + } + + private AvatarAppearance CreateDefaultAppearance(UUID avatarId) + { + AvatarAppearance appearance = null; + AvatarWearable[] wearables; + byte[] visualParams; + GetDefaultAvatarAppearance(out wearables, out visualParams); + appearance = new AvatarAppearance(avatarId, wearables, visualParams); + + return appearance; + } + + private static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) + { + visualParams = GetDefaultVisualParams(); + wearables = AvatarWearable.DefaultWearables; + } + + private static byte[] GetDefaultVisualParams() + { + byte[] visualParams; + visualParams = new byte[218]; + for (int i = 0; i < 218; i++) + { + visualParams[i] = 100; + } + return visualParams; + } + #endregion + + + + private bool CloneFolder(List avatarInventory, UUID avID, UUID parentFolder, AvatarAppearance appearance, InventoryFolderBase templateFolder, List templateFolders) + { + bool success = false; + UUID templateFolderId = templateFolder.ID; + if (templateFolderId != UUID.Zero) + { + InventoryFolderBase toFolder = FindFolder(templateFolder.Name, parentFolder.Guid, avatarInventory); + if (toFolder == null) + { + //create new folder + toFolder = new InventoryFolderBase(); + toFolder.ID = UUID.Random(); + toFolder.Name = templateFolder.Name; + toFolder.Owner = avID; + toFolder.Type = templateFolder.Type; + toFolder.Version = 1; + toFolder.ParentID = parentFolder; + if (!SynchronousRestObjectRequester.MakeRequest( + "POST", m_inventoryServerUrl + "CreateFolder/", toFolder)) + { + m_log.InfoFormat("[AvatarApperance] Couldn't make new folder {0} in users inventory", toFolder.Name); + return false; + } + else + { + // m_log.InfoFormat("made new folder {0} in users inventory", toFolder.Name); + } + } + + List templateItems = SynchronousRestObjectRequester.MakeRequest>( + "POST", m_inventoryServerUrl + "GetItems/", templateFolderId.Guid); + if ((templateItems != null) && (templateItems.Count > 0)) + { + foreach (InventoryItemBase item in templateItems) + { + + UUID clonedItemId = CloneInventoryItem(avID, toFolder.ID, item, false); + if (clonedItemId != UUID.Zero) + { + int appearanceType = ItemIsPartOfAppearance(item, appearance); + if (appearanceType >= 0) + { + UpdateAvatarAppearance(avID, appearanceType, clonedItemId, item.AssetID); + } + + if (appearance != null) + { + int attachment = appearance.GetAttachpoint(item.ID); + if (attachment > 0) + { + UpdateAvatarAttachment(avID, attachment, clonedItemId, item.AssetID); + } + } + success = true; + } + } + } + + List subFolders = FindSubFolders(templateFolder.ID.Guid, templateFolders); + foreach (InventoryFolderBase subFolder in subFolders) + { + if (subFolder.Name.ToLower() != "trash") + { + success = CloneFolder(avatarInventory, avID, toFolder.ID, appearance, subFolder, templateFolders); + } + } + } + else + { + m_log.Info("[AvatarAppearance] Failed to find the template folder"); + } + return success; + } + + private int ItemIsPartOfAppearance(InventoryItemBase item, AvatarAppearance appearance) + { + if (appearance != null) + { + if (appearance.BodyItem == item.ID) + return (int)WearableType.Shape; + + if (appearance.EyesItem == item.ID) + return (int)WearableType.Eyes; + + if (appearance.GlovesItem == item.ID) + return (int)WearableType.Gloves; + + if (appearance.HairItem == item.ID) + return (int)WearableType.Hair; + + if (appearance.JacketItem == item.ID) + return (int)WearableType.Jacket; + + if (appearance.PantsItem == item.ID) + return (int)WearableType.Pants; + + if (appearance.ShirtItem == item.ID) + return (int)WearableType.Shirt; + + if (appearance.ShoesItem == item.ID) + return (int)WearableType.Shoes; + + if (appearance.SkinItem == item.ID) + return (int)WearableType.Skin; + + if (appearance.SkirtItem == item.ID) + return (int)WearableType.Skirt; + + if (appearance.SocksItem == item.ID) + return (int)WearableType.Socks; + + if (appearance.UnderPantsItem == item.ID) + return (int)WearableType.Underpants; + + if (appearance.UnderShirtItem == item.ID) + return (int)WearableType.Undershirt; + } + return -1; + } + + } + public enum PermissionMask + { + None = 0, + Transfer = 8192, + Modify = 16384, + Copy = 32768, + Move = 524288, + Damage = 1048576, + All = 2147483647, + } + + public enum WearableType + { + Shape = 0, + Skin = 1, + Hair = 2, + Eyes = 3, + Shirt = 4, + Pants = 5, + Shoes = 6, + Socks = 7, + Jacket = 8, + Gloves = 9, + Undershirt = 10, + Underpants = 11, + Skirt = 12, + } +} diff --git a/OpenSim/Grid/UserServer/Main.cs b/OpenSim/Grid/UserServer/Main.cs index 7bb8b12..d9b3d3f 100644 --- a/OpenSim/Grid/UserServer/Main.cs +++ b/OpenSim/Grid/UserServer/Main.cs @@ -71,6 +71,8 @@ namespace OpenSim.Grid.UserServer protected UserServerCommandModule m_consoleCommandModule; protected UserServerEventDispatchModule m_eventDispatcher; + protected AvatarCreationModule m_appearanceModule; + public static void Main(string[] args) { XmlConfigurator.Configure(); @@ -180,6 +182,9 @@ namespace OpenSim.Grid.UserServer protected virtual void StartOtherComponents(IInterServiceInventoryServices inventoryService) { + m_appearanceModule = new AvatarCreationModule(m_userDataBaseService, Cfg, inventoryService); + m_appearanceModule.Initialise(this); + StartupLoginService(inventoryService); // // Get the minimum defaultLevel to access to the grid @@ -216,6 +221,8 @@ namespace OpenSim.Grid.UserServer m_userManager.PostInitialise(); m_avatarAppearanceModule.PostInitialise(); m_friendsModule.PostInitialise(); + + m_avatarAppearanceModule.PostInitialise(); } protected virtual void RegisterHttpHandlers() @@ -230,6 +237,8 @@ namespace OpenSim.Grid.UserServer m_avatarAppearanceModule.RegisterHandlers(m_httpServer); m_messagesService.RegisterHandlers(m_httpServer); m_gridInfoService.RegisterHandlers(m_httpServer); + + m_avatarAppearanceModule.RegisterHandlers(m_httpServer); } public override void ShutdownSpecific() -- cgit v1.1