diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs
index 73b068d026..02af5d9d7c 100644
--- a/OpenSim/Framework/AvatarAppearance.cs
+++ b/OpenSim/Framework/AvatarAppearance.cs
@@ -539,7 +539,7 @@ namespace OpenSim.Framework
///
public void Unpack(OSDMap data)
{
- if ((data != null) && (data["serial"] != null))
+ if ((data != null) && (data["serial"] != null))
m_serial = data["serial"].AsInteger();
if ((data != null) && (data["height"] != null))
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 e3e34523a8..75d8143edc 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
public void NewClient(IClientAPI client)
{
client.OnRequestWearables += SendWearables;
- client.OnSetAppearance += SetAppearance;
+ client.OnSetAppearance += SetAppearanceFromClient;
client.OnAvatarNowWearing += AvatarIsWearing;
}
@@ -189,7 +189,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
///
///
///
- public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
+ public void SetAppearanceFromClient(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
{
ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
if (sp == null)
@@ -257,6 +257,47 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
return true;
}
+ public bool SaveBakedTextures(UUID agentId)
+ {
+ ScenePresence sp = m_scene.GetScenePresence(agentId);
+
+ if (sp == null || sp.IsChildAgent)
+ return false;
+
+ AvatarAppearance appearance = sp.Appearance;
+ Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures;
+
+ m_log.DebugFormat(
+ "[AV FACTORY]: Permanently saving baked textures for {0} in {1}",
+ sp.Name, m_scene.RegionInfo.RegionName);
+
+ for (int i = 0; i < faceTextures.Length; i++)
+ {
+// m_log.DebugFormat(
+// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
+// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
+
+ if (faceTextures[i] == null)
+ continue;
+
+ AssetBase asset = m_scene.AssetService.Get(faceTextures[i].TextureID.ToString());
+
+ if (asset != null)
+ {
+ asset.Temporary = false;
+ m_scene.AssetService.Store(asset);
+ }
+ else
+ {
+ m_log.WarnFormat(
+ "[AV FACTORY]: Baked texture {0} for {1} in {2} unexpectedly not found when trying to save permanently",
+ faceTextures[i].TextureID, sp.Name, m_scene.RegionInfo.RegionName);
+ }
+ }
+
+ return true;
+ }
+
#region UpdateAppearanceTimer
///
@@ -289,25 +330,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
}
}
- private void HandleAppearanceSend(UUID agentid)
- {
- ScenePresence sp = m_scene.GetScenePresence(agentid);
- if (sp == null)
- {
- m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
- return;
- }
-
- // m_log.WarnFormat("[AVFACTORY]: Handle appearance send for {0}", agentid);
-
- // Send the appearance to everyone in the scene
- sp.SendAppearanceToAllOtherAgents();
-
- // Send animations back to the avatar as well
- sp.Animator.SendAnimPack();
- }
-
- private void HandleAppearanceSave(UUID agentid)
+ private void SaveAppearance(UUID agentid)
{
// We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
// in a culture where decimal points are commas and then reloaded in a culture which just treats them as
@@ -337,7 +360,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
{
if (kvp.Value < now)
{
- Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); });
+ Util.FireAndForget(delegate(object o) { SendAppearance(kvp.Key); });
m_sendqueue.Remove(kvp.Key);
}
}
@@ -350,7 +373,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
{
if (kvp.Value < now)
{
- Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); });
+ Util.FireAndForget(delegate(object o) { SaveAppearance(kvp.Key); });
m_savequeue.Remove(kvp.Key);
}
}
@@ -427,6 +450,24 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
}
}
+ public bool SendAppearance(UUID agentId)
+ {
+ ScenePresence sp = m_scene.GetScenePresence(agentId);
+ if (sp == null)
+ {
+ m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
+ return false;
+ }
+
+ // Send the appearance to everyone in the scene
+ sp.SendAppearanceToAllOtherAgents();
+
+ // Send animations back to the avatar as well
+ sp.Animator.SendAnimPack();
+
+ return true;
+ }
+
private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance)
{
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 1bd3b6e5e9..b831b31776 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
for (byte i = 0; i < visualParams.Length; i++)
visualParams[i] = i;
- afm.SetAppearance(tc, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams);
+ afm.SetAppearanceFromClient(tc, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams);
ScenePresence sp = scene.GetScenePresence(userId);
diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
index d0e56098c7..6817725864 100644
--- a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs
@@ -32,6 +32,14 @@ namespace OpenSim.Region.Framework.Interfaces
{
public interface IAvatarFactory
{
+ ///
+ /// Send the appearance of an avatar to others in the scene.
+ ///
+ ///
+ ///
+ bool SendAppearance(UUID agentId);
+
+ bool SaveBakedTextures(UUID agentId);
bool ValidateBakedTextureCache(IClientAPI client);
void QueueAppearanceSend(UUID agentid);
void QueueAppearanceSave(UUID agentid);
diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
index fa8d6b69b4..54575ca40a 100644
--- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
@@ -26,6 +26,7 @@
*/
using OpenMetaverse;
+using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.Framework.Interfaces
@@ -43,6 +44,23 @@ namespace OpenSim.Region.Framework.Interfaces
/// The UUID of the ScenePresence created.
UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom);
+ ///
+ /// Check if the agent is an NPC.
+ ///
+ ///
+ ///
+ /// True if the agent is an NPC in the given scene. False otherwise.
+ bool IsNPC(UUID agentID, Scene scene);
+
+ ///
+ /// Set the appearance for an NPC.
+ ///
+ ///
+ ///
+ ///
+ ///
+ bool SetNPCAppearance(UUID agentID, AvatarAppearance appearance, Scene scene);
+
///
/// Move an NPC to a target over time.
///
@@ -59,7 +77,6 @@ namespace OpenSim.Region.Framework.Interfaces
///
void Say(UUID agentID, Scene scene, string text);
-
///
/// Delete an NPC.
///
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index 4f21d9d4ec..d966345092 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
}
}
+ public bool IsNPC(UUID agentId, Scene scene)
+ {
+ ScenePresence sp = scene.GetScenePresence(agentId);
+ if (sp == null || sp.IsChildAgent)
+ return false;
+
+ lock (m_avatars)
+ return m_avatars.ContainsKey(agentId);
+ }
+
+ public bool SetNPCAppearance(UUID agentId, AvatarAppearance appearance, Scene scene)
+ {
+ ScenePresence sp = scene.GetScenePresence(agentId);
+ if (sp == null || sp.IsChildAgent)
+ return false;
+
+ lock (m_avatars)
+ if (!m_avatars.ContainsKey(agentId))
+ return false;
+
+ AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true);
+ sp.Appearance = npcAppearance;
+
+ IAvatarFactory module = scene.RequestModuleInterface();
+ module.SendAppearance(sp.UUID);
+
+ return true;
+ }
+
public UUID CreateNPC(string firstname, string lastname, Vector3 position, Scene scene, UUID cloneAppearanceFrom)
{
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 a0260a5bd3..2ec354fb84 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
// ScenePresence.SendInitialData() to reset our entire appearance.
scene.AssetService.Store(AssetHelpers.CreateAsset(originalFace8TextureId));
- afm.SetAppearance(originalClient, originalTe, null);
+ afm.SetAppearanceFromClient(originalClient, originalTe, null);
INPCModule npcModule = scene.RequestModuleInterface();
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 7c21ba9eb5..86ee28aeb4 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
}
}
- public static string GetLine(UUID assetID, int line, int maxLength)
+ ///
+ /// Get a notecard line.
+ ///
+ ///
+ /// Lines start at index 0
+ ///
+ public static string GetLine(UUID assetID, int lineNumber)
{
- if (line < 0)
+ if (lineNumber < 0)
return "";
string data;
@@ -10579,17 +10585,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_Notecards[assetID].lastRef = DateTime.Now;
- if (line >= m_Notecards[assetID].text.Length)
+ if (lineNumber >= m_Notecards[assetID].text.Length)
return "\n\n\n";
- data = m_Notecards[assetID].text[line];
- if (data.Length > maxLength)
- data = data.Substring(0, maxLength);
+ data = m_Notecards[assetID].text[lineNumber];
return data;
}
}
+ ///
+ /// Get a notecard line.
+ ///
+ ///
+ /// Lines start at index 0
+ /// Maximum length of the returned line. Longer lines will be truncated
+ ///
+ public static string GetLine(UUID assetID, int lineNumber, int maxLength)
+ {
+ string line = GetLine(assetID, lineNumber);
+
+ if (line.Length > maxLength)
+ line = line.Substring(0, maxLength);
+
+ return line;
+ }
+
public static void CacheCheck()
{
foreach (UUID key in new List(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 154179c491..07b36def01 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 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
using System.Runtime.Remoting.Lifetime;
using System.Text;
using System.Net;
using System.Threading;
+using System.Xml;
+using log4net;
using OpenMetaverse;
+using OpenMetaverse.StructuredData;
using Nini.Config;
using OpenSim;
using OpenSim.Framework;
@@ -119,6 +124,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
[Serializable]
public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi
{
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
internal IScriptEngine m_ScriptEngine;
internal ILSL_Api m_LSL_Api = null; // get a reference to the LSL API so we can call methods housed there
internal SceneObjectPart m_host;
@@ -1730,26 +1737,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
for (int i = 0; i < contents.Length; i++)
notecardData.Append((string)(contents.GetLSLStringItem(i) + "\n"));
- SaveNotecard(notecardName, notecardData.ToString());
+ SaveNotecard(notecardName, "Script generated notecard", notecardData.ToString(), false);
}
///
/// Save a notecard to prim inventory.
///
- ///
+ ///
+ /// Description of notecard
///
+ ///
+ /// If true, then if an item exists with the same name, it is replaced.
+ /// If false, then a new item is created witha slightly different name (e.g. name 1)
+ ///
/// Prim inventory item created.
- protected TaskInventoryItem SaveNotecard(string notecardName, string notecardData)
+ protected TaskInventoryItem SaveNotecard(string name, string description, string data, bool forceSameName)
{
// Create new asset
- AssetBase asset = new AssetBase(UUID.Random(), notecardName, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString());
- asset.Description = "Script Generated Notecard";
+ AssetBase asset = new AssetBase(UUID.Random(), name, (sbyte)AssetType.Notecard, m_host.OwnerID.ToString());
+ asset.Description = description;
- int textLength = notecardData.Length;
- notecardData = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length "
- + textLength.ToString() + "\n" + notecardData + "}\n";
+ int textLength = data.Length;
+ data
+ = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length "
+ + textLength.ToString() + "\n" + data + "}\n";
- asset.Data = Util.UTF8.GetBytes(notecardData);
+ asset.Data = Util.UTF8.GetBytes(data);
World.AssetService.Store(asset);
// Create Task Entry
@@ -1775,7 +1788,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
taskItem.PermsMask = 0;
taskItem.AssetID = asset.FullID;
- m_host.Inventory.AddInventoryItem(taskItem, false);
+ if (forceSameName)
+ m_host.Inventory.AddInventoryItemExclusive(taskItem, false);
+ else
+ m_host.Inventory.AddInventoryItem(taskItem, false);
return taskItem;
}
@@ -1791,7 +1807,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
StringBuilder notecardData = new StringBuilder();
for (int count = 0; count < NotecardCache.GetLines(assetID); count++)
- notecardData.Append(NotecardCache.GetLine(assetID, count, 255) + "\n");
+ {
+ string line = NotecardCache.GetLine(assetID, count) + "\n";
+
+// m_log.DebugFormat("[OSSL]: From notecard {0} loading line {1}", notecardNameOrUuid, line);
+
+ notecardData.Append(line);
+ }
return notecardData.ToString();
}
@@ -1807,7 +1829,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
protected UUID CacheNotecard(string notecardNameOrUuid)
{
UUID assetID = UUID.Zero;
- StringBuilder notecardData = new StringBuilder();
if (!UUID.TryParse(notecardNameOrUuid, out assetID))
{
@@ -1864,7 +1885,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return "ERROR!";
}
- return NotecardCache.GetLine(assetID, line, 255);
+ return NotecardCache.GetLine(assetID, line);
}
///
@@ -2122,9 +2143,66 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return new LSL_Key(x.ToString());
}
+
return new LSL_Key(UUID.Zero.ToString());
}
+ public LSL_Key osNpcSaveAppearance(string avatar, string notecardName)
+ {
+ CheckThreatLevel(ThreatLevel.High, "osNpcSaveAppearance");
+
+ INPCModule npcModule = World.RequestModuleInterface();
+ IAvatarFactory appearanceModule = World.RequestModuleInterface();
+
+ if (npcModule != null && appearanceModule != null)
+ {
+ UUID avatarId = UUID.Zero;
+ if (!UUID.TryParse(avatar, out avatarId))
+ return new LSL_Key(UUID.Zero.ToString());
+
+ if (!npcModule.IsNPC(avatarId, m_host.ParentGroup.Scene))
+ return new LSL_Key(UUID.Zero.ToString());
+
+ appearanceModule.SaveBakedTextures(avatarId);
+ ScenePresence sp = m_host.ParentGroup.Scene.GetScenePresence(avatarId);
+ OSDMap appearancePacked = sp.Appearance.Pack();
+
+ TaskInventoryItem item
+ = SaveNotecard(notecardName, "Avatar Appearance", Util.GetFormattedXml(appearancePacked as OSD), true);
+
+ return new LSL_Key(item.AssetID.ToString());
+ }
+
+ return new LSL_Key(UUID.Zero.ToString());
+ }
+
+ public void osNpcLoadAppearance(string avatar, string notecardNameOrUuid)
+ {
+ CheckThreatLevel(ThreatLevel.High, "osNpcLoadAppearance");
+
+ INPCModule npcModule = World.RequestModuleInterface();
+
+ if (npcModule != null)
+ {
+ UUID avatarId = UUID.Zero;
+ if (!UUID.TryParse(avatar, out avatarId))
+ return;
+
+ if (!npcModule.IsNPC(avatarId, m_host.ParentGroup.Scene))
+ return;
+
+ string appearanceSerialized = LoadNotecard(notecardNameOrUuid);
+ OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized);
+// OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized);
+// Console.WriteLine("appearanceSerialized {0}", appearanceSerialized);
+// Console.WriteLine("a.Type {0}, a.ToString() {1}", a.Type, a);
+ AvatarAppearance appearance = new AvatarAppearance();
+ appearance.Unpack(appearanceOsd);
+
+ npcModule.SetNPCAppearance(avatarId, appearance, m_host.ParentGroup.Scene);
+ }
+ }
+
public void osNpcMoveTo(LSL_Key npc, LSL_Vector position)
{
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 19352f0166..868af2794b 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
key osNpcCreate(string user, string name, vector position, key cloneFrom);
+ LSL_Key osNpcSaveAppearance(string avatar, string notecardName);
+ void osNpcLoadAppearance(string avatar, string notecardNameOrUuid);
void osNpcMoveTo(key npc, vector position);
void osNpcSay(key npc, string message);
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 7c59098a11..959b5d5e16 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
return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom);
}
+ public key osNpcSaveAppearance(string avatar, string notecardName)
+ {
+ return m_OSSL_Functions.osNpcSaveAppearance(avatar, notecardName);
+ }
+
+ public void osNpcLoadAppearance(string avatar, string notecardNameOrUuid)
+ {
+ m_OSSL_Functions.osNpcLoadAppearance(avatar, notecardNameOrUuid);
+ }
+
public void osNpcMoveTo(key npc, vector position)
{
m_OSSL_Functions.osNpcMoveTo(npc, position);
diff --git a/prebuild.xml b/prebuild.xml
index 92368ef8e4..9d1be3a2b0 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -2308,6 +2308,7 @@
+