aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2011-08-09 03:51:34 +0100
committerJustin Clark-Casey (justincc)2011-08-09 03:51:34 +0100
commite869eeb0bfc48c769f680970f99e4c67dd5a1a70 (patch)
tree749440ee4ba12140b708e2fe68e98419710d6ea0
parentfactor out common notecard caching code from 3 methods. (diff)
downloadopensim-SC-e869eeb0bfc48c769f680970f99e4c67dd5a1a70.zip
opensim-SC-e869eeb0bfc48c769f680970f99e4c67dd5a1a70.tar.gz
opensim-SC-e869eeb0bfc48c769f680970f99e4c67dd5a1a70.tar.bz2
opensim-SC-e869eeb0bfc48c769f680970f99e4c67dd5a1a70.tar.xz
Implement first draft functions for saving and loading NPC appearance from storage.
This works by serializing and deserializing NPC AvatarAppearance to a notecard in the prim inventory and making the required baked textures permanent. By using notecards, we avoid lots of awkward, technical and user-unfriendly issues concerning retaining asset references and creating a new asset type. Notecards also allow different appearances to be swapped and manipulated easily. This also allows stored NPC appearances to work transparently with OARs/IARs since the UUID scan will pick up and store the necessary references from the notecard text. This works in my basic test but is not at all ready for user use or bug reporting yet.
-rw-r--r--OpenSim/Framework/AvatarAppearance.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs87
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs8
-rw-r--r--OpenSim/Region/Framework/Interfaces/INPCModule.cs19
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs29
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs33
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs104
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs10
-rw-r--r--prebuild.xml1
12 files changed, 253 insertions, 46 deletions
diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs
index 73b068d..02af5d9 100644
--- a/OpenSim/Framework/AvatarAppearance.cs
+++ b/OpenSim/Framework/AvatarAppearance.cs
@@ -539,7 +539,7 @@ namespace OpenSim.Framework
539 /// </summary> 539 /// </summary>
540 public void Unpack(OSDMap data) 540 public void Unpack(OSDMap data)
541 { 541 {
542 if ((data != null) && (data["serial"] != null)) 542 if ((data != null) && (data["serial"] != null))
543 m_serial = data["serial"].AsInteger(); 543 m_serial = data["serial"].AsInteger();
544 if ((data != null) && (data["height"] != null)) 544 if ((data != null) && (data["height"] != null))
545 m_avatarHeight = (float)data["height"].AsReal(); 545 m_avatarHeight = (float)data["height"].AsReal();
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index e3e3452..75d8143 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
104 public void NewClient(IClientAPI client) 104 public void NewClient(IClientAPI client)
105 { 105 {
106 client.OnRequestWearables += SendWearables; 106 client.OnRequestWearables += SendWearables;
107 client.OnSetAppearance += SetAppearance; 107 client.OnSetAppearance += SetAppearanceFromClient;
108 client.OnAvatarNowWearing += AvatarIsWearing; 108 client.OnAvatarNowWearing += AvatarIsWearing;
109 } 109 }
110 110
@@ -189,7 +189,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
189 /// <param name="client"></param> 189 /// <param name="client"></param>
190 /// <param name="texture"></param> 190 /// <param name="texture"></param>
191 /// <param name="visualParam"></param> 191 /// <param name="visualParam"></param>
192 public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) 192 public void SetAppearanceFromClient(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
193 { 193 {
194 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 194 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
195 if (sp == null) 195 if (sp == null)
@@ -257,6 +257,47 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
257 return true; 257 return true;
258 } 258 }
259 259
260 public bool SaveBakedTextures(UUID agentId)
261 {
262 ScenePresence sp = m_scene.GetScenePresence(agentId);
263
264 if (sp == null || sp.IsChildAgent)
265 return false;
266
267 AvatarAppearance appearance = sp.Appearance;
268 Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures;
269
270 m_log.DebugFormat(
271 "[AV FACTORY]: Permanently saving baked textures for {0} in {1}",
272 sp.Name, m_scene.RegionInfo.RegionName);
273
274 for (int i = 0; i < faceTextures.Length; i++)
275 {
276// m_log.DebugFormat(
277// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
278// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
279
280 if (faceTextures[i] == null)
281 continue;
282
283 AssetBase asset = m_scene.AssetService.Get(faceTextures[i].TextureID.ToString());
284
285 if (asset != null)
286 {
287 asset.Temporary = false;
288 m_scene.AssetService.Store(asset);
289 }
290 else
291 {
292 m_log.WarnFormat(
293 "[AV FACTORY]: Baked texture {0} for {1} in {2} unexpectedly not found when trying to save permanently",
294 faceTextures[i].TextureID, sp.Name, m_scene.RegionInfo.RegionName);
295 }
296 }
297
298 return true;
299 }
300
260 #region UpdateAppearanceTimer 301 #region UpdateAppearanceTimer
261 302
262 /// <summary> 303 /// <summary>
@@ -289,25 +330,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
289 } 330 }
290 } 331 }
291 332
292 private void HandleAppearanceSend(UUID agentid) 333 private void SaveAppearance(UUID agentid)
293 {
294 ScenePresence sp = m_scene.GetScenePresence(agentid);
295 if (sp == null)
296 {
297 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
298 return;
299 }
300
301 // m_log.WarnFormat("[AVFACTORY]: Handle appearance send for {0}", agentid);
302
303 // Send the appearance to everyone in the scene
304 sp.SendAppearanceToAllOtherAgents();
305
306 // Send animations back to the avatar as well
307 sp.Animator.SendAnimPack();
308 }
309
310 private void HandleAppearanceSave(UUID agentid)
311 { 334 {
312 // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved 335 // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
313 // in a culture where decimal points are commas and then reloaded in a culture which just treats them as 336 // in a culture where decimal points are commas and then reloaded in a culture which just treats them as
@@ -337,7 +360,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
337 { 360 {
338 if (kvp.Value < now) 361 if (kvp.Value < now)
339 { 362 {
340 Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); }); 363 Util.FireAndForget(delegate(object o) { SendAppearance(kvp.Key); });
341 m_sendqueue.Remove(kvp.Key); 364 m_sendqueue.Remove(kvp.Key);
342 } 365 }
343 } 366 }
@@ -350,7 +373,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
350 { 373 {
351 if (kvp.Value < now) 374 if (kvp.Value < now)
352 { 375 {
353 Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); }); 376 Util.FireAndForget(delegate(object o) { SaveAppearance(kvp.Key); });
354 m_savequeue.Remove(kvp.Key); 377 m_savequeue.Remove(kvp.Key);
355 } 378 }
356 } 379 }
@@ -427,6 +450,24 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
427 } 450 }
428 } 451 }
429 452
453 public bool SendAppearance(UUID agentId)
454 {
455 ScenePresence sp = m_scene.GetScenePresence(agentId);
456 if (sp == null)
457 {
458 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
459 return false;
460 }
461
462 // Send the appearance to everyone in the scene
463 sp.SendAppearanceToAllOtherAgents();
464
465 // Send animations back to the avatar as well
466 sp.Animator.SendAnimPack();
467
468 return true;
469 }
470
430 private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) 471 private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance)
431 { 472 {
432 IInventoryService invService = m_scene.InventoryService; 473 IInventoryService invService = m_scene.InventoryService;
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
index 1bd3b6e..b831b31 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
58 for (byte i = 0; i < visualParams.Length; i++) 58 for (byte i = 0; i < visualParams.Length; i++)
59 visualParams[i] = i; 59 visualParams[i] = i;
60 60
61 afm.SetAppearance(tc, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams); 61 afm.SetAppearanceFromClient(tc, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams);
62 62
63 ScenePresence sp = scene.GetScenePresence(userId); 63 ScenePresence sp = scene.GetScenePresence(userId);
64 64
diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
index d0e5609..6817725 100644
--- a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
@@ -32,6 +32,14 @@ namespace OpenSim.Region.Framework.Interfaces
32{ 32{
33 public interface IAvatarFactory 33 public interface IAvatarFactory
34 { 34 {
35 /// <summary>
36 /// Send the appearance of an avatar to others in the scene.
37 /// </summary>
38 /// <param name="agentId"></param>
39 /// <returns></returns>
40 bool SendAppearance(UUID agentId);
41
42 bool SaveBakedTextures(UUID agentId);
35 bool ValidateBakedTextureCache(IClientAPI client); 43 bool ValidateBakedTextureCache(IClientAPI client);
36 void QueueAppearanceSend(UUID agentid); 44 void QueueAppearanceSend(UUID agentid);
37 void QueueAppearanceSave(UUID agentid); 45 void QueueAppearanceSave(UUID agentid);
diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
index fa8d6b6..54575ca 100644
--- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using OpenMetaverse; 28using OpenMetaverse;
29using OpenSim.Framework;
29using OpenSim.Region.Framework.Scenes; 30using OpenSim.Region.Framework.Scenes;
30 31
31namespace OpenSim.Region.Framework.Interfaces 32namespace OpenSim.Region.Framework.Interfaces
@@ -44,6 +45,23 @@ namespace OpenSim.Region.Framework.Interfaces
44 UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom); 45 UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom);
45 46
46 /// <summary> 47 /// <summary>
48 /// Check if the agent is an NPC.
49 /// </summary>
50 /// <param name="agentID"></param>
51 /// <param name="scene"></param>
52 /// <returns>True if the agent is an NPC in the given scene. False otherwise.</returns>
53 bool IsNPC(UUID agentID, Scene scene);
54
55 /// <summary>
56 /// Set the appearance for an NPC.
57 /// </summary>
58 /// <param name="agentID"></param>
59 /// <param name="appearance"></param>
60 /// <param name="scene"></param>
61 /// <returns></returns>
62 bool SetNPCAppearance(UUID agentID, AvatarAppearance appearance, Scene scene);
63
64 /// <summary>
47 /// Move an NPC to a target over time. 65 /// Move an NPC to a target over time.
48 /// </summary> 66 /// </summary>
49 /// <param name="agentID">The UUID of the NPC</param> 67 /// <param name="agentID">The UUID of the NPC</param>
@@ -59,7 +77,6 @@ namespace OpenSim.Region.Framework.Interfaces
59 /// <param name="text"></param> 77 /// <param name="text"></param>
60 void Say(UUID agentID, Scene scene, string text); 78 void Say(UUID agentID, Scene scene, string text);
61 79
62
63 /// <summary> 80 /// <summary>
64 /// Delete an NPC. 81 /// Delete an NPC.
65 /// </summary> 82 /// </summary>
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index 4f21d9d..d966345 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -137,6 +137,35 @@ namespace OpenSim.Region.OptionalModules.World.NPC
137 } 137 }
138 } 138 }
139 139
140 public bool IsNPC(UUID agentId, Scene scene)
141 {
142 ScenePresence sp = scene.GetScenePresence(agentId);
143 if (sp == null || sp.IsChildAgent)
144 return false;
145
146 lock (m_avatars)
147 return m_avatars.ContainsKey(agentId);
148 }
149
150 public bool SetNPCAppearance(UUID agentId, AvatarAppearance appearance, Scene scene)
151 {
152 ScenePresence sp = scene.GetScenePresence(agentId);
153 if (sp == null || sp.IsChildAgent)
154 return false;
155
156 lock (m_avatars)
157 if (!m_avatars.ContainsKey(agentId))
158 return false;
159
160 AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true);
161 sp.Appearance = npcAppearance;
162
163 IAvatarFactory module = scene.RequestModuleInterface<IAvatarFactory>();
164 module.SendAppearance(sp.UUID);
165
166 return true;
167 }
168
140 public UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom) 169 public UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom)
141 { 170 {
142 NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene); 171 NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position, scene);
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
index a0260a5..2ec354f 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
@@ -72,7 +72,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests
72 // ScenePresence.SendInitialData() to reset our entire appearance. 72 // ScenePresence.SendInitialData() to reset our entire appearance.
73 scene.AssetService.Store(AssetHelpers.CreateAsset(originalFace8TextureId)); 73 scene.AssetService.Store(AssetHelpers.CreateAsset(originalFace8TextureId));
74 74
75 afm.SetAppearance(originalClient, originalTe, null); 75 afm.SetAppearanceFromClient(originalClient, originalTe, null);
76 76
77 INPCModule npcModule = scene.RequestModuleInterface<INPCModule>(); 77 INPCModule npcModule = scene.RequestModuleInterface<INPCModule>();
78 UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, originalClient.AgentId); 78 UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, originalClient.AgentId);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 7c21ba9..86ee28a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -10565,9 +10565,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10565 } 10565 }
10566 } 10566 }
10567 10567
10568 public static string GetLine(UUID assetID, int line, int maxLength) 10568 /// <summary>
10569 /// Get a notecard line.
10570 /// </summary>
10571 /// <param name="assetID"></param>
10572 /// <param name="line">Lines start at index 0</param>
10573 /// <returns></returns>
10574 public static string GetLine(UUID assetID, int lineNumber)
10569 { 10575 {
10570 if (line < 0) 10576 if (lineNumber < 0)
10571 return ""; 10577 return "";
10572 10578
10573 string data; 10579 string data;
@@ -10579,17 +10585,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10579 { 10585 {
10580 m_Notecards[assetID].lastRef = DateTime.Now; 10586 m_Notecards[assetID].lastRef = DateTime.Now;
10581 10587
10582 if (line >= m_Notecards[assetID].text.Length) 10588 if (lineNumber >= m_Notecards[assetID].text.Length)
10583 return "\n\n\n"; 10589 return "\n\n\n";
10584 10590
10585 data = m_Notecards[assetID].text[line]; 10591 data = m_Notecards[assetID].text[lineNumber];
10586 if (data.Length > maxLength)
10587 data = data.Substring(0, maxLength);
10588 10592
10589 return data; 10593 return data;
10590 } 10594 }
10591 } 10595 }
10592 10596
10597 /// <summary>
10598 /// Get a notecard line.
10599 /// </summary>
10600 /// <param name="assetID"></param>
10601 /// <param name="line">Lines start at index 0</param>
10602 /// <param name="maxLength">Maximum length of the returned line. Longer lines will be truncated</para>
10603 /// <returns></returns>
10604 public static string GetLine(UUID assetID, int lineNumber, int maxLength)
10605 {
10606 string line = GetLine(assetID, lineNumber);
10607
10608 if (line.Length > maxLength)
10609 line = line.Substring(0, maxLength);
10610
10611 return line;
10612 }
10613
10593 public static void CacheCheck() 10614 public static void CacheCheck()
10594 { 10615 {
10595 foreach (UUID key in new List<UUID>(m_Notecards.Keys)) 10616 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 154179c..07b36de 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -28,11 +28,16 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
31using System.Runtime.Remoting.Lifetime; 33using System.Runtime.Remoting.Lifetime;
32using System.Text; 34using System.Text;
33using System.Net; 35using System.Net;
34using System.Threading; 36using System.Threading;
37using System.Xml;
38using log4net;
35using OpenMetaverse; 39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
36using Nini.Config; 41using Nini.Config;
37using OpenSim; 42using OpenSim;
38using OpenSim.Framework; 43using OpenSim.Framework;
@@ -119,6 +124,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
119 [Serializable] 124 [Serializable]
120 public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi 125 public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi
121 { 126 {
127// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
128
122 internal IScriptEngine m_ScriptEngine; 129 internal IScriptEngine m_ScriptEngine;
123 internal ILSL_Api m_LSL_Api = null; // get a reference to the LSL API so we can call methods housed there 130 internal ILSL_Api m_LSL_Api = null; // get a reference to the LSL API so we can call methods housed there
124 internal SceneObjectPart m_host; 131 internal SceneObjectPart m_host;
@@ -1730,26 +1737,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1730 for (int i = 0; i < contents.Length; i++) 1737 for (int i = 0; i < contents.Length; i++)
1731 notecardData.Append((string)(contents.GetLSLStringItem(i) + "\n")); 1738 notecardData.Append((string)(contents.GetLSLStringItem(i) + "\n"));
1732 1739
1733 SaveNotecard(notecardName, notecardData.ToString()); 1740 SaveNotecard(notecardName, "Script generated notecard", notecardData.ToString(), false);
1734 } 1741 }
1735 1742
1736 /// <summary> 1743 /// <summary>
1737 /// Save a notecard to prim inventory. 1744 /// Save a notecard to prim inventory.
1738 /// </summary> 1745 /// </summary>
1739 /// <param name="notecardName"></param> 1746 /// <param name="name"></param>
1747 /// <param name="description">Description of notecard</param>
1740 /// <param name="notecardData"></param> 1748 /// <param name="notecardData"></param>
1749 /// <param name="forceSameName">
1750 /// If true, then if an item exists with the same name, it is replaced.
1751 /// If false, then a new item is created witha slightly different name (e.g. name 1)
1752 /// </param>
1741 /// <returns>Prim inventory item created.</returns> 1753 /// <returns>Prim inventory item created.</returns>
1742 protected TaskInventoryItem SaveNotecard(string notecardName, string notecardData) 1754 protected TaskInventoryItem SaveNotecard(string name, string description, string data, bool forceSameName)
1743 { 1755 {
1744 // Create new asset 1756 // Create new asset
1745 AssetBase asset = new AssetBase(UUID.Random(), notecardName, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString()); 1757 AssetBase asset = new AssetBase(UUID.Random(), name, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString());
1746 asset.Description = "Script Generated Notecard"; 1758 asset.Description = description;
1747 1759
1748 int textLength = notecardData.Length; 1760 int textLength = data.Length;
1749 notecardData = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length " 1761 data
1750 + textLength.ToString() + "\n" + notecardData + "}\n"; 1762 = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length "
1763 + textLength.ToString() + "\n" + data + "}\n";
1751 1764
1752 asset.Data = Util.UTF8.GetBytes(notecardData); 1765 asset.Data = Util.UTF8.GetBytes(data);
1753 World.AssetService.Store(asset); 1766 World.AssetService.Store(asset);
1754 1767
1755 // Create Task Entry 1768 // Create Task Entry
@@ -1775,7 +1788,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1775 taskItem.PermsMask = 0; 1788 taskItem.PermsMask = 0;
1776 taskItem.AssetID = asset.FullID; 1789 taskItem.AssetID = asset.FullID;
1777 1790
1778 m_host.Inventory.AddInventoryItem(taskItem, false); 1791 if (forceSameName)
1792 m_host.Inventory.AddInventoryItemExclusive(taskItem, false);
1793 else
1794 m_host.Inventory.AddInventoryItem(taskItem, false);
1779 1795
1780 return taskItem; 1796 return taskItem;
1781 } 1797 }
@@ -1791,7 +1807,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1791 StringBuilder notecardData = new StringBuilder(); 1807 StringBuilder notecardData = new StringBuilder();
1792 1808
1793 for (int count = 0; count < NotecardCache.GetLines(assetID); count++) 1809 for (int count = 0; count < NotecardCache.GetLines(assetID); count++)
1794 notecardData.Append(NotecardCache.GetLine(assetID, count, 255) + "\n"); 1810 {
1811 string line = NotecardCache.GetLine(assetID, count) + "\n";
1812
1813// m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line);
1814
1815 notecardData.Append(line);
1816 }
1795 1817
1796 return notecardData.ToString(); 1818 return notecardData.ToString();
1797 } 1819 }
@@ -1807,7 +1829,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1807 protected UUID CacheNotecard(string notecardNameOrUuid) 1829 protected UUID CacheNotecard(string notecardNameOrUuid)
1808 { 1830 {
1809 UUID assetID = UUID.Zero; 1831 UUID assetID = UUID.Zero;
1810 StringBuilder notecardData = new StringBuilder();
1811 1832
1812 if (!UUID.TryParse(notecardNameOrUuid, out assetID)) 1833 if (!UUID.TryParse(notecardNameOrUuid, out assetID))
1813 { 1834 {
@@ -1864,7 +1885,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1864 return "ERROR!"; 1885 return "ERROR!";
1865 } 1886 }
1866 1887
1867 return NotecardCache.GetLine(assetID, line, 255); 1888 return NotecardCache.GetLine(assetID, line);
1868 } 1889 }
1869 1890
1870 /// <summary> 1891 /// <summary>
@@ -2122,9 +2143,66 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2122 2143
2123 return new LSL_Key(x.ToString()); 2144 return new LSL_Key(x.ToString());
2124 } 2145 }
2146
2125 return new LSL_Key(UUID.Zero.ToString()); 2147 return new LSL_Key(UUID.Zero.ToString());
2126 } 2148 }
2127 2149
2150 public LSL_Key osNpcSaveAppearance(string avatar, string notecardName)
2151 {
2152 CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance");
2153
2154 INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
2155 IAvatarFactory appearanceModule = World.RequestModuleInterface<IAvatarFactory>();
2156
2157 if (npcModule != null && appearanceModule != null)
2158 {
2159 UUID avatarId = UUID.Zero;
2160 if (!UUID.TryParse(avatar, out avatarId))
2161 return new LSL_Key(UUID.Zero.ToString());
2162
2163 if (!npcModule.IsNPC(avatarId, m_host.ParentGroup.Scene))
2164 return new LSL_Key(UUID.Zero.ToString());
2165
2166 appearanceModule.SaveBakedTextures(avatarId);
2167 ScenePresence sp = m_host.ParentGroup.Scene.GetScenePresence(avatarId);
2168 OSDMap appearancePacked = sp.Appearance.Pack();
2169
2170 TaskInventoryItem item
2171 = SaveNotecard(notecardName, "Avatar Appearance", Util.GetFormattedXml(appearancePacked as OSD), true);
2172
2173 return new LSL_Key(item.AssetID.ToString());
2174 }
2175
2176 return new LSL_Key(UUID.Zero.ToString());
2177 }
2178
2179 public void osNpcLoadAppearance(string avatar, string notecardNameOrUuid)
2180 {
2181 CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance");
2182
2183 INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
2184
2185 if (npcModule != null)
2186 {
2187 UUID avatarId = UUID.Zero;
2188 if (!UUID.TryParse(avatar, out avatarId))
2189 return;
2190
2191 if (!npcModule.IsNPC(avatarId, m_host.ParentGroup.Scene))
2192 return;
2193
2194 string appearanceSerialized = LoadNotecard(notecardNameOrUuid);
2195 OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized);
2196// OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized);
2197// Console.WriteLine("appearanceSerialized {0}", appearanceSerialized);
2198// Console.WriteLine("a.Type {0}, a.ToString() {1}", a.Type, a);
2199 AvatarAppearance appearance = new AvatarAppearance();
2200 appearance.Unpack(appearanceOsd);
2201
2202 npcModule.SetNPCAppearance(avatarId, appearance, m_host.ParentGroup.Scene);
2203 }
2204 }
2205
2128 public void osNpcMoveTo(LSL_Key npc, LSL_Vector position) 2206 public void osNpcMoveTo(LSL_Key npc, LSL_Vector position)
2129 { 2207 {
2130 CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo"); 2208 CheckThreatLevel(ThreatLevel.High, "osNpcMoveTo");
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 19352f0..868af27 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -170,6 +170,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
170 170
171 171
172 key osNpcCreate(string user, string name, vector position, key cloneFrom); 172 key osNpcCreate(string user, string name, vector position, key cloneFrom);
173 LSL_Key osNpcSaveAppearance(string avatar, string notecardName);
174 void osNpcLoadAppearance(string avatar, string notecardNameOrUuid);
173 void osNpcMoveTo(key npc, vector position); 175 void osNpcMoveTo(key npc, vector position);
174 void osNpcSay(key npc, string message); 176 void osNpcSay(key npc, string message);
175 void osNpcRemove(key npc); 177 void osNpcRemove(key npc);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index 7c59098..959b5d5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -483,6 +483,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
483 return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom); 483 return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom);
484 } 484 }
485 485
486 public key osNpcSaveAppearance(string avatar, string notecardName)
487 {
488 return m_OSSL_Functions.osNpcSaveAppearance(avatar, notecardName);
489 }
490
491 public void osNpcLoadAppearance(string avatar, string notecardNameOrUuid)
492 {
493 m_OSSL_Functions.osNpcLoadAppearance(avatar, notecardNameOrUuid);
494 }
495
486 public void osNpcMoveTo(key npc, vector position) 496 public void osNpcMoveTo(key npc, vector position)
487 { 497 {
488 m_OSSL_Functions.osNpcMoveTo(npc, position); 498 m_OSSL_Functions.osNpcMoveTo(npc, position);
diff --git a/prebuild.xml b/prebuild.xml
index 92368ef..9d1be3a 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -2308,6 +2308,7 @@
2308 <Reference name="System.Xml"/> 2308 <Reference name="System.Xml"/>
2309 <Reference name="OpenMetaverseTypes" path="../../../../../../bin/"/> 2309 <Reference name="OpenMetaverseTypes" path="../../../../../../bin/"/>
2310 <Reference name="OpenMetaverse" path="../../../../../../bin/"/> 2310 <Reference name="OpenMetaverse" path="../../../../../../bin/"/>
2311 <Reference name="OpenMetaverse.StructuredData" path="../../../../../../bin/"/>
2311 <Reference name="OpenSim"/> 2312 <Reference name="OpenSim"/>
2312 <Reference name="OpenSim.Framework"/> 2313 <Reference name="OpenSim.Framework"/>
2313 <Reference name="OpenSim.Framework.Communications"/> 2314 <Reference name="OpenSim.Framework.Communications"/>