From e7fd7322095d518ccd7b446cf5c0683ef8009793 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 11 Feb 2012 00:10:59 +0000 Subject: Make ScenePresence.MovementFlag a private only settable value to reduce complexity of code analysis --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 5c56150..77f7b32 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -291,13 +291,10 @@ namespace OpenSim.Region.Framework.Scenes /// public PhysicsActor PhysicsActor { get; private set; } - private byte m_movementflag; - - public byte MovementFlag - { - set { m_movementflag = value; } - get { return m_movementflag; } - } + /// + /// Record user movement inputs. + /// + public byte MovementFlag { get; private set; } private bool m_updateflag; -- cgit v1.1 From f49897a4195df5fbd00e2c16461bcebb36ce8f72 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 11 Feb 2012 02:26:53 +0000 Subject: Clamp ODE character velocity. Make ODE falling character 54m/s by default. If velocity reaches 256 in any vector then bad things happen with ODE, so we now clamp this value. In addition, a falling avatar is clamped by default at 54 m/s, which is the same as a falling skydiver. This also appears to be the value used on the linden lab grid. This should resolve http://opensimulator.org/mantis/view.php?id=5882 --- OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 43 +++++++++++++++++++++++- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 11 ++++++ 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 7c1c046..6d1f41d 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -156,6 +156,22 @@ namespace OpenSim.Region.Physics.OdePlugin internal UUID m_uuid { get; private set; } internal bool bad = false; + /// + /// ODE Avatar. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Only used right now to return information to LSL. Not actually used to set mass in ODE! + /// + /// + /// public OdeCharacter( String avName, OdeScene parent_scene, Vector3 pos, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, @@ -786,6 +802,10 @@ namespace OpenSim.Region.Physics.OdePlugin Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); +// m_log.DebugFormat( +// "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}", +// vel.X, vel.Y, vel.Z, _target_velocity, Name); + float movementdivisor = 1f; if (!m_alwaysRun) @@ -884,18 +904,20 @@ namespace OpenSim.Region.Physics.OdePlugin if (flying) { + // This also acts as anti-gravity so that we hover when flying rather than fall. vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); } } if (flying) { + // Anti-gravity so that we hover when flying rather than fall. vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); //Added for auto fly height. Kitto Flora //d.Vector3 pos = d.BodyGetPosition(Body); float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; - + if (_position.Z < target_altitude) { vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; @@ -921,6 +943,25 @@ namespace OpenSim.Region.Physics.OdePlugin return; } + + d.Vector3 newVel = d.BodyGetLinearVel(Body); + if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256) + { +// m_log.DebugFormat( +// "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name); + + newVel.X = Util.Clamp(newVel.X, -255f, 255f); + newVel.Y = Util.Clamp(newVel.Y, -255f, 255f); + + if (!flying) + newVel.Z + = Util.Clamp( + newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity); + else + newVel.Z = Util.Clamp(newVel.Z, -255f, 255f); + + d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z); + } } /// diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 4530c09..7d1401c 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -144,6 +144,8 @@ namespace OpenSim.Region.Physics.OdePlugin public float gravityy = 0f; public float gravityz = -9.8f; + public float AvatarTerminalVelocity { get; set; } + private float contactsurfacelayer = 0.001f; private int worldHashspaceLow = -4; @@ -459,6 +461,15 @@ namespace OpenSim.Region.Physics.OdePlugin gravityy = physicsconfig.GetFloat("world_gravityy", 0f); gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); + float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 9f); + AvatarTerminalVelocity = Util.Clamp(avatarTerminalVelocity, 0, 255f); + if (AvatarTerminalVelocity != avatarTerminalVelocity) + { + m_log.WarnFormat( + "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}", + avatarTerminalVelocity, AvatarTerminalVelocity); + } + worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4); worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128); -- cgit v1.1 From b92b9228ef5c7833dac019aba12babb5df954d35 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 11 Feb 2012 02:29:07 +0000 Subject: correct the default avatar_terminal_velocity value that I accidentally left in whilst testing --- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 7d1401c..598530c 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -461,7 +461,7 @@ namespace OpenSim.Region.Physics.OdePlugin gravityy = physicsconfig.GetFloat("world_gravityy", 0f); gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); - float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 9f); + float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f); AvatarTerminalVelocity = Util.Clamp(avatarTerminalVelocity, 0, 255f); if (AvatarTerminalVelocity != avatarTerminalVelocity) { -- cgit v1.1 From 189c67db957cadfe1bb5bd8aad0c86dec1ff295b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 13 Feb 2012 20:43:26 +0000 Subject: On object deserialization, go back to logging errors at DEBUG level rather than ERROR. Restore extra log message if shape processing fails. Logging level was DEBUG before 312e145 (Fri Feb 3 2012). 312e145 also accidentally removed the 'general error' log message if any shape deserialization failed. This commit restores it, though this has no functional impact. --- .../Scenes/Serialization/SceneObjectSerializer.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index ab02f92..0a32214 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1470,7 +1470,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors, reader, (o, nodeName, e) - => m_log.ErrorFormat( + => m_log.DebugFormat( "[SceneObjectSerializer]: Exception while parsing {0} in object {1} {2}: {3}{4}", ((SceneObjectPart)o).Name, ((SceneObjectPart)o).UUID, nodeName, e.Message, e.StackTrace)); @@ -1535,14 +1535,18 @@ namespace OpenSim.Region.Framework.Scenes.Serialization reader.ReadStartElement(name, String.Empty); // Shape - ExternalRepresentationUtils.ExecuteReadProcessors( + errors = ExternalRepresentationUtils.ExecuteReadProcessors( shape, m_ShapeXmlProcessors, reader, (o, nodeName, e) - => m_log.ErrorFormat( - "[SceneObjectSerializer]: Exception while parsing Shape property {0}: {1}{2}", - nodeName, e.Message, e.StackTrace)); + => + { + m_log.DebugFormat( + "[SceneObjectSerializer]: Exception while parsing Shape property {0}: {1}{2}", + nodeName, e.Message, e.StackTrace); + } + ); reader.ReadEndElement(); // Shape -- cgit v1.1 From 04a195266bd68f8c62129246a98aefb3201c90f1 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 13 Feb 2012 13:21:42 -0800 Subject: short circuit the expensive parts of the permission checking code if the current user is the owner of an object. none of the later checks can reverse the outcome. --- OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index cdecd2f..f3c6a30 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -707,7 +707,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions // Object owners should be able to edit their own content if (currentUser == objectOwner) { - permission = true; + // there is no way that later code can change this back to false + // so just return true immediately and short circuit the more + // expensive group checks + return true; + + //permission = true; } else if (group.IsAttachment) { -- cgit v1.1 From 04986bbb159754cb835ef6f698b2cc9c37f02b4b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 14 Feb 2012 01:50:51 +0000 Subject: Add some more data to the new user connection logging for debug purposes. --- OpenSim/Region/Framework/Scenes/Scene.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 3347822..4c8e2d2 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3272,9 +3272,9 @@ namespace OpenSim.Region.Framework.Scenes // Don't disable this log message - it's too helpful m_log.DebugFormat( - "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, teleportflags {6}, position {7})", - RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, - agent.AgentID, agent.circuitcode, teleportFlags, agent.startpos); + "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags {8}, position {9})", + RegionInfo.RegionName, (agent.child ? "child" : "root"),agent.firstname, agent.lastname, + agent.AgentID, agent.circuitcode, agent.IPAddress, agent.Viewer, teleportFlags, agent.startpos); if (LoginsDisabled) { -- cgit v1.1 From 4589ce61bc68311d6ab7b5e7aa40ed1def40f52e Mon Sep 17 00:00:00 2001 From: PixelTomsen Date: Sat, 11 Feb 2012 19:00:01 +0100 Subject: Fix: get embedded objects from Notecard fails with activated FreeSwitchVoiceModul http://opensimulator.org/mantis/view.php?id=2607 --- .../Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index 5323a95..05678c0 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs @@ -63,9 +63,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // Capability string prefixes - private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; - private static readonly string m_provisionVoiceAccountRequestPath = "0008/"; - private static readonly string m_chatSessionRequestPath = "0009/"; + private static readonly string m_parcelVoiceInfoRequestPath = "0207/"; + private static readonly string m_provisionVoiceAccountRequestPath = "0208/"; + private static readonly string m_chatSessionRequestPath = "0209/"; // Control info private static bool m_Enabled = false; -- cgit v1.1 From a9e8bd59a377e7c7ce81e3693875467926dd7d4b Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 13 Feb 2012 19:38:22 -0800 Subject: Fix a race condition in the simian groups connector. When requests were too slow they would circumvent the cache (piling up on the network service and making the problem even worse). This condition happens frequently during permission checks. --- .../SimianGroupsServicesConnectorModule.cs | 71 +++++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs index 42008da..130513d 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Reflection; +using System.Threading; using Nwc.XmlRpc; @@ -167,6 +168,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups private bool m_debugEnabled = false; + private Dictionary m_pendingRequests = new Dictionary(); + private ExpiringCache m_memoryCache; private int m_cacheTimeout = 30; @@ -1348,6 +1351,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // Immediately forward the request if the cache is disabled. if (m_cacheTimeout == 0) { + m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: cache is disabled"); return WebUtil.PostToService(m_groupsServerURI, requestArgs); } @@ -1355,6 +1359,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups if (requestArgs["RequestMethod"] == "RemoveGeneric" || requestArgs["RequestMethod"] == "AddGeneric") { + m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: clearing generics cache"); + // Any and all updates cause the cache to clear m_memoryCache.Clear(); @@ -1366,18 +1372,67 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // Create the cache key for the request and see if we have it cached string CacheKey = WebUtil.BuildQueryString(requestArgs); - OSDMap response = null; - if (!m_memoryCache.TryGetValue(CacheKey, out response)) + + // This code uses a leader/follower pattern. On a cache miss, the request is added + // to a queue; the first thread to add it to the queue completes the request while + // follow on threads busy wait for the results, this situation seems to happen + // often when checking permissions + while (true) { - // if it wasn't in the cache, pass the request to the Simian Grid Services - response = WebUtil.PostToService(m_groupsServerURI, requestArgs); + OSDMap response = null; + bool firstRequest = false; - // and cache the response - m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout)); + lock (m_memoryCache) + { + if (m_memoryCache.TryGetValue(CacheKey, out response)) + return response; + + if (! m_pendingRequests.ContainsKey(CacheKey)) + { + m_pendingRequests.Add(CacheKey,true); + firstRequest = true; + } + } + + if (firstRequest) + { + // if it wasn't in the cache, pass the request to the Simian Grid Services + try + { + response = WebUtil.PostToService(m_groupsServerURI, requestArgs); + } + catch (Exception e) + { + m_log.InfoFormat("[SIMIAN GROUPS CONNECTOR] request failed {0}",CacheKey); + } + + // and cache the response + lock (m_memoryCache) + { + m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout)); + m_pendingRequests.Remove(CacheKey); + } + + return response; + } + + Thread.Sleep(50); // waiting for a web request to complete, 50msecs is reasonable } - // return cached response - return response; + // if (!m_memoryCache.TryGetValue(CacheKey, out response)) + // { + // m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: query not in the cache"); + // Util.PrintCallStack(); + + // // if it wasn't in the cache, pass the request to the Simian Grid Services + // response = WebUtil.PostToService(m_groupsServerURI, requestArgs); + + // // and cache the response + // m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout)); + // } + + // // return cached response + // return response; } #endregion -- cgit v1.1 From 2ebb421331c4e6c4f57e0cc1bab79cea70937172 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Tue, 14 Feb 2012 17:20:34 -0800 Subject: Refactor appearance saving for NPC to use AvatarFactoryModule interface. --- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 40 +++++++++++++++++----- .../Framework/Interfaces/IAvatarFactoryModule.cs | 1 + .../Region/OptionalModules/World/NPC/NPCModule.cs | 12 +++---- 3 files changed, 38 insertions(+), 15 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 8d503bd..c7f4c20 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -111,6 +111,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory #region IAvatarFactoryModule + /// + /// + /// + /// + public void SetAppearance(IScenePresence sp, AvatarAppearance appearance) + { + SetAppearance(sp, appearance.Texture, appearance.VisualParams); + } + /// /// Set appearance data (texture asset IDs and slider settings) /// @@ -156,14 +165,23 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; // WriteBakedTexturesReport(sp, m_log.DebugFormat); - if (!ValidateBakedTextureCache(sp)) + + // If bake textures are missing and this is not an NPC, request a rebake from client + if (!ValidateBakedTextureCache(sp) && (((ScenePresence)sp).PresenceType != PresenceType.Npc)) RequestRebake(sp, true); // This appears to be set only in the final stage of the appearance // update transaction. In theory, we should be able to do an immediate // appearance send and save here. } - + + // NPC should send to clients immediately and skip saving appearance + if (((ScenePresence)sp).PresenceType == PresenceType.Npc) + { + SendAppearance((ScenePresence)sp); + return; + } + // save only if there were changes, send no matter what (doesn't hurt to send twice) if (changed) QueueAppearanceSave(sp.ControllingClient.AgentId); @@ -174,6 +192,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString()); } + private void SendAppearance(ScenePresence sp) + { + // Send the appearance to everyone in the scene + sp.SendAppearanceToAllOtherAgents(); + + // Send animations back to the avatar as well + sp.Animator.SendAnimPack(); + } + public bool SendAppearance(UUID agentId) { // m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId); @@ -185,12 +212,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return false; } - // Send the appearance to everyone in the scene - sp.SendAppearanceToAllOtherAgents(); - - // Send animations back to the avatar as well - sp.Animator.SendAnimPack(); - + SendAppearance(sp); return true; } @@ -626,4 +648,4 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactoryModule.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactoryModule.cs index 39a760c..34aca33 100644 --- a/OpenSim/Region/Framework/Interfaces/IAvatarFactoryModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactoryModule.cs @@ -35,6 +35,7 @@ namespace OpenSim.Region.Framework.Interfaces public interface IAvatarFactoryModule { + void SetAppearance(IScenePresence sp, AvatarAppearance appearance); void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams); /// diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index dc6eefc..5359354 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -96,15 +96,15 @@ namespace OpenSim.Region.OptionalModules.World.NPC if (!m_avatars.ContainsKey(agentId)) return false; + // Delete existing sp attachments scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, false); - AvatarAppearance npcAppearance = new AvatarAppearance(appearance, true); - sp.Appearance = npcAppearance; + // Set new sp appearance. Also sends to clients. + scene.RequestModuleInterface().SetAppearance(sp, new AvatarAppearance(appearance, true)); + + // Rez needed sp attachments scene.AttachmentsModule.RezAttachments(sp); - - IAvatarFactoryModule module = scene.RequestModuleInterface(); - module.SendAppearance(sp.UUID); - + return true; } -- cgit v1.1