diff options
author | MW | 2009-05-30 12:51:28 +0000 |
---|---|---|
committer | MW | 2009-05-30 12:51:28 +0000 |
commit | 69817b4d6a08d3f9866796c50a0d0fb0d28ded77 (patch) | |
tree | 7e35f8ac4f54d9586a8c2d7a051a079487a66e5e /OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs | |
parent | * Tweaks to /WHO listings. (diff) | |
download | opensim-SC-69817b4d6a08d3f9866796c50a0d0fb0d28ded77.zip opensim-SC-69817b4d6a08d3f9866796c50a0d0fb0d28ded77.tar.gz opensim-SC-69817b4d6a08d3f9866796c50a0d0fb0d28ded77.tar.bz2 opensim-SC-69817b4d6a08d3f9866796c50a0d0fb0d28ded77.tar.xz |
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 <templateAvatarFirstName> <templateAvatarLastName> <targetAvatarFirstName> <targetAvatarLastName>" (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.
Diffstat (limited to 'OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs')
-rw-r--r-- | OpenSim/Grid/UserServer.Modules/AvatarCreationModule.cs | 499 |
1 files changed, 499 insertions, 0 deletions
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 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Threading; | ||
33 | using log4net; | ||
34 | using Nwc.XmlRpc; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Console; | ||
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Grid.Framework; | ||
42 | |||
43 | |||
44 | namespace OpenSim.Grid.UserServer.Modules | ||
45 | { | ||
46 | public class AvatarCreationModule | ||
47 | { | ||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | private UserDataBaseService m_userDataBaseService; | ||
51 | // private BaseHttpServer m_httpServer; | ||
52 | private UserConfig m_config; | ||
53 | |||
54 | private string m_inventoryServerUrl; | ||
55 | private IInterServiceInventoryServices m_inventoryService; | ||
56 | |||
57 | public AvatarCreationModule(UserDataBaseService userDataBaseService, UserConfig config, IInterServiceInventoryServices inventoryService) | ||
58 | { | ||
59 | m_config = config; | ||
60 | m_userDataBaseService = userDataBaseService; | ||
61 | m_inventoryService = inventoryService; | ||
62 | m_inventoryServerUrl = config.InventoryUrl.OriginalString; | ||
63 | } | ||
64 | |||
65 | public void Initialise(IGridServiceCore core) | ||
66 | { | ||
67 | CommandConsole console; | ||
68 | if (core.TryGet<CommandConsole>(out console)) | ||
69 | { | ||
70 | console.Commands.AddCommand("userserver", false, "clone avatar", | ||
71 | "clone avatar <TemplateAvatarFirstName> <TemplateAvatarLastName> <TargetAvatarFirstName> <TargetAvatarLastName>", | ||
72 | "Clone the template avatar inventory into a target avatar", RunCommand); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public void PostInitialise() | ||
77 | { | ||
78 | |||
79 | } | ||
80 | |||
81 | public void RegisterHandlers(BaseHttpServer httpServer) | ||
82 | { | ||
83 | } | ||
84 | |||
85 | public void RunCommand(string module, string[] cmd) | ||
86 | { | ||
87 | if ((cmd.Length == 6) && (cmd[0] == "clone") && (cmd[1] == "avatar")) | ||
88 | { | ||
89 | try | ||
90 | { | ||
91 | string tFirst = cmd[2]; | ||
92 | string tLast = cmd[3]; | ||
93 | |||
94 | string nFirst = cmd[4]; | ||
95 | string nLast = cmd[5]; | ||
96 | |||
97 | UserProfileData templateAvatar = m_userDataBaseService.GetUserProfile(tFirst, tLast); | ||
98 | UserProfileData newAvatar = m_userDataBaseService.GetUserProfile(nFirst, nLast); | ||
99 | |||
100 | if (templateAvatar == null) | ||
101 | { | ||
102 | m_log.ErrorFormat("[AvatarAppearance] Clone Avatar: Could not find template avatar {0} , {1}", tFirst, tLast); | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | if (newAvatar == null) | ||
107 | { | ||
108 | m_log.ErrorFormat("[AvatarAppearance] Clone Avatar: Could not find target avatar {0} , {1}", nFirst, nLast); | ||
109 | return; | ||
110 | } | ||
111 | Guid avatar = newAvatar.ID.Guid; | ||
112 | Guid template = templateAvatar.ID.Guid; | ||
113 | CloneAvatar(avatar, template); | ||
114 | |||
115 | } | ||
116 | catch (Exception e) | ||
117 | { | ||
118 | m_log.Error("Error: " + e.ToString()); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | #region Avatar Appearance Creation | ||
123 | |||
124 | public bool CloneAvatar(Guid avatarID, Guid templateID) | ||
125 | { | ||
126 | m_log.InfoFormat("[AvatarAppearance] Starting to create avatar's appearance for user {0}", avatarID.ToString()); | ||
127 | Guid bodyFolder = Guid.Empty; | ||
128 | Guid clothesFolder = Guid.Empty; | ||
129 | bool success = false; | ||
130 | |||
131 | UUID avID = new UUID(avatarID); | ||
132 | List<InventoryFolderBase> avatarInventory = m_inventoryService.GetInventorySkeleton(avID); | ||
133 | if ((avatarInventory == null) || (avatarInventory.Count == 0)) | ||
134 | { | ||
135 | m_log.InfoFormat("[AvatarAppearance] No inventory found for user {0} , so creating it", avID.ToString()); | ||
136 | m_inventoryService.CreateNewUserInventory(avID); | ||
137 | Thread.Sleep(5000); | ||
138 | avatarInventory = m_inventoryService.GetInventorySkeleton(avID); | ||
139 | } | ||
140 | |||
141 | if ((avatarInventory != null) && (avatarInventory.Count > 0)) | ||
142 | { | ||
143 | UUID tempOwnID = new UUID(templateID); | ||
144 | AvatarAppearance appearance = m_userDataBaseService.GetUserAppearance(tempOwnID); | ||
145 | |||
146 | List<InventoryFolderBase> templateInventory = m_inventoryService.GetInventorySkeleton(tempOwnID); | ||
147 | if ((templateInventory != null) && (templateInventory.Count != 0)) | ||
148 | { | ||
149 | for (int i = 0; i < templateInventory.Count; i++) | ||
150 | { | ||
151 | if (templateInventory[i].ParentID == UUID.Zero) | ||
152 | { | ||
153 | success = CloneFolder(avatarInventory, avID, UUID.Zero, appearance, templateInventory[i], templateInventory); | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | else | ||
159 | { | ||
160 | m_log.InfoFormat("[AvatarAppearance] Failed to find the template owner's {0} inventory", tempOwnID); | ||
161 | } | ||
162 | } | ||
163 | m_log.InfoFormat("[AvatarAppearance] finished cloning avatar with result: {0}", success); | ||
164 | return success; | ||
165 | } | ||
166 | |||
167 | private void UpdateAvatarAppearance(UUID avatarID, int wearableType, UUID itemID, UUID assetID) | ||
168 | { | ||
169 | AvatarAppearance appearance = m_userDataBaseService.GetUserAppearance(avatarID); | ||
170 | if (appearance == null) | ||
171 | { | ||
172 | appearance = CreateDefaultAppearance(avatarID); | ||
173 | } | ||
174 | |||
175 | appearance.Wearables[wearableType].AssetID = assetID; | ||
176 | appearance.Wearables[wearableType].ItemID = itemID; | ||
177 | |||
178 | m_userDataBaseService.UpdateUserAppearance(avatarID, appearance); | ||
179 | |||
180 | } | ||
181 | |||
182 | private void UpdateAvatarAttachment(UUID avatarID, int attachmentPoint, UUID itemID, UUID assetID) | ||
183 | { | ||
184 | AvatarAppearance appearance = m_userDataBaseService.GetUserAppearance(avatarID); | ||
185 | if (appearance == null) | ||
186 | { | ||
187 | appearance = CreateDefaultAppearance(avatarID); | ||
188 | } | ||
189 | |||
190 | appearance.SetAttachment(attachmentPoint, itemID, assetID); | ||
191 | |||
192 | m_userDataBaseService.UpdateUserAppearance(avatarID, appearance); | ||
193 | |||
194 | } | ||
195 | |||
196 | private UUID FindFolderID(string name, List<InventoryFolderBase> folders) | ||
197 | { | ||
198 | foreach (InventoryFolderBase folder in folders) | ||
199 | { | ||
200 | if (folder.Name == name) | ||
201 | { | ||
202 | return folder.ID; | ||
203 | } | ||
204 | } | ||
205 | return UUID.Zero; | ||
206 | } | ||
207 | |||
208 | private InventoryFolderBase FindFolder(string name, List<InventoryFolderBase> folders) | ||
209 | { | ||
210 | foreach (InventoryFolderBase folder in folders) | ||
211 | { | ||
212 | if (folder.Name == name) | ||
213 | { | ||
214 | return folder; | ||
215 | } | ||
216 | } | ||
217 | return null; | ||
218 | } | ||
219 | |||
220 | private InventoryFolderBase FindFolder(string name, Guid parentFolderID, List<InventoryFolderBase> folders) | ||
221 | { | ||
222 | foreach (InventoryFolderBase folder in folders) | ||
223 | { | ||
224 | if ((folder.Name == name) && (folder.ParentID.Guid == parentFolderID)) | ||
225 | { | ||
226 | return folder; | ||
227 | } | ||
228 | } | ||
229 | return null; | ||
230 | } | ||
231 | |||
232 | private InventoryItemBase GetItem(string itemName, List<InventoryItemBase> items) | ||
233 | { | ||
234 | foreach (InventoryItemBase item in items) | ||
235 | { | ||
236 | if (item.Name.ToLower() == itemName.ToLower()) | ||
237 | { | ||
238 | return item; | ||
239 | } | ||
240 | } | ||
241 | return null; | ||
242 | } | ||
243 | |||
244 | private List<InventoryFolderBase> FindSubFolders(Guid parentFolderID, List<InventoryFolderBase> folders) | ||
245 | { | ||
246 | List<InventoryFolderBase> subFolders = new List<InventoryFolderBase>(); | ||
247 | foreach (InventoryFolderBase folder in folders) | ||
248 | { | ||
249 | if (folder.ParentID.Guid == parentFolderID) | ||
250 | { | ||
251 | subFolders.Add(folder); | ||
252 | } | ||
253 | } | ||
254 | return subFolders; | ||
255 | } | ||
256 | |||
257 | |||
258 | private UUID CloneInventoryItem(UUID avatarID, UUID avatarFolder, InventoryItemBase item, bool modifyPerms) | ||
259 | { | ||
260 | if (avatarFolder != UUID.Zero) | ||
261 | { | ||
262 | InventoryItemBase clonedItem = new InventoryItemBase(); | ||
263 | clonedItem.Owner = avatarID; | ||
264 | clonedItem.AssetID = item.AssetID; | ||
265 | clonedItem.AssetType = item.AssetType; | ||
266 | clonedItem.BasePermissions = item.BasePermissions; | ||
267 | clonedItem.CreationDate = item.CreationDate; | ||
268 | clonedItem.CreatorId = item.CreatorId; | ||
269 | clonedItem.CreatorIdAsUuid = item.CreatorIdAsUuid; | ||
270 | clonedItem.CurrentPermissions = item.CurrentPermissions; | ||
271 | clonedItem.Description = item.Description; | ||
272 | clonedItem.EveryOnePermissions = item.EveryOnePermissions; | ||
273 | clonedItem.Flags = item.Flags; | ||
274 | clonedItem.Folder = avatarFolder; | ||
275 | clonedItem.GroupID = item.GroupID; | ||
276 | clonedItem.GroupOwned = item.GroupOwned; | ||
277 | clonedItem.GroupPermissions = item.GroupPermissions; | ||
278 | clonedItem.ID = UUID.Random(); | ||
279 | clonedItem.InvType = item.InvType; | ||
280 | clonedItem.Name = item.Name; | ||
281 | clonedItem.NextPermissions = item.NextPermissions; | ||
282 | clonedItem.SalePrice = item.SalePrice; | ||
283 | clonedItem.SaleType = item.SaleType; | ||
284 | |||
285 | if (modifyPerms) | ||
286 | { | ||
287 | ModifyPermissions(clonedItem); | ||
288 | } | ||
289 | |||
290 | SynchronousRestObjectRequester.MakeRequest<InventoryItemBase, bool>( | ||
291 | "POST", m_inventoryServerUrl + "AddNewItem/", clonedItem); | ||
292 | |||
293 | return clonedItem.ID; | ||
294 | } | ||
295 | |||
296 | return UUID.Zero; | ||
297 | } | ||
298 | |||
299 | private static void ModifyPermissions(InventoryItemBase clonedItem) | ||
300 | { | ||
301 | if ((clonedItem.CurrentPermissions & (uint)PermissionMask.Modify) == 0) | ||
302 | clonedItem.CurrentPermissions |= (uint)PermissionMask.Modify; | ||
303 | |||
304 | if ((clonedItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0) | ||
305 | clonedItem.CurrentPermissions |= (uint)PermissionMask.Copy; | ||
306 | |||
307 | if ((clonedItem.CurrentPermissions & (uint)PermissionMask.Transfer) != 0) | ||
308 | clonedItem.CurrentPermissions &= ~(uint)PermissionMask.Transfer; | ||
309 | |||
310 | if ((clonedItem.NextPermissions & (uint)PermissionMask.Modify) == 0) | ||
311 | clonedItem.NextPermissions |= (uint)PermissionMask.Modify; | ||
312 | |||
313 | if ((clonedItem.NextPermissions & (uint)PermissionMask.Copy) == 0) | ||
314 | clonedItem.NextPermissions |= (uint)PermissionMask.Copy; | ||
315 | |||
316 | if ((clonedItem.NextPermissions & (uint)PermissionMask.Transfer) != 0) | ||
317 | clonedItem.NextPermissions &= ~(uint)PermissionMask.Transfer; | ||
318 | } | ||
319 | |||
320 | private AvatarAppearance CreateDefaultAppearance(UUID avatarId) | ||
321 | { | ||
322 | AvatarAppearance appearance = null; | ||
323 | AvatarWearable[] wearables; | ||
324 | byte[] visualParams; | ||
325 | GetDefaultAvatarAppearance(out wearables, out visualParams); | ||
326 | appearance = new AvatarAppearance(avatarId, wearables, visualParams); | ||
327 | |||
328 | return appearance; | ||
329 | } | ||
330 | |||
331 | private static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams) | ||
332 | { | ||
333 | visualParams = GetDefaultVisualParams(); | ||
334 | wearables = AvatarWearable.DefaultWearables; | ||
335 | } | ||
336 | |||
337 | private static byte[] GetDefaultVisualParams() | ||
338 | { | ||
339 | byte[] visualParams; | ||
340 | visualParams = new byte[218]; | ||
341 | for (int i = 0; i < 218; i++) | ||
342 | { | ||
343 | visualParams[i] = 100; | ||
344 | } | ||
345 | return visualParams; | ||
346 | } | ||
347 | #endregion | ||
348 | |||
349 | |||
350 | |||
351 | private bool CloneFolder(List<InventoryFolderBase> avatarInventory, UUID avID, UUID parentFolder, AvatarAppearance appearance, InventoryFolderBase templateFolder, List<InventoryFolderBase> templateFolders) | ||
352 | { | ||
353 | bool success = false; | ||
354 | UUID templateFolderId = templateFolder.ID; | ||
355 | if (templateFolderId != UUID.Zero) | ||
356 | { | ||
357 | InventoryFolderBase toFolder = FindFolder(templateFolder.Name, parentFolder.Guid, avatarInventory); | ||
358 | if (toFolder == null) | ||
359 | { | ||
360 | //create new folder | ||
361 | toFolder = new InventoryFolderBase(); | ||
362 | toFolder.ID = UUID.Random(); | ||
363 | toFolder.Name = templateFolder.Name; | ||
364 | toFolder.Owner = avID; | ||
365 | toFolder.Type = templateFolder.Type; | ||
366 | toFolder.Version = 1; | ||
367 | toFolder.ParentID = parentFolder; | ||
368 | if (!SynchronousRestObjectRequester.MakeRequest<InventoryFolderBase, bool>( | ||
369 | "POST", m_inventoryServerUrl + "CreateFolder/", toFolder)) | ||
370 | { | ||
371 | m_log.InfoFormat("[AvatarApperance] Couldn't make new folder {0} in users inventory", toFolder.Name); | ||
372 | return false; | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | // m_log.InfoFormat("made new folder {0} in users inventory", toFolder.Name); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | List<InventoryItemBase> templateItems = SynchronousRestObjectRequester.MakeRequest<Guid, List<InventoryItemBase>>( | ||
381 | "POST", m_inventoryServerUrl + "GetItems/", templateFolderId.Guid); | ||
382 | if ((templateItems != null) && (templateItems.Count > 0)) | ||
383 | { | ||
384 | foreach (InventoryItemBase item in templateItems) | ||
385 | { | ||
386 | |||
387 | UUID clonedItemId = CloneInventoryItem(avID, toFolder.ID, item, false); | ||
388 | if (clonedItemId != UUID.Zero) | ||
389 | { | ||
390 | int appearanceType = ItemIsPartOfAppearance(item, appearance); | ||
391 | if (appearanceType >= 0) | ||
392 | { | ||
393 | UpdateAvatarAppearance(avID, appearanceType, clonedItemId, item.AssetID); | ||
394 | } | ||
395 | |||
396 | if (appearance != null) | ||
397 | { | ||
398 | int attachment = appearance.GetAttachpoint(item.ID); | ||
399 | if (attachment > 0) | ||
400 | { | ||
401 | UpdateAvatarAttachment(avID, attachment, clonedItemId, item.AssetID); | ||
402 | } | ||
403 | } | ||
404 | success = true; | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | List<InventoryFolderBase> subFolders = FindSubFolders(templateFolder.ID.Guid, templateFolders); | ||
410 | foreach (InventoryFolderBase subFolder in subFolders) | ||
411 | { | ||
412 | if (subFolder.Name.ToLower() != "trash") | ||
413 | { | ||
414 | success = CloneFolder(avatarInventory, avID, toFolder.ID, appearance, subFolder, templateFolders); | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | m_log.Info("[AvatarAppearance] Failed to find the template folder"); | ||
421 | } | ||
422 | return success; | ||
423 | } | ||
424 | |||
425 | private int ItemIsPartOfAppearance(InventoryItemBase item, AvatarAppearance appearance) | ||
426 | { | ||
427 | if (appearance != null) | ||
428 | { | ||
429 | if (appearance.BodyItem == item.ID) | ||
430 | return (int)WearableType.Shape; | ||
431 | |||
432 | if (appearance.EyesItem == item.ID) | ||
433 | return (int)WearableType.Eyes; | ||
434 | |||
435 | if (appearance.GlovesItem == item.ID) | ||
436 | return (int)WearableType.Gloves; | ||
437 | |||
438 | if (appearance.HairItem == item.ID) | ||
439 | return (int)WearableType.Hair; | ||
440 | |||
441 | if (appearance.JacketItem == item.ID) | ||
442 | return (int)WearableType.Jacket; | ||
443 | |||
444 | if (appearance.PantsItem == item.ID) | ||
445 | return (int)WearableType.Pants; | ||
446 | |||
447 | if (appearance.ShirtItem == item.ID) | ||
448 | return (int)WearableType.Shirt; | ||
449 | |||
450 | if (appearance.ShoesItem == item.ID) | ||
451 | return (int)WearableType.Shoes; | ||
452 | |||
453 | if (appearance.SkinItem == item.ID) | ||
454 | return (int)WearableType.Skin; | ||
455 | |||
456 | if (appearance.SkirtItem == item.ID) | ||
457 | return (int)WearableType.Skirt; | ||
458 | |||
459 | if (appearance.SocksItem == item.ID) | ||
460 | return (int)WearableType.Socks; | ||
461 | |||
462 | if (appearance.UnderPantsItem == item.ID) | ||
463 | return (int)WearableType.Underpants; | ||
464 | |||
465 | if (appearance.UnderShirtItem == item.ID) | ||
466 | return (int)WearableType.Undershirt; | ||
467 | } | ||
468 | return -1; | ||
469 | } | ||
470 | |||
471 | } | ||
472 | public enum PermissionMask | ||
473 | { | ||
474 | None = 0, | ||
475 | Transfer = 8192, | ||
476 | Modify = 16384, | ||
477 | Copy = 32768, | ||
478 | Move = 524288, | ||
479 | Damage = 1048576, | ||
480 | All = 2147483647, | ||
481 | } | ||
482 | |||
483 | public enum WearableType | ||
484 | { | ||
485 | Shape = 0, | ||
486 | Skin = 1, | ||
487 | Hair = 2, | ||
488 | Eyes = 3, | ||
489 | Shirt = 4, | ||
490 | Pants = 5, | ||
491 | Shoes = 6, | ||
492 | Socks = 7, | ||
493 | Jacket = 8, | ||
494 | Gloves = 9, | ||
495 | Undershirt = 10, | ||
496 | Underpants = 11, | ||
497 | Skirt = 12, | ||
498 | } | ||
499 | } | ||