aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Data/Tests/RegionTests.cs4
-rw-r--r--OpenSim/Framework/Watchdog.cs24
-rw-r--r--OpenSim/Region/Application/Application.cs8
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs161
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs44
-rw-r--r--OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml1
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs8
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityInventory.cs15
-rw-r--r--OpenSim/Region/Framework/Interfaces/INPCModule.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs75
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs129
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs59
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs74
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs24
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs47
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs10
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs102
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs11
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs29
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs23
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs60
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs19
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs10
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs14
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs55
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs6
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs98
-rw-r--r--OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs9
33 files changed, 891 insertions, 305 deletions
diff --git a/OpenSim/Data/Tests/RegionTests.cs b/OpenSim/Data/Tests/RegionTests.cs
index 474609b..dbed8f6 100644
--- a/OpenSim/Data/Tests/RegionTests.cs
+++ b/OpenSim/Data/Tests/RegionTests.cs
@@ -1069,8 +1069,6 @@ namespace OpenSim.Data.Tests
1069 regionInfo.RegionLocX = 0; 1069 regionInfo.RegionLocX = 0;
1070 regionInfo.RegionLocY = 0; 1070 regionInfo.RegionLocY = 0;
1071 1071
1072 Scene scene = new Scene(regionInfo);
1073
1074 SceneObjectPart sop = new SceneObjectPart(); 1072 SceneObjectPart sop = new SceneObjectPart();
1075 sop.Name = name; 1073 sop.Name = name;
1076 sop.Description = name; 1074 sop.Description = name;
@@ -1081,7 +1079,7 @@ namespace OpenSim.Data.Tests
1081 sop.Shape = PrimitiveBaseShape.Default; 1079 sop.Shape = PrimitiveBaseShape.Default;
1082 1080
1083 SceneObjectGroup sog = new SceneObjectGroup(sop); 1081 SceneObjectGroup sog = new SceneObjectGroup(sop);
1084 sog.SetScene(scene); 1082// sog.SetScene(scene);
1085 1083
1086 return sog; 1084 return sog;
1087 } 1085 }
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs
index e091ea0..449d014 100644
--- a/OpenSim/Framework/Watchdog.cs
+++ b/OpenSim/Framework/Watchdog.cs
@@ -101,12 +101,24 @@ namespace OpenSim.Framework
101 private static Dictionary<int, ThreadWatchdogInfo> m_threads; 101 private static Dictionary<int, ThreadWatchdogInfo> m_threads;
102 private static System.Timers.Timer m_watchdogTimer; 102 private static System.Timers.Timer m_watchdogTimer;
103 103
104 /// <summary>
105 /// Last time the watchdog thread ran.
106 /// </summary>
107 /// <remarks>
108 /// Should run every WATCHDOG_INTERVAL_MS
109 /// </remarks>
110 public static int LastWatchdogThreadTick { get; private set; }
111
104 static Watchdog() 112 static Watchdog()
105 { 113 {
106 m_threads = new Dictionary<int, ThreadWatchdogInfo>(); 114 m_threads = new Dictionary<int, ThreadWatchdogInfo>();
107 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS); 115 m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
108 m_watchdogTimer.AutoReset = false; 116 m_watchdogTimer.AutoReset = false;
109 m_watchdogTimer.Elapsed += WatchdogTimerElapsed; 117 m_watchdogTimer.Elapsed += WatchdogTimerElapsed;
118
119 // Set now so we don't get alerted on the first run
120 LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
121
110 m_watchdogTimer.Start(); 122 m_watchdogTimer.Start();
111 } 123 }
112 124
@@ -264,6 +276,16 @@ namespace OpenSim.Framework
264 /// <param name="e"></param> 276 /// <param name="e"></param>
265 private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) 277 private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
266 { 278 {
279 int now = Environment.TickCount & Int32.MaxValue;
280 int msElapsed = now - LastWatchdogThreadTick;
281
282 if (msElapsed > WATCHDOG_INTERVAL_MS * 2)
283 m_log.WarnFormat(
284 "[WATCHDOG]: {0} ms since Watchdog last ran. Interval should be approximately {1} ms",
285 msElapsed, WATCHDOG_INTERVAL_MS);
286
287 LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
288
267 Action<ThreadWatchdogInfo> callback = OnWatchdogTimeout; 289 Action<ThreadWatchdogInfo> callback = OnWatchdogTimeout;
268 290
269 if (callback != null) 291 if (callback != null)
@@ -272,8 +294,6 @@ namespace OpenSim.Framework
272 294
273 lock (m_threads) 295 lock (m_threads)
274 { 296 {
275 int now = Environment.TickCount;
276
277 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) 297 foreach (ThreadWatchdogInfo threadInfo in m_threads.Values)
278 { 298 {
279 if (threadInfo.Thread.ThreadState == ThreadState.Stopped) 299 if (threadInfo.Thread.ThreadState == ThreadState.Stopped)
diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs
index c130038..ebfebc4 100644
--- a/OpenSim/Region/Application/Application.cs
+++ b/OpenSim/Region/Application/Application.cs
@@ -92,9 +92,14 @@ namespace OpenSim
92 m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config"); 92 m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config");
93 } 93 }
94 94
95 m_log.DebugFormat( 95 m_log.InfoFormat(
96 "[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture); 96 "[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture);
97 97
98 string monoThreadsPerCpu = System.Environment.GetEnvironmentVariable("MONO_THREADS_PER_CPU");
99
100 m_log.InfoFormat(
101 "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
102
98 // Increase the number of IOCP threads available. Mono defaults to a tragically low number 103 // Increase the number of IOCP threads available. Mono defaults to a tragically low number
99 int workerThreads, iocpThreads; 104 int workerThreads, iocpThreads;
100 System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); 105 System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
@@ -109,7 +114,6 @@ namespace OpenSim
109 114
110 // Check if the system is compatible with OpenSimulator. 115 // Check if the system is compatible with OpenSimulator.
111 // Ensures that the minimum system requirements are met 116 // Ensures that the minimum system requirements are met
112 m_log.Info("Performing compatibility checks... \n");
113 string supported = String.Empty; 117 string supported = String.Empty;
114 if (Util.IsEnvironmentSupported(ref supported)) 118 if (Util.IsEnvironmentSupported(ref supported))
115 { 119 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 1fa5ec0..2bb60d5 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -257,16 +257,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
257 257
258 lock (sp.AttachmentsSyncLock) 258 lock (sp.AttachmentsSyncLock)
259 { 259 {
260 foreach (SceneObjectGroup grp in sp.GetAttachments()) 260 foreach (SceneObjectGroup so in sp.GetAttachments())
261 { 261 {
262 grp.Scene.DeleteSceneObject(grp, false); 262 // We can only remove the script instances from the script engine after we've retrieved their xml state
263 // when we update the attachment item.
264 m_scene.DeleteSceneObject(so, false, false);
263 265
264 if (saveChanged || saveAllScripted) 266 if (saveChanged || saveAllScripted)
265 { 267 {
266 grp.IsAttachment = false; 268 so.IsAttachment = false;
267 grp.AbsolutePosition = grp.RootPart.AttachedPos; 269 so.AbsolutePosition = so.RootPart.AttachedPos;
268 UpdateKnownItem(sp, grp, saveAllScripted); 270 UpdateKnownItem(sp, so, saveAllScripted);
269 } 271 }
272
273 so.RemoveScriptInstances(true);
270 } 274 }
271 275
272 sp.ClearAttachments(); 276 sp.ClearAttachments();
@@ -297,6 +301,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
297// m_log.DebugFormat( 301// m_log.DebugFormat(
298// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 302// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
299// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 303// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
304
305 if (group.GetSittingAvatarsCount() != 0)
306 {
307// m_log.WarnFormat(
308// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
309// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
310
311 return false;
312 }
300 313
301 if (sp.GetAttachments(attachmentPt).Contains(group)) 314 if (sp.GetAttachments(attachmentPt).Contains(group))
302 { 315 {
@@ -357,30 +370,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
357 group.AttachmentPoint = attachmentPt; 370 group.AttachmentPoint = attachmentPt;
358 group.AbsolutePosition = attachPos; 371 group.AbsolutePosition = attachPos;
359 372
360 // We also don't want to do any of the inventory operations for an NPC.
361 if (sp.PresenceType != PresenceType.Npc) 373 if (sp.PresenceType != PresenceType.Npc)
362 { 374 UpdateUserInventoryWithAttachment(sp, group, attachmentPt);
363 // Remove any previous attachments
364 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
365
366 // At the moment we can only deal with a single attachment
367 if (attachments.Count != 0)
368 {
369 if (attachments[0].FromItemID != UUID.Zero)
370 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
371 else
372 m_log.WarnFormat(
373 "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
374 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
375 }
376
377 // Add the new attachment to inventory if we don't already have it.
378 UUID newAttachmentItemID = group.FromItemID;
379 if (newAttachmentItemID == UUID.Zero)
380 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
381
382 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
383 }
384 375
385 AttachToAgent(sp, group, attachmentPt, attachPos, silent); 376 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
386 } 377 }
@@ -388,6 +379,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
388 return true; 379 return true;
389 } 380 }
390 381
382 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt)
383 {
384 // Remove any previous attachments
385 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
386
387 // At the moment we can only deal with a single attachment
388 if (attachments.Count != 0)
389 {
390 if (attachments[0].FromItemID != UUID.Zero)
391 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
392 else
393 m_log.WarnFormat(
394 "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
395 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
396 }
397
398 // Add the new attachment to inventory if we don't already have it.
399 UUID newAttachmentItemID = group.FromItemID;
400 if (newAttachmentItemID == UUID.Zero)
401 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
402
403 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
404 }
405
391 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) 406 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
392 { 407 {
393 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, true, null); 408 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, true, null);
@@ -721,79 +736,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
721 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", 736 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
722 // grp.Name, grp.LocalId, remoteClient.Name); 737 // grp.Name, grp.LocalId, remoteClient.Name);
723 738
724// Vector3 inventoryStoredPosition = new Vector3 739 InventoryItemBase newItem
725// (((grp.AbsolutePosition.X > (int)Constants.RegionSize) 740 = m_invAccessModule.CopyToInventory(
726// ? (float)Constants.RegionSize - 6 741 DeRezAction.TakeCopy,
727// : grp.AbsolutePosition.X) 742 m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID,
728// , 743 new List<SceneObjectGroup> { grp },
729// (grp.AbsolutePosition.Y > (int)Constants.RegionSize) 744 sp.ControllingClient, true)[0];
730// ? (float)Constants.RegionSize - 6
731// : grp.AbsolutePosition.Y,
732// grp.AbsolutePosition.Z);
733//
734// Vector3 originalPosition = grp.AbsolutePosition;
735//
736// grp.AbsolutePosition = inventoryStoredPosition;
737
738 // If we're being called from a script, then trying to serialize that same script's state will not complete
739 // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if
740 // the client/server crashes rather than logging out normally, the attachment's scripts will resume
741 // without state on relog. Arguably, this is what we want anyway.
742 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false);
743
744// grp.AbsolutePosition = originalPosition;
745
746 AssetBase asset = m_scene.CreateAsset(
747 grp.GetPartName(grp.LocalId),
748 grp.GetPartDescription(grp.LocalId),
749 (sbyte)AssetType.Object,
750 Utils.StringToBytes(sceneObjectXml),
751 sp.UUID);
752
753 m_scene.AssetService.Store(asset);
754
755 InventoryItemBase item = new InventoryItemBase();
756 item.CreatorId = grp.RootPart.CreatorID.ToString();
757 item.CreatorData = grp.RootPart.CreatorData;
758 item.Owner = sp.UUID;
759 item.ID = UUID.Random();
760 item.AssetID = asset.FullID;
761 item.Description = asset.Description;
762 item.Name = asset.Name;
763 item.AssetType = asset.Type;
764 item.InvType = (int)InventoryType.Object;
765
766 InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
767 if (folder != null)
768 item.Folder = folder.ID;
769 else // oopsies
770 item.Folder = UUID.Zero;
771
772 // Nix the special bits we used to use for slam and the folded perms
773 uint allowablePermissionsMask = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move);
774
775 if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions())
776 {
777 item.BasePermissions = grp.RootPart.BaseMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
778 item.CurrentPermissions = grp.RootPart.BaseMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
779 item.NextPermissions = grp.RootPart.NextOwnerMask & allowablePermissionsMask;
780 item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
781 item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
782 }
783 else
784 {
785 item.BasePermissions = grp.RootPart.BaseMask & allowablePermissionsMask;
786 item.CurrentPermissions = grp.RootPart.OwnerMask & allowablePermissionsMask;
787 item.NextPermissions = grp.RootPart.NextOwnerMask & allowablePermissionsMask;
788 item.EveryOnePermissions = grp.RootPart.EveryoneMask & allowablePermissionsMask;
789 item.GroupPermissions = grp.RootPart.GroupMask & allowablePermissionsMask;
790 }
791 item.CreationDate = Util.UnixTimeSinceEpoch();
792 745
793 // sets itemID so client can show item as 'attached' in inventory 746 // sets itemID so client can show item as 'attached' in inventory
794 grp.FromItemID = item.ID; 747 grp.FromItemID = newItem.ID;
795 748
796 return item; 749 return newItem;
797 } 750 }
798 751
799 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) 752 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
@@ -802,7 +755,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
802 755
803 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); 756 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
804 sp.RemoveAttachment(so); 757 sp.RemoveAttachment(so);
805 m_scene.DeleteSceneObject(so, false); 758
759 // We can only remove the script instances from the script engine after we've retrieved their xml state
760 // when we update the attachment item.
761 m_scene.DeleteSceneObject(so, false, false);
806 762
807 // Prepare sog for storage 763 // Prepare sog for storage
808 so.AttachedAvatar = UUID.Zero; 764 so.AttachedAvatar = UUID.Zero;
@@ -811,6 +767,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
811 so.AbsolutePosition = so.RootPart.AttachedPos; 767 so.AbsolutePosition = so.RootPart.AttachedPos;
812 768
813 UpdateKnownItem(sp, so, true); 769 UpdateKnownItem(sp, so, true);
770 so.RemoveScriptInstances(true);
814 } 771 }
815 772
816 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 773 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
@@ -920,7 +877,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
920 item = m_scene.InventoryService.GetItem(item); 877 item = m_scene.InventoryService.GetItem(item);
921 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 878 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
922 if (changed && m_scene.AvatarFactory != null) 879 if (changed && m_scene.AvatarFactory != null)
880 {
881// m_log.DebugFormat(
882// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
883// sp.Name, att.Name, AttachmentPt);
884
923 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 885 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
886 }
924 } 887 }
925 888
926 #endregion 889 #endregion
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 2eb0ac5..8423d43 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -118,7 +118,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
118 118
119 Scene scene = CreateDefaultTestScene(); 119 Scene scene = CreateDefaultTestScene();
120 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); 120 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
121 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); 121 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
122 122
123 string attName = "att"; 123 string attName = "att";
124 124
@@ -149,9 +149,41 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
149 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); 149 InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
150 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); 150 Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
151 151
152 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
153
152// TestHelpers.DisableLogging(); 154// TestHelpers.DisableLogging();
153 } 155 }
154 156
157 /// <summary>
158 /// Test that we do not attempt to attach an in-world object that someone else is sitting on.
159 /// </summary>
160 [Test]
161 public void TestAddSatOnAttachmentFromGround()
162 {
163 TestHelpers.InMethod();
164// TestHelpers.EnableLogging();
165
166 Scene scene = CreateDefaultTestScene();
167 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
168 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
169
170 string attName = "att";
171
172 SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
173
174 UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(scene, 0x2);
175 ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, ua2);
176
177 // Put avatar within 10m of the prim so that sit doesn't fail.
178 sp2.AbsolutePosition = new Vector3(0, 0, 0);
179 sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
180
181 scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false);
182
183 Assert.That(sp.HasAttachments(), Is.False);
184 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
185 }
186
155 [Test] 187 [Test]
156 public void TestAddAttachmentFromInventory() 188 public void TestAddAttachmentFromInventory()
157 { 189 {
@@ -181,6 +213,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
181 // Check appearance status 213 // Check appearance status
182 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); 214 Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
183 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 215 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
216
217 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
184 } 218 }
185 219
186 [Test] 220 [Test]
@@ -239,6 +273,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
239 273
240 // Check item status 274 // Check item status
241 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); 275 Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
276
277 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
242 } 278 }
243 279
244 /// <summary> 280 /// <summary>
@@ -300,6 +336,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
300 Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItem.ID)); 336 Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItem.ID));
301 Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); 337 Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attItem.AssetID));
302 Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 338 Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
339
340 Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
303 } 341 }
304 342
305 [Test] 343 [Test]
@@ -399,6 +437,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
399 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); 437 Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
400 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); 438 Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
401 439
440 Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
441
402 // Check attachments have been removed from sceneA 442 // Check attachments have been removed from sceneA
403 ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID); 443 ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID);
404 444
@@ -410,6 +450,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
410 // This is the actual attachment, which should no longer exist 450 // This is the actual attachment, which should no longer exist
411 List<SceneObjectGroup> actualSceneAAttachments = afterTeleportSceneASp.GetAttachments(); 451 List<SceneObjectGroup> actualSceneAAttachments = afterTeleportSceneASp.GetAttachments();
412 Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); 452 Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
453
454 Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
413 } 455 }
414 456
415 // I'm commenting this test because scene setup NEEDS InventoryService to 457 // I'm commenting this test because scene setup NEEDS InventoryService to
diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml
index dc6efed..424e0ab 100644
--- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml
+++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml
@@ -79,7 +79,6 @@
79 <RegionModule id="AuthenticationServiceInConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsIn.Authentication.AuthenticationServiceInConnectorModule" /> 79 <RegionModule id="AuthenticationServiceInConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsIn.Authentication.AuthenticationServiceInConnectorModule" />
80 <RegionModule id="AccessModule" type="OpenSim.Region.CoreModules.World.AccessModule" /> \ 80 <RegionModule id="AccessModule" type="OpenSim.Region.CoreModules.World.AccessModule" /> \
81 <RegionModule id="MapImageModule" type="OpenSim.Region.CoreModules.World.LegacyMap.MapImageModule" /> \ 81 <RegionModule id="MapImageModule" type="OpenSim.Region.CoreModules.World.LegacyMap.MapImageModule" /> \
82 <RegionModule id="Warp3DImageModule" type="OpenSim.Region.CoreModules.World.Warp3DMap.Warp3DImageModule" /> \
83 82
84 </Extension> 83 </Extension>
85 84
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index 724bb4c..00be5df 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -730,7 +730,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
730 { 730 {
731 if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout)) 731 if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout))
732 { 732 {
733 m_log.DebugFormat("[WORLDMAP]: Unblock blacklisted region {0}", regionhandle); 733 m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted region {0}", regionhandle);
734 734
735 m_blacklistedregions.Remove(regionhandle); 735 m_blacklistedregions.Remove(regionhandle);
736 } 736 }
@@ -781,7 +781,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
781 { 781 {
782 if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout)) 782 if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout))
783 { 783 {
784 m_log.DebugFormat("[WORLDMAP]: Unblock blacklisted URL {0}", httpserver); 784 m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted URL {0}", httpserver);
785 785
786 m_blacklistedurls.Remove(httpserver); 786 m_blacklistedurls.Remove(httpserver);
787 } 787 }
@@ -1343,7 +1343,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1343 if (terrain == null) 1343 if (terrain == null)
1344 return; 1344 return;
1345 1345
1346 m_log.DebugFormat("[WORLDMAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName); 1346 m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName);
1347 1347
1348 byte[] data = terrain.WriteJpeg2000Image(); 1348 byte[] data = terrain.WriteJpeg2000Image();
1349 if (data == null) 1349 if (data == null)
@@ -1365,7 +1365,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1365 asset.Flags = AssetFlags.Maptile; 1365 asset.Flags = AssetFlags.Maptile;
1366 1366
1367 // Store the new one 1367 // Store the new one
1368 m_log.DebugFormat("[WORLDMAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName); 1368 m_log.DebugFormat("[WORLD MAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName);
1369 1369
1370 m_scene.AssetService.Store(asset); 1370 m_scene.AssetService.Store(asset);
1371 1371
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
index 4f0e100..4274cbe 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
@@ -92,7 +92,7 @@ namespace OpenSim.Region.Framework.Interfaces
92 void ResumeScripts(); 92 void ResumeScripts();
93 93
94 /// <summary> 94 /// <summary>
95 /// Stop all the scripts in this entity. 95 /// Stop and remove all the scripts in this entity from the scene.
96 /// </summary> 96 /// </summary>
97 /// <param name="sceneObjectBeingDeleted"> 97 /// <param name="sceneObjectBeingDeleted">
98 /// Should be true if these scripts are being removed because the scene 98 /// Should be true if these scripts are being removed because the scene
@@ -101,6 +101,11 @@ namespace OpenSim.Region.Framework.Interfaces
101 void RemoveScriptInstances(bool sceneObjectBeingDeleted); 101 void RemoveScriptInstances(bool sceneObjectBeingDeleted);
102 102
103 /// <summary> 103 /// <summary>
104 /// Stop all the scripts in this entity.
105 /// </summary>
106 void StopScriptInstances();
107
108 /// <summary>
104 /// Start a script which is in this entity's inventory. 109 /// Start a script which is in this entity's inventory.
105 /// </summary> 110 /// </summary>
106 /// <param name="item"></param> 111 /// <param name="item"></param>
@@ -131,7 +136,7 @@ namespace OpenSim.Region.Framework.Interfaces
131 ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); 136 ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource);
132 137
133 /// <summary> 138 /// <summary>
134 /// Stop a script which is in this prim's inventory. 139 /// Stop and remove a script which is in this prim's inventory from the scene.
135 /// </summary> 140 /// </summary>
136 /// <param name="itemId"></param> 141 /// <param name="itemId"></param>
137 /// <param name="sceneObjectBeingDeleted"> 142 /// <param name="sceneObjectBeingDeleted">
@@ -141,6 +146,12 @@ namespace OpenSim.Region.Framework.Interfaces
141 void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted); 146 void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted);
142 147
143 /// <summary> 148 /// <summary>
149 /// Stop a script which is in this prim's inventory.
150 /// </summary>
151 /// <param name="itemId"></param>
152 void StopScriptInstance(UUID itemId);
153
154 /// <summary>
144 /// Add an item to this entity's inventory. If an item with the same name already exists, then an alternative 155 /// Add an item to this entity's inventory. If an item with the same name already exists, then an alternative
145 /// name is chosen. 156 /// name is chosen.
146 /// </summary> 157 /// </summary>
diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
index 860483d..d582149 100644
--- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
@@ -184,6 +184,14 @@ namespace OpenSim.Region.Framework.Interfaces
184 bool Stand(UUID agentID, Scene scene); 184 bool Stand(UUID agentID, Scene scene);
185 185
186 /// <summary> 186 /// <summary>
187 /// Get the NPC to touch an object.
188 /// </summary>
189 /// <param name="agentID"></param>
190 /// <param name="partID"></param>
191 /// <returns>true if the touch is actually attempted, false if not</returns>
192 bool Touch(UUID agentID, UUID partID);
193
194 /// <summary>
187 /// Delete an NPC. 195 /// Delete an NPC.
188 /// </summary> 196 /// </summary>
189 /// <param name="agentID">The UUID of the NPC</param> 197 /// <param name="agentID">The UUID of the NPC</param>
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index a63ed13..eae8b8e 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -2281,13 +2281,30 @@ namespace OpenSim.Region.Framework.Scenes
2281 /// <summary> 2281 /// <summary>
2282 /// Synchronously delete the given object from the scene. 2282 /// Synchronously delete the given object from the scene.
2283 /// </summary> 2283 /// </summary>
2284 /// <remarks>
2285 /// Scripts are also removed.
2286 /// </remarks>
2284 /// <param name="group">Object Id</param> 2287 /// <param name="group">Object Id</param>
2285 /// <param name="silent">Suppress broadcasting changes to other clients.</param> 2288 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2286 public void DeleteSceneObject(SceneObjectGroup group, bool silent) 2289 public void DeleteSceneObject(SceneObjectGroup group, bool silent)
2290 {
2291 DeleteSceneObject(group, silent, true);
2292 }
2293
2294 /// <summary>
2295 /// Synchronously delete the given object from the scene.
2296 /// </summary>
2297 /// <param name="group">Object Id</param>
2298 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
2299 /// <param name="removeScripts">If true, then scripts are removed. If false, then they are only stopped.</para>
2300 public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts)
2287 { 2301 {
2288// m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); 2302// m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID);
2289 2303
2290 group.RemoveScriptInstances(true); 2304 if (removeScripts)
2305 group.RemoveScriptInstances(true);
2306 else
2307 group.StopScriptInstances();
2291 2308
2292 SceneObjectPart[] partList = group.Parts; 2309 SceneObjectPart[] partList = group.Parts;
2293 2310
@@ -2595,7 +2612,16 @@ namespace OpenSim.Region.Framework.Scenes
2595 } 2612 }
2596 catch (Exception e) 2613 catch (Exception e)
2597 { 2614 {
2598 m_log.WarnFormat("[SCENE]: Problem casting object, exception {0}{1}", e.Message, e.StackTrace); 2615 m_log.WarnFormat("[INTERREGION]: Problem casting object, exception {0}{1}", e.Message, e.StackTrace);
2616 return false;
2617 }
2618
2619 // If the user is banned, we won't let any of their objects
2620 // enter. Period.
2621 //
2622 if (RegionInfo.EstateSettings.IsBanned(newObject.OwnerID, 36))
2623 {
2624 m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", newObject.OwnerID);
2599 return false; 2625 return false;
2600 } 2626 }
2601 2627
@@ -2606,14 +2632,28 @@ namespace OpenSim.Region.Framework.Scenes
2606 2632
2607 if (!AddSceneObject(newObject)) 2633 if (!AddSceneObject(newObject))
2608 { 2634 {
2609 m_log.DebugFormat("[SCENE]: Problem adding scene object {0} in {1} ", sog.UUID, RegionInfo.RegionName); 2635 m_log.DebugFormat(
2636 "[INTERREGION]: Problem adding scene object {0} in {1} ", newObject.UUID, RegionInfo.RegionName);
2610 return false; 2637 return false;
2611 } 2638 }
2612 2639
2613 // For attachments, we need to wait until the agent is root
2614 // before we restart the scripts, or else some functions won't work.
2615 if (!newObject.IsAttachment) 2640 if (!newObject.IsAttachment)
2616 { 2641 {
2642 // FIXME: It would be better to never add the scene object at all rather than add it and then delete
2643 // it
2644 if (!Permissions.CanObjectEntry(newObject.UUID, true, newObject.AbsolutePosition))
2645 {
2646 // Deny non attachments based on parcel settings
2647 //
2648 m_log.Info("[INTERREGION]: Denied prim crossing because of parcel settings");
2649
2650 DeleteSceneObject(newObject, false);
2651
2652 return false;
2653 }
2654
2655 // For attachments, we need to wait until the agent is root
2656 // before we restart the scripts, or else some functions won't work.
2617 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); 2657 newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject));
2618 newObject.ResumeScripts(); 2658 newObject.ResumeScripts();
2619 } 2659 }
@@ -2650,8 +2690,6 @@ namespace OpenSim.Region.Framework.Scenes
2650 return false; 2690 return false;
2651 } 2691 }
2652 2692
2653 sceneObject.SetScene(this);
2654
2655 // Force allocation of new LocalId 2693 // Force allocation of new LocalId
2656 // 2694 //
2657 SceneObjectPart[] parts = sceneObject.Parts; 2695 SceneObjectPart[] parts = sceneObject.Parts;
@@ -2707,18 +2745,6 @@ namespace OpenSim.Region.Framework.Scenes
2707 return false; 2745 return false;
2708 } 2746 }
2709 AddRestoredSceneObject(sceneObject, true, false); 2747 AddRestoredSceneObject(sceneObject, true, false);
2710
2711 if (!Permissions.CanObjectEntry(sceneObject.UUID,
2712 true, sceneObject.AbsolutePosition))
2713 {
2714 // Deny non attachments based on parcel settings
2715 //
2716 m_log.Info("[INTERREGION]: Denied prim crossing because of parcel settings");
2717
2718 DeleteSceneObject(sceneObject, false);
2719
2720 return false;
2721 }
2722 } 2748 }
2723 2749
2724 return true; 2750 return true;
@@ -4654,6 +4680,17 @@ namespace OpenSim.Region.Framework.Scenes
4654 } 4680 }
4655 4681
4656 /// <summary> 4682 /// <summary>
4683 /// Get all the scene object groups.
4684 /// </summary>
4685 /// <returns>
4686 /// The scene object groups. If the scene is empty then an empty list is returned.
4687 /// </returns>
4688 public List<SceneObjectGroup> GetSceneObjectGroups()
4689 {
4690 return m_sceneGraph.GetSceneObjectGroups();
4691 }
4692
4693 /// <summary>
4657 /// Get a group via its UUID 4694 /// Get a group via its UUID
4658 /// </summary> 4695 /// </summary>
4659 /// <param name="fullID"></param> 4696 /// <param name="fullID"></param>
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 3390aba..b23d2e5 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -401,9 +401,9 @@ namespace OpenSim.Region.Framework.Scenes
401 401
402 if (Entities.ContainsKey(sceneObject.UUID)) 402 if (Entities.ContainsKey(sceneObject.UUID))
403 { 403 {
404// m_log.DebugFormat( 404 m_log.DebugFormat(
405// "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()", 405 "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()",
406// m_parentScene.RegionInfo.RegionName, sceneObject.UUID); 406 m_parentScene.RegionInfo.RegionName, sceneObject.UUID);
407 407
408 return false; 408 return false;
409 } 409 }
@@ -1038,6 +1038,18 @@ namespace OpenSim.Region.Framework.Scenes
1038 } 1038 }
1039 1039
1040 /// <summary> 1040 /// <summary>
1041 /// Get all the scene object groups.
1042 /// </summary>
1043 /// <returns>
1044 /// The scene object groups. If the scene is empty then an empty list is returned.
1045 /// </returns>
1046 protected internal List<SceneObjectGroup> GetSceneObjectGroups()
1047 {
1048 lock (SceneObjectGroupsByFullID)
1049 return new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
1050 }
1051
1052 /// <summary>
1041 /// Get a group in the scene 1053 /// Get a group in the scene
1042 /// </summary> 1054 /// </summary>
1043 /// <param name="fullID">UUID of the group</param> 1055 /// <param name="fullID">UUID of the group</param>
@@ -1180,11 +1192,7 @@ namespace OpenSim.Region.Framework.Scenes
1180 /// <param name="action"></param> 1192 /// <param name="action"></param>
1181 protected internal void ForEachSOG(Action<SceneObjectGroup> action) 1193 protected internal void ForEachSOG(Action<SceneObjectGroup> action)
1182 { 1194 {
1183 List<SceneObjectGroup> objlist; 1195 foreach (SceneObjectGroup obj in GetSceneObjectGroups())
1184 lock (SceneObjectGroupsByFullID)
1185 objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
1186
1187 foreach (SceneObjectGroup obj in objlist)
1188 { 1196 {
1189 try 1197 try
1190 { 1198 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index 1038111..26524fb 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -79,7 +79,7 @@ namespace OpenSim.Region.Framework.Scenes
79 } 79 }
80 80
81 /// <summary> 81 /// <summary>
82 /// Stop the scripts contained in all the prims in this group 82 /// Stop and remove the scripts contained in all the prims in this group
83 /// </summary> 83 /// </summary>
84 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 84 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
85 { 85 {
@@ -89,6 +89,14 @@ namespace OpenSim.Region.Framework.Scenes
89 } 89 }
90 90
91 /// <summary> 91 /// <summary>
92 /// Stop the scripts contained in all the prims in this group
93 /// </summary>
94 public void StopScriptInstances()
95 {
96 Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => p.Inventory.StopScriptInstances());
97 }
98
99 /// <summary>
92 /// Add an inventory item from a user's inventory to a prim in this scene object. 100 /// Add an inventory item from a user's inventory to a prim in this scene object.
93 /// </summary> 101 /// </summary>
94 /// <param name="agentID">The agent adding the item.</param> 102 /// <param name="agentID">The agent adding the item.</param>
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index f68a5b3..cc7d0fb 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1674,16 +1674,6 @@ namespace OpenSim.Region.Framework.Scenes
1674 { 1674 {
1675 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); 1675 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
1676 } 1676 }
1677
1678 /// <summary>
1679 /// Added as a way for the storage provider to reset the scene,
1680 /// most likely a better way to do this sort of thing but for now...
1681 /// </summary>
1682 /// <param name="scene"></param>
1683 public void SetScene(Scene scene)
1684 {
1685 m_scene = scene;
1686 }
1687 1677
1688 /// <summary> 1678 /// <summary>
1689 /// Set a part to act as the root part for this scene object 1679 /// Set a part to act as the root part for this scene object
@@ -4324,6 +4314,20 @@ namespace OpenSim.Region.Framework.Scenes
4324 return count; 4314 return count;
4325 } 4315 }
4326 4316
4317 /// <summary>
4318 /// Gets the number of sitting avatars.
4319 /// </summary>
4320 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4321 /// <returns></returns>
4322 public int GetSittingAvatarsCount()
4323 {
4324 int count = 0;
4325
4326 Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount());
4327
4328 return count;
4329 }
4330
4327 public override string ToString() 4331 public override string ToString()
4328 { 4332 {
4329 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); 4333 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 7b1f5d2..1f1caca 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -147,6 +147,21 @@ namespace OpenSim.Region.Framework.Scenes
147 get { return ParentGroup.RootPart == this; } 147 get { return ParentGroup.RootPart == this; }
148 } 148 }
149 149
150 /// <summary>
151 /// Is an explicit sit target set for this part?
152 /// </summary>
153 public bool IsSitTargetSet
154 {
155 get
156 {
157 return
158 !(SitTargetPosition == Vector3.Zero
159 && (SitTargetOrientation == Quaternion.Identity // Valid Zero Rotation quaternion
160 || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 1f && SitTargetOrientation.W == 0f // W-Z Mapping was invalid at one point
161 || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f && SitTargetOrientation.W == 0f)); // Invalid Quaternion
162 }
163 }
164
150 #region Fields 165 #region Fields
151 166
152 public bool AllowedDrop; 167 public bool AllowedDrop;
@@ -426,7 +441,6 @@ namespace OpenSim.Region.Framework.Scenes
426 private uint _category; 441 private uint _category;
427 private Int32 _creationDate; 442 private Int32 _creationDate;
428 private uint _parentID = 0; 443 private uint _parentID = 0;
429 private UUID m_sitTargetAvatar = UUID.Zero;
430 private uint _baseMask = (uint)PermissionMask.All; 444 private uint _baseMask = (uint)PermissionMask.All;
431 private uint _ownerMask = (uint)PermissionMask.All; 445 private uint _ownerMask = (uint)PermissionMask.All;
432 private uint _groupMask = (uint)PermissionMask.None; 446 private uint _groupMask = (uint)PermissionMask.None;
@@ -1312,13 +1326,20 @@ namespace OpenSim.Region.Framework.Scenes
1312 } 1326 }
1313 1327
1314 /// <summary> 1328 /// <summary>
1315 /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero 1329 /// ID of the avatar that is sat on us if we have a sit target. If there is no such avatar then is UUID.Zero
1316 /// </summary> 1330 /// </summary>
1317 public UUID SitTargetAvatar 1331 public UUID SitTargetAvatar { get; set; }
1318 { 1332
1319 get { return m_sitTargetAvatar; } 1333 /// <summary>
1320 set { m_sitTargetAvatar = value; } 1334 /// IDs of all avatars start on this object part.
1321 } 1335 /// </summary>
1336 /// <remarks>
1337 /// We need to track this so that we can stop sat upon prims from being attached.
1338 /// </remarks>
1339 /// <value>
1340 /// null if there are no sitting avatars. This is to save us create a hashset for every prim in a scene.
1341 /// </value>
1342 private HashSet<UUID> m_sittingAvatars;
1322 1343
1323 public virtual UUID RegionID 1344 public virtual UUID RegionID
1324 { 1345 {
@@ -5128,5 +5149,99 @@ namespace OpenSim.Region.Framework.Scenes
5128 Inventory.UpdateInventoryItem(item, false, false); 5149 Inventory.UpdateInventoryItem(item, false, false);
5129 } 5150 }
5130 } 5151 }
5152
5153 /// <summary>
5154 /// Record an avatar sitting on this part.
5155 /// </summary>
5156 /// <remarks>This is called for all the sitting avatars whether there is a sit target set or not.</remarks>
5157 /// <returns>
5158 /// true if the avatar was not already recorded, false otherwise.
5159 /// </returns>
5160 /// <param name='avatarId'></param>
5161 protected internal bool AddSittingAvatar(UUID avatarId)
5162 {
5163 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
5164 SitTargetAvatar = avatarId;
5165
5166 HashSet<UUID> sittingAvatars = m_sittingAvatars;
5167
5168 if (sittingAvatars == null)
5169 sittingAvatars = new HashSet<UUID>();
5170
5171 lock (sittingAvatars)
5172 {
5173 m_sittingAvatars = sittingAvatars;
5174 return m_sittingAvatars.Add(avatarId);
5175 }
5176 }
5177
5178 /// <summary>
5179 /// Remove an avatar recorded as sitting on this part.
5180 /// </summary>
5181 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
5182 /// <returns>
5183 /// true if the avatar was present and removed, false if it was not present.
5184 /// </returns>
5185 /// <param name='avatarId'></param>
5186 protected internal bool RemoveSittingAvatar(UUID avatarId)
5187 {
5188 if (SitTargetAvatar == avatarId)
5189 SitTargetAvatar = UUID.Zero;
5190
5191 HashSet<UUID> sittingAvatars = m_sittingAvatars;
5192
5193 // This can occur under a race condition where another thread
5194 if (sittingAvatars == null)
5195 return false;
5196
5197 lock (sittingAvatars)
5198 {
5199 if (sittingAvatars.Remove(avatarId))
5200 {
5201 if (sittingAvatars.Count == 0)
5202 m_sittingAvatars = null;
5203
5204 return true;
5205 }
5206 }
5207
5208 return false;
5209 }
5210
5211 /// <summary>
5212 /// Get a copy of the list of sitting avatars.
5213 /// </summary>
5214 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
5215 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
5216 public HashSet<UUID> GetSittingAvatars()
5217 {
5218 HashSet<UUID> sittingAvatars = m_sittingAvatars;
5219
5220 if (sittingAvatars == null)
5221 {
5222 return null;
5223 }
5224 else
5225 {
5226 lock (sittingAvatars)
5227 return new HashSet<UUID>(sittingAvatars);
5228 }
5229 }
5230
5231 /// <summary>
5232 /// Gets the number of sitting avatars.
5233 /// </summary>
5234 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
5235 /// <returns></returns>
5236 public int GetSittingAvatarsCount()
5237 {
5238 HashSet<UUID> sittingAvatars = m_sittingAvatars;
5239
5240 if (sittingAvatars == null)
5241 return 0;
5242
5243 lock (sittingAvatars)
5244 return sittingAvatars.Count;
5245 }
5131 } 5246 }
5132} 5247}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 1dff088..e5e29d0 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -292,7 +292,7 @@ namespace OpenSim.Region.Framework.Scenes
292 } 292 }
293 293
294 /// <summary> 294 /// <summary>
295 /// Stop all the scripts in this prim. 295 /// Stop and remove all the scripts in this prim.
296 /// </summary> 296 /// </summary>
297 /// <param name="sceneObjectBeingDeleted"> 297 /// <param name="sceneObjectBeingDeleted">
298 /// Should be true if these scripts are being removed because the scene 298 /// Should be true if these scripts are being removed because the scene
@@ -309,6 +309,14 @@ namespace OpenSim.Region.Framework.Scenes
309 } 309 }
310 310
311 /// <summary> 311 /// <summary>
312 /// Stop all the scripts in this prim.
313 /// </summary>
314 public void StopScriptInstances()
315 {
316 GetInventoryItems(InventoryType.LSL).ForEach(i => StopScriptInstance(i));
317 }
318
319 /// <summary>
312 /// Start a script which is in this prim's inventory. 320 /// Start a script which is in this prim's inventory.
313 /// </summary> 321 /// </summary>
314 /// <param name="item"></param> 322 /// <param name="item"></param>
@@ -596,7 +604,7 @@ namespace OpenSim.Region.Framework.Scenes
596 } 604 }
597 605
598 /// <summary> 606 /// <summary>
599 /// Stop a script which is in this prim's inventory. 607 /// Stop and remove a script which is in this prim's inventory.
600 /// </summary> 608 /// </summary>
601 /// <param name="itemId"></param> 609 /// <param name="itemId"></param>
602 /// <param name="sceneObjectBeingDeleted"> 610 /// <param name="sceneObjectBeingDeleted">
@@ -615,7 +623,7 @@ namespace OpenSim.Region.Framework.Scenes
615 } 623 }
616 else 624 else
617 { 625 {
618 m_log.ErrorFormat( 626 m_log.WarnFormat(
619 "[PRIM INVENTORY]: " + 627 "[PRIM INVENTORY]: " +
620 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", 628 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
621 itemId, m_part.Name, m_part.UUID, 629 itemId, m_part.Name, m_part.UUID,
@@ -624,6 +632,51 @@ namespace OpenSim.Region.Framework.Scenes
624 } 632 }
625 633
626 /// <summary> 634 /// <summary>
635 /// Stop a script which is in this prim's inventory.
636 /// </summary>
637 /// <param name="itemId"></param>
638 /// <param name="sceneObjectBeingDeleted">
639 /// Should be true if this script is being removed because the scene
640 /// object is being deleted. This will prevent spurious updates to the client.
641 /// </param>
642 public void StopScriptInstance(UUID itemId)
643 {
644 TaskInventoryItem scriptItem;
645
646 lock (m_items)
647 m_items.TryGetValue(itemId, out scriptItem);
648
649 if (scriptItem != null)
650 {
651 StopScriptInstance(scriptItem);
652 }
653 else
654 {
655 m_log.WarnFormat(
656 "[PRIM INVENTORY]: " +
657 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
658 itemId, m_part.Name, m_part.UUID,
659 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
660 }
661 }
662
663 /// <summary>
664 /// Stop a script which is in this prim's inventory.
665 /// </summary>
666 /// <param name="itemId"></param>
667 /// <param name="sceneObjectBeingDeleted">
668 /// Should be true if this script is being removed because the scene
669 /// object is being deleted. This will prevent spurious updates to the client.
670 /// </param>
671 public void StopScriptInstance(TaskInventoryItem item)
672 {
673 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID);
674
675 // At the moment, even stopped scripts are counted as active, which is probably wrong.
676// m_part.ParentGroup.AddActiveScriptCount(-1);
677 }
678
679 /// <summary>
627 /// Check if the inventory holds an item with a given name. 680 /// Check if the inventory holds an item with a given name.
628 /// </summary> 681 /// </summary>
629 /// <param name="name"></param> 682 /// <param name="name"></param>
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index f0ceff6..e27d309 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -594,6 +594,12 @@ namespace OpenSim.Region.Framework.Scenes
594 private UUID m_parentUUID = UUID.Zero; 594 private UUID m_parentUUID = UUID.Zero;
595 595
596 /// <summary> 596 /// <summary>
597 /// Are we sitting on an object?
598 /// </summary>
599 /// <remarks>A more readable way of testing presence sit status than ParentID == 0</remarks>
600 public bool IsSatOnObject { get { return ParentID != 0; } }
601
602 /// <summary>
597 /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null. 603 /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null.
598 /// </summary> 604 /// </summary>
599 /// <remarks> 605 /// <remarks>
@@ -1940,10 +1946,6 @@ namespace OpenSim.Region.Framework.Scenes
1940 } 1946 }
1941 } 1947 }
1942 1948
1943 // Reset sit target.
1944 if (part.SitTargetAvatar == UUID)
1945 part.SitTargetAvatar = UUID.Zero;
1946
1947 part.ParentGroup.DeleteAvatar(UUID); 1949 part.ParentGroup.DeleteAvatar(UUID);
1948// ParentPosition = part.GetWorldPosition(); 1950// ParentPosition = part.GetWorldPosition();
1949 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 1951 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
@@ -1961,6 +1963,8 @@ namespace OpenSim.Region.Framework.Scenes
1961 SendAvatarDataToAllAgents(); 1963 SendAvatarDataToAllAgents();
1962 m_requestedSitTargetID = 0; 1964 m_requestedSitTargetID = 0;
1963 1965
1966 part.RemoveSittingAvatar(UUID);
1967
1964 if (part != null) 1968 if (part != null)
1965 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); 1969 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
1966 } 1970 }
@@ -1994,15 +1998,7 @@ namespace OpenSim.Region.Framework.Scenes
1994 //look for prims with explicit sit targets that are available 1998 //look for prims with explicit sit targets that are available
1995 foreach (SceneObjectPart part in partArray) 1999 foreach (SceneObjectPart part in partArray)
1996 { 2000 {
1997 // Is a sit target available? 2001 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
1998 Vector3 avSitOffset = part.SitTargetPosition;
1999 Quaternion avSitOrientation = part.SitTargetOrientation;
2000 UUID avOnTargetAlready = part.SitTargetAvatar;
2001
2002 bool SitTargetUnOccupied = avOnTargetAlready == UUID.Zero;
2003 bool SitTargetisSet = avSitOffset != Vector3.Zero || avSitOrientation != Quaternion.Identity;
2004
2005 if (SitTargetisSet && SitTargetUnOccupied)
2006 { 2002 {
2007 //switch the target to this prim 2003 //switch the target to this prim
2008 return part; 2004 return part;
@@ -2013,10 +2009,8 @@ namespace OpenSim.Region.Framework.Scenes
2013 return targetPart; 2009 return targetPart;
2014 } 2010 }
2015 2011
2016 private void SendSitResponse(UUID targetID, Vector3 offset, Quaternion pSitOrientation) 2012 private void SendSitResponse(UUID targetID, Vector3 offset, Quaternion sitOrientation)
2017 { 2013 {
2018 Vector3 pos = new Vector3();
2019 Quaternion sitOrientation = pSitOrientation;
2020 Vector3 cameraEyeOffset = Vector3.Zero; 2014 Vector3 cameraEyeOffset = Vector3.Zero;
2021 Vector3 cameraAtOffset = Vector3.Zero; 2015 Vector3 cameraAtOffset = Vector3.Zero;
2022 bool forceMouselook = false; 2016 bool forceMouselook = false;
@@ -2028,42 +2022,21 @@ namespace OpenSim.Region.Framework.Scenes
2028 // TODO: determine position to sit at based on scene geometry; don't trust offset from client 2022 // TODO: determine position to sit at based on scene geometry; don't trust offset from client
2029 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it 2023 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
2030 2024
2031 // Is a sit target available?
2032 Vector3 avSitOffSet = part.SitTargetPosition;
2033 Quaternion avSitOrientation = part.SitTargetOrientation;
2034 UUID avOnTargetAlready = part.SitTargetAvatar;
2035
2036 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero));
2037 bool SitTargetisSet =
2038 (!(avSitOffSet == Vector3.Zero &&
2039 (
2040 avSitOrientation == Quaternion.Identity // Valid Zero Rotation quaternion
2041 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point
2042 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion
2043 )
2044 ));
2045
2046// m_log.DebugFormat("[SCENE PRESENCE]: {0} {1}", SitTargetisSet, SitTargetUnOccupied);
2047
2048 if (PhysicsActor != null) 2025 if (PhysicsActor != null)
2049 m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f; 2026 m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f;
2050 2027
2051 bool canSit = false; 2028 bool canSit = false;
2052 pos = part.AbsolutePosition + offset; 2029 Vector3 pos = part.AbsolutePosition + offset;
2053 2030
2054 if (SitTargetisSet) 2031 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
2055 { 2032 {
2056 if (SitTargetUnOccupied)
2057 {
2058// m_log.DebugFormat( 2033// m_log.DebugFormat(
2059// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied", 2034// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied",
2060// Name, part.Name, part.LocalId); 2035// Name, part.Name, part.LocalId);
2061 2036
2062 part.SitTargetAvatar = UUID; 2037 offset = part.SitTargetPosition;
2063 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); 2038 sitOrientation = part.SitTargetOrientation;
2064 sitOrientation = avSitOrientation; 2039 canSit = true;
2065 canSit = true;
2066 }
2067 } 2040 }
2068 else 2041 else
2069 { 2042 {
@@ -2076,6 +2049,12 @@ namespace OpenSim.Region.Framework.Scenes
2076 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); 2049 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
2077 canSit = true; 2050 canSit = true;
2078 } 2051 }
2052// else
2053// {
2054// m_log.DebugFormat(
2055// "[SCENE PRESENCE]: Ignoring sit request of {0} on {1} {2} because sit target is unset and outside 10m",
2056// Name, part.Name, part.LocalId);
2057// }
2079 } 2058 }
2080 2059
2081 if (canSit) 2060 if (canSit)
@@ -2086,6 +2065,8 @@ namespace OpenSim.Region.Framework.Scenes
2086 RemoveFromPhysicalScene(); 2065 RemoveFromPhysicalScene();
2087 } 2066 }
2088 2067
2068 part.AddSittingAvatar(UUID);
2069
2089 cameraAtOffset = part.GetCameraAtOffset(); 2070 cameraAtOffset = part.GetCameraAtOffset();
2090 cameraEyeOffset = part.GetCameraEyeOffset(); 2071 cameraEyeOffset = part.GetCameraEyeOffset();
2091 forceMouselook = part.GetForceMouselook(); 2072 forceMouselook = part.GetForceMouselook();
@@ -2362,6 +2343,15 @@ namespace OpenSim.Region.Framework.Scenes
2362 2343
2363 if (part != null) 2344 if (part != null)
2364 { 2345 {
2346 if (part.ParentGroup.IsAttachment)
2347 {
2348 m_log.WarnFormat(
2349 "[SCENE PRESENCE]: Avatar {0} tried to sit on part {1} from object {2} in {3} but this is an attachment for avatar id {4}",
2350 Name, part.Name, part.ParentGroup.Name, Scene.Name, part.ParentGroup.AttachedAvatar);
2351
2352 return;
2353 }
2354
2365 if (part.SitTargetAvatar == UUID) 2355 if (part.SitTargetAvatar == UUID)
2366 { 2356 {
2367 Vector3 sitTargetPos = part.SitTargetPosition; 2357 Vector3 sitTargetPos = part.SitTargetPosition;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
index ed39be1..493ab70 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
29using System.Reflection; 30using System.Reflection;
30using Nini.Config; 31using Nini.Config;
31using NUnit.Framework; 32using NUnit.Framework;
@@ -69,6 +70,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
69 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); 70 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero);
70 71
71 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); 72 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
73 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0));
74 Assert.That(part.GetSittingAvatars(), Is.Null);
72 Assert.That(m_sp.ParentID, Is.EqualTo(0)); 75 Assert.That(m_sp.ParentID, Is.EqualTo(0));
73 } 76 }
74 77
@@ -86,7 +89,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests
86 89
87 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); 90 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero);
88 91
92 Assert.That(m_sp.PhysicsActor, Is.Null);
93
89 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); 94 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
95 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1));
96 HashSet<UUID> sittingAvatars = part.GetSittingAvatars();
97 Assert.That(sittingAvatars.Count, Is.EqualTo(1));
98 Assert.That(sittingAvatars.Contains(m_sp.UUID));
90 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); 99 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId));
91 } 100 }
92 101
@@ -104,10 +113,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
104 113
105 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); 114 m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero);
106 115
107 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
108 Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId));
109 Assert.That(m_sp.PhysicsActor, Is.Null);
110
111 // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the 116 // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the
112 // default avatar. 117 // default avatar.
113 // Curiously, Vector3.ToString() will not display the last two places of the float. For example, 118 // Curiously, Vector3.ToString() will not display the last two places of the float. For example,
@@ -119,6 +124,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
119 m_sp.StandUp(); 124 m_sp.StandUp();
120 125
121 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); 126 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
127 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0));
128 Assert.That(part.GetSittingAvatars(), Is.Null);
122 Assert.That(m_sp.ParentID, Is.EqualTo(0)); 129 Assert.That(m_sp.ParentID, Is.EqualTo(0));
123 Assert.That(m_sp.PhysicsActor, Is.Not.Null); 130 Assert.That(m_sp.PhysicsActor, Is.Not.Null);
124 } 131 }
@@ -145,11 +152,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests
145 Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); 152 Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT));
146 Assert.That(m_sp.PhysicsActor, Is.Null); 153 Assert.That(m_sp.PhysicsActor, Is.Null);
147 154
155 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1));
156 HashSet<UUID> sittingAvatars = part.GetSittingAvatars();
157 Assert.That(sittingAvatars.Count, Is.EqualTo(1));
158 Assert.That(sittingAvatars.Contains(m_sp.UUID));
159
148 m_sp.StandUp(); 160 m_sp.StandUp();
149 161
150 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); 162 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
151 Assert.That(m_sp.ParentID, Is.EqualTo(0)); 163 Assert.That(m_sp.ParentID, Is.EqualTo(0));
152 Assert.That(m_sp.PhysicsActor, Is.Not.Null); 164 Assert.That(m_sp.PhysicsActor, Is.Not.Null);
165
166 Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero));
167 Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0));
168 Assert.That(part.GetSittingAvatars(), Is.Null);
153 } 169 }
154 170
155 [Test] 171 [Test]
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index 0b9f875..600cafb 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -228,9 +228,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
228 // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}", 228 // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}",
229 // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString()); 229 // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString());
230 230
231 m_log.InfoFormat("[RegionReady]: Initialization complete - logins enabled for {0}", m_scene.RegionInfo.RegionName); 231 m_log.InfoFormat(
232 "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name);
232 233
233 if ( m_uri != string.Empty ) 234 if (m_uri != string.Empty)
234 { 235 {
235 RRAlert("enabled"); 236 RRAlert("enabled");
236 } 237 }
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 4fcf40d..045661a 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -104,6 +104,45 @@ namespace OpenSim.Region.OptionalModules.World.NPC
104 OnMoneyTransferRequest(m_uuid, target, amount, 1, "Payment"); 104 OnMoneyTransferRequest(m_uuid, target, amount, 1, "Payment");
105 } 105 }
106 106
107 public bool Touch(UUID target)
108 {
109 SceneObjectPart part = m_scene.GetSceneObjectPart(target);
110 if (part == null)
111 return false;
112 bool objectTouchable = hasTouchEvents(part); // Only touch an object that is scripted to respond
113 if (!objectTouchable && !part.IsRoot)
114 objectTouchable = hasTouchEvents(part.ParentGroup.RootPart);
115 if (!objectTouchable)
116 return false;
117 // Set up the surface args as if the touch is from a client that does not support this
118 SurfaceTouchEventArgs surfaceArgs = new SurfaceTouchEventArgs();
119 surfaceArgs.FaceIndex = -1; // TOUCH_INVALID_FACE
120 surfaceArgs.Binormal = Vector3.Zero; // TOUCH_INVALID_VECTOR
121 surfaceArgs.Normal = Vector3.Zero; // TOUCH_INVALID_VECTOR
122 surfaceArgs.STCoord = new Vector3(-1.0f, -1.0f, 0.0f); // TOUCH_INVALID_TEXCOORD
123 surfaceArgs.UVCoord = surfaceArgs.STCoord; // TOUCH_INVALID_TEXCOORD
124 List<SurfaceTouchEventArgs> touchArgs = new List<SurfaceTouchEventArgs>();
125 touchArgs.Add(surfaceArgs);
126 Vector3 offset = part.OffsetPosition * -1.0f;
127 if (OnGrabObject == null)
128 return false;
129 OnGrabObject(part.LocalId, offset, this, touchArgs);
130 if (OnGrabUpdate != null)
131 OnGrabUpdate(part.UUID, offset, part.ParentGroup.RootPart.GroupPosition, this, touchArgs);
132 if (OnDeGrabObject != null)
133 OnDeGrabObject(part.LocalId, this, touchArgs);
134 return true;
135 }
136
137 private bool hasTouchEvents(SceneObjectPart part)
138 {
139 if ((part.ScriptEvents & scriptEvents.touch) != 0 ||
140 (part.ScriptEvents & scriptEvents.touch_start) != 0 ||
141 (part.ScriptEvents & scriptEvents.touch_end) != 0)
142 return true;
143 return false;
144 }
145
107 public void InstantMessage(UUID target, string message) 146 public void InstantMessage(UUID target, string message)
108 { 147 {
109 OnInstantMessage(this, new GridInstantMessage(m_scene, 148 OnInstantMessage(this, new GridInstantMessage(m_scene,
@@ -153,6 +192,14 @@ namespace OpenSim.Region.OptionalModules.World.NPC
153 192
154 private void SendOnChatFromClient(int channel, string message, ChatTypeEnum chatType) 193 private void SendOnChatFromClient(int channel, string message, ChatTypeEnum chatType)
155 { 194 {
195 if (channel == 0)
196 {
197 message = message.Trim();
198 if (string.IsNullOrEmpty(message))
199 {
200 return;
201 }
202 }
156 OSChatMessage chatFromClient = new OSChatMessage(); 203 OSChatMessage chatFromClient = new OSChatMessage();
157 chatFromClient.Channel = channel; 204 chatFromClient.Channel = channel;
158 chatFromClient.From = Name; 205 chatFromClient.From = Name;
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index a32ab2a..b37aba3 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -306,6 +306,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC
306 return false; 306 return false;
307 } 307 }
308 308
309 public bool Touch(UUID agentID, UUID objectID)
310 {
311 lock (m_avatars)
312 {
313 if (m_avatars.ContainsKey(agentID))
314 return m_avatars[agentID].Touch(objectID);
315 return false;
316 }
317 }
318
309 public UUID GetOwner(UUID agentID) 319 public UUID GetOwner(UUID agentID)
310 { 320 {
311 lock (m_avatars) 321 lock (m_avatars)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index b08d5db..dc0c008 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -74,7 +74,7 @@ public class BSCharacter : PhysicsActor
74 private float _buoyancy; 74 private float _buoyancy;
75 75
76 private int _subscribedEventsMs = 0; 76 private int _subscribedEventsMs = 0;
77 private int _lastCollisionTime = 0; 77 private int _nextCollisionOkTime = 0;
78 78
79 private Vector3 _PIDTarget; 79 private Vector3 _PIDTarget;
80 private bool _usePID; 80 private bool _usePID;
@@ -360,17 +360,22 @@ public class BSCharacter : PhysicsActor
360 } 360 }
361 //m_lastUpdateSent = false; 361 //m_lastUpdateSent = false;
362 } 362 }
363
363 public override void AddAngularForce(Vector3 force, bool pushforce) { 364 public override void AddAngularForce(Vector3 force, bool pushforce) {
364 } 365 }
365 public override void SetMomentum(Vector3 momentum) { 366 public override void SetMomentum(Vector3 momentum) {
366 } 367 }
368
369 // Turn on collision events at a rate no faster than one every the given milliseconds
367 public override void SubscribeEvents(int ms) { 370 public override void SubscribeEvents(int ms) {
368 _subscribedEventsMs = ms; 371 _subscribedEventsMs = ms;
369 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen 372 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
370 } 373 }
374 // Stop collision events
371 public override void UnSubscribeEvents() { 375 public override void UnSubscribeEvents() {
372 _subscribedEventsMs = 0; 376 _subscribedEventsMs = 0;
373 } 377 }
378 // Return 'true' if someone has subscribed to events
374 public override bool SubscribedEvents() { 379 public override bool SubscribedEvents() {
375 return (_subscribedEventsMs > 0); 380 return (_subscribedEventsMs > 0);
376 } 381 }
@@ -386,47 +391,57 @@ public class BSCharacter : PhysicsActor
386 _mass = _density * _avatarVolume; 391 _mass = _density * _avatarVolume;
387 } 392 }
388 393
394 // Set to 'true' if the individual changed items should be checked
395 // (someday RequestPhysicsTerseUpdate() will take a bitmap of changed properties)
396 const bool SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES = false;
397
389 // The physics engine says that properties have updated. Update same and inform 398 // The physics engine says that properties have updated. Update same and inform
390 // the world that things have changed. 399 // the world that things have changed.
391 public void UpdateProperties(EntityProperties entprop) 400 public void UpdateProperties(EntityProperties entprop)
392 { 401 {
393 bool changed = false; 402 bool changed = false;
394 // we assign to the local variables so the normal set action does not happen 403 if (SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES) {
395 if (_position != entprop.Position) 404 // we assign to the local variables so the normal set action does not happen
396 { 405 if (_position != entprop.Position) {
397 _position = entprop.Position; 406 _position = entprop.Position;
398 changed = true; 407 changed = true;
408 }
409 if (_orientation != entprop.Rotation) {
410 _orientation = entprop.Rotation;
411 changed = true;
412 }
413 if (_velocity != entprop.Velocity) {
414 _velocity = entprop.Velocity;
415 changed = true;
416 }
417 if (_acceleration != entprop.Acceleration) {
418 _acceleration = entprop.Acceleration;
419 changed = true;
420 }
421 if (_rotationalVelocity != entprop.RotationalVelocity) {
422 _rotationalVelocity = entprop.RotationalVelocity;
423 changed = true;
424 }
425 if (changed) {
426 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
427 // Avatar movement is not done by generating this event. There is code in the heartbeat
428 // loop that updates avatars.
429 // base.RequestPhysicsterseUpdate();
430 }
399 } 431 }
400 if (_orientation != entprop.Rotation) 432 else {
401 { 433 _position = entprop.Position;
402 _orientation = entprop.Rotation; 434 _orientation = entprop.Rotation;
403 changed = true;
404 }
405 if (_velocity != entprop.Velocity)
406 {
407 _velocity = entprop.Velocity; 435 _velocity = entprop.Velocity;
408 changed = true;
409 }
410 if (_acceleration != entprop.Acceleration)
411 {
412 _acceleration = entprop.Acceleration; 436 _acceleration = entprop.Acceleration;
413 changed = true;
414 }
415 if (_rotationalVelocity != entprop.RotationalVelocity)
416 {
417 _rotationalVelocity = entprop.RotationalVelocity; 437 _rotationalVelocity = entprop.RotationalVelocity;
418 changed = true;
419 }
420 if (changed)
421 {
422 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
423 // Avatar movement is not done by generating this event. There is a system that
424 // checks for avatar updates each heartbeat loop.
425 // base.RequestPhysicsterseUpdate(); 438 // base.RequestPhysicsterseUpdate();
426 } 439 }
427 } 440 }
428 441
429 // Called by the scene when a collision with this object is reported 442 // Called by the scene when a collision with this object is reported
443 // The collision, if it should be reported to the character, is placed in a collection
444 // that will later be sent to the simulator when SendCollisions() is called.
430 CollisionEventUpdate collisionCollection = null; 445 CollisionEventUpdate collisionCollection = null;
431 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth) 446 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
432 { 447 {
@@ -440,29 +455,34 @@ public class BSCharacter : PhysicsActor
440 } 455 }
441 456
442 // throttle collisions to the rate specified in the subscription 457 // throttle collisions to the rate specified in the subscription
443 if (_subscribedEventsMs == 0) return; // don't want collisions 458 if (_subscribedEventsMs != 0) {
444 int nowTime = _scene.SimulationNowTime; 459 int nowTime = _scene.SimulationNowTime;
445 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; 460 if (nowTime >= _nextCollisionOkTime) {
446 _lastCollisionTime = nowTime; 461 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
447 462
448 if (collisionCollection == null) 463 if (collisionCollection == null)
449 collisionCollection = new CollisionEventUpdate(); 464 collisionCollection = new CollisionEventUpdate();
450 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 465 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
466 }
467 }
451 } 468 }
452 469
453 public void SendCollisions() 470 public void SendCollisions()
454 { 471 {
455 // if (collisionCollection != null) 472 /*
456 // { 473 if (collisionCollection != null && collisionCollection.Count > 0)
457 // base.SendCollisionUpdate(collisionCollection); 474 {
458 // collisionCollection = null; 475 base.SendCollisionUpdate(collisionCollection);
459 // } 476 collisionCollection = null;
477 }
478 */
460 // Kludge to make a collision call even if there are no collisions. 479 // Kludge to make a collision call even if there are no collisions.
461 // This causes the avatar animation to get updated. 480 // This causes the avatar animation to get updated.
462 if (collisionCollection == null) 481 if (collisionCollection == null)
463 collisionCollection = new CollisionEventUpdate(); 482 collisionCollection = new CollisionEventUpdate();
464 base.SendCollisionUpdate(collisionCollection); 483 base.SendCollisionUpdate(collisionCollection);
465 collisionCollection = null; 484 collisionCollection.Clear();
485 // End kludge
466 } 486 }
467 487
468} 488}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 0730824..0f027b8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -32,6 +32,14 @@ using OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
40 /// The unmanaged library is compiled and linked statically with Bullet
41 /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit).
42 /// </summary>
35public class BSPlugin : IPhysicsPlugin 43public class BSPlugin : IPhysicsPlugin
36{ 44{
37 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 45 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
@@ -53,6 +61,9 @@ public class BSPlugin : IPhysicsPlugin
53 { 61 {
54 if (Util.IsWindows()) 62 if (Util.IsWindows())
55 Util.LoadArchSpecificWindowsDll("BulletSim.dll"); 63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the
65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
56 67
57 _mScene = new BSScene(sceneIdentifier); 68 _mScene = new BSScene(sceneIdentifier);
58 } 69 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 248d1f2..130f1ca 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -90,7 +90,7 @@ public sealed class BSPrim : PhysicsActor
90 private BSPrim _parentPrim; 90 private BSPrim _parentPrim;
91 91
92 private int _subscribedEventsMs = 0; 92 private int _subscribedEventsMs = 0;
93 private int _lastCollisionTime = 0; 93 private int _nextCollisionOkTime = 0;
94 long _collidingStep; 94 long _collidingStep;
95 long _collidingGroundStep; 95 long _collidingGroundStep;
96 96
@@ -597,7 +597,8 @@ public sealed class BSPrim : PhysicsActor
597 } 597 }
598 public override void SubscribeEvents(int ms) { 598 public override void SubscribeEvents(int ms) {
599 _subscribedEventsMs = ms; 599 _subscribedEventsMs = ms;
600 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen 600 // make sure first collision happens
601 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
601 } 602 }
602 public override void UnSubscribeEvents() { 603 public override void UnSubscribeEvents() {
603 _subscribedEventsMs = 0; 604 _subscribedEventsMs = 0;
@@ -1338,23 +1339,27 @@ public sealed class BSPrim : PhysicsActor
1338 _collidingGroundStep = _scene.SimulationStep; 1339 _collidingGroundStep = _scene.SimulationStep;
1339 } 1340 }
1340 1341
1341 if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events 1342 // if someone is subscribed to collision events....
1342 // throttle the collisions to the number of milliseconds specified in the subscription 1343 if (_subscribedEventsMs != 0) {
1343 int nowTime = _scene.SimulationNowTime; 1344 // throttle the collisions to the number of milliseconds specified in the subscription
1344 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; 1345 int nowTime = _scene.SimulationNowTime;
1345 _lastCollisionTime = nowTime; 1346 if (nowTime >= _nextCollisionOkTime) {
1347 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
1346 1348
1347 if (collisionCollection == null) 1349 if (collisionCollection == null)
1348 collisionCollection = new CollisionEventUpdate(); 1350 collisionCollection = new CollisionEventUpdate();
1349 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 1351 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1352 }
1353 }
1350 } 1354 }
1351 1355
1356 // The scene is telling us it's time to pass our collected collisions into the simulator
1352 public void SendCollisions() 1357 public void SendCollisions()
1353 { 1358 {
1354 if (collisionCollection != null) 1359 if (collisionCollection != null && collisionCollection.Count > 0)
1355 { 1360 {
1356 base.SendCollisionUpdate(collisionCollection); 1361 base.SendCollisionUpdate(collisionCollection);
1357 collisionCollection = null; 1362 collisionCollection.Clear();
1358 } 1363 }
1359 } 1364 }
1360} 1365}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 94a0ccf..417cb5f 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -52,6 +52,7 @@ using OpenSim.Region.Framework;
52// Should prim.link() and prim.delink() membership checking happen at taint time? 52// Should prim.link() and prim.delink() membership checking happen at taint time?
53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
54// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 54// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
55// Use collision masks for collision with terrain and phantom objects
55// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) 56// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
56// Implement LockAngularMotion 57// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@@ -62,9 +63,6 @@ using OpenSim.Region.Framework;
62// Multiple contact points on collision? 63// Multiple contact points on collision?
63// See code in ode::near... calls to collision_accounting_events() 64// See code in ode::near... calls to collision_accounting_events()
64// (This might not be a problem. ODE collects all the collisions with one object in one tick.) 65// (This might not be a problem. ODE collects all the collisions with one object in one tick.)
65// Use collision masks for collision with terrain and phantom objects
66// Figure out how to not allocate a new Dictionary and List for every collision
67// in BSPrim.Collide() and BSCharacter.Collide(). Can the same ones be reused?
68// Raycast 66// Raycast
69// 67//
70namespace OpenSim.Region.Physics.BulletSPlugin 68namespace OpenSim.Region.Physics.BulletSPlugin
@@ -405,6 +403,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
405 // prevent simulation until we've been initialized 403 // prevent simulation until we've been initialized
406 if (!m_initialized) return 10.0f; 404 if (!m_initialized) return 10.0f;
407 405
406 long simulateStartTime = Util.EnvironmentTickCount();
407
408 // update the prim states while we know the physics engine is not busy 408 // update the prim states while we know the physics engine is not busy
409 ProcessTaints(); 409 ProcessTaints();
410 410
@@ -437,13 +437,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
437 } 437 }
438 } 438 }
439 439
440 // The SendCollision's batch up the collisions on the objects. Now push the collisions into the simulator. 440 // The above SendCollision's batch up the collisions on the objects.
441 // Now push the collisions into the simulator.
441 foreach (BSPrim bsp in m_primsWithCollisions) 442 foreach (BSPrim bsp in m_primsWithCollisions)
442 bsp.SendCollisions(); 443 bsp.SendCollisions();
443 m_primsWithCollisions.Clear(); 444 m_primsWithCollisions.Clear();
445
446 // This is a kludge to get avatar movement updated.
447 // Don't send collisions only if there were collisions -- send everytime.
448 // ODE sends collisions even if there are none and this is used to update
449 // avatar animations and stuff.
444 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 450 // foreach (BSCharacter bsc in m_avatarsWithCollisions)
445 // bsc.SendCollisions(); 451 // bsc.SendCollisions();
446 // This is a kludge to get avatar movement updated. ODE sends collisions even if there isn't any
447 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 452 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
448 kvp.Value.SendCollisions(); 453 kvp.Value.SendCollisions();
449 m_avatarsWithCollisions.Clear(); 454 m_avatarsWithCollisions.Clear();
@@ -465,10 +470,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
465 if (m_avatars.TryGetValue(entprop.ID, out actor)) 470 if (m_avatars.TryGetValue(entprop.ID, out actor))
466 { 471 {
467 actor.UpdateProperties(entprop); 472 actor.UpdateProperties(entprop);
473 continue;
468 } 474 }
469 } 475 }
470 } 476 }
471 477
478 // If enabled, call into the physics engine to dump statistics
472 if (m_detailedStatsStep > 0) 479 if (m_detailedStatsStep > 0)
473 { 480 {
474 if ((m_simulationStep % m_detailedStatsStep) == 0) 481 if ((m_simulationStep % m_detailedStatsStep) == 0)
@@ -477,6 +484,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
477 } 484 }
478 } 485 }
479 486
487 // this is a waste since the outside routine also calcuates the physics simulation
488 // period. TODO: There should be a way of computing physics frames from simulator computation.
489 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime);
490 // return (timeStep * (float)simulateTotalTime);
491
480 // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation. 492 // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation.
481 return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f; 493 return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
482 } 494 }
@@ -528,6 +540,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
528 public override void SetWaterLevel(float baseheight) 540 public override void SetWaterLevel(float baseheight)
529 { 541 {
530 m_waterLevel = baseheight; 542 m_waterLevel = baseheight;
543 // TODO: pass to physics engine so things will float?
531 } 544 }
532 public float GetWaterLevel() 545 public float GetWaterLevel()
533 { 546 {
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 77b659b..b639d36 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -2725,6 +2725,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2725 } 2725 }
2726 } 2726 }
2727 2727
2728 public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num)
2729 {
2730 CheckThreatLevel(ThreatLevel.High, "osNpcTouch");
2731 m_host.AddScriptLPS(1);
2732 INPCModule module = World.RequestModuleInterface<INPCModule>();
2733 int linkNum = link_num.value;
2734 if (module != null || (linkNum < 0 && linkNum != ScriptBaseClass.LINK_THIS))
2735 {
2736 UUID npcId;
2737 if (!UUID.TryParse(npcLSL_Key, out npcId) || !module.CheckPermissions(npcId, m_host.OwnerID))
2738 return;
2739 SceneObjectPart part = null;
2740 UUID objectId;
2741 if (UUID.TryParse(LSL_String.ToString(object_key), out objectId))
2742 part = World.GetSceneObjectPart(objectId);
2743 if (part == null)
2744 return;
2745 if (linkNum != ScriptBaseClass.LINK_THIS)
2746 {
2747 if (linkNum == 0 || linkNum == ScriptBaseClass.LINK_ROOT)
2748 { // 0 and 1 are treated as root, find the root if the current part isnt it
2749 if (!part.IsRoot)
2750 part = part.ParentGroup.RootPart;
2751 }
2752 else
2753 { // Find the prim with the given link number if not found then fail silently
2754 part = part.ParentGroup.GetLinkNumPart(linkNum);
2755 if (part == null)
2756 return;
2757 }
2758 }
2759 module.Touch(npcId, part.UUID);
2760 }
2761 }
2762
2728 /// <summary> 2763 /// <summary>
2729 /// Save the current appearance of the script owner permanently to the named notecard. 2764 /// Save the current appearance of the script owner permanently to the named notecard.
2730 /// </summary> 2765 /// </summary>
@@ -3203,13 +3238,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3203 { 3238 {
3204 CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory"); 3239 CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory");
3205 3240
3241 m_host.AddScriptLPS(1);
3242
3243 ForceAttachToAvatarFromInventory(m_host.OwnerID, itemName, attachmentPoint);
3244 }
3245
3246 public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint)
3247 {
3248 CheckThreatLevel(ThreatLevel.Severe, "osForceAttachToOtherAvatarFromInventory");
3249
3250 m_host.AddScriptLPS(1);
3251
3252 UUID avatarId;
3253
3254 if (!UUID.TryParse(rawAvatarId, out avatarId))
3255 return;
3256
3257 ForceAttachToAvatarFromInventory(avatarId, itemName, attachmentPoint);
3258 }
3259
3260 public void ForceAttachToAvatarFromInventory(UUID avatarId, string itemName, int attachmentPoint)
3261 {
3206 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; 3262 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
3207 3263
3208 if (attachmentsModule == null) 3264 if (attachmentsModule == null)
3209 return; 3265 return;
3210 3266
3211 m_host.AddScriptLPS(1);
3212
3213 InitLSL(); 3267 InitLSL();
3214 3268
3215 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName); 3269 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
@@ -3232,7 +3286,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3232 return; 3286 return;
3233 } 3287 }
3234 3288
3235 ScenePresence sp = World.GetScenePresence(m_host.OwnerID); 3289 ScenePresence sp = World.GetScenePresence(avatarId);
3236 3290
3237 if (sp == null) 3291 if (sp == null)
3238 return; 3292 return;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index a790cdc..1facc96 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -101,19 +101,33 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
101 // Attachment commands 101 // Attachment commands
102 102
103 /// <summary> 103 /// <summary>
104 /// Attach the object containing this script to the avatar that owns it without checking for PERMISSION_ATTACH 104 /// Attach the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH
105 /// </summary> 105 /// </summary>
106 /// <param name='attachment'>The attachment point. For example, ATTACH_CHEST</param> 106 /// <param name='attachment'>The attachment point. For example, ATTACH_CHEST</param>
107 void osForceAttachToAvatar(int attachment); 107 void osForceAttachToAvatar(int attachment);
108 108
109 /// <summary> 109 /// <summary>
110 /// Attach the inventory item in the object containing this script to the avatar that owns it without checking for PERMISSION_ATTACH 110 /// Attach an inventory item in the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH
111 /// </summary> 111 /// </summary>
112 /// <remarks>
113 /// Nothing happens if the owner is not in the region.
114 /// </remarks>
112 /// <param name='itemName'>Tha name of the item. If this is not found then a warning is said to the owner</param> 115 /// <param name='itemName'>Tha name of the item. If this is not found then a warning is said to the owner</param>
113 /// <param name='attachment'>The attachment point. For example, ATTACH_CHEST</param> 116 /// <param name='attachment'>The attachment point. For example, ATTACH_CHEST</param>
114 void osForceAttachToAvatarFromInventory(string itemName, int attachment); 117 void osForceAttachToAvatarFromInventory(string itemName, int attachment);
115 118
116 /// <summary> 119 /// <summary>
120 /// Attach an inventory item in the object containing this script to any avatar in the region without asking for PERMISSION_ATTACH
121 /// </summary>
122 /// <remarks>
123 /// Nothing happens if the avatar is not in the region.
124 /// </remarks>
125 /// <param name='rawAvatarId'>The UUID of the avatar to which to attach. Nothing happens if this is not a UUID</para>
126 /// <param name='itemName'>The name of the item. If this is not found then a warning is said to the owner</param>
127 /// <param name='attachment'>The attachment point. For example, ATTACH_CHEST</param>
128 void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint);
129
130 /// <summary>
117 /// Detach the object containing this script from the avatar it is attached to without checking for PERMISSION_ATTACH 131 /// Detach the object containing this script from the avatar it is attached to without checking for PERMISSION_ATTACH
118 /// </summary> 132 /// </summary>
119 /// <remarks>Nothing happens if the object is not attached.</remarks> 133 /// <remarks>Nothing happens if the object is not attached.</remarks>
@@ -231,6 +245,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
231 void osNpcRemove(key npc); 245 void osNpcRemove(key npc);
232 void osNpcPlayAnimation(LSL_Key npc, string animation); 246 void osNpcPlayAnimation(LSL_Key npc, string animation);
233 void osNpcStopAnimation(LSL_Key npc, string animation); 247 void osNpcStopAnimation(LSL_Key npc, string animation);
248 void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num);
234 void osNpcWhisper(key npc, int channel, string message); 249 void osNpcWhisper(key npc, int channel, string message);
235 250
236 LSL_Key osOwnerSaveAppearance(string notecard); 251 LSL_Key osOwnerSaveAppearance(string notecard);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index 500ed96..b40bdf0 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -301,6 +301,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
301 m_OSSL_Functions.osForceAttachToAvatarFromInventory(itemName, attachmentPoint); 301 m_OSSL_Functions.osForceAttachToAvatarFromInventory(itemName, attachmentPoint);
302 } 302 }
303 303
304 public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint)
305 {
306 m_OSSL_Functions.osForceAttachToOtherAvatarFromInventory(rawAvatarId, itemName, attachmentPoint);
307 }
308
304 public void osForceDetachFromAvatar() 309 public void osForceDetachFromAvatar()
305 { 310 {
306 m_OSSL_Functions.osForceDetachFromAvatar(); 311 m_OSSL_Functions.osForceDetachFromAvatar();
@@ -626,6 +631,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
626 m_OSSL_Functions.osNpcWhisper(npc, channel, message); 631 m_OSSL_Functions.osNpcWhisper(npc, channel, message);
627 } 632 }
628 633
634 public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num)
635 {
636 m_OSSL_Functions.osNpcTouch(npcLSL_Key, object_key, link_num);
637 }
638
629 public LSL_Key osOwnerSaveAppearance(string notecard) 639 public LSL_Key osOwnerSaveAppearance(string notecard)
630 { 640 {
631 return m_OSSL_Functions.osOwnerSaveAppearance(notecard); 641 return m_OSSL_Functions.osOwnerSaveAppearance(notecard);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
index 3965734..c8718d9 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs
@@ -79,7 +79,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
79 /// Test creation of an NPC where the appearance data comes from a notecard 79 /// Test creation of an NPC where the appearance data comes from a notecard
80 /// </summary> 80 /// </summary>
81 [Test] 81 [Test]
82 public void TestOsNpcCreateFromNotecard() 82 public void TestOsNpcCreateUsingAppearanceFromNotecard()
83 { 83 {
84 TestHelpers.InMethod(); 84 TestHelpers.InMethod();
85// log4net.Config.XmlConfigurator.Configure(); 85// log4net.Config.XmlConfigurator.Configure();
@@ -90,7 +90,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
90 90
91 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 91 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
92 sp.Appearance.AvatarHeight = newHeight; 92 sp.Appearance.AvatarHeight = newHeight;
93 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); 93 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
94 SceneObjectPart part = so.RootPart; 94 SceneObjectPart part = so.RootPart;
95 m_scene.AddSceneObject(so); 95 m_scene.AddSceneObject(so);
96 96
@@ -114,10 +114,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
114 /// Test creation of an NPC where the appearance data comes from an avatar already in the region. 114 /// Test creation of an NPC where the appearance data comes from an avatar already in the region.
115 /// </summary> 115 /// </summary>
116 [Test] 116 [Test]
117 public void TestOsNpcCreateFromAvatar() 117 public void TestOsNpcCreateUsingAppearanceFromAvatar()
118 { 118 {
119 TestHelpers.InMethod(); 119 TestHelpers.InMethod();
120// log4net.Config.XmlConfigurator.Configure(); 120// TestHelpers.EnableLogging();
121 121
122 // Store an avatar with a different height from default in a notecard. 122 // Store an avatar with a different height from default in a notecard.
123 UUID userId = TestHelpers.ParseTail(0x1); 123 UUID userId = TestHelpers.ParseTail(0x1);
@@ -125,7 +125,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
125 125
126 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 126 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
127 sp.Appearance.AvatarHeight = newHeight; 127 sp.Appearance.AvatarHeight = newHeight;
128 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); 128 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
129 SceneObjectPart part = so.RootPart; 129 SceneObjectPart part = so.RootPart;
130 m_scene.AddSceneObject(so); 130 m_scene.AddSceneObject(so);
131 131
@@ -156,7 +156,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
156 156
157 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 157 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
158 sp.Appearance.AvatarHeight = newHeight; 158 sp.Appearance.AvatarHeight = newHeight;
159 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); 159 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
160 SceneObjectPart part = so.RootPart; 160 SceneObjectPart part = so.RootPart;
161 m_scene.AddSceneObject(so); 161 m_scene.AddSceneObject(so);
162 162
@@ -197,7 +197,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
197 197
198 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, nonOwnerId); 198 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, nonOwnerId);
199 sp.Appearance.AvatarHeight = newHeight; 199 sp.Appearance.AvatarHeight = newHeight;
200 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId); 200 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId, 0x10);
201 SceneObjectPart part = so.RootPart; 201 SceneObjectPart part = so.RootPart;
202 m_scene.AddSceneObject(so); 202 m_scene.AddSceneObject(so);
203 203
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
index 537b8aa..5ed1f3d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
@@ -158,7 +158,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
158 { 158 {
159 osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint); 159 osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint);
160 } 160 }
161 catch (Exception e) 161 catch (Exception)
162 { 162 {
163 exceptionCaught = true; 163 exceptionCaught = true;
164 } 164 }
@@ -174,5 +174,58 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
174 List<AvatarAttachment> attachmentsInAppearance = sp.Appearance.GetAttachments(); 174 List<AvatarAttachment> attachmentsInAppearance = sp.Appearance.GetAttachments();
175 Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0)); 175 Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0));
176 } 176 }
177
178 [Test]
179 public void TestOsForceAttachToOtherAvatarFromInventory()
180 {
181 TestHelpers.InMethod();
182// TestHelpers.EnableLogging();
183
184 string taskInvObjItemName = "sphere";
185 UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000");
186 AttachmentPoint attachPoint = AttachmentPoint.Chin;
187
188 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "one", 0x1, "pass");
189 UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "two", 0x2, "pass");
190
191 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1);
192 SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID);
193 TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart);
194
195 new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem);
196 OSSL_Api osslApi = new OSSL_Api();
197 osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem);
198
199 // Create an object embedded inside the first
200 TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID);
201
202 ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2);
203
204 osslApi.osForceAttachToOtherAvatarFromInventory(sp2.UUID.ToString(), taskInvObjItemName, (int)attachPoint);
205
206 // Check scene presence status
207 Assert.That(sp.HasAttachments(), Is.False);
208 List<SceneObjectGroup> attachments = sp.GetAttachments();
209 Assert.That(attachments.Count, Is.EqualTo(0));
210
211 Assert.That(sp2.HasAttachments(), Is.True);
212 List<SceneObjectGroup> attachments2 = sp2.GetAttachments();
213 Assert.That(attachments2.Count, Is.EqualTo(1));
214 SceneObjectGroup attSo = attachments2[0];
215 Assert.That(attSo.Name, Is.EqualTo(taskInvObjItemName));
216 Assert.That(attSo.OwnerID, Is.EqualTo(ua2.PrincipalID));
217 Assert.That(attSo.AttachmentPoint, Is.EqualTo((uint)attachPoint));
218 Assert.That(attSo.IsAttachment);
219 Assert.That(attSo.UsesPhysics, Is.False);
220 Assert.That(attSo.IsTemporary, Is.False);
221
222 // Check appearance status
223 List<AvatarAttachment> attachmentsInAppearance = sp.Appearance.GetAttachments();
224 Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0));
225
226 List<AvatarAttachment> attachmentsInAppearance2 = sp2.Appearance.GetAttachments();
227 Assert.That(attachmentsInAppearance2.Count, Is.EqualTo(1));
228 Assert.That(sp2.Appearance.GetAttachpoint(attachmentsInAppearance2[0].ItemID), Is.EqualTo((uint)attachPoint));
229 }
177 } 230 }
178} \ No newline at end of file 231} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
index 813e53b..25679a6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs
@@ -97,11 +97,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
97 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 97 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
98 sp.Appearance.AvatarHeight = newHeight; 98 sp.Appearance.AvatarHeight = newHeight;
99 99
100 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); 100 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
101 SceneObjectPart part = so.RootPart; 101 SceneObjectPart part = so.RootPart;
102 m_scene.AddSceneObject(so); 102 m_scene.AddSceneObject(so);
103 103
104 SceneObjectGroup otherSo = SceneHelpers.CreateSceneObject(1, otherUserId); 104 SceneObjectGroup otherSo = SceneHelpers.CreateSceneObject(1, otherUserId, 0x20);
105 SceneObjectPart otherPart = otherSo.RootPart; 105 SceneObjectPart otherPart = otherSo.RootPart;
106 m_scene.AddSceneObject(otherSo); 106 m_scene.AddSceneObject(otherSo);
107 107
@@ -148,7 +148,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
148 148
149 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); 149 ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId);
150 sp.Appearance.AvatarHeight = newHeight; 150 sp.Appearance.AvatarHeight = newHeight;
151 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); 151 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10);
152 SceneObjectPart part = so.RootPart; 152 SceneObjectPart part = so.RootPart;
153 m_scene.AddSceneObject(so); 153 m_scene.AddSceneObject(so);
154 154
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 7364b19..2886344 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -1662,7 +1662,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1662 { 1662 {
1663 IScriptInstance instance = GetInstance(itemID); 1663 IScriptInstance instance = GetInstance(itemID);
1664 if (instance != null) 1664 if (instance != null)
1665 instance.Stop(0); 1665 {
1666 // Give the script some time to finish processing its last event. Simply aborting the script thread can
1667 // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort.
1668 instance.Stop(1000);
1669 }
1666 } 1670 }
1667 1671
1668 public DetectParams GetDetectParams(UUID itemID, int idx) 1672 public DetectParams GetDetectParams(UUID itemID, int idx)
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index 3a2e420..769de83 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -412,26 +412,49 @@ namespace OpenSim.Tests.Common
412 /// <returns></returns> 412 /// <returns></returns>
413 public static AgentCircuitData GenerateAgentData(UUID agentId) 413 public static AgentCircuitData GenerateAgentData(UUID agentId)
414 { 414 {
415 string firstName = "testfirstname"; 415 AgentCircuitData acd = GenerateCommonAgentData();
416 416
417 AgentCircuitData agentData = new AgentCircuitData(); 417 acd.AgentID = agentId;
418 agentData.AgentID = agentId; 418 acd.firstname = "testfirstname";
419 agentData.firstname = firstName; 419 acd.lastname = "testlastname";
420 agentData.lastname = "testlastname"; 420 acd.ServiceURLs = new Dictionary<string, object>();
421
422 return acd;
423 }
424
425 /// <summary>
426 /// Generate some standard agent connection data.
427 /// </summary>
428 /// <param name="agentId"></param>
429 /// <returns></returns>
430 public static AgentCircuitData GenerateAgentData(UserAccount ua)
431 {
432 AgentCircuitData acd = GenerateCommonAgentData();
433
434 acd.AgentID = ua.PrincipalID;
435 acd.firstname = ua.FirstName;
436 acd.lastname = ua.LastName;
437 acd.ServiceURLs = ua.ServiceURLs;
438
439 return acd;
440 }
441
442 private static AgentCircuitData GenerateCommonAgentData()
443 {
444 AgentCircuitData acd = new AgentCircuitData();
421 445
422 // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData. 446 // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData.
423 agentData.SessionID = UUID.Random(); 447 acd.SessionID = UUID.Random();
424 agentData.SecureSessionID = UUID.Random(); 448 acd.SecureSessionID = UUID.Random();
425 449
426 agentData.circuitcode = 123; 450 acd.circuitcode = 123;
427 agentData.BaseFolder = UUID.Zero; 451 acd.BaseFolder = UUID.Zero;
428 agentData.InventoryFolder = UUID.Zero; 452 acd.InventoryFolder = UUID.Zero;
429 agentData.startpos = Vector3.Zero; 453 acd.startpos = Vector3.Zero;
430 agentData.CapsPath = "http://wibble.com"; 454 acd.CapsPath = "http://wibble.com";
431 agentData.ServiceURLs = new Dictionary<string, object>(); 455 acd.Appearance = new AvatarAppearance();
432 agentData.Appearance = new AvatarAppearance(); 456
433 457 return acd;
434 return agentData;
435 } 458 }
436 459
437 /// <summary> 460 /// <summary>
@@ -440,6 +463,9 @@ namespace OpenSim.Tests.Common
440 /// <remarks> 463 /// <remarks>
441 /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions 464 /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions
442 /// and teleport doesn't take place. 465 /// and teleport doesn't take place.
466 ///
467 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will
468 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data.
443 /// </remarks> 469 /// </remarks>
444 /// <param name="scene"></param> 470 /// <param name="scene"></param>
445 /// <param name="agentId"></param> 471 /// <param name="agentId"></param>
@@ -452,6 +478,10 @@ namespace OpenSim.Tests.Common
452 /// <summary> 478 /// <summary>
453 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test 479 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test
454 /// </summary> 480 /// </summary>
481 /// <remarks>
482 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will
483 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data.
484 /// </remarks>
455 /// <param name="scene"></param> 485 /// <param name="scene"></param>
456 /// <param name="agentId"></param> 486 /// <param name="agentId"></param>
457 /// <param name="sceneManager"></param> 487 /// <param name="sceneManager"></param>
@@ -464,6 +494,17 @@ namespace OpenSim.Tests.Common
464 /// <summary> 494 /// <summary>
465 /// Add a root agent. 495 /// Add a root agent.
466 /// </summary> 496 /// </summary>
497 /// <param name="scene"></param>
498 /// <param name="ua"></param>
499 /// <returns></returns>
500 public static ScenePresence AddScenePresence(Scene scene, UserAccount ua)
501 {
502 return AddScenePresence(scene, GenerateAgentData(ua));
503 }
504
505 /// <summary>
506 /// Add a root agent.
507 /// </summary>
467 /// <remarks> 508 /// <remarks>
468 /// This function 509 /// This function
469 /// 510 ///
@@ -601,19 +642,36 @@ namespace OpenSim.Tests.Common
601 ownerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) 642 ownerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
602 { Name = name, UUID = id, Scale = new Vector3(1, 1, 1) }; 643 { Name = name, UUID = id, Scale = new Vector3(1, 1, 1) };
603 } 644 }
604 645
605 /// <summary> 646 /// <summary>
606 /// Create a scene object but do not add it to the scene. 647 /// Create a scene object but do not add it to the scene.
607 /// </summary> 648 /// </summary>
608 /// <remarks> 649 /// <remarks>
609 /// UUID always starts at 00000000-0000-0000-0000-000000000001 650 /// UUID always starts at 00000000-0000-0000-0000-000000000001. For some purposes, (e.g. serializing direct
651 /// to another object's inventory) we do not need a scene unique ID. So it would be better to add the
652 /// UUID when we actually add an object to a scene rather than on creation.
610 /// </remarks> 653 /// </remarks>
611 /// <param name="parts">The number of parts that should be in the scene object</param> 654 /// <param name="parts">The number of parts that should be in the scene object</param>
612 /// <param name="ownerId"></param> 655 /// <param name="ownerId"></param>
613 /// <returns></returns> 656 /// <returns></returns>
614 public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId) 657 public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId)
615 { 658 {
616 return CreateSceneObject(parts, ownerId, "", 0x1); 659 return CreateSceneObject(parts, ownerId, 0x1);
660 }
661
662 /// <summary>
663 /// Create a scene object but do not add it to the scene.
664 /// </summary>
665 /// <param name="parts">The number of parts that should be in the scene object</param>
666 /// <param name="ownerId"></param>
667 /// <param name="uuidTail">
668 /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}"
669 /// will be given to the root part, and incremented for each part thereafter.
670 /// </param>
671 /// <returns></returns>
672 public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId, int uuidTail)
673 {
674 return CreateSceneObject(parts, ownerId, "", uuidTail);
617 } 675 }
618 676
619 /// <summary> 677 /// <summary>
diff --git a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs
index 3d3e65c..2fbebc4 100644
--- a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs
@@ -138,6 +138,15 @@ namespace OpenSim.Tests.Common
138 CreateUserWithInventory(scene, ua, pw); 138 CreateUserWithInventory(scene, ua, pw);
139 return ua; 139 return ua;
140 } 140 }
141
142 public static UserAccount CreateUserWithInventory(
143 Scene scene, string firstName, string lastName, int userId, string pw)
144 {
145 UserAccount ua
146 = new UserAccount(TestHelpers.ParseTail(userId)) { FirstName = firstName, LastName = lastName };
147 CreateUserWithInventory(scene, ua, pw);
148 return ua;
149 }
141 150
142 public static void CreateUserWithInventory(Scene scene, UserAccount ua, string pw) 151 public static void CreateUserWithInventory(Scene scene, UserAccount ua, string pw)
143 { 152 {