diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 2ad30a0a0d..80ab30c3ef 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -413,14 +413,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement user.Id = uuid; user.FirstName = first; user.LastName = last; - // user.ProfileURL = we should initialize this to the default AddUserInternal(user); } - public void AddUser(UUID uuid, string first, string last, string profileURL) + public void AddUser(UUID uuid, string first, string last, string homeURL) { - AddUser(uuid, profileURL + ";" + first + " " + last); + AddUser(uuid, homeURL + ";" + first + " " + last); } public void AddUser (UUID id, string creatorData) @@ -492,36 +491,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // user.Id, user.FirstName, user.LastName, user.HomeURL); } - //public void AddUser(UUID uuid, string userData) - //{ - // if (m_UserCache.ContainsKey(uuid)) - // return; - - // UserData user = new UserData(); - // user.Id = uuid; - - // // userData = ; - // string[] parts = userData.Split(';'); - // if (parts.Length >= 1) - // user.ProfileURL = parts[0].Trim(); - // if (parts.Length >= 2) - // { - // string[] name = parts[1].Trim().Split(' '); - // if (name.Length >= 1) - // user.FirstName = name[0]; - // if (name.Length >= 2) - // user.LastName = name[1]; - // else - // user.LastName = "?"; - // } - - // lock (m_UserCache) - // m_UserCache.Add(uuid, user); - - // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", user.Id, user.FirstName, user.LastName, user.ProfileURL); - - //} - public bool IsLocalGridUser(UUID uuid) { UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid); diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index cac8479142..c50e734c18 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -52,6 +52,14 @@ namespace OpenSim.Region.Framework.Interfaces /// True if the agent is an NPC in the given scene. False otherwise. bool IsNPC(UUID agentID, Scene scene); + /// + /// Check if the caller has permission to manipulate the given NPC. + /// + /// + /// + /// true if they do, false if they don't or if there's no NPC with the given ID. + bool CheckPermissions(UUID npcID, UUID callerID); + /// /// Set the appearance for an NPC. /// @@ -117,7 +125,7 @@ namespace OpenSim.Region.Framework.Interfaces /// The UUID of the NPC /// /// True if the operation succeeded, false if there was no such agent or the agent was not an NPC - bool DeleteNPC(UUID agentID, UUID CallerID, Scene scene); + bool DeleteNPC(UUID agentID, Scene scene); /// /// Get the owner of a NPC diff --git a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs index 54dfaf4c63..4f62e28789 100644 --- a/OpenSim/Region/Framework/Interfaces/IUserManagement.cs +++ b/OpenSim/Region/Framework/Interfaces/IUserManagement.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void AddUser(UUID uuid, string firstName, string lastName, string profileURL); + void AddUser(UUID uuid, string firstName, string lastName, string homeURL); bool IsLocalGridUser(UUID uuid); } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index e87441703a..d90309f66f 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -56,6 +56,24 @@ namespace OpenSim.Region.OptionalModules.World.NPC } } + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "NPCModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + public bool IsNPC(UUID agentId, Scene scene) { // FIXME: This implementation could not just use the ScenePresence.PresenceType (and callers could inspect @@ -248,16 +266,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC return UUID.Zero; } - public bool DeleteNPC(UUID agentID, UUID callerID, Scene scene) + public bool DeleteNPC(UUID agentID, Scene scene) { lock (m_avatars) { NPCAvatar av; if (m_avatars.TryGetValue(agentID, out av)) { - if (av.OwnerID != UUID.Zero && callerID != UUID.Zero && av.OwnerID != callerID) - return false; - scene.RemoveClient(agentID, false); m_avatars.Remove(agentID); @@ -268,22 +283,27 @@ namespace OpenSim.Region.OptionalModules.World.NPC return false; } - public void PostInitialise() + public bool CheckPermissions(UUID npcID, UUID callerID) { + lock (m_avatars) + { + NPCAvatar av; + if (m_avatars.TryGetValue(npcID, out av)) + return CheckPermissions(av, callerID); + else + return false; + } } - public void Close() + /// + /// Check if the caller has permission to manipulate the given NPC. + /// + /// + /// + /// true if they do, false if they don't. + private bool CheckPermissions(NPCAvatar av, UUID callerID) { - } - - public string Name - { - get { return "NPCModule"; } - } - - public bool IsSharedModule - { - get { return true; } + return callerID == UUID.Zero || av.OwnerID == UUID.Zero || av.OwnerID == callerID; } } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 571d33d9ce..d21d601482 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -118,6 +118,26 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(umm.GetUserName(npc.UUID), Is.EqualTo(string.Format("{0} {1}", npc.Firstname, npc.Lastname))); } + [Test] + public void TestRemove() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + Vector3 startPos = new Vector3(128, 128, 30); + INPCModule npcModule = scene.RequestModuleInterface(); + UUID npcId = npcModule.CreateNPC("John", "Smith", startPos, UUID.Zero, scene, sp.Appearance); + + npcModule.DeleteNPC(npcId, scene); + + ScenePresence deletedNpc = scene.GetScenePresence(npcId); + + Assert.That(deletedNpc, Is.Null); + } + [Test] public void TestAttachments() { diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 8999f004a9..62cd75fc48 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2098,6 +2098,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return NpcCreate(firstname, lastname, position, notecard, false); } + public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, int options) + { + CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); + return NpcCreate(firstname, lastname, position, notecard, (options & ScriptBaseClass.OS_NPC_NOT_OWNED) == 0); + } + private LSL_Key NpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, bool owned) { string groupTitle = String.Empty; @@ -2175,11 +2181,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(npc.m_string, out npcId)) return new LSL_Key(UUID.Zero.ToString()); - if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) - return new LSL_Key(UUID.Zero.ToString()); - - UUID ownerID = npcModule.GetOwner(npcId); - if (ownerID != UUID.Zero && ownerID != m_host.OwnerID) + if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) return new LSL_Key(UUID.Zero.ToString()); return SaveAppearanceToNotecard(npcId, notecard); @@ -2200,6 +2202,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(npc.m_string, out npcId)) return; + if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) + return; + string appearanceSerialized = LoadNotecard(notecard); OSDMap appearanceOsd = (OSDMap)OSDParser.DeserializeLLSDXml(appearanceSerialized); // OSD a = OSDParser.DeserializeLLSDXml(appearanceSerialized); @@ -2223,7 +2228,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(npc.m_string, out npcId)) return new LSL_Vector(0, 0, 0); - if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) + if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) return new LSL_Vector(0, 0, 0); Vector3 pos = World.GetScenePresence(npcId).AbsolutePosition; @@ -2243,6 +2248,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID npcId; if (!UUID.TryParse(npc.m_string, out npcId)) return; + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; Vector3 pos = new Vector3((float) position.x, (float) position.y, (float) position.z); module.MoveToTarget(npcId, World, pos, false, true); @@ -2260,6 +2268,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(npc.m_string, out npcId)) return; + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + Vector3 pos = new Vector3((float)target.x, (float)target.y, (float)target.z); module.MoveToTarget( new UUID(npc.m_string), @@ -2281,7 +2292,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(npc.m_string, out npcId)) return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); - if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) + if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W); ScenePresence sp = World.GetScenePresence(npcId); @@ -2304,7 +2315,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!UUID.TryParse(npc.m_string, out npcId)) return; - if (!npcModule.IsNPC(npcId, m_host.ParentGroup.Scene)) + if (!npcModule.CheckPermissions(npcId, m_host.OwnerID)) return; ScenePresence sp = World.GetScenePresence(npcId); @@ -2318,7 +2329,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api INPCModule module = World.RequestModuleInterface(); if (module != null) - module.StopMoveToTarget(new UUID(npc.m_string), World); + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.StopMoveToTarget(npcId, World); + } } public void osNpcSay(LSL_Key npc, string message) @@ -2328,7 +2346,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api INPCModule module = World.RequestModuleInterface(); if (module != null) { - module.Say(new UUID(npc.m_string), World, message); + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.Say(npcId, World, message); } } @@ -2339,7 +2362,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api INPCModule module = World.RequestModuleInterface(); if (module != null) { - module.Sit(new UUID(npc.m_string), new UUID(target.m_string), World); + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.Sit(npcId, new UUID(target.m_string), World); } } @@ -2350,7 +2378,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api INPCModule module = World.RequestModuleInterface(); if (module != null) { - module.Stand(new UUID(npc.m_string), World); + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.Stand(npcId, World); } } @@ -2361,7 +2394,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api INPCModule module = World.RequestModuleInterface(); if (module != null) { - module.DeleteNPC(new UUID(npc.m_string), m_host.OwnerID, World); + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.DeleteNPC(npcId, World); } } @@ -2373,12 +2411,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (module != null) { UUID npcID = new UUID(npc.m_string); - if (module.IsNPC(npcID, m_host.ParentGroup.Scene)) - { - UUID ownerID = module.GetOwner(npcID); - if (ownerID == UUID.Zero || ownerID == m_host.OwnerID) - AvatarPlayAnimation(npcID.ToString(), animation); - } + + if (module.CheckPermissions(npcID, m_host.OwnerID)) + AvatarPlayAnimation(npcID.ToString(), animation); } } @@ -2390,12 +2425,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (module != null) { UUID npcID = new UUID(npc.m_string); - if (module.IsNPC(npcID, m_host.ParentGroup.Scene)) - { - UUID ownerID = module.GetOwner(npcID); - if (ownerID == UUID.Zero || ownerID == m_host.OwnerID) - AvatarStopAnimation(npcID.ToString(), animation); - } + + if (module.CheckPermissions(npcID, m_host.OwnerID)) + AvatarPlayAnimation(npcID.ToString(), animation); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index ac1c1a98fb..dddf91340a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -468,12 +468,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins toRegionPos = presence.AbsolutePosition; dis = Math.Abs(Util.GetDistanceTo(toRegionPos, fromRegionPos)); - if (presence.PresenceType == PresenceType.Npc && npcModule != null) - { - UUID npcOwner = npcModule.GetOwner(presence.UUID); - if (npcOwner != UUID.Zero && npcOwner != SensePoint.OwnerID) - return; - } + // Disabled for now since all osNpc* methods check for appropriate ownership permission. + // Perhaps could be re-enabled as an NPC setting at some point since being able to make NPCs not + // sensed might be useful. +// if (presence.PresenceType == PresenceType.Npc && npcModule != null) +// { +// UUID npcOwner = npcModule.GetOwner(presence.UUID); +// if (npcOwner != UUID.Zero && npcOwner != SensePoint.OwnerID) +// return; +// } // are they in range if (dis <= ts.range) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 44aff21e62..25f359a347 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -172,6 +172,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_List osGetLinkPrimitiveParams(int linknumber, LSL_List rules); key osNpcCreate(string user, string name, vector position, string notecard); + key osNpcCreate(string user, string name, vector position, string notecard, int options); key osNpcCreateOwned(string user, string name, vector position, string notecard); LSL_Key osNpcSaveAppearance(key npc, string notecard); void osNpcLoadAppearance(key npc, string notecard); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 3c258d8b96..32226f97aa 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -609,6 +609,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OS_NPC_SIT_NOW = 0; + public const int OS_NPC_CREATOR_OWNED = 0x1; + public const int OS_NPC_NOT_OWNED = 0x2; + public const string URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED"; public const string URL_REQUEST_DENIED = "URL_REQUEST_DENIED"; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index a94392a27a..ceccceb82c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -488,6 +488,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom); } + public key osNpcCreate(string user, string name, vector position, key cloneFrom, int options) + { + return m_OSSL_Functions.osNpcCreate(user, name, position, cloneFrom, options); + } + public key osNpcCreateOwned(string user, string name, vector position, key cloneFrom) { return m_OSSL_Functions.osNpcCreateOwned(user, name, position, cloneFrom); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs new file mode 100644 index 0000000000..f0b28b22de --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs @@ -0,0 +1,168 @@ +/* + * 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 OpenSimulator 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.Generic; +using System.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for OSSL NPC API + /// + [TestFixture] + public class OSSL_NpcApiAppearanceTest + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public void SetUp() + { + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + config.Set("AllowOSFunctions", "true"); + config.Set("OSFunctionThreatLevel", "Severe"); + config = initConfigSource.AddConfig("NPC"); + config.Set("Enabled", "true"); + + m_scene = SceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new AvatarFactoryModule(), new NPCModule()); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + /// + /// Test removal of an owned NPC. + /// + [Test] + public void TestOsNpcRemoveOwned() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + UUID otherUserId = TestHelpers.ParseTail(0x2); + float newHeight = 1.9f; + + SceneHelpers.AddScenePresence(m_scene, otherUserId); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + SceneObjectGroup otherSo = SceneHelpers.CreateSceneObject(1, otherUserId); + SceneObjectPart otherPart = otherSo.RootPart; + m_scene.AddSceneObject(otherSo); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + + OSSL_Api otherOsslApi = new OSSL_Api(); + otherOsslApi.Initialize(m_engine, otherPart, otherPart.LocalId, otherPart.UUID); + + string notecardName = "appearanceNc"; + osslApi.osOwnerSaveAppearance(notecardName); + + string npcRaw + = osslApi.osNpcCreate( + "Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName, ScriptBaseClass.OS_NPC_CREATOR_OWNED); + + otherOsslApi.osNpcRemove(npcRaw); + + // Should still be around + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Not.Null); + + osslApi.osNpcRemove(npcRaw); + + npc = m_scene.GetScenePresence(npcId); + + } + + /// + /// Test removal of an unowned NPC. + /// + [Test] + public void TestOsNpcRemoveUnowned() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + // Store an avatar with a different height from default in a notecard. + UUID userId = TestHelpers.ParseTail(0x1); + float newHeight = 1.9f; + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); + sp.Appearance.AvatarHeight = newHeight; + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectPart part = so.RootPart; + m_scene.AddSceneObject(so); + + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + + string notecardName = "appearanceNc"; + osslApi.osOwnerSaveAppearance(notecardName); + + string npcRaw + = osslApi.osNpcCreate( + "Jane", "Doe", new LSL_Types.Vector3(128, 128, 128), notecardName, ScriptBaseClass.OS_NPC_NOT_OWNED); + + osslApi.osNpcRemove(npcRaw); + + UUID npcId = new UUID(npcRaw); + ScenePresence npc = m_scene.GetScenePresence(npcId); + Assert.That(npc, Is.Null); + } + } +} \ No newline at end of file