aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Application/OpenSim.cs2
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs76
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs251
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs10
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs27
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs66
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs39
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs106
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs25
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs70
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs61
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs744
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs74
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs17
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs15
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs18
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs37
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs349
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs2
-rw-r--r--OpenSim/Region/Examples/SimpleModule/ComplexObject.cs5
-rw-r--r--OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs13
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs7
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityInventory.cs3
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IInterregionComms.cs8
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISnmpModule.cs27
-rw-r--r--OpenSim/Region/Framework/ModuleLoader.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs214
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs20
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs221
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs268
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs238
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs666
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs282
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs595
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs1062
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs168
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs12
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs3
-rw-r--r--OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs16
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs13
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs4
-rw-r--r--OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs3
-rw-r--r--OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs1437
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs3917
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs375
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs (renamed from OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs)46
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs3869
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs122
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs98
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs1
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs6
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSPrim.cs2
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs82
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs20
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs1819
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs53
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs13
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs32
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs1
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs15
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs47
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs28
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs341
86 files changed, 15829 insertions, 2560 deletions
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 7a0142f..edbae59 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -436,7 +436,7 @@ namespace OpenSim
436 if (alert != null) 436 if (alert != null)
437 presence.ControllingClient.Kick(alert); 437 presence.ControllingClient.Kick(alert);
438 else 438 else
439 presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); 439 presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n");
440 440
441 // ...and close on our side 441 // ...and close on our side
442 presence.Scene.IncomingCloseAgent(presence.UUID); 442 presence.Scene.IncomingCloseAgent(presence.UUID);
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index 74ad168..c5ee385 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -88,6 +88,10 @@ namespace OpenSim
88 88
89 protected List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>(); 89 protected List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>();
90 90
91 private List<string> m_permsModules;
92
93 private bool m_securePermissionsLoading = true;
94
91 /// <value> 95 /// <value>
92 /// The config information passed into the OpenSimulator region server. 96 /// The config information passed into the OpenSimulator region server.
93 /// </value> 97 /// </value>
@@ -185,6 +189,11 @@ namespace OpenSim
185 CreatePIDFile(pidFile); 189 CreatePIDFile(pidFile);
186 190
187 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty); 191 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty);
192
193 m_securePermissionsLoading = startupConfig.GetBoolean("SecurePermissionsLoading", true);
194
195 string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule");
196 m_permsModules = new List<string>(permissionModules.Split(','));
188 } 197 }
189 198
190 // Load the simulation data service 199 // Load the simulation data service
@@ -360,7 +369,41 @@ namespace OpenSim
360 } 369 }
361 else m_log.Error("[MODULES]: The new RegionModulesController is missing..."); 370 else m_log.Error("[MODULES]: The new RegionModulesController is missing...");
362 371
372 if (m_securePermissionsLoading)
373 {
374 foreach (string s in m_permsModules)
375 {
376 if (!scene.RegionModules.ContainsKey(s))
377 {
378 bool found = false;
379 foreach (IRegionModule m in modules)
380 {
381 if (m.Name == s)
382 {
383 found = true;
384 }
385 }
386 if (!found)
387 {
388 m_log.Fatal("[MODULES]: Required module " + s + " not found.");
389 Environment.Exit(0);
390 }
391 }
392 }
393 }
394
363 scene.SetModuleInterfaces(); 395 scene.SetModuleInterfaces();
396// First Step of bootreport sequence
397 if (scene.SnmpService != null)
398 {
399 scene.SnmpService.ColdStart(1,scene);
400 scene.SnmpService.LinkDown(scene);
401 }
402
403 if (scene.SnmpService != null)
404 {
405 scene.SnmpService.BootInfo("Loading prins", scene);
406 }
364 407
365 // Prims have to be loaded after module configuration since some modules may be invoked during the load 408 // Prims have to be loaded after module configuration since some modules may be invoked during the load
366 scene.LoadPrimsFromStorage(regionInfo.originRegionID); 409 scene.LoadPrimsFromStorage(regionInfo.originRegionID);
@@ -368,6 +411,10 @@ namespace OpenSim
368 // TODO : Try setting resource for region xstats here on scene 411 // TODO : Try setting resource for region xstats here on scene
369 MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo)); 412 MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo));
370 413
414 if (scene.SnmpService != null)
415 {
416 scene.SnmpService.BootInfo("Grid Registration in progress", scene);
417 }
371 try 418 try
372 { 419 {
373 scene.RegisterRegionWithGrid(); 420 scene.RegisterRegionWithGrid();
@@ -378,11 +425,20 @@ namespace OpenSim
378 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}", 425 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}",
379 e.Message, e.StackTrace); 426 e.Message, e.StackTrace);
380 427
428 if (scene.SnmpService != null)
429 {
430 scene.SnmpService.Critical("Grid registration failed. Startup aborted.", scene);
431 }
381 // Carrying on now causes a lot of confusion down the 432 // Carrying on now causes a lot of confusion down the
382 // line - we need to get the user's attention 433 // line - we need to get the user's attention
383 Environment.Exit(1); 434 Environment.Exit(1);
384 } 435 }
385 436
437 if (scene.SnmpService != null)
438 {
439 scene.SnmpService.BootInfo("Grid Registration done", scene);
440 }
441
386 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID); 442 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
387 scene.EventManager.TriggerParcelPrimCountUpdate(); 443 scene.EventManager.TriggerParcelPrimCountUpdate();
388 444
@@ -390,6 +446,11 @@ namespace OpenSim
390 // scripting engines. 446 // scripting engines.
391 scene.CreateScriptInstances(); 447 scene.CreateScriptInstances();
392 448
449 if (scene.SnmpService != null)
450 {
451 scene.SnmpService.BootInfo("ScriptEngine started", scene);
452 }
453
393 m_sceneManager.Add(scene); 454 m_sceneManager.Add(scene);
394 455
395 if (m_autoCreateClientStack) 456 if (m_autoCreateClientStack)
@@ -398,6 +459,10 @@ namespace OpenSim
398 clientServer.Start(); 459 clientServer.Start();
399 } 460 }
400 461
462 if (scene.SnmpService != null)
463 {
464 scene.SnmpService.BootInfo("Initializing region modules", scene);
465 }
401 if (do_post_init) 466 if (do_post_init)
402 { 467 {
403 foreach (IRegionModule module in modules) 468 foreach (IRegionModule module in modules)
@@ -409,6 +474,12 @@ namespace OpenSim
409 474
410 mscene = scene; 475 mscene = scene;
411 476
477 if (scene.SnmpService != null)
478 {
479 scene.SnmpService.BootInfo("The region is operational", scene);
480 scene.SnmpService.LinkUp(scene);
481 }
482
412 scene.StartTimer(); 483 scene.StartTimer();
413 484
414 return clientServer; 485 return clientServer;
@@ -417,6 +488,11 @@ namespace OpenSim
417 private void ShutdownRegion(Scene scene) 488 private void ShutdownRegion(Scene scene)
418 { 489 {
419 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName); 490 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName);
491 if (scene.SnmpService != null)
492 {
493 scene.SnmpService.BootInfo("The region is shutting down", scene);
494 scene.SnmpService.LinkDown(scene);
495 }
420 IRegionModulesController controller; 496 IRegionModulesController controller;
421 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller)) 497 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller))
422 { 498 {
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
index e9e2dca..9dd6663 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
@@ -202,6 +202,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
202 m_stopPacket = TexturePacketCount(); 202 m_stopPacket = TexturePacketCount();
203 } 203 }
204 204
205 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
206 if (m_stopPacket == 1 && Layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
207
205 m_currentPacket = StartPacket; 208 m_currentPacket = StartPacket;
206 } 209 }
207 } 210 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 48d5a12..fff4300 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -155,6 +155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
155 public event RequestTaskInventory OnRequestTaskInventory; 155 public event RequestTaskInventory OnRequestTaskInventory;
156 public event UpdateInventoryItem OnUpdateInventoryItem; 156 public event UpdateInventoryItem OnUpdateInventoryItem;
157 public event CopyInventoryItem OnCopyInventoryItem; 157 public event CopyInventoryItem OnCopyInventoryItem;
158 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
158 public event MoveInventoryItem OnMoveInventoryItem; 159 public event MoveInventoryItem OnMoveInventoryItem;
159 public event RemoveInventoryItem OnRemoveInventoryItem; 160 public event RemoveInventoryItem OnRemoveInventoryItem;
160 public event RemoveInventoryFolder OnRemoveInventoryFolder; 161 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -335,11 +336,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
335// protected HashSet<uint> m_attachmentsSent; 336// protected HashSet<uint> m_attachmentsSent;
336 337
337 private int m_moneyBalance; 338 private int m_moneyBalance;
339 private bool m_deliverPackets = true;
338 private int m_animationSequenceNumber = 1; 340 private int m_animationSequenceNumber = 1;
339 private bool m_SendLogoutPacketWhenClosing = true; 341 private bool m_SendLogoutPacketWhenClosing = true;
340 private AgentUpdateArgs lastarg; 342 private AgentUpdateArgs lastarg;
341 private bool m_IsActive = true; 343 private bool m_IsActive = true;
342 private bool m_IsLoggingOut = false; 344 private bool m_IsLoggingOut = false;
345 private bool m_IsPresenceReady = false;
343 346
344 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>(); 347 protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
345 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers 348 protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
@@ -362,6 +365,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
362 365
363 private Timer m_propertiesPacketTimer; 366 private Timer m_propertiesPacketTimer;
364 private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>(); 367 private List<ObjectPropertiesPacket.ObjectDataBlock> m_propertiesBlocks = new List<ObjectPropertiesPacket.ObjectDataBlock>();
368 private List<Packet> m_pendingPackets;
365 369
366 #endregion Class Members 370 #endregion Class Members
367 371
@@ -377,6 +381,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
377 get { return m_startpos; } 381 get { return m_startpos; }
378 set { m_startpos = value; } 382 set { m_startpos = value; }
379 } 383 }
384 public bool DeliverPackets
385 {
386 get { return m_deliverPackets; }
387 set {
388 m_deliverPackets = value;
389 m_udpClient.m_deliverPackets = value;
390 }
391 }
380 public UUID AgentId { get { return m_agentId; } } 392 public UUID AgentId { get { return m_agentId; } }
381 public UUID ActiveGroupId { get { return m_activeGroupID; } } 393 public UUID ActiveGroupId { get { return m_activeGroupID; } }
382 public string ActiveGroupName { get { return m_activeGroupName; } } 394 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -406,6 +418,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
406 get { return m_IsActive; } 418 get { return m_IsActive; }
407 set { m_IsActive = value; } 419 set { m_IsActive = value; }
408 } 420 }
421
409 public bool IsLoggingOut 422 public bool IsLoggingOut
410 { 423 {
411 get { return m_IsLoggingOut; } 424 get { return m_IsLoggingOut; }
@@ -475,18 +488,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
475 488
476 #region Client Methods 489 #region Client Methods
477 490
491
478 /// <summary> 492 /// <summary>
479 /// Shut down the client view 493 /// Shut down the client view
480 /// </summary> 494 /// </summary>
481 public void Close() 495 public void Close()
482 { 496 {
497 Close(true);
498 }
499
500 /// <summary>
501 /// Shut down the client view
502 /// </summary>
503 public void Close(bool sendStop)
504 {
483 m_log.DebugFormat( 505 m_log.DebugFormat(
484 "[CLIENT]: Close has been called for {0} attached to scene {1}", 506 "[CLIENT]: Close has been called for {0} attached to scene {1}",
485 Name, m_scene.RegionInfo.RegionName); 507 Name, m_scene.RegionInfo.RegionName);
486 508
487 // Send the STOP packet 509 if (sendStop)
488 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 510 {
489 OutPacket(disable, ThrottleOutPacketType.Unknown); 511 // Send the STOP packet
512 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
513 OutPacket(disable, ThrottleOutPacketType.Unknown);
514 }
490 515
491 IsActive = false; 516 IsActive = false;
492 517
@@ -766,7 +791,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
766 reply.ChatData.OwnerID = fromAgentID; 791 reply.ChatData.OwnerID = fromAgentID;
767 reply.ChatData.SourceID = fromAgentID; 792 reply.ChatData.SourceID = fromAgentID;
768 793
769 OutPacket(reply, ThrottleOutPacketType.Task); 794 OutPacket(reply, ThrottleOutPacketType.Unknown);
770 } 795 }
771 796
772 /// <summary> 797 /// <summary>
@@ -1052,6 +1077,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1052 public virtual void SendLayerData(float[] map) 1077 public virtual void SendLayerData(float[] map)
1053 { 1078 {
1054 Util.FireAndForget(DoSendLayerData, map); 1079 Util.FireAndForget(DoSendLayerData, map);
1080
1081 // Send it sync, and async. It's not that much data
1082 // and it improves user experience just so much!
1083 DoSendLayerData(map);
1055 } 1084 }
1056 1085
1057 /// <summary> 1086 /// <summary>
@@ -1064,16 +1093,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1064 1093
1065 try 1094 try
1066 { 1095 {
1067 //for (int y = 0; y < 16; y++) 1096 for (int y = 0; y < 16; y++)
1068 //{ 1097 {
1069 // for (int x = 0; x < 16; x++) 1098 for (int x = 0; x < 16; x+=4)
1070 // { 1099 {
1071 // SendLayerData(x, y, map); 1100 SendLayerPacket(x, y, map);
1072 // } 1101 }
1073 //} 1102 }
1074
1075 // Send LayerData in a spiral pattern. Fun!
1076 SendLayerTopRight(map, 0, 0, 15, 15);
1077 } 1103 }
1078 catch (Exception e) 1104 catch (Exception e)
1079 { 1105 {
@@ -1081,51 +1107,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 } 1107 }
1082 } 1108 }
1083 1109
1084 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1085 {
1086 // Row
1087 for (int i = x1; i <= x2; i++)
1088 SendLayerData(i, y1, map);
1089
1090 // Column
1091 for (int j = y1 + 1; j <= y2; j++)
1092 SendLayerData(x2, j, map);
1093
1094 if (x2 - x1 > 0)
1095 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1096 }
1097
1098 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1099 {
1100 // Row in reverse
1101 for (int i = x2; i >= x1; i--)
1102 SendLayerData(i, y2, map);
1103
1104 // Column in reverse
1105 for (int j = y2 - 1; j >= y1; j--)
1106 SendLayerData(x1, j, map);
1107
1108 if (x2 - x1 > 0)
1109 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1110 }
1111
1112 /// <summary> 1110 /// <summary>
1113 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1111 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1114 /// </summary> 1112 /// </summary>
1115 /// <param name="map">heightmap</param> 1113 /// <param name="map">heightmap</param>
1116 /// <param name="px">X coordinate for patches 0..12</param> 1114 /// <param name="px">X coordinate for patches 0..12</param>
1117 /// <param name="py">Y coordinate for patches 0..15</param> 1115 /// <param name="py">Y coordinate for patches 0..15</param>
1118 // private void SendLayerPacket(float[] map, int y, int x) 1116 private void SendLayerPacket(int x, int y, float[] map)
1119 // { 1117 {
1120 // int[] patches = new int[4]; 1118 int[] patches = new int[4];
1121 // patches[0] = x + 0 + y * 16; 1119 patches[0] = x + 0 + y * 16;
1122 // patches[1] = x + 1 + y * 16; 1120 patches[1] = x + 1 + y * 16;
1123 // patches[2] = x + 2 + y * 16; 1121 patches[2] = x + 2 + y * 16;
1124 // patches[3] = x + 3 + y * 16; 1122 patches[3] = x + 3 + y * 16;
1125 1123
1126 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1124 float[] heightmap = (map.Length == 65536) ?
1127 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1125 map :
1128 // } 1126 LLHeightFieldMoronize(map);
1127
1128 try
1129 {
1130 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1131 OutPacket(layerpack, ThrottleOutPacketType.Land);
1132 }
1133 catch
1134 {
1135 for (int px = x ; px < x + 4 ; px++)
1136 SendLayerData(px, y, map);
1137 }
1138 }
1129 1139
1130 /// <summary> 1140 /// <summary>
1131 /// Sends a specified patch to a client 1141 /// Sends a specified patch to a client
@@ -1145,7 +1155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1155 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1146 layerpack.Header.Reliable = true; 1156 layerpack.Header.Reliable = true;
1147 1157
1148 OutPacket(layerpack, ThrottleOutPacketType.Land); 1158 OutPacket(layerpack, ThrottleOutPacketType.Task);
1149 } 1159 }
1150 catch (Exception e) 1160 catch (Exception e)
1151 { 1161 {
@@ -1506,35 +1516,46 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1506 OutPacket(pc, ThrottleOutPacketType.Unknown); 1516 OutPacket(pc, ThrottleOutPacketType.Unknown);
1507 } 1517 }
1508 1518
1509 public void SendKillObject(ulong regionHandle, uint localID) 1519 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1510 { 1520 {
1511// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1521// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1512 1522
1513 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1523 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1514 // TODO: don't create new blocks if recycling an old packet 1524 // TODO: don't create new blocks if recycling an old packet
1515 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1525 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1516 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1526 for (int i = 0 ; i < localIDs.Count ; i++ )
1517 kill.ObjectData[0].ID = localID; 1527 {
1528 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1529 kill.ObjectData[i].ID = localIDs[i];
1530 }
1518 kill.Header.Reliable = true; 1531 kill.Header.Reliable = true;
1519 kill.Header.Zerocoded = true; 1532 kill.Header.Zerocoded = true;
1520 1533
1521 if (m_scene.GetScenePresence(localID) == null) 1534 if (localIDs.Count == 1)
1522 { 1535 {
1523 lock (m_entityUpdates.SyncRoot) 1536 if (m_scene.GetScenePresence(localIDs[0]) != null)
1524 { 1537 {
1525 m_killRecord.Add(localID); 1538 OutPacket(kill, ThrottleOutPacketType.State);
1526 1539 return;
1527 // The throttle queue used here must match that being used for updates. Otherwise, there is a
1528 // chance that a kill packet put on a separate queue will be sent to the client before an existing
1529 // update packet on another queue. Receiving updates after kills results in unowned and undeletable
1530 // scene objects in a viewer until that viewer is relogged in.
1531 OutPacket(kill, ThrottleOutPacketType.Task);
1532 } 1540 }
1541 m_killRecord.Add(localIDs[0]);
1533 } 1542 }
1534 else 1543 else
1535 { 1544 {
1536 OutPacket(kill, ThrottleOutPacketType.State); 1545 lock (m_entityUpdates.SyncRoot)
1546 {
1547 foreach (uint localID in localIDs)
1548 m_killRecord.Add(localID);
1549 }
1537 } 1550 }
1551
1552 // The throttle queue used here must match that being used for
1553 // updates. Otherwise, there is a chance that a kill packet put
1554 // on a separate queue will be sent to the client before an
1555 // existing update packet on another queue. Receiving updates
1556 // after kills results in unowned and undeletable
1557 // scene objects in a viewer until that viewer is relogged in.
1558 OutPacket(kill, ThrottleOutPacketType.Task);
1538 } 1559 }
1539 1560
1540 /// <summary> 1561 /// <summary>
@@ -2240,6 +2261,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2240 OutPacket(sound, ThrottleOutPacketType.Task); 2261 OutPacket(sound, ThrottleOutPacketType.Task);
2241 } 2262 }
2242 2263
2264 public void SendTransferAbort(TransferRequestPacket transferRequest)
2265 {
2266 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2267 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2268 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2269 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2270 OutPacket(abort, ThrottleOutPacketType.Task);
2271 }
2272
2243 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2273 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2244 { 2274 {
2245 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2275 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3532,6 +3562,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3532 /// </summary> 3562 /// </summary>
3533 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3563 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3534 { 3564 {
3565 if (entity is SceneObjectPart)
3566 {
3567 SceneObjectPart e = (SceneObjectPart)entity;
3568 SceneObjectGroup g = e.ParentGroup;
3569 if (g.RootPart.Shape.State > 30) // HUD
3570 if (g.OwnerID != AgentId)
3571 return; // Don't send updates for other people's HUDs
3572 }
3573
3535 double priority = m_prioritizer.GetUpdatePriority(this, entity); 3574 double priority = m_prioritizer.GetUpdatePriority(this, entity);
3536 3575
3537 lock (m_entityUpdates.SyncRoot) 3576 lock (m_entityUpdates.SyncRoot)
@@ -3552,23 +3591,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3552 EntityUpdate update; 3591 EntityUpdate update;
3553 while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update)) 3592 while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update))
3554 { 3593 {
3555 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client 3594 // If we have sent a kill packet for this object
3556 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good 3595 // drop any updates on the floor
3557 // safety measure.
3558 //
3559 // Receiving updates after kills results in undeleteable prims that persist until relog and
3560 // currently occurs because prims can be deleted before all queued updates are sent.
3561 if (m_killRecord.Contains(update.Entity.LocalId))
3562 {
3563// m_log.WarnFormat(
3564// "[CLIENT]: Preventing full update for prim with local id {0} after client for user {1} told it was deleted",
3565// update.Entity.LocalId, Name);
3566 continue;
3567 }
3568
3569 if (update.Entity is SceneObjectPart) 3596 if (update.Entity is SceneObjectPart)
3570 { 3597 {
3571 SceneObjectPart part = (SceneObjectPart)update.Entity; 3598 SceneObjectPart part = (SceneObjectPart)update.Entity;
3599 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3600 continue;
3572 3601
3573 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3602 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3574 { 3603 {
@@ -4002,6 +4031,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4002 { 4031 {
4003 m_propertiesPacketTimer.Stop(); 4032 m_propertiesPacketTimer.Stop();
4004 4033
4034 if (m_propertiesBlocks.Count == 0)
4035 return;
4036
4005 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; 4037 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
4006 4038
4007 int index = 0; 4039 int index = 0;
@@ -4908,6 +4940,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4908 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 4940 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
4909 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 4941 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
4910 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 4942 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
4943 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
4911 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 4944 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
4912 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 4945 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
4913 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 4946 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5007,6 +5040,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5007 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5040 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5008 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5041 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5009 (x.ControlFlags != lastarg.ControlFlags) || 5042 (x.ControlFlags != lastarg.ControlFlags) ||
5043 (x.ControlFlags != 0) ||
5010 (x.Far != lastarg.Far) || 5044 (x.Far != lastarg.Far) ||
5011 (x.Flags != lastarg.Flags) || 5045 (x.Flags != lastarg.Flags) ||
5012 (x.State != lastarg.State) || 5046 (x.State != lastarg.State) ||
@@ -5380,7 +5414,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5380 args.Channel = ch; 5414 args.Channel = ch;
5381 args.From = String.Empty; 5415 args.From = String.Empty;
5382 args.Message = Utils.BytesToString(msg); 5416 args.Message = Utils.BytesToString(msg);
5383 args.Type = ChatTypeEnum.Shout; 5417 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5384 args.Position = new Vector3(); 5418 args.Position = new Vector3();
5385 args.Scene = Scene; 5419 args.Scene = Scene;
5386 args.Sender = this; 5420 args.Sender = this;
@@ -9418,6 +9452,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9418 { 9452 {
9419 return true; 9453 return true;
9420 } 9454 }
9455
9456 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9457 {
9458 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9459
9460 #region Packet Session and User Check
9461 if (m_checkPackets)
9462 {
9463 if (packet.AgentData.SessionID != SessionId ||
9464 packet.AgentData.AgentID != AgentId)
9465 return true;
9466 }
9467 #endregion
9468 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9469 List<InventoryItemBase> items = new List<InventoryItemBase>();
9470 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9471 {
9472 InventoryItemBase b = new InventoryItemBase();
9473 b.ID = n.OldItemID;
9474 b.Folder = n.OldFolderID;
9475 items.Add(b);
9476 }
9477
9478 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9479 if (handlerMoveItemsAndLeaveCopy != null)
9480 {
9481 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9482 }
9483
9484 return true;
9485 }
9421 9486
9422 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9487 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9423 { 9488 {
@@ -10915,7 +10980,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10915 { 10980 {
10916 // It's a ghost! tell the client to delete it from view. 10981 // It's a ghost! tell the client to delete it from view.
10917 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 10982 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
10918 localId); 10983 new List<uint>() { localId });
10919 } 10984 }
10920 else 10985 else
10921 { 10986 {
@@ -11280,6 +11345,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11280 } 11345 }
11281 11346
11282 /// <summary> 11347 /// <summary>
11348 /// This processes packets which have accumulated while the presence was still in the process of initialising.
11349 /// </summary>
11350 public void ProcessPendingPackets()
11351 {
11352 m_IsPresenceReady = true;
11353 if (m_pendingPackets == null)
11354 return;
11355 foreach (Packet p in m_pendingPackets)
11356 {
11357 ProcessInPacket(p);
11358 }
11359 m_pendingPackets.Clear();
11360 }
11361
11362 /// <summary>
11283 /// Entryway from the client to the simulator. All UDP packets from the client will end up here 11363 /// Entryway from the client to the simulator. All UDP packets from the client will end up here
11284 /// </summary> 11364 /// </summary>
11285 /// <param name="Pack">OpenMetaverse.packet</param> 11365 /// <param name="Pack">OpenMetaverse.packet</param>
@@ -11542,7 +11622,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11542 11622
11543// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11623// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11544 11624
11625
11626 //Note, the bool returned from the below function is useless since it is always false.
11545 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11627 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11628
11546 } 11629 }
11547 11630
11548 /// <summary> 11631 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index ca5a7bd..a4738ff 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -149,6 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 149
150 private int m_defaultRTO = 3000; 150 private int m_defaultRTO = 3000;
151 private int m_maxRTO = 60000; 151 private int m_maxRTO = 60000;
152 public bool m_deliverPackets = true;
152 153
153 /// <summary> 154 /// <summary>
154 /// Default constructor 155 /// Default constructor
@@ -389,6 +390,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 if (category >= 0 && category < m_packetOutboxes.Length) 390 if (category >= 0 && category < m_packetOutboxes.Length)
390 { 391 {
391 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 392 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
393
394 if (m_deliverPackets == false)
395 {
396 queue.Enqueue(packet);
397 return true;
398 }
399
392 TokenBucket bucket = m_throttleCategories[category]; 400 TokenBucket bucket = m_throttleCategories[category];
393 401
394 if (bucket.RemoveTokens(packet.Buffer.DataLength)) 402 if (bucket.RemoveTokens(packet.Buffer.DataLength))
@@ -425,6 +433,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
425 /// <returns>True if any packets were sent, otherwise false</returns> 433 /// <returns>True if any packets were sent, otherwise false</returns>
426 public bool DequeueOutgoing() 434 public bool DequeueOutgoing()
427 { 435 {
436 if (m_deliverPackets == false) return false;
437
428 OutgoingPacket packet; 438 OutgoingPacket packet;
429 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 439 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
430 TokenBucket bucket; 440 TokenBucket bucket;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index cb298fd..e2cda6d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -912,7 +912,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
912 client.DisableFacelights = m_disableFacelights; 912 client.DisableFacelights = m_disableFacelights;
913 913
914 // Start the IClientAPI 914 // Start the IClientAPI
915 client.Start(); 915 // Spin it off so that it doesn't clog up the LLUDPServer
916
917 //First, and very importantly:
918 //
919 //Set our DeliverPackets flag in the client to *false*
920 //this will prevent us from missing important messages
921 //before the modules are bound
922 client.DeliverPackets = false;
923 client.DisableFacelights = m_disableFacelights;
924
925 Util.FireAndForget(
926 delegate
927 {
928 try
929 {
930 client.Start();
931 }
932 finally
933 {
934 //Now, release the hounds. er, packets.
935 client.DeliverPackets = true;
936 }
937 }
938 );
916 } 939 }
917 else 940 else
918 { 941 {
@@ -928,7 +951,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
928 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 951 if (m_scene.TryGetClient(udpClient.AgentID, out client))
929 { 952 {
930 client.IsLoggingOut = true; 953 client.IsLoggingOut = true;
931 client.Close(); 954 client.Close(false);
932 } 955 }
933 } 956 }
934 957
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index bdbd284..91e3d20 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -133,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
133 this.parent = parent; 133 this.parent = parent;
134 MaxBurst = maxBurst; 134 MaxBurst = maxBurst;
135 DripRate = dripRate; 135 DripRate = dripRate;
136 lastDrip = Environment.TickCount & Int32.MaxValue; 136 lastDrip = Environment.TickCount;
137 } 137 }
138 138
139 /// <summary> 139 /// <summary>
@@ -144,40 +144,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
144 /// the bucket, otherwise false</returns> 144 /// the bucket, otherwise false</returns>
145 public bool RemoveTokens(int amount) 145 public bool RemoveTokens(int amount)
146 { 146 {
147 bool dummy;
148 return RemoveTokens(amount, out dummy);
149 }
150
151 /// <summary>
152 /// Remove a given number of tokens from the bucket
153 /// </summary>
154 /// <param name="amount">Number of tokens to remove from the bucket</param>
155 /// <param name="dripSucceeded">True if tokens were added to the bucket
156 /// during this call, otherwise false</param>
157 /// <returns>True if the requested number of tokens were removed from
158 /// the bucket, otherwise false</returns>
159 public bool RemoveTokens(int amount, out bool dripSucceeded)
160 {
161 if (maxBurst == 0) 147 if (maxBurst == 0)
162 { 148 {
163 dripSucceeded = true;
164 return true; 149 return true;
165 } 150 }
166 151
167 dripSucceeded = Drip(); 152 if (amount > maxBurst)
168
169 if (content - amount >= 0)
170 { 153 {
171 if (parent != null && !parent.RemoveTokens(amount)) 154 throw new Exception("amount " + amount + " exceeds maxBurst " + maxBurst);
172 return false; 155 }
173 156
174 content -= amount; 157 Drip();
175 return true; 158
159 if (content < amount)
160 {
161 return false;
176 } 162 }
177 else 163
164 if (parent != null && !parent.RemoveTokens(amount))
178 { 165 {
179 return false; 166 return false;
180 } 167 }
168
169 content -= amount;
170 return true;
181 } 171 }
182 172
183 /// <summary> 173 /// <summary>
@@ -193,25 +183,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
193 content = maxBurst; 183 content = maxBurst;
194 return true; 184 return true;
195 } 185 }
196 else
197 {
198 int now = Environment.TickCount & Int32.MaxValue;
199 int deltaMS = now - lastDrip;
200 186
201 if (deltaMS <= 0) 187 int now = Environment.TickCount;
202 { 188 int deltaMS = now - lastDrip;
203 if (deltaMS < 0) 189 lastDrip = now;
204 lastDrip = now;
205 return false;
206 }
207 190
208 int dripAmount = deltaMS * tokensPerMS; 191 if (deltaMS <= 0)
209 192 {
210 content = Math.Min(content + dripAmount, maxBurst); 193 return false;
211 lastDrip = now; 194 }
212 195
213 return true; 196 long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content;
197 if (dripAmount > maxBurst)
198 {
199 dripAmount = maxBurst;
214 } 200 }
201 content = (int)dripAmount;
202 return true;
215 } 203 }
216 } 204 }
217} 205}
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 2a0c0b1..bf71c07 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Xml;
31using log4net; 32using log4net;
32using Mono.Addins; 33using Mono.Addins;
33using Nini.Config; 34using Nini.Config;
@@ -232,15 +233,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
232 public UUID RezSingleAttachmentFromInventory( 233 public UUID RezSingleAttachmentFromInventory(
233 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) 234 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
234 { 235 {
235 m_log.DebugFormat( 236 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null);
236 "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 237 }
237 (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); 238
238 239 public UUID RezSingleAttachmentFromInventory(
240 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc)
241 {
239 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 242 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
240 // be removed when that functionality is implemented in opensim 243 // be removed when that functionality is implemented in opensim
241 AttachmentPt &= 0x7f; 244 AttachmentPt &= 0x7f;
242 245
243 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt); 246 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt, doc);
244 247
245 if (updateInventoryStatus) 248 if (updateInventoryStatus)
246 { 249 {
@@ -257,7 +260,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
257 } 260 }
258 261
259 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 262 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
260 IClientAPI remoteClient, UUID itemID, uint AttachmentPt) 263 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, XmlDocument doc)
261 { 264 {
262 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 265 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
263 if (invAccess != null) 266 if (invAccess != null)
@@ -291,13 +294,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
291 if (tainted) 294 if (tainted)
292 objatt.HasGroupChanged = true; 295 objatt.HasGroupChanged = true;
293 296
297 if (doc != null)
298 {
299 objatt.LoadScriptState(doc);
300 objatt.ResetOwnerChangeFlag();
301 }
302
294 // Fire after attach, so we don't get messy perms dialogs 303 // Fire after attach, so we don't get messy perms dialogs
295 // 4 == AttachedRez 304 // 4 == AttachedRez
296 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 305 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
297 objatt.ResumeScripts(); 306 objatt.ResumeScripts();
298 307
299 // Do this last so that event listeners have access to all the effects of the attachment 308 // Do this last so that event listeners have access to all the effects of the attachment
300 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); 309 //m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId);
301 } 310 }
302 else 311 else
303 { 312 {
@@ -334,9 +343,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
334 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 343 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
335 { 344 {
336 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 345 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
337 item = m_scene.InventoryService.GetItem(item); 346 if (m_scene.InventoryService != null)
347 item = m_scene.InventoryService.GetItem(item);
338 348
339 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/); 349 if (presence.Appearance != null)
350 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/);
340 } 351 }
341 352
342 return att.UUID; 353 return att.UUID;
@@ -379,6 +390,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
379 { 390 {
380 // XXYY!! 391 // XXYY!!
381 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 392 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
393 if (item == null)
394 m_log.Error("[ATTACHMENT]: item == null");
395 if (m_scene == null)
396 m_log.Error("[ATTACHMENT]: m_scene == null");
397 if (m_scene.InventoryService == null)
398 m_log.Error("[ATTACHMENT]: m_scene.InventoryService == null");
382 item = m_scene.InventoryService.GetItem(item); 399 item = m_scene.InventoryService.GetItem(item);
383 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */); 400 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */);
384 401
@@ -470,6 +487,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
470 if (group.GetFromItemID() == itemID) 487 if (group.GetFromItemID() == itemID)
471 { 488 {
472 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); 489 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
490 // CM / XMREngine!!!! Needed to conclude attach event
491 SceneObjectSerializer.ToOriginalXmlFormat(group);
473 group.DetachToInventoryPrep(); 492 group.DetachToInventoryPrep();
474 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 493 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
475 UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID); 494 UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID);
@@ -609,7 +628,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
609 // 628 //
610 if (so.IsSelected) 629 if (so.IsSelected)
611 { 630 {
612 m_scene.SendKillObject(so.RootPart.LocalId); 631 m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId });
613 } 632 }
614 633
615 so.IsSelected = false; // fudge.... 634 so.IsSelected = false; // fudge....
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index ef5efdd..2a590f1 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -49,7 +49,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
49 private int m_shoutdistance = 100; 49 private int m_shoutdistance = 100;
50 private int m_whisperdistance = 10; 50 private int m_whisperdistance = 10;
51 private List<Scene> m_scenes = new List<Scene>(); 51 private List<Scene> m_scenes = new List<Scene>();
52 52 private List<string> FreezeCache = new List<string>();
53 private string m_adminPrefix = "";
53 internal object m_syncy = new object(); 54 internal object m_syncy = new object();
54 55
55 internal IConfig m_config; 56 internal IConfig m_config;
@@ -76,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
76 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance); 77 m_whisperdistance = config.Configs["Chat"].GetInt("whisper_distance", m_whisperdistance);
77 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance); 78 m_saydistance = config.Configs["Chat"].GetInt("say_distance", m_saydistance);
78 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance); 79 m_shoutdistance = config.Configs["Chat"].GetInt("shout_distance", m_shoutdistance);
80 m_adminPrefix = config.Configs["Chat"].GetString("admin_prefix", "");
79 } 81 }
80 82
81 public virtual void AddRegion(Scene scene) 83 public virtual void AddRegion(Scene scene)
@@ -171,7 +173,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
171 return; 173 return;
172 } 174 }
173 175
174 DeliverChatToAvatars(ChatSourceType.Agent, c); 176 if (FreezeCache.Contains(c.Sender.AgentId.ToString()))
177 {
178 if (c.Type != ChatTypeEnum.StartTyping || c.Type != ChatTypeEnum.StopTyping)
179 c.Sender.SendAgentAlertMessage("You may not talk as you are frozen.", false);
180 }
181 else
182 {
183 DeliverChatToAvatars(ChatSourceType.Agent, c);
184 }
175 } 185 }
176 186
177 public virtual void OnChatFromWorld(Object sender, OSChatMessage c) 187 public virtual void OnChatFromWorld(Object sender, OSChatMessage c)
@@ -185,6 +195,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
185 protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c) 195 protected virtual void DeliverChatToAvatars(ChatSourceType sourceType, OSChatMessage c)
186 { 196 {
187 string fromName = c.From; 197 string fromName = c.From;
198 string fromNamePrefix = "";
188 UUID fromID = UUID.Zero; 199 UUID fromID = UUID.Zero;
189 string message = c.Message; 200 string message = c.Message;
190 IScene scene = c.Scene; 201 IScene scene = c.Scene;
@@ -207,7 +218,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
207 fromPos = avatar.AbsolutePosition; 218 fromPos = avatar.AbsolutePosition;
208 fromName = avatar.Name; 219 fromName = avatar.Name;
209 fromID = c.Sender.AgentId; 220 fromID = c.Sender.AgentId;
210 221 if (avatar.GodLevel >= 200)
222 {
223 fromNamePrefix = m_adminPrefix;
224 }
211 break; 225 break;
212 226
213 case ChatSourceType.Object: 227 case ChatSourceType.Object:
@@ -227,7 +241,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
227 s.ForEachScenePresence( 241 s.ForEachScenePresence(
228 delegate(ScenePresence presence) 242 delegate(ScenePresence presence)
229 { 243 {
230 TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType); 244 ILandObject Presencecheck = s.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
245 if (Presencecheck != null)
246 {
247 // This will pass all chat from objects. Not
248 // perfect, but it will do. For now. Better
249 // than the prior behavior of muting all
250 // objects on a parcel with access restrictions
251 if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true)
252 {
253 TrySendChatMessage(presence, fromPos, regionPos, fromID, fromNamePrefix+fromName, c.Type, message, sourceType);
254 }
255 }
256
231 } 257 }
232 ); 258 );
233 } 259 }
@@ -268,25 +294,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
268 } 294 }
269 295
270 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); 296 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
271 297 if (c.Scene != null)
272 ((Scene)c.Scene).ForEachScenePresence( 298 {
273 delegate(ScenePresence presence) 299 ((Scene)c.Scene).ForEachScenePresence
274 { 300 (
275 // ignore chat from child agents 301 delegate(ScenePresence presence)
276 if (presence.IsChildAgent) return; 302 {
277 303 // ignore chat from child agents
278 IClientAPI client = presence.ControllingClient; 304 if (presence.IsChildAgent) return;
279 305
280 // don't forward SayOwner chat from objects to 306 IClientAPI client = presence.ControllingClient;
281 // non-owner agents 307
282 if ((c.Type == ChatTypeEnum.Owner) && 308 // don't forward SayOwner chat from objects to
283 (null != c.SenderObject) && 309 // non-owner agents
284 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) 310 if ((c.Type == ChatTypeEnum.Owner) &&
285 return; 311 (null != c.SenderObject) &&
286 312 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
287 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, 313 return;
288 (byte)sourceType, (byte)ChatAudibleLevel.Fully); 314
289 }); 315 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
316 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
317 }
318 );
319 }
290 } 320 }
291 321
292 322
@@ -315,5 +345,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
315 presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName, 345 presence.ControllingClient.SendChatMessage(message, (byte) type, fromPos, fromName,
316 fromAgentID,(byte)src,(byte)ChatAudibleLevel.Fully); 346 fromAgentID,(byte)src,(byte)ChatAudibleLevel.Fully);
317 } 347 }
348
349 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
350 public void ParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
351 {
352 System.Threading.Timer Timer;
353 if (flags == 0)
354 {
355 FreezeCache.Add(target.ToString());
356 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
357 Timer = new System.Threading.Timer(timeCB, target, 30000, 0);
358 Timers.Add(target, Timer);
359 }
360 else
361 {
362 FreezeCache.Remove(target.ToString());
363 Timers.TryGetValue(target, out Timer);
364 Timers.Remove(target);
365 Timer.Dispose();
366 }
367 }
368
369 private void OnEndParcelFrozen(object avatar)
370 {
371 UUID target = (UUID)avatar;
372 FreezeCache.Remove(target.ToString());
373 System.Threading.Timer Timer;
374 Timers.TryGetValue(target, out Timer);
375 Timers.Remove(target);
376 Timer.Dispose();
377 }
318 } 378 }
319} 379}
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index 2b3d2a9..a514a83 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -239,4 +239,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
239 return result; 239 return result;
240 } 240 }
241 } 241 }
242} \ No newline at end of file 242}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index b3f0a25..45c3f49 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -273,7 +273,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
273 273
274 // Inform the friends that this user is online 274 // Inform the friends that this user is online
275 StatusChange(agentID, true); 275 StatusChange(agentID, true);
276 276
277 // Register that we need to send the list of online friends to this user 277 // Register that we need to send the list of online friends to this user
278 lock (m_NeedsListOfFriends) 278 lock (m_NeedsListOfFriends)
279 m_NeedsListOfFriends.Add(agentID); 279 m_NeedsListOfFriends.Add(agentID);
@@ -701,7 +701,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
701 // we're done 701 // we're done
702 return true; 702 return true;
703 } 703 }
704 704
705 return false; 705 return false;
706 } 706 }
707 707
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
index af39565..347708d 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -156,6 +156,31 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
156 return; 156 return;
157 } 157 }
158 158
159 DateTime dt = DateTime.UtcNow;
160
161 // Ticks from UtcNow, but make it look like local. Evil, huh?
162 dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
163
164 try
165 {
166 // Convert that to the PST timezone
167 TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
168 dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
169 }
170 catch
171 {
172 //m_log.Info("[OFFLINE MESSAGING]: No PST timezone found on this machine. Saving with local timestamp.");
173 }
174
175 // And make it look local again to fool the unix time util
176 dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
177
178 im.timestamp = (uint)Util.ToUnixTime(dt);
179
180 // If client is null, this message comes from storage and IS offline
181 if (client != null)
182 im.offline = 0;
183
159 if (m_TransferModule != null) 184 if (m_TransferModule != null)
160 { 185 {
161 if (client != null) 186 if (client != null)
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 918fa04..d8e0f96 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -145,8 +145,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
145 ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; 145 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
146 if (!user.IsChildAgent) 146 if (!user.IsChildAgent)
147 { 147 {
148 // Local message 148 // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
149 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to root agent {0} {1}", user.Name, toAgentID);
150 user.ControllingClient.SendInstantMessage(im); 149 user.ControllingClient.SendInstantMessage(im);
151 150
152 // Message sent 151 // Message sent
@@ -168,7 +167,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
168 // Local message 167 // Local message
169 ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; 168 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
170 169
171 m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); 170 // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
172 user.ControllingClient.SendInstantMessage(im); 171 user.ControllingClient.SendInstantMessage(im);
173 172
174 // Message sent 173 // Message sent
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index fdfcd10..d3db5b7 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -172,13 +172,16 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
172 172
173 private void RetrieveInstantMessages(IClientAPI client) 173 private void RetrieveInstantMessages(IClientAPI client)
174 { 174 {
175 if (m_RestURL != "") 175 if (m_RestURL == String.Empty)
176 { 176 return;
177 m_log.DebugFormat("[OFFLINE MESSAGING] Retrieving stored messages for {0}", client.AgentId);
178 177
179 List<GridInstantMessage> msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>( 178 m_log.DebugFormat("[OFFLINE MESSAGING] Retrieving stored messages for {0}", client.AgentId);
179
180 List<GridInstantMessage> msglist = SynchronousRestObjectPoster.BeginPostObject<UUID, List<GridInstantMessage>>(
180 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); 181 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId);
181 182
183 if (msglist != null)
184 {
182 foreach (GridInstantMessage im in msglist) 185 foreach (GridInstantMessage im in msglist)
183 { 186 {
184 // client.SendInstantMessage(im); 187 // client.SendInstantMessage(im);
@@ -189,6 +192,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
189 // Needed for proper state management for stored group 192 // Needed for proper state management for stored group
190 // invitations 193 // invitations
191 // 194 //
195
196 im.offline = 1;
197
198 // Reconstruct imSessionID
199 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
200 {
201 UUID fromAgentID = new UUID(im.fromAgentID);
202 UUID sessionID = fromAgentID ^ client.AgentId;
203 im.imSessionID = new Guid(sessionID.ToString());
204 }
205
192 Scene s = FindScene(client.AgentId); 206 Scene s = FindScene(client.AgentId);
193 if (s != null) 207 if (s != null)
194 s.EventManager.TriggerIncomingInstantMessage(im); 208 s.EventManager.TriggerIncomingInstantMessage(im);
@@ -198,26 +212,38 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
198 212
199 private void UndeliveredMessage(GridInstantMessage im) 213 private void UndeliveredMessage(GridInstantMessage im)
200 { 214 {
201 if ((im.offline != 0) 215 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
202 && (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) 216 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
217 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
218 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
219 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
203 { 220 {
204 bool success = SynchronousRestObjectPoster.BeginPostObject<GridInstantMessage, bool>( 221 return;
205 "POST", m_RestURL+"/SaveMessage/", im); 222 }
206 223
207 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) 224 // It's not delivered. Make sure the scope id is saved
208 { 225 // We don't need the imSessionID here anymore, overwrite it
209 IClientAPI client = FindClient(new UUID(im.fromAgentID)); 226 Scene scene = FindScene(new UUID(im.fromAgentID));
210 if (client == null) 227 if (scene == null)
211 return; 228 scene = m_SceneList[0];
212 229 im.imSessionID = new Guid(scene.RegionInfo.ScopeID.ToString());
213 client.SendInstantMessage(new GridInstantMessage( 230
214 null, new UUID(im.toAgentID), 231 bool success = SynchronousRestObjectPoster.BeginPostObject<GridInstantMessage, bool>(
215 "System", new UUID(im.fromAgentID), 232 "POST", m_RestURL+"/SaveMessage/", im);
216 (byte)InstantMessageDialog.MessageFromAgent, 233
217 "User is not logged in. "+ 234 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
218 (success ? "Message saved." : "Message not saved"), 235 {
219 false, new Vector3())); 236 IClientAPI client = FindClient(new UUID(im.fromAgentID));
220 } 237 if (client == null)
238 return;
239
240 client.SendInstantMessage(new GridInstantMessage(
241 null, new UUID(im.toAgentID),
242 "System", new UUID(im.fromAgentID),
243 (byte)InstantMessageDialog.MessageFromAgent,
244 "User is not logged in. "+
245 (success ? "Message saved." : "Message not saved"),
246 false, new Vector3()));
221 } 247 }
222 } 248 }
223 } 249 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index d1274e9..a08a628 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -159,10 +159,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
159 159
160 private void OnInstantMessage(IClientAPI client, GridInstantMessage im) 160 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
161 { 161 {
162 m_log.DebugFormat( 162 //m_log.InfoFormat("[INVENTORY TRANSFER]: OnInstantMessage {0}", im.dialog);
163 "[INVENTORY TRANSFER]: {0} IM type received from {1}", 163
164 (InstantMessageDialog)im.dialog, client.Name);
165
166 Scene scene = FindClientScene(client.AgentId); 164 Scene scene = FindClientScene(client.AgentId);
167 165
168 if (scene == null) // Something seriously wrong here. 166 if (scene == null) // Something seriously wrong here.
@@ -248,6 +246,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
248 im.imSessionID = itemID.Guid; 246 im.imSessionID = itemID.Guid;
249 } 247 }
250 248
249 im.offline = 1; // Remember these
250
251 // Send the IM to the recipient. The item is already 251 // Send the IM to the recipient. The item is already
252 // in their inventory, so it will not be lost if 252 // in their inventory, so it will not be lost if
253 // they are offline. 253 // they are offline.
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 38fff1c..2921b0d 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -99,7 +99,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
99 99
100 protected virtual void OnNewClient(IClientAPI client) 100 protected virtual void OnNewClient(IClientAPI client)
101 { 101 {
102 client.OnTeleportHomeRequest += TeleportHome; 102 client.OnTeleportHomeRequest += TeleportHomeFired;
103 } 103 }
104 104
105 public virtual void Close() 105 public virtual void Close()
@@ -268,7 +268,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
268 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 268 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
269 // it's actually doing a lot of work. 269 // it's actually doing a lot of work.
270 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 270 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
271 if (endPoint.Address != null) 271 if (endPoint != null && endPoint.Address != null)
272 { 272 {
273 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 273 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
274 // both regions 274 // both regions
@@ -459,6 +459,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
459 // Now let's make it officially a child agent 459 // Now let's make it officially a child agent
460 sp.MakeChildAgent(); 460 sp.MakeChildAgent();
461 461
462 sp.Scene.CleanDroppedAttachments();
463
462 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 464 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
463 465
464 if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 466 if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
@@ -527,7 +529,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
527 529
528 protected void KillEntity(Scene scene, uint localID) 530 protected void KillEntity(Scene scene, uint localID)
529 { 531 {
530 scene.SendKillObject(localID); 532 scene.SendKillObject(new List<uint>() { localID });
531 } 533 }
532 534
533 protected virtual GridRegion GetFinalDestination(GridRegion region) 535 protected virtual GridRegion GetFinalDestination(GridRegion region)
@@ -565,7 +567,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
565 567
566 #region Teleport Home 568 #region Teleport Home
567 569
568 public virtual void TeleportHome(UUID id, IClientAPI client) 570 public void TeleportHomeFired(UUID id, IClientAPI client)
571 {
572 TeleportHome(id, client);
573 }
574
575 public virtual bool TeleportHome(UUID id, IClientAPI client)
569 { 576 {
570 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 577 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
571 578
@@ -574,14 +581,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
574 581
575 if (uinfo != null) 582 if (uinfo != null)
576 { 583 {
584 if (uinfo.HomeRegionID == UUID.Zero)
585 {
586 // can't find the Home region: Tell viewer and abort
587 client.SendTeleportFailed("You don't have a home position set.");
588 return false;
589 }
577 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 590 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
578 if (regionInfo == null) 591 if (regionInfo == null)
579 { 592 {
580 // can't find the Home region: Tell viewer and abort 593 // can't find the Home region: Tell viewer and abort
581 client.SendTeleportFailed("Your home region could not be found."); 594 client.SendTeleportFailed("Your home region could not be found.");
582 return; 595 return false;
583 } 596 }
584 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})", 597 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})",
585 regionInfo.RegionName, regionInfo.RegionID, regionInfo.RegionLocX / Constants.RegionSize, regionInfo.RegionLocY / Constants.RegionSize); 598 regionInfo.RegionName, regionInfo.RegionID, regionInfo.RegionLocX / Constants.RegionSize, regionInfo.RegionLocY / Constants.RegionSize);
586 599
587 // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point... 600 // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point...
@@ -589,6 +602,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
589 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 602 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
590 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 603 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
591 } 604 }
605 else
606 {
607 // can't find the Home region: Tell viewer and abort
608 client.SendTeleportFailed("Your home region could not be found.");
609 return false;
610 }
611 return true;
592 } 612 }
593 613
594 #endregion 614 #endregion
@@ -876,15 +896,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
876 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); 896 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
877 897
878 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>(); 898 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>();
879 if (eq != null) 899 IPEndPoint neighbourExternal = neighbourRegion.ExternalEndPoint;
880 { 900 if (neighbourExternal != null)
881 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
882 capsPath, agent.UUID, agent.ControllingClient.SessionId);
883 }
884 else
885 { 901 {
886 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint, 902 if (eq != null)
887 capsPath); 903 {
904 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourExternal,
905 capsPath, agent.UUID, agent.ControllingClient.SessionId);
906 }
907 else
908 {
909 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourExternal,
910 capsPath);
911 }
888 } 912 }
889 913
890 if (!WaitForCallback(agent.UUID)) 914 if (!WaitForCallback(agent.UUID))
@@ -986,10 +1010,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
986 agent.Id0 = currentAgentCircuit.Id0; 1010 agent.Id0 = currentAgentCircuit.Id0;
987 } 1011 }
988 1012
989 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1013 IPEndPoint external = region.ExternalEndPoint;
990 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 1014 if (external != null)
1015 {
1016 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1017 d.BeginInvoke(sp, agent, region, external, true,
991 InformClientOfNeighbourCompleted, 1018 InformClientOfNeighbourCompleted,
992 d); 1019 d);
1020 }
993 } 1021 }
994 #endregion 1022 #endregion
995 1023
@@ -1122,6 +1150,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1122 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1150 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1123 try 1151 try
1124 { 1152 {
1153 //neighbour.ExternalEndPoint may return null, which will be caught
1125 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, 1154 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
1126 InformClientOfNeighbourCompleted, 1155 InformClientOfNeighbourCompleted,
1127 d); 1156 d);
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 1ac7508..47898cc 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -86,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
86 86
87 protected override void OnNewClient(IClientAPI client) 87 protected override void OnNewClient(IClientAPI client)
88 { 88 {
89 client.OnTeleportHomeRequest += TeleportHome; 89 client.OnTeleportHomeRequest += TeleportHomeFired;
90 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 90 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
91 } 91 }
92 92
@@ -174,7 +174,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
174 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason); 174 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason);
175 } 175 }
176 176
177 public override void TeleportHome(UUID id, IClientAPI client) 177 public void TeleportHomeFired(UUID id, IClientAPI client)
178 {
179 TeleportHome(id, client);
180 }
181
182 public override bool TeleportHome(UUID id, IClientAPI client)
178 { 183 {
179 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 184 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
180 185
@@ -184,8 +189,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
184 { 189 {
185 // local grid user 190 // local grid user
186 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 191 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
187 base.TeleportHome(id, client); 192 return base.TeleportHome(id, client);
188 return;
189 } 193 }
190 194
191 // Foreign user wants to go home 195 // Foreign user wants to go home
@@ -195,7 +199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
195 { 199 {
196 client.SendTeleportFailed("Your information has been lost"); 200 client.SendTeleportFailed("Your information has been lost");
197 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 201 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
198 return; 202 return false;
199 } 203 }
200 204
201 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 205 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
@@ -205,7 +209,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
205 { 209 {
206 client.SendTeleportFailed("Your home region could not be found"); 210 client.SendTeleportFailed("Your home region could not be found");
207 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 211 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
208 return; 212 return false;
209 } 213 }
210 214
211 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 215 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -213,7 +217,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
213 { 217 {
214 client.SendTeleportFailed("Internal error"); 218 client.SendTeleportFailed("Internal error");
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
216 return; 220 return false;
217 } 221 }
218 222
219 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); 223 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
@@ -223,6 +227,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
223 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName); 227 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName);
224 228
225 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); 229 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq);
230 return true;
226 } 231 }
227 #endregion 232 #endregion
228 233
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 7a175ea..d429979 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Net; 30using System.Net;
31using System.Xml;
31using System.Reflection; 32using System.Reflection;
32using System.Threading; 33using System.Threading;
33 34
@@ -191,11 +192,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
191 public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID, 192 public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID,
192 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient) 193 List<SceneObjectGroup> objectGroups, IClientAPI remoteClient)
193 { 194 {
194 // HACK: This is only working for lists containing a single item!
195 // It's just a hack to make this WIP compile and run. Nothing
196 // currently calls this with multiple items.
197 UUID ret = UUID.Zero; 195 UUID ret = UUID.Zero;
198 196
197 // The following code groups the SOG's by owner. No objects
198 // belonging to different people can be coalesced, for obvious
199 // reasons.
199 Dictionary<UUID, List<SceneObjectGroup>> deletes = 200 Dictionary<UUID, List<SceneObjectGroup>> deletes =
200 new Dictionary<UUID, List<SceneObjectGroup>>(); 201 new Dictionary<UUID, List<SceneObjectGroup>>();
201 202
@@ -207,264 +208,334 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
207 deletes[g.OwnerID].Add(g); 208 deletes[g.OwnerID].Add(g);
208 } 209 }
209 210
211 // This is pethod scoped and will be returned. It will be the
212 // last created asset id
213 UUID assetID = UUID.Zero;
214
215 // Each iteration is really a separate asset being created,
216 // with distinct destinations as well.
210 foreach (List<SceneObjectGroup> objlist in deletes.Values) 217 foreach (List<SceneObjectGroup> objlist in deletes.Values)
211 { 218 {
212 foreach (SceneObjectGroup g in objlist) 219 Dictionary<UUID, string> xmlStrings =
213 ret = DeleteToInventory(action, folderID, g, remoteClient); 220 new Dictionary<UUID, string>();
214 }
215 221
216 return ret; 222 foreach (SceneObjectGroup objectGroup in objlist)
217 } 223 {
224 Vector3 inventoryStoredPosition = new Vector3
225 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
226 ? 250
227 : objectGroup.AbsolutePosition.X)
228 ,
229 (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
230 ? 250
231 : objectGroup.AbsolutePosition.X,
232 objectGroup.AbsolutePosition.Z);
218 233
219 private UUID DeleteToInventory(DeRezAction action, UUID folderID, 234 Vector3 originalPosition = objectGroup.AbsolutePosition;
220 SceneObjectGroup objectGroup, IClientAPI remoteClient)
221 {
222 UUID assetID = UUID.Zero;
223 235
224 Vector3 inventoryStoredPosition = new Vector3 236 // Restore attachment data after trip through the sim
225 (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) 237 if (objectGroup.RootPart.AttachPoint > 0)
226 ? 250 238 inventoryStoredPosition = objectGroup.RootPart.AttachOffset;
227 : objectGroup.AbsolutePosition.X) 239 objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint;
228 ,
229 (objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
230 ? 250
231 : objectGroup.AbsolutePosition.X,
232 objectGroup.AbsolutePosition.Z);
233 240
234 Vector3 originalPosition = objectGroup.AbsolutePosition; 241 objectGroup.AbsolutePosition = inventoryStoredPosition;
235 242
236 objectGroup.AbsolutePosition = inventoryStoredPosition; 243 // Make sure all bits but the ones we want are clear
244 // on take.
245 // This will be applied to the current perms, so
246 // it will do what we want.
247 objectGroup.RootPart.NextOwnerMask &=
248 ((uint)PermissionMask.Copy |
249 (uint)PermissionMask.Transfer |
250 (uint)PermissionMask.Modify);
251 objectGroup.RootPart.NextOwnerMask |=
252 (uint)PermissionMask.Move;
237 253
238 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup); 254 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup);
239 255
240 objectGroup.AbsolutePosition = originalPosition; 256 objectGroup.AbsolutePosition = originalPosition;
241 257
242 // Get the user info of the item destination 258 xmlStrings[objectGroup.UUID] = sceneObjectXml;
243 // 259 }
244 UUID userID = UUID.Zero;
245 260
246 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy || 261 string itemXml;
247 action == DeRezAction.SaveToExistingUserInventoryItem)
248 {
249 // Take or take copy require a taker
250 // Saving changes requires a local user
251 //
252 if (remoteClient == null)
253 return UUID.Zero;
254 262
255 userID = remoteClient.AgentId; 263 if (objlist.Count > 1)
256 } 264 {
257 else 265 float minX, minY, minZ;
258 { 266 float maxX, maxY, maxZ;
259 // All returns / deletes go to the object owner
260 //
261 267
262 userID = objectGroup.RootPart.OwnerID; 268 Vector3[] offsets = m_Scene.GetCombinedBoundingBox(objlist,
263 } 269 out minX, out maxX, out minY, out maxY,
270 out minZ, out maxZ);
264 271
265 if (userID == UUID.Zero) // Can't proceed 272 // CreateWrapper
266 { 273 XmlDocument itemDoc = new XmlDocument();
267 return UUID.Zero; 274 XmlElement root = itemDoc.CreateElement("", "CoalescedObject", "");
268 } 275 itemDoc.AppendChild(root);
269 276
270 // If we're returning someone's item, it goes back to the 277 // Embed the offsets into the group XML
271 // owner's Lost And Found folder. 278 for ( int i = 0 ; i < objlist.Count ; i++ )
272 // Delete is treated like return in this case 279 {
273 // Deleting your own items makes them go to trash 280 XmlDocument doc = new XmlDocument();
274 // 281 SceneObjectGroup g = objlist[i];
275 282 doc.LoadXml(xmlStrings[g.UUID]);
276 InventoryFolderBase folder = null; 283 XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup");
277 InventoryItemBase item = null; 284 e.SetAttribute("offsetx", offsets[i].X.ToString());
285 e.SetAttribute("offsety", offsets[i].Y.ToString());
286 e.SetAttribute("offsetz", offsets[i].Z.ToString());
287
288 XmlNode objectNode = itemDoc.ImportNode(e, true);
289 root.AppendChild(objectNode);
290 }
278 291
279 if (DeRezAction.SaveToExistingUserInventoryItem == action) 292 float sizeX = maxX - minX;
280 { 293 float sizeY = maxY - minY;
281 item = new InventoryItemBase(objectGroup.RootPart.FromUserInventoryItemID, userID); 294 float sizeZ = maxZ - minZ;
282 item = m_Scene.InventoryService.GetItem(item);
283 295
284 //item = userInfo.RootFolder.FindItem( 296 root.SetAttribute("x", sizeX.ToString());
285 // objectGroup.RootPart.FromUserInventoryItemID); 297 root.SetAttribute("y", sizeY.ToString());
298 root.SetAttribute("z", sizeZ.ToString());
286 299
287 if (null == item) 300 itemXml = itemDoc.InnerXml;
301 }
302 else
288 { 303 {
289 m_log.DebugFormat( 304 itemXml = xmlStrings[objlist[0].UUID];
290 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
291 objectGroup.Name, objectGroup.UUID);
292 return UUID.Zero;
293 } 305 }
294 } 306
295 else 307 // Get the user info of the item destination
296 {
297 // Folder magic
298 // 308 //
299 if (action == DeRezAction.Delete) 309 UUID userID = UUID.Zero;
310
311 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
312 action == DeRezAction.SaveToExistingUserInventoryItem)
300 { 313 {
301 // Deleting someone else's item 314 // Take or take copy require a taker
315 // Saving changes requires a local user
302 // 316 //
303 if (remoteClient == null || 317 if (remoteClient == null)
304 objectGroup.OwnerID != remoteClient.AgentId) 318 return UUID.Zero;
305 {
306 319
307 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 320 userID = remoteClient.AgentId;
308 }
309 else
310 {
311 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
312 }
313 } 321 }
314 else if (action == DeRezAction.Return) 322 else
315 { 323 {
316 324 // All returns / deletes go to the object owner
317 // Dump to lost + found unconditionally
318 // 325 //
319 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 326
327 userID = objlist[0].RootPart.OwnerID;
320 } 328 }
321 329
322 if (folderID == UUID.Zero && folder == null) 330 if (userID == UUID.Zero) // Can't proceed
323 { 331 {
324 if (action == DeRezAction.Delete) 332 return UUID.Zero;
333 }
334
335 // If we're returning someone's item, it goes back to the
336 // owner's Lost And Found folder.
337 // Delete is treated like return in this case
338 // Deleting your own items makes them go to trash
339 //
340
341 InventoryFolderBase folder = null;
342 InventoryItemBase item = null;
343
344 if (DeRezAction.SaveToExistingUserInventoryItem == action)
345 {
346 item = new InventoryItemBase(objlist[0].RootPart.FromUserInventoryItemID, userID);
347 item = m_Scene.InventoryService.GetItem(item);
348
349 //item = userInfo.RootFolder.FindItem(
350 // objectGroup.RootPart.FromUserInventoryItemID);
351
352 if (null == item)
325 { 353 {
326 // Deletes go to trash by default 354 m_log.DebugFormat(
327 // 355 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
328 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 356 objlist[0].Name, objlist[0].UUID);
357 return UUID.Zero;
329 } 358 }
330 else 359 }
360 else
361 {
362 // Folder magic
363 //
364 if (action == DeRezAction.Delete)
331 { 365 {
366 // Deleting someone else's item
367 //
332 if (remoteClient == null || 368 if (remoteClient == null ||
333 objectGroup.OwnerID != remoteClient.AgentId) 369 objlist[0].OwnerID != remoteClient.AgentId)
334 { 370 {
335 // Taking copy of another person's item. Take to 371
336 // Objects folder. 372 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
337 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
338 } 373 }
339 else 374 else
340 { 375 {
341 // Catch all. Use lost & found 376 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
377 }
378 }
379 else if (action == DeRezAction.Return)
380 {
381
382 // Dump to lost + found unconditionally
383 //
384 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
385 }
386
387 if (folderID == UUID.Zero && folder == null)
388 {
389 if (action == DeRezAction.Delete)
390 {
391 // Deletes go to trash by default
342 // 392 //
393 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
394 }
395 else
396 {
397 if (remoteClient == null ||
398 objlist[0].OwnerID != remoteClient.AgentId)
399 {
400 // Taking copy of another person's item. Take to
401 // Objects folder.
402 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object);
403 }
404 else
405 {
406 // Catch all. Use lost & found
407 //
343 408
344 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 409 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
410 }
345 } 411 }
346 } 412 }
347 }
348 413
349 // Override and put into where it came from, if it came 414 // Override and put into where it came from, if it came
350 // from anywhere in inventory 415 // from anywhere in inventory
351 // 416 //
352 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 417 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
353 {
354 if (objectGroup.RootPart.FromFolderID != UUID.Zero)
355 { 418 {
356 InventoryFolderBase f = new InventoryFolderBase(objectGroup.RootPart.FromFolderID, userID); 419 if (objlist[0].RootPart.FromFolderID != UUID.Zero)
357 folder = m_Scene.InventoryService.GetFolder(f); 420 {
421 InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID);
422 folder = m_Scene.InventoryService.GetFolder(f);
423 }
358 } 424 }
359 }
360 425
361 if (folder == null) // None of the above 426 if (folder == null) // None of the above
362 { 427 {
363 folder = new InventoryFolderBase(folderID); 428 folder = new InventoryFolderBase(folderID);
364 429
365 if (folder == null) // Nowhere to put it 430 if (folder == null) // Nowhere to put it
431 {
432 return UUID.Zero;
433 }
434 }
435
436 item = new InventoryItemBase();
437 // Can't know creator is the same, so null it in inventory
438 if (objlist.Count > 1)
439 item.CreatorId = UUID.Zero.ToString();
440 else
441 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
442 item.ID = UUID.Random();
443 item.InvType = (int)InventoryType.Object;
444 item.Folder = folder.ID;
445 item.Owner = userID;
446 if (objlist.Count > 1)
366 { 447 {
367 return UUID.Zero; 448 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
449 }
450 else
451 {
452 item.SaleType = objlist[0].RootPart.ObjectSaleType;
453 item.SalePrice = objlist[0].RootPart.SalePrice;
368 } 454 }
369 } 455 }
370 456
371 item = new InventoryItemBase(); 457 AssetBase asset = CreateAsset(
372 item.CreatorId = objectGroup.RootPart.CreatorID.ToString(); 458 objlist[0].GetPartName(objlist[0].RootPart.LocalId),
373 item.ID = UUID.Random(); 459 objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
374 item.InvType = (int)InventoryType.Object; 460 (sbyte)AssetType.Object,
375 item.Folder = folder.ID; 461 Utils.StringToBytes(itemXml),
376 item.Owner = userID; 462 objlist[0].OwnerID.ToString());
377 } 463 m_Scene.AssetService.Store(asset);
378 464 assetID = asset.FullID;
379 AssetBase asset = CreateAsset(
380 objectGroup.GetPartName(objectGroup.RootPart.LocalId),
381 objectGroup.GetPartDescription(objectGroup.RootPart.LocalId),
382 (sbyte)AssetType.Object,
383 Utils.StringToBytes(sceneObjectXml),
384 objectGroup.OwnerID.ToString());
385 m_Scene.AssetService.Store(asset);
386 assetID = asset.FullID;
387
388 if (DeRezAction.SaveToExistingUserInventoryItem == action)
389 {
390 item.AssetID = asset.FullID;
391 m_Scene.InventoryService.UpdateItem(item);
392 }
393 else
394 {
395 item.AssetID = asset.FullID;
396 465
397 if (remoteClient != null && (remoteClient.AgentId != objectGroup.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) 466 if (DeRezAction.SaveToExistingUserInventoryItem == action)
398 { 467 {
399 uint perms = objectGroup.GetEffectivePermissions(); 468 item.AssetID = asset.FullID;
400 uint nextPerms = (perms & 7) << 13; 469 m_Scene.InventoryService.UpdateItem(item);
401 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
402 perms &= ~(uint)PermissionMask.Copy;
403 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
404 perms &= ~(uint)PermissionMask.Transfer;
405 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
406 perms &= ~(uint)PermissionMask.Modify;
407
408 // Make sure all bits but the ones we want are clear
409 // on take.
410 // This will be applied to the current perms, so
411 // it will do what we want.
412 objectGroup.RootPart.NextOwnerMask &=
413 ((uint)PermissionMask.Copy |
414 (uint)PermissionMask.Transfer |
415 (uint)PermissionMask.Modify);
416 objectGroup.RootPart.NextOwnerMask |=
417 (uint)PermissionMask.Move;
418
419 item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
420 item.CurrentPermissions = item.BasePermissions;
421 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
422 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
423 item.GroupPermissions = objectGroup.RootPart.GroupMask & objectGroup.RootPart.NextOwnerMask;
424
425 // Magic number badness. Maybe this deserves an enum.
426 // bit 4 (16) is the "Slam" bit, it means treat as passed
427 // and apply next owner perms on rez
428 item.CurrentPermissions |= 16; // Slam!
429 } 470 }
430 else 471 else
431 { 472 {
432 item.BasePermissions = objectGroup.GetEffectivePermissions(); 473 item.AssetID = asset.FullID;
433 item.CurrentPermissions = objectGroup.GetEffectivePermissions();
434 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
435 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
436 item.GroupPermissions = objectGroup.RootPart.GroupMask;
437 474
438 item.CurrentPermissions &= 475 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7;
439 ((uint)PermissionMask.Copy | 476 foreach (SceneObjectGroup grp in objlist)
440 (uint)PermissionMask.Transfer | 477 effectivePerms &= grp.GetEffectivePermissions();
441 (uint)PermissionMask.Modify | 478 effectivePerms |= (uint)PermissionMask.Move;
442 (uint)PermissionMask.Move | 479
443 7); // Preserve folded permissions 480 if (remoteClient != null && (remoteClient.AgentId != objlist[0].RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
444 } 481 {
482 uint perms = effectivePerms;
483 uint nextPerms = (perms & 7) << 13;
484 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
485 perms &= ~(uint)PermissionMask.Copy;
486 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
487 perms &= ~(uint)PermissionMask.Transfer;
488 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
489 perms &= ~(uint)PermissionMask.Modify;
490
491 item.BasePermissions = perms & objlist[0].RootPart.NextOwnerMask;
492 item.CurrentPermissions = item.BasePermissions;
493 item.NextPermissions = perms & objlist[0].RootPart.NextOwnerMask;
494 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask;
495 item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask;
496
497 // Magic number badness. Maybe this deserves an enum.
498 // bit 4 (16) is the "Slam" bit, it means treat as passed
499 // and apply next owner perms on rez
500 item.CurrentPermissions |= 16; // Slam!
501 }
502 else
503 {
504 item.BasePermissions = effectivePerms;
505 item.CurrentPermissions = effectivePerms;
506 item.NextPermissions = objlist[0].RootPart.NextOwnerMask & effectivePerms;
507 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & effectivePerms;
508 item.GroupPermissions = objlist[0].RootPart.GroupMask & effectivePerms;
509
510 item.CurrentPermissions &=
511 ((uint)PermissionMask.Copy |
512 (uint)PermissionMask.Transfer |
513 (uint)PermissionMask.Modify |
514 (uint)PermissionMask.Move |
515 7); // Preserve folded permissions
516 }
445 517
446 // TODO: add the new fields (Flags, Sale info, etc) 518 item.CreationDate = Util.UnixTimeSinceEpoch();
447 item.CreationDate = Util.UnixTimeSinceEpoch(); 519 item.Description = asset.Description;
448 item.Description = asset.Description; 520 item.Name = asset.Name;
449 item.Name = asset.Name; 521 item.AssetType = asset.Type;
450 item.AssetType = asset.Type;
451 522
452 m_Scene.AddInventoryItem(item); 523 m_Scene.AddInventoryItem(item);
453 524
454 if (remoteClient != null && item.Owner == remoteClient.AgentId) 525 if (remoteClient != null && item.Owner == remoteClient.AgentId)
455 {
456 remoteClient.SendInventoryItemCreateUpdate(item, 0);
457 }
458 else
459 {
460 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
461 if (notifyUser != null)
462 { 526 {
463 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); 527 remoteClient.SendInventoryItemCreateUpdate(item, 0);
528 }
529 else
530 {
531 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
532 if (notifyUser != null)
533 {
534 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
535 }
464 } 536 }
465 } 537 }
466 } 538 }
467
468 return assetID; 539 return assetID;
469 } 540 }
470 541
@@ -515,8 +586,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
515 586
516 if (item != null) 587 if (item != null)
517 { 588 {
589 if (item.ID == UUID.Zero)
590 {
591 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 1");
592 }
593
518 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); 594 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
519 595
596 SceneObjectGroup group = null;
597
520 if (rezAsset != null) 598 if (rezAsset != null)
521 { 599 {
522 UUID itemId = UUID.Zero; 600 UUID itemId = UUID.Zero;
@@ -525,32 +603,83 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
525 // item that it came from. This allows us to enable 'save object to inventory' 603 // item that it came from. This allows us to enable 'save object to inventory'
526 if (!m_Scene.Permissions.BypassPermissions()) 604 if (!m_Scene.Permissions.BypassPermissions())
527 { 605 {
528 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy) 606 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
529 { 607 {
530 itemId = item.ID; 608 itemId = item.ID;
531 } 609 }
532 } 610 }
533 else 611 else
534 { 612 {
535 // Brave new fullperm world 613 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
536 // 614 {
537 itemId = item.ID; 615 // Brave new fullperm world
616 itemId = item.ID;
617 }
618 }
619
620 if (item.ID == UUID.Zero)
621 {
622 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 2");
538 } 623 }
539 624
540 string xmlData = Utils.BytesToString(rezAsset.Data); 625 string xmlData = Utils.BytesToString(rezAsset.Data);
541 SceneObjectGroup group 626 List<SceneObjectGroup> objlist =
542 = SceneObjectSerializer.FromOriginalXmlFormat(itemId, xmlData); 627 new List<SceneObjectGroup>();
628 List<Vector3> veclist = new List<Vector3>();
629
630 XmlDocument doc = new XmlDocument();
631 doc.LoadXml(xmlData);
632 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
633 if (e == null || attachment) // Single
634 {
635 SceneObjectGroup g =
636 SceneObjectSerializer.FromOriginalXmlFormat(
637 itemId, xmlData);
638 objlist.Add(g);
639 veclist.Add(new Vector3(0, 0, 0));
640
641 float offsetHeight = 0;
642 pos = m_Scene.GetNewRezLocation(
643 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
644 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false);
645 pos.Z += offsetHeight;
646 }
647 else
648 {
649 XmlElement coll = (XmlElement)e;
650 float bx = Convert.ToSingle(coll.GetAttribute("x"));
651 float by = Convert.ToSingle(coll.GetAttribute("y"));
652 float bz = Convert.ToSingle(coll.GetAttribute("z"));
653 Vector3 bbox = new Vector3(bx, by, bz);
543 654
544 group.RootPart.FromFolderID = item.Folder; 655 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
656 RayTargetID, Quaternion.Identity,
657 BypassRayCast, bRayEndIsIntersection, true,
658 bbox, false);
545 659
546 // If it's rezzed in world, select it. Much easier to 660 pos -= bbox / 2;
547 // find small items. 661
548 // 662 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
549 if (!attachment) 663 foreach (XmlNode n in groups)
550 group.RootPart.CreateSelected = true; 664 {
665 SceneObjectGroup g =
666 SceneObjectSerializer.FromOriginalXmlFormat(
667 itemId, n.OuterXml);
668 objlist.Add(g);
669 XmlElement el = (XmlElement)n;
670 float x = Convert.ToSingle(el.GetAttribute("offsetx"));
671 float y = Convert.ToSingle(el.GetAttribute("offsety"));
672 float z = Convert.ToSingle(el.GetAttribute("offsetz"));
673 veclist.Add(new Vector3(x, y, z));
674 }
675 }
676
677 int primcount = 0;
678 foreach (SceneObjectGroup g in objlist)
679 primcount += g.PrimCount;
551 680
552 if (!m_Scene.Permissions.CanRezObject( 681 if (!m_Scene.Permissions.CanRezObject(
553 group.PrimCount, remoteClient.AgentId, pos) 682 primcount, remoteClient.AgentId, pos)
554 && !attachment) 683 && !attachment)
555 { 684 {
556 // The client operates in no fail mode. It will 685 // The client operates in no fail mode. It will
@@ -563,108 +692,138 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
563 return null; 692 return null;
564 } 693 }
565 694
566 group.ResetIDs(); 695 for (int i = 0 ; i < objlist.Count ; i++ )
567
568 if (attachment)
569 { 696 {
570 group.RootPart.Flags |= PrimFlags.Phantom; 697 group = objlist[i];
571 group.RootPart.IsAttachment = true;
572 }
573
574 // If we're rezzing an attachment then don't ask AddNewSceneObject() to update the client since
575 // we'll be doing that later on. Scheduling more than one full update during the attachment
576 // process causes some clients to fail to display the attachment properly.
577 m_Scene.AddNewSceneObject(group, true, false);
578 698
579 // m_log.InfoFormat("ray end point for inventory rezz is {0} {1} {2} ", RayEnd.X, RayEnd.Y, RayEnd.Z); 699 Vector3 storedPosition = group.AbsolutePosition;
580 // if attachment we set it's asset id so object updates can reflect that 700 if (group.UUID == UUID.Zero)
581 // if not, we set it's position in world. 701 {
582 if (!attachment) 702 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 3");
583 { 703 }
584 group.ScheduleGroupForFullUpdate(); 704 group.RootPart.FromFolderID = item.Folder;
585
586 float offsetHeight = 0;
587 pos = m_Scene.GetNewRezLocation(
588 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
589 BypassRayCast, bRayEndIsIntersection, true, group.GetAxisAlignedBoundingBox(out offsetHeight), false);
590 pos.Z += offsetHeight;
591 group.AbsolutePosition = pos;
592 // m_log.InfoFormat("rezx point for inventory rezz is {0} {1} {2} and offsetheight was {3}", pos.X, pos.Y, pos.Z, offsetHeight);
593 705
594 } 706 // If it's rezzed in world, select it. Much easier to
595 else 707 // find small items.
596 { 708 //
597 group.SetFromItemID(itemID); 709 if (!attachment)
598 } 710 {
711 group.RootPart.CreateSelected = true;
712 foreach (SceneObjectPart child in group.Parts)
713 child.CreateSelected = true;
714 }
599 715
600 SceneObjectPart rootPart = null; 716 group.ResetIDs();
601 try
602 {
603 rootPart = group.GetChildPart(group.UUID);
604 }
605 catch (NullReferenceException)
606 {
607 string isAttachment = "";
608 717
609 if (attachment) 718 if (attachment)
610 isAttachment = " Object was an attachment"; 719 {
720 group.RootPart.Flags |= PrimFlags.Phantom;
721 group.RootPart.IsAttachment = true;
722 }
611 723
612 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment); 724 // If we're rezzing an attachment then don't ask
613 } 725 // AddNewSceneObject() to update the client since
726 // we'll be doing that later on. Scheduling more than
727 // one full update during the attachment
728 // process causes some clients to fail to display the
729 // attachment properly.
730 m_Scene.AddNewSceneObject(group, true, false);
731
732 // if attachment we set it's asset id so object updates
733 // can reflect that, if not, we set it's position in world.
734 if (!attachment)
735 {
736 group.ScheduleGroupForFullUpdate();
737
738 group.AbsolutePosition = pos + veclist[i];
739 }
740 else
741 {
742 group.SetFromItemID(itemID);
743 }
614 744
615 // Since renaming the item in the inventory does not affect the name stored 745 SceneObjectPart rootPart = null;
616 // in the serialization, transfer the correct name from the inventory to the
617 // object itself before we rez.
618 rootPart.Name = item.Name;
619 rootPart.Description = item.Description;
620 746
621 group.SetGroup(remoteClient.ActiveGroupId, remoteClient); 747 try
622 if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0) 748 {
623 { 749 rootPart = group.GetChildPart(group.UUID);
624 //Need to kill the for sale here 750 }
625 rootPart.ObjectSaleType = 0; 751 catch (NullReferenceException)
626 rootPart.SalePrice = 10; 752 {
753 string isAttachment = "";
627 754
628 if (m_Scene.Permissions.PropagatePermissions()) 755 if (attachment)
756 isAttachment = " Object was an attachment";
757
758 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment);
759 }
760
761 // Since renaming the item in the inventory does not
762 // affect the name stored in the serialization, transfer
763 // the correct name from the inventory to the
764 // object itself before we rez.
765 rootPart.Name = item.Name;
766 rootPart.Description = item.Description;
767 rootPart.ObjectSaleType = item.SaleType;
768 rootPart.SalePrice = item.SalePrice;
769
770 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
771 if ((rootPart.OwnerID != item.Owner) ||
772 (item.CurrentPermissions & 16) != 0)
629 { 773 {
630 foreach (SceneObjectPart part in group.Parts) 774 //Need to kill the for sale here
775 rootPart.ObjectSaleType = 0;
776 rootPart.SalePrice = 10;
777
778 if (m_Scene.Permissions.PropagatePermissions())
631 { 779 {
632 part.EveryoneMask = item.EveryOnePermissions; 780 foreach (SceneObjectPart part in group.Parts)
633 part.NextOwnerMask = item.NextPermissions; 781 {
634 part.GroupMask = 0; // DO NOT propagate here 782 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
783 {
784 part.EveryoneMask = item.EveryOnePermissions;
785 part.NextOwnerMask = item.NextPermissions;
786 }
787 part.GroupMask = 0; // DO NOT propagate here
788 }
789
790 group.ApplyNextOwnerPermissions();
635 } 791 }
636
637 group.ApplyNextOwnerPermissions();
638 } 792 }
639 }
640 793
641 foreach (SceneObjectPart part in group.Parts) 794 foreach (SceneObjectPart part in group.Parts)
642 {
643 if ((part.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0)
644 { 795 {
645 part.LastOwnerID = part.OwnerID; 796 if ((part.OwnerID != item.Owner) ||
646 part.OwnerID = item.Owner; 797 (item.CurrentPermissions & 16) != 0)
647 part.Inventory.ChangeInventoryOwner(item.Owner); 798 {
648 part.GroupMask = 0; // DO NOT propagate here 799 part.LastOwnerID = part.OwnerID;
800 part.OwnerID = item.Owner;
801 part.Inventory.ChangeInventoryOwner(item.Owner);
802 part.GroupMask = 0; // DO NOT propagate here
803 }
804 part.EveryoneMask = item.EveryOnePermissions;
805 part.NextOwnerMask = item.NextPermissions;
649 } 806 }
650 part.EveryoneMask = item.EveryOnePermissions;
651 part.NextOwnerMask = item.NextPermissions;
652 }
653 807
654 rootPart.TrimPermissions(); 808 rootPart.TrimPermissions();
655 809
656 if (!attachment) 810 if (!attachment)
657 {
658 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
659 { 811 {
660 group.ClearPartAttachmentData(); 812 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
661 } 813 {
662 814 // Save attachment data
663 // Fire on_rez 815 group.RootPart.AttachPoint = group.RootPart.Shape.State;
664 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); 816 group.RootPart.AttachOffset = storedPosition;
665 rootPart.ParentGroup.ResumeScripts();
666 817
667 rootPart.ScheduleFullUpdate(); 818 group.ClearPartAttachmentData();
819 }
820
821 // Fire on_rez
822 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
823 rootPart.ParentGroup.ResumeScripts();
824
825 rootPart.ScheduleFullUpdate();
826 }
668 } 827 }
669 828
670 if (!m_Scene.Permissions.BypassPermissions()) 829 if (!m_Scene.Permissions.BypassPermissions())
@@ -682,9 +841,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
682 } 841 }
683 } 842 }
684 } 843 }
685
686 return rootPart.ParentGroup;
687 } 844 }
845 return group;
688 } 846 }
689 847
690 return null; 848 return null;
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 9b565ed..1fd1f47 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -142,7 +142,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
142 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 142 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
143 return urlcode; 143 return urlcode;
144 } 144 }
145 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/"; 145 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString();
146 146
147 UrlData urlData = new UrlData(); 147 UrlData urlData = new UrlData();
148 urlData.hostID = host.UUID; 148 urlData.hostID = host.UUID;
@@ -152,10 +152,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
152 urlData.urlcode = urlcode; 152 urlData.urlcode = urlcode;
153 urlData.requests = new Dictionary<UUID, RequestData>(); 153 urlData.requests = new Dictionary<UUID, RequestData>();
154 154
155
156 m_UrlMap[url] = urlData; 155 m_UrlMap[url] = urlData;
157 156
158 string uri = "/lslhttp/" + urlcode.ToString() + "/"; 157 string uri = "/lslhttp/" + urlcode.ToString();
159 158
160 m_HttpServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll, 159 m_HttpServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll,
161 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents, 160 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents,
@@ -386,6 +385,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
386 385
387 return response; 386 return response;
388 } 387 }
388
389 public void HttpRequestHandler(UUID requestID, Hashtable request) 389 public void HttpRequestHandler(UUID requestID, Hashtable request)
390 { 390 {
391 lock (request) 391 lock (request)
@@ -400,8 +400,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
400 400
401 int pos1 = uri.IndexOf("/");// /lslhttp 401 int pos1 = uri.IndexOf("/");// /lslhttp
402 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ 402 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/
403 int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp/<UUID>/ 403 int pos3 = pos2 + 37; // /lslhttp/urlcode
404 string uri_tmp = uri.Substring(0, pos3 + 1); 404 string uri_tmp = uri.Substring(0, pos3);
405 //HTTP server code doesn't provide us with QueryStrings 405 //HTTP server code doesn't provide us with QueryStrings
406 string pathInfo; 406 string pathInfo;
407 string queryString; 407 string queryString;
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index e54ee02..ebfba2b 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -57,9 +57,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
57 config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector"); 57 config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector");
58 config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); 58 config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService");
59 config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); 59 config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
60 config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion"); 60 config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion");
61 config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion"); 61 config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion");
62 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); 62 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion");
63 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); 63 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion");
64 64
65 m_LocalConnector = new LocalGridServicesConnector(config); 65 m_LocalConnector = new LocalGridServicesConnector(config);
@@ -128,8 +128,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
128 Assert.IsNotNull(result, "Retrieved GetRegionByName is null"); 128 Assert.IsNotNull(result, "Retrieved GetRegionByName is null");
129 Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match"); 129 Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match");
130 130
131 m_LocalConnector.RegisterRegion(UUID.Zero, r2); 131 m_LocalConnector.RegisterRegion(UUID.Zero, r2);
132 m_LocalConnector.RegisterRegion(UUID.Zero, r3); 132 m_LocalConnector.RegisterRegion(UUID.Zero, r3);
133 m_LocalConnector.RegisterRegion(UUID.Zero, r4); 133 m_LocalConnector.RegisterRegion(UUID.Zero, r4);
134 134
135 result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1)); 135 result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1));
@@ -154,38 +154,38 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
154 Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null"); 154 Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null");
155 Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected"); 155 Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected");
156 156
157 results = m_LocalConnector.GetDefaultRegions(UUID.Zero); 157 results = m_LocalConnector.GetDefaultRegions(UUID.Zero);
158 Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null"); 158 Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null");
159 Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size"); 159 Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size");
160 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match"); 160 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match");
161 161
162 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY); 162 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY);
163 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null"); 163 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null");
164 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size"); 164 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size");
165 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 165 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions for default region are not in the expected order 2-4-3");
166 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 166 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3");
167 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 167 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3");
168 168
169 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY); 169 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY);
170 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null"); 170 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null");
171 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size"); 171 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size");
172 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3"); 172 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3");
173 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3"); 173 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3");
174 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3"); 174 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3");
175 175
176 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY); 176 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY);
177 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null"); 177 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null");
178 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size"); 178 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size");
179 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2"); 179 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2");
180 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2"); 180 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2");
181 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2"); 181 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2");
182 182
183 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY); 183 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY);
184 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null"); 184 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null");
185 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size"); 185 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size");
186 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2"); 186 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2");
187 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2"); 187 Assert.That(results[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2");
188 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2"); 188 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2");
189 189
190 results = m_LocalConnector.GetHyperlinks(UUID.Zero); 190 results = m_LocalConnector.GetHyperlinks(UUID.Zero);
191 Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null"); 191 Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null");
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index e32dbb3..329a259 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -290,6 +290,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
290 return false; 290 return false;
291 } 291 }
292 292
293 public bool CloseChildAgent(GridRegion destination, UUID id)
294 {
295 if (destination == null)
296 return false;
297
298 foreach (Scene s in m_sceneList)
299 {
300 if (s.RegionInfo.RegionID == destination.RegionID)
301 {
302 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent");
303 return s.IncomingCloseChildAgent(id);
304 }
305 }
306 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
307 return false;
308 }
309
293 /** 310 /**
294 * Object-related communications 311 * Object-related communications
295 */ 312 */
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
index 3f577f2..e16e273 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -252,6 +252,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
252 return false; 252 return false;
253 } 253 }
254 254
255 public bool CloseChildAgent(GridRegion destination, UUID id)
256 {
257 if (destination == null)
258 return false;
259
260 // Try local first
261 if (m_localBackend.CloseChildAgent(destination, id))
262 return true;
263
264 // else do the remote thing
265 if (!m_localBackend.IsLocalRegion(destination.RegionHandle))
266 return m_remoteConnector.CloseChildAgent(destination, id);
267
268 return false;
269 }
255 270
256 public bool CloseAgent(GridRegion destination, UUID id) 271 public bool CloseAgent(GridRegion destination, UUID id)
257 { 272 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
index e7cfda1..0da3f5f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
57 if (account != null) 57 if (account != null)
58 m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS); 58 m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, CACHE_EXPIRATION_SECONDS);
59 59
60 m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); 60 // m_log.DebugFormat("[USER CACHE]: cached user {0}", userID);
61 } 61 }
62 62
63 public UserAccount Get(UUID userID, out bool inCache) 63 public UserAccount Get(UUID userID, out bool inCache)
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index f1f5258..7d77a77 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -269,6 +269,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
269 // being no copy/no mod for everyone 269 // being no copy/no mod for everyone
270 lock (part.TaskInventory) 270 lock (part.TaskInventory)
271 { 271 {
272 if (!ResolveUserUuid(part.CreatorID))
273 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
274
275 if (!ResolveUserUuid(part.OwnerID))
276 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
277
278 if (!ResolveUserUuid(part.LastOwnerID))
279 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
280
281 // And zap any troublesome sit target information
282 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
283 part.SitTargetPosition = new Vector3(0, 0, 0);
284
285 // Fix ownership/creator of inventory items
286 // Not doing so results in inventory items
287 // being no copy/no mod for everyone
288 part.TaskInventory.LockItemsForRead(true);
272 TaskInventoryDictionary inv = part.TaskInventory; 289 TaskInventoryDictionary inv = part.TaskInventory;
273 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) 290 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
274 { 291 {
@@ -281,6 +298,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
281 kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; 298 kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
282 } 299 }
283 } 300 }
301 part.TaskInventory.LockItemsForRead(false);
284 } 302 }
285 } 303 }
286 304
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index 1bf0d67..9df13d8 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -29,6 +29,7 @@ using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Security; 31using System.Security;
32using System.Timers;
32using log4net; 33using log4net;
33using Nini.Config; 34using Nini.Config;
34using OpenMetaverse; 35using OpenMetaverse;
@@ -45,6 +46,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
45 private delegate void LookupUUIDS(List<UUID> uuidLst); 46 private delegate void LookupUUIDS(List<UUID> uuidLst);
46 47
47 private Scene m_scene; 48 private Scene m_scene;
49 private Timer m_regionChangeTimer = new Timer();
48 50
49 private EstateTerrainXferHandler TerrainUploader; 51 private EstateTerrainXferHandler TerrainUploader;
50 52
@@ -250,7 +252,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
250 252
251 if ((estateAccessType & 4) != 0) // User add 253 if ((estateAccessType & 4) != 0) // User add
252 { 254 {
253 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 255 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
254 { 256 {
255 m_scene.RegionInfo.EstateSettings.AddEstateUser(user); 257 m_scene.RegionInfo.EstateSettings.AddEstateUser(user);
256 m_scene.RegionInfo.EstateSettings.Save(); 258 m_scene.RegionInfo.EstateSettings.Save();
@@ -265,7 +267,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
265 } 267 }
266 if ((estateAccessType & 8) != 0) // User remove 268 if ((estateAccessType & 8) != 0) // User remove
267 { 269 {
268 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 270 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
269 { 271 {
270 m_scene.RegionInfo.EstateSettings.RemoveEstateUser(user); 272 m_scene.RegionInfo.EstateSettings.RemoveEstateUser(user);
271 m_scene.RegionInfo.EstateSettings.Save(); 273 m_scene.RegionInfo.EstateSettings.Save();
@@ -280,7 +282,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
280 } 282 }
281 if ((estateAccessType & 16) != 0) // Group add 283 if ((estateAccessType & 16) != 0) // Group add
282 { 284 {
283 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 285 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
284 { 286 {
285 m_scene.RegionInfo.EstateSettings.AddEstateGroup(user); 287 m_scene.RegionInfo.EstateSettings.AddEstateGroup(user);
286 m_scene.RegionInfo.EstateSettings.Save(); 288 m_scene.RegionInfo.EstateSettings.Save();
@@ -294,7 +296,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
294 } 296 }
295 if ((estateAccessType & 32) != 0) // Group remove 297 if ((estateAccessType & 32) != 0) // Group remove
296 { 298 {
297 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, true) || m_scene.Permissions.BypassPermissions()) 299 if (m_scene.Permissions.CanIssueEstateCommand(remote_client.AgentId, false) || m_scene.Permissions.BypassPermissions())
298 { 300 {
299 m_scene.RegionInfo.EstateSettings.RemoveEstateGroup(user); 301 m_scene.RegionInfo.EstateSettings.RemoveEstateGroup(user);
300 m_scene.RegionInfo.EstateSettings.Save(); 302 m_scene.RegionInfo.EstateSettings.Save();
@@ -343,7 +345,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
343 { 345 {
344 if (!s.IsChildAgent) 346 if (!s.IsChildAgent)
345 { 347 {
346 m_scene.TeleportClientHome(user, s.ControllingClient); 348 if (!m_scene.TeleportClientHome(user, s.ControllingClient))
349 {
350 s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
351 s.ControllingClient.Close();
352 }
347 } 353 }
348 } 354 }
349 355
@@ -477,7 +483,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
477 ScenePresence s = m_scene.GetScenePresence(prey); 483 ScenePresence s = m_scene.GetScenePresence(prey);
478 if (s != null) 484 if (s != null)
479 { 485 {
480 m_scene.TeleportClientHome(prey, s.ControllingClient); 486 if (!m_scene.TeleportClientHome(prey, s.ControllingClient))
487 {
488 s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
489 s.ControllingClient.Close();
490 }
481 } 491 }
482 } 492 }
483 } 493 }
@@ -496,7 +506,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
496 // Also make sure they are actually in the region 506 // Also make sure they are actually in the region
497 if (p != null && !p.IsChildAgent) 507 if (p != null && !p.IsChildAgent)
498 { 508 {
499 m_scene.TeleportClientHome(p.UUID, p.ControllingClient); 509 if (!m_scene.TeleportClientHome(p.UUID, p.ControllingClient))
510 {
511 p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
512 p.ControllingClient.Close();
513 }
500 } 514 }
501 } 515 }
502 }); 516 });
@@ -899,6 +913,9 @@ namespace OpenSim.Region.CoreModules.World.Estate
899 m_scene.RegisterModuleInterface<IEstateModule>(this); 913 m_scene.RegisterModuleInterface<IEstateModule>(this);
900 m_scene.EventManager.OnNewClient += EventManager_OnNewClient; 914 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
901 m_scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight; 915 m_scene.EventManager.OnRequestChangeWaterHeight += changeWaterHeight;
916 m_regionChangeTimer.AutoReset = false;
917 m_regionChangeTimer.Interval = 2000;
918 m_regionChangeTimer.Elapsed += RaiseRegionInfoChange;
902 919
903 m_scene.AddCommand(this, "set terrain texture", 920 m_scene.AddCommand(this, "set terrain texture",
904 "set terrain texture <number> <uuid> [<x>] [<y>]", 921 "set terrain texture <number> <uuid> [<x>] [<y>]",
@@ -1169,6 +1186,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1169 1186
1170 protected void TriggerRegionInfoChange() 1187 protected void TriggerRegionInfoChange()
1171 { 1188 {
1189 m_regionChangeTimer.Stop();
1190 m_regionChangeTimer.Start();
1191 }
1192
1193 protected void RaiseRegionInfoChange(object sender, ElapsedEventArgs e)
1194 {
1172 ChangeDelegate change = OnRegionInfoChange; 1195 ChangeDelegate change = OnRegionInfoChange;
1173 1196
1174 if (change != null) 1197 if (change != null)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index 634685a..5bd72ee 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -85,6 +85,8 @@ namespace OpenSim.Region.CoreModules.World.Land
85 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 85 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
86 86
87 private bool m_allowedForcefulBans = true; 87 private bool m_allowedForcefulBans = true;
88 private UUID DefaultGodParcelGroup;
89 private string DefaultGodParcelName;
88 90
89 // caches ExtendedLandData 91 // caches ExtendedLandData
90 private Cache parcelInfoCache; 92 private Cache parcelInfoCache;
@@ -99,6 +101,12 @@ namespace OpenSim.Region.CoreModules.World.Land
99 101
100 public void Initialise(IConfigSource source) 102 public void Initialise(IConfigSource source)
101 { 103 {
104 IConfig cnf = source.Configs["LandManagement"];
105 if (cnf != null)
106 {
107 DefaultGodParcelGroup = new UUID(cnf.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString()));
108 DefaultGodParcelName = cnf.GetString("DefaultAdministratorParcelName", "Default Parcel");
109 }
102 } 110 }
103 111
104 public void AddRegion(Scene scene) 112 public void AddRegion(Scene scene)
@@ -350,7 +358,7 @@ namespace OpenSim.Region.CoreModules.World.Land
350 { 358 {
351 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT) 359 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT)
352 { 360 {
353 if (parcelAvatarIsEntering.IsBannedFromLand(avatar.UUID)) 361 if (parcelAvatarIsEntering.IsEitherBannedOrRestricted(avatar.UUID))
354 { 362 {
355 SendYouAreBannedNotice(avatar); 363 SendYouAreBannedNotice(avatar);
356 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar)); 364 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar));
@@ -647,7 +655,7 @@ namespace OpenSim.Region.CoreModules.World.Land
647 int x; 655 int x;
648 int y; 656 int y;
649 657
650 if (x_float > Constants.RegionSize || x_float <= 0 || y_float > Constants.RegionSize || y_float <= 0) 658 if (x_float > Constants.RegionSize || x_float < 0 || y_float > Constants.RegionSize || y_float < 0)
651 return null; 659 return null;
652 660
653 try 661 try
@@ -990,6 +998,10 @@ namespace OpenSim.Region.CoreModules.World.Land
990 //Owner Flag 998 //Owner Flag
991 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 999 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
992 } 1000 }
1001 else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID))
1002 {
1003 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_GROUP);
1004 }
993 else if (currentParcelBlock.LandData.SalePrice > 0 && 1005 else if (currentParcelBlock.LandData.SalePrice > 0 &&
994 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || 1006 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
995 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) 1007 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
@@ -1292,18 +1304,31 @@ namespace OpenSim.Region.CoreModules.World.Land
1292 1304
1293 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1305 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1294 { 1306 {
1295 for (int i = 0; i < data.Count; i++) 1307 lock (m_landList)
1296 { 1308 {
1297 IncomingLandObjectFromStorage(data[i]); 1309 //Remove all the land objects in the sim and then process our new data
1310 foreach (int n in m_landList.Keys)
1311 {
1312 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[n].LandData.GlobalID);
1313 }
1314 m_landIDList.Initialize();
1315 m_landList.Clear();
1316
1317 for (int i = 0; i < data.Count; i++)
1318 {
1319 IncomingLandObjectFromStorage(data[i]);
1320 }
1298 } 1321 }
1299 } 1322 }
1300 1323
1301 public void IncomingLandObjectFromStorage(LandData data) 1324 public void IncomingLandObjectFromStorage(LandData data)
1302 { 1325 {
1326
1303 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1327 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1304 new_land.LandData = data.Copy(); 1328 new_land.LandData = data.Copy();
1305 new_land.SetLandBitmapFromByteArray(); 1329 new_land.SetLandBitmapFromByteArray();
1306 AddLandObject(new_land); 1330 AddLandObject(new_land);
1331 new_land.SendLandUpdateToAvatarsOverMe();
1307 } 1332 }
1308 1333
1309 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) 1334 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
@@ -1576,5 +1601,321 @@ namespace OpenSim.Region.CoreModules.World.Land
1576 1601
1577 UpdateLandObject(localID, land.LandData); 1602 UpdateLandObject(localID, land.LandData);
1578 } 1603 }
1604
1605 public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
1606 {
1607 ILandObject land = null;
1608 List<ILandObject> Land = ((Scene)client.Scene).LandChannel.AllParcels();
1609 foreach (ILandObject landObject in Land)
1610 {
1611 if (landObject.LandData.LocalID == landID)
1612 {
1613 land = landObject;
1614 }
1615 }
1616 land.DeedToGroup(DefaultGodParcelGroup);
1617 land.LandData.Name = DefaultGodParcelName;
1618 land.SendLandUpdateToAvatarsOverMe();
1619 }
1620
1621 private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID)
1622 {
1623 ScenePresence SP;
1624 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out SP);
1625 List<SceneObjectGroup> returns = new List<SceneObjectGroup>();
1626 if (SP.GodLevel != 0)
1627 {
1628 if (flags == 0) //All parcels, scripted or not
1629 {
1630 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1631 {
1632 if (e.OwnerID == targetID)
1633 {
1634 returns.Add(e);
1635 }
1636 }
1637 );
1638 }
1639 if (flags == 4) //All parcels, scripted object
1640 {
1641 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1642 {
1643 if (e.OwnerID == targetID)
1644 {
1645 if (e.scriptScore >= 0.01)
1646 {
1647 returns.Add(e);
1648 }
1649 }
1650 }
1651 );
1652 }
1653 if (flags == 4) //not target parcel, scripted object
1654 {
1655 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1656 {
1657 if (e.OwnerID == targetID)
1658 {
1659 ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y);
1660 if (landobject.LandData.OwnerID != e.OwnerID)
1661 {
1662 if (e.scriptScore >= 0.01)
1663 {
1664 returns.Add(e);
1665 }
1666 }
1667 }
1668 }
1669 );
1670 }
1671 foreach (SceneObjectGroup ol in returns)
1672 {
1673 ReturnObject(ol, client);
1674 }
1675 }
1676 }
1677 public void ReturnObject(SceneObjectGroup obj, IClientAPI client)
1678 {
1679 SceneObjectGroup[] objs = new SceneObjectGroup[1];
1680 objs[0] = obj;
1681 ((Scene)client.Scene).returnObjects(objs, client.AgentId);
1682 }
1683
1684 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1685
1686 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1687 {
1688 ScenePresence targetAvatar = null;
1689 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1690 ScenePresence parcelManager = null;
1691 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1692 System.Threading.Timer Timer;
1693
1694 if (targetAvatar.GodLevel == 0)
1695 {
1696 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1697 if (!((Scene)client.Scene).Permissions.CanEditParcel(client.AgentId, land))
1698 return;
1699 if (flags == 0)
1700 {
1701 targetAvatar.AllowMovement = false;
1702 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1703 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1704 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1705 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1706 Timers.Add(targetAvatar.UUID, Timer);
1707 }
1708 else
1709 {
1710 targetAvatar.AllowMovement = true;
1711 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1712 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1713 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1714 Timers.Remove(targetAvatar.UUID);
1715 Timer.Dispose();
1716 }
1717 }
1718 }
1719 private void OnEndParcelFrozen(object avatar)
1720 {
1721 ScenePresence targetAvatar = (ScenePresence)avatar;
1722 targetAvatar.AllowMovement = true;
1723 System.Threading.Timer Timer;
1724 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1725 Timers.Remove(targetAvatar.UUID);
1726 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1727 }
1728
1729
1730 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1731 {
1732 ScenePresence targetAvatar = null;
1733 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1734 ScenePresence parcelManager = null;
1735 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1736 //Just eject
1737 if (flags == 0)
1738 {
1739 if (targetAvatar.GodLevel == 0)
1740 {
1741 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1742 if (!((Scene)client.Scene).Permissions.CanEditParcel(client.AgentId, land))
1743 return;
1744
1745 Vector3 position = new Vector3(0, 0, 0);
1746 List<ILandObject> allParcels = new List<ILandObject>();
1747 allParcels = AllParcels();
1748 if (allParcels.Count != 1)
1749 {
1750 foreach (ILandObject parcel in allParcels)
1751 {
1752 if (parcel.LandData.GlobalID != land.LandData.GlobalID)
1753 {
1754 if (parcel.IsEitherBannedOrRestricted(targetAvatar.UUID) != true)
1755 {
1756 for (int x = 1; x <= Constants.RegionSize; x += 2)
1757 {
1758 for (int y = 1; y <= Constants.RegionSize; y += 2)
1759 {
1760 if (parcel.ContainsPoint(x, y))
1761 {
1762 position = new Vector3(x, y, targetAvatar.AbsolutePosition.Z);
1763 targetAvatar.TeleportWithMomentum(position);
1764 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1765 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1766 return;
1767 }
1768 }
1769 }
1770 }
1771 }
1772 }
1773 }
1774 Vector3 targetVector;
1775 if (targetAvatar.AbsolutePosition.X > targetAvatar.AbsolutePosition.Y)
1776 {
1777 if (targetAvatar.AbsolutePosition.X > .5 * Constants.RegionSize)
1778 {
1779 targetVector = new Vector3(Constants.RegionSize, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1780 targetAvatar.TeleportWithMomentum(targetVector);
1781 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1782 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1783 return;
1784 }
1785 else
1786 {
1787 targetVector = new Vector3(0, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1788 targetAvatar.TeleportWithMomentum(targetVector);
1789 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1790 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1791 return;
1792 }
1793 }
1794 else
1795 {
1796 if (targetAvatar.AbsolutePosition.Y > .5 * Constants.RegionSize)
1797 {
1798 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, Constants.RegionSize, targetAvatar.AbsolutePosition.Z); ;
1799 targetAvatar.TeleportWithMomentum(targetVector);
1800 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1801 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1802 return;
1803 }
1804 else
1805 {
1806 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, 0, targetAvatar.AbsolutePosition.Z); ;
1807 targetAvatar.TeleportWithMomentum(targetVector);
1808 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1809 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1810 return;
1811 }
1812 }
1813 }
1814 }
1815 //Eject and ban
1816 if (flags == 1)
1817 {
1818 if (targetAvatar.GodLevel == 0)
1819 {
1820 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1821 if (!((Scene)client.Scene).Permissions.CanEditParcel(client.AgentId, land))
1822 return;
1823
1824 Vector3 position = new Vector3(0, 0, 0);
1825 List<ILandObject> allParcels = new List<ILandObject>();
1826 allParcels = AllParcels();
1827 if (allParcels.Count != 1)
1828 {
1829 foreach (ILandObject parcel in allParcels)
1830 {
1831 if (parcel.LandData.GlobalID != land.LandData.GlobalID)
1832 {
1833 if (parcel.IsEitherBannedOrRestricted(targetAvatar.UUID) != true)
1834 {
1835 for (int x = 1; x <= Constants.RegionSize; x += 2)
1836 {
1837 for (int y = 1; y <= Constants.RegionSize; y += 2)
1838 {
1839 if (parcel.ContainsPoint(x, y))
1840 {
1841 position = new Vector3(x, y, targetAvatar.AbsolutePosition.Z);
1842 targetAvatar.TeleportWithMomentum(position);
1843 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1844 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1845 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1846 entry.AgentID = targetAvatar.UUID;
1847 entry.Flags = AccessList.Ban;
1848 entry.Time = new DateTime();
1849 land.LandData.ParcelAccessList.Add(entry);
1850 return;
1851 }
1852 }
1853 }
1854 }
1855 }
1856 }
1857 }
1858 Vector3 targetVector;
1859 if (targetAvatar.AbsolutePosition.X > targetAvatar.AbsolutePosition.Y)
1860 {
1861 if (targetAvatar.AbsolutePosition.X > .5 * Constants.RegionSize)
1862 {
1863 targetVector = new Vector3(Constants.RegionSize, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1864 targetAvatar.TeleportWithMomentum(targetVector);
1865 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1866 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1867 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1868 entry.AgentID = targetAvatar.UUID;
1869 entry.Flags = AccessList.Ban;
1870 entry.Time = new DateTime();
1871 land.LandData.ParcelAccessList.Add(entry);
1872 return;
1873 }
1874 else
1875 {
1876 targetVector = new Vector3(0, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1877 targetAvatar.TeleportWithMomentum(targetVector);
1878 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1879 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1880 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1881 entry.AgentID = targetAvatar.UUID;
1882 entry.Flags = AccessList.Ban;
1883 entry.Time = new DateTime();
1884 land.LandData.ParcelAccessList.Add(entry);
1885 return;
1886 }
1887 }
1888 else
1889 {
1890 if (targetAvatar.AbsolutePosition.Y > .5 * Constants.RegionSize)
1891 {
1892 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, Constants.RegionSize, targetAvatar.AbsolutePosition.Z); ;
1893 targetAvatar.TeleportWithMomentum(targetVector);
1894 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1895 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1896 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1897 entry.AgentID = targetAvatar.UUID;
1898 entry.Flags = AccessList.Ban;
1899 entry.Time = new DateTime();
1900 land.LandData.ParcelAccessList.Add(entry);
1901 return;
1902 }
1903 else
1904 {
1905 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, 0, targetAvatar.AbsolutePosition.Z); ;
1906 targetAvatar.TeleportWithMomentum(targetVector);
1907 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1908 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1909 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1910 entry.AgentID = targetAvatar.UUID;
1911 entry.Flags = AccessList.Ban;
1912 entry.Time = new DateTime();
1913 land.LandData.ParcelAccessList.Add(entry);
1914 return;
1915 }
1916 }
1917 }
1918 }
1919 }
1579 } 1920 }
1580} 1921}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index d87352f..bd1dd66 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -288,6 +288,34 @@ namespace OpenSim.Region.CoreModules.World.Land
288 return false; 288 return false;
289 } 289 }
290 290
291 public bool HasGroupAccess(UUID avatar)
292 {
293 if ((LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
294 {
295 IGroupsModule groupsModule =
296 m_scene.RequestModuleInterface<IGroupsModule>();
297
298 List<UUID> agentGroups = new List<UUID>();
299 if (groupsModule != null)
300 {
301 GroupMembershipData[] GroupMembership =
302 groupsModule.GetMembershipData(avatar);
303
304 if (GroupMembership != null)
305 {
306 for (int i = 0; i < GroupMembership.Length; i++)
307 {
308 if (LandData.GroupID == GroupMembership[i].GroupID)
309 {
310 return true;
311 }
312 }
313 }
314 }
315 }
316 return false;
317 }
318
291 public bool IsBannedFromLand(UUID avatar) 319 public bool IsBannedFromLand(UUID avatar)
292 { 320 {
293 if (m_scene.Permissions.IsAdministrator(avatar)) 321 if (m_scene.Permissions.IsAdministrator(avatar))
@@ -324,10 +352,14 @@ namespace OpenSim.Region.CoreModules.World.Land
324 //If they are not on the access list and are not the owner 352 //If they are not on the access list and are not the owner
325 if (!LandData.ParcelAccessList.Contains(entry) && LandData.OwnerID != avatar) 353 if (!LandData.ParcelAccessList.Contains(entry) && LandData.OwnerID != avatar)
326 { 354 {
327 //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel 355 if (!HasGroupAccess(avatar))
328 return true; 356 {
357 //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel
358 return true;
359 }
329 } 360 }
330 } 361 }
362
331 return false; 363 return false;
332 } 364 }
333 365
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index f5f3839..289741f 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -412,7 +412,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
412 412
413 public string Name 413 public string Name
414 { 414 {
415 get { return "PermissionsModule"; } 415 get { return "DefaultPermissionsModule"; }
416 } 416 }
417 417
418 public bool IsSharedModule 418 public bool IsSharedModule
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 25d73c2..4611352 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -549,6 +549,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
549 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); 549 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
550 m_scene.SaveTerrain(); 550 m_scene.SaveTerrain();
551 551
552 m_scene.EventManager.TriggerTerrainUpdate();
553
552 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. 554 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
553 //m_scene.CreateTerrainTexture(true); 555 //m_scene.CreateTerrainTexture(true);
554 } 556 }
diff --git a/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs b/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs
index e951bef..7a0ce51 100644
--- a/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs
+++ b/OpenSim/Region/Examples/SimpleModule/ComplexObject.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Collections.Generic;
28using OpenMetaverse; 29using OpenMetaverse;
29using OpenSim.Framework; 30using OpenSim.Framework;
30using OpenSim.Region.Framework.Scenes; 31using OpenSim.Region.Framework.Scenes;
@@ -110,7 +111,7 @@ namespace OpenSim.Region.Examples.SimpleModule
110 { 111 {
111 m_parts.Remove(part.UUID); 112 m_parts.Remove(part.UUID);
112 113
113 remoteClient.SendKillObject(m_regionHandle, part.LocalId); 114 remoteClient.SendKillObject(m_regionHandle, new List<uint>() { part.LocalId} );
114 remoteClient.AddMoney(1); 115 remoteClient.AddMoney(1);
115 remoteClient.SendChatMessage("Poof!", 1, AbsolutePosition, "Party Party", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); 116 remoteClient.SendChatMessage("Poof!", 1, AbsolutePosition, "Party Party", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
116 } 117 }
@@ -121,7 +122,7 @@ namespace OpenSim.Region.Examples.SimpleModule
121 { 122 {
122 m_parts.Remove(m_rootPart.UUID); 123 m_parts.Remove(m_rootPart.UUID);
123 m_scene.DeleteSceneObject(this, false); 124 m_scene.DeleteSceneObject(this, false);
124 remoteClient.SendKillObject(m_regionHandle, m_rootPart.LocalId); 125 remoteClient.SendKillObject(m_regionHandle, new List<uint>() { m_rootPart.LocalId });
125 remoteClient.AddMoney(50); 126 remoteClient.AddMoney(50);
126 remoteClient.SendChatMessage("KABLAM!!!", 1, AbsolutePosition, "Groupie Groupie", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); 127 remoteClient.SendChatMessage("KABLAM!!!", 1, AbsolutePosition, "Groupie Groupie", UUID.Zero, (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
127 } 128 }
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 268612e..db427b4 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -79,7 +79,7 @@ namespace OpenSim.Region.Examples.SimpleModule
79 public event DisconnectUser OnDisconnectUser; 79 public event DisconnectUser OnDisconnectUser;
80 public event RequestAvatarProperties OnRequestAvatarProperties; 80 public event RequestAvatarProperties OnRequestAvatarProperties;
81 public event SetAlwaysRun OnSetAlwaysRun; 81 public event SetAlwaysRun OnSetAlwaysRun;
82 82 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
83 public event DeRezObject OnDeRezObject; 83 public event DeRezObject OnDeRezObject;
84 public event Action<IClientAPI> OnRegionHandShakeReply; 84 public event Action<IClientAPI> OnRegionHandShakeReply;
85 public event GenericCall2 OnRequestWearables; 85 public event GenericCall2 OnRequestWearables;
@@ -429,7 +429,7 @@ namespace OpenSim.Region.Examples.SimpleModule
429 429
430 } 430 }
431 431
432 public virtual void SendKillObject(ulong regionHandle, uint localID) 432 public virtual void SendKillObject(ulong regionHandle, List<uint> localID)
433 { 433 {
434 } 434 }
435 435
@@ -821,12 +821,21 @@ namespace OpenSim.Region.Examples.SimpleModule
821 { 821 {
822 } 822 }
823 823
824 public void ProcessPendingPackets()
825 {
826 }
827
824 public void ProcessInPacket(Packet NewPack) 828 public void ProcessInPacket(Packet NewPack)
825 { 829 {
826 } 830 }
827 831
828 public void Close() 832 public void Close()
829 { 833 {
834 Close(true);
835 }
836
837 public void Close(bool sendStop)
838 {
830 } 839 }
831 840
832 public void Start() 841 public void Start()
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 24e481b..a675928 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Xml;
29using OpenMetaverse; 30using OpenMetaverse;
30using OpenMetaverse.Packets; 31using OpenMetaverse.Packets;
31using OpenSim.Framework; 32using OpenSim.Framework;
@@ -82,6 +83,10 @@ namespace OpenSim.Region.Framework.Interfaces
82 UUID RezSingleAttachmentFromInventory( 83 UUID RezSingleAttachmentFromInventory(
83 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); 84 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus);
84 85
86 // Same as above, but also load script states from a separate doc
87 UUID RezSingleAttachmentFromInventory(
88 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc);
89
85 /// <summary> 90 /// <summary>
86 /// Rez multiple attachments from a user's inventory 91 /// Rez multiple attachments from a user's inventory
87 /// </summary> 92 /// </summary>
@@ -129,4 +134,4 @@ namespace OpenSim.Region.Framework.Interfaces
129 /// <param name="pos"></param> 134 /// <param name="pos"></param>
130 void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos); 135 void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos);
131 } 136 }
132} \ No newline at end of file 137}
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
index 2e6faa0..59ce090 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
@@ -115,6 +115,8 @@ namespace OpenSim.Region.Framework.Interfaces
115 /// <param name="stateSource"></param> 115 /// <param name="stateSource"></param>
116 void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); 116 void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource);
117 117
118 ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource);
119
118 /// <summary> 120 /// <summary>
119 /// Stop a script which is in this prim's inventory. 121 /// Stop a script which is in this prim's inventory.
120 /// </summary> 122 /// </summary>
@@ -235,5 +237,6 @@ namespace OpenSim.Region.Framework.Interfaces
235 /// A <see cref="Dictionary`2"/> 237 /// A <see cref="Dictionary`2"/>
236 /// </returns> 238 /// </returns>
237 Dictionary<UUID, string> GetScriptStates(); 239 Dictionary<UUID, string> GetScriptStates();
240 Dictionary<UUID, string> GetScriptStates(bool oldIDs);
238 } 241 }
239} 242}
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
index e8738c4..45ca5c5 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
@@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Interfaces
40 void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, 40 void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position,
41 Vector3 lookAt, uint teleportFlags); 41 Vector3 lookAt, uint teleportFlags);
42 42
43 void TeleportHome(UUID id, IClientAPI client); 43 bool TeleportHome(UUID id, IClientAPI client);
44 44
45 void Cross(ScenePresence agent, bool isFlying); 45 void Cross(ScenePresence agent, bool isFlying);
46 46
diff --git a/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs b/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs
index 2d6287f..67a500f 100644
--- a/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs
+++ b/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs
@@ -68,6 +68,14 @@ namespace OpenSim.Region.Framework.Interfaces
68 bool SendReleaseAgent(ulong regionHandle, UUID id, string uri); 68 bool SendReleaseAgent(ulong regionHandle, UUID id, string uri);
69 69
70 /// <summary> 70 /// <summary>
71 /// Close chid agent.
72 /// </summary>
73 /// <param name="regionHandle"></param>
74 /// <param name="id"></param>
75 /// <returns></returns>
76 bool SendCloseChildAgent(ulong regionHandle, UUID id);
77
78 /// <summary>
71 /// Close agent. 79 /// Close agent.
72 /// </summary> 80 /// </summary>
73 /// <param name="regionHandle"></param> 81 /// <param name="regionHandle"></param>
diff --git a/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs b/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs
new file mode 100644
index 0000000..e01f649
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/ISnmpModule.cs
@@ -0,0 +1,27 @@
1///////////////////////////////////////////////////////////////////
2//
3// (c) Careminster LImited, Melanie Thielker and the Meta7 Team
4//
5// This file is not open source. All rights reserved
6// Mod 2
7
8using OpenSim.Region.Framework.Scenes;
9
10public interface ISnmpModule
11{
12 void Trap(int code, string Message, Scene scene);
13 void Critical(string Message, Scene scene);
14 void Warning(string Message, Scene scene);
15 void Major(string Message, Scene scene);
16 void ColdStart(int step , Scene scene);
17 void Shutdown(int step , Scene scene);
18 //
19 // Node Start/stop events
20 //
21 void LinkUp(Scene scene);
22 void LinkDown(Scene scene);
23 void BootInfo(string data, Scene scene);
24 void trapDebug(string Module,string data, Scene scene);
25 void trapXMRE(int data, string Message, Scene scene);
26
27}
diff --git a/OpenSim/Region/Framework/ModuleLoader.cs b/OpenSim/Region/Framework/ModuleLoader.cs
index 23be9c2..69ba2042 100644
--- a/OpenSim/Region/Framework/ModuleLoader.cs
+++ b/OpenSim/Region/Framework/ModuleLoader.cs
@@ -226,7 +226,8 @@ namespace OpenSim.Region.Framework
226 "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e); 226 "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e);
227 227
228 // justincc: Right now this is fatal to really get the user's attention 228 // justincc: Right now this is fatal to really get the user's attention
229 throw e; 229 // TomMeta: WTF? No, how about we /don't/ throw a fatal exception when there's no need to?
230 //throw e;
230 } 231 }
231 } 232 }
232 233
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index a90e0f3..9658e11 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -53,11 +53,17 @@ namespace OpenSim.Region.Framework.Scenes.Animation
53 { 53 {
54 get { return m_movementAnimation; } 54 get { return m_movementAnimation; }
55 } 55 }
56 protected string m_movementAnimation = "DEFAULT"; 56 // protected string m_movementAnimation = "DEFAULT"; //KF: 'DEFAULT' does not exist!
57 57 protected string m_movementAnimation = "CROUCH"; //KF: CROUCH ensures reliable Av Anim. init.
58 private int m_animTickFall; 58 private int m_animTickFall;
59 private int m_animTickJump; 59// private int m_animTickJump;
60 60 public int m_animTickJump; // ScenePresence has to see this to control +Z force
61 public bool m_jumping = false; // Add for jumping
62 public float m_jumpVelocity = 0f; // Add for jumping
63 private int m_landing = 0; // Add for jumping
64 public bool m_falling = false; // Add for falling
65 private float m_fallHeight; // Add for falling
66
61 /// <value> 67 /// <value>
62 /// The scene presence that this animator applies to 68 /// The scene presence that this animator applies to
63 /// </value> 69 /// </value>
@@ -114,7 +120,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation
114 120
115 public void ResetAnimations() 121 public void ResetAnimations()
116 { 122 {
123Console.WriteLine("ResetA.............");
117 m_animations.Clear(); 124 m_animations.Clear();
125TrySetMovementAnimation("STAND");
118 } 126 }
119 127
120 /// <summary> 128 /// <summary>
@@ -123,8 +131,6 @@ namespace OpenSim.Region.Framework.Scenes.Animation
123 /// </summary> 131 /// </summary>
124 public void TrySetMovementAnimation(string anim) 132 public void TrySetMovementAnimation(string anim)
125 { 133 {
126 //m_log.DebugFormat("Updating movement animation to {0}", anim);
127
128 if (!m_scenePresence.IsChildAgent) 134 if (!m_scenePresence.IsChildAgent)
129 { 135 {
130 if (m_animations.TrySetDefaultAnimation( 136 if (m_animations.TrySetDefaultAnimation(
@@ -142,14 +148,14 @@ namespace OpenSim.Region.Framework.Scenes.Animation
142 /// </summary> 148 /// </summary>
143 public string GetMovementAnimation() 149 public string GetMovementAnimation()
144 { 150 {
145 const float FALL_DELAY = 0.33f; 151//Console.WriteLine("GMA-------"); //##
146 const float PREJUMP_DELAY = 0.25f; 152//#@ const float FALL_DELAY = 0.33f;
147 153 const float FALL_DELAY = 800f; //## mS
154//rm for jumping const float PREJUMP_DELAY = 0.25f;
155 const float PREJUMP_DELAY = 200f; // mS add for jumping
156 const float JUMP_PERIOD = 800f; // mS add for jumping
148 #region Inputs 157 #region Inputs
149 if (m_scenePresence.SitGround) 158
150 {
151 return "SIT_GROUND_CONSTRAINED";
152 }
153 AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; 159 AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags;
154 PhysicsActor actor = m_scenePresence.PhysicsActor; 160 PhysicsActor actor = m_scenePresence.PhysicsActor;
155 161
@@ -159,11 +165,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation
159 Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); 165 Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix);
160 166
161 // Check control flags 167 // Check control flags
162 bool heldForward = 168 bool heldForward = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS);
163 (((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) || ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS)); 169 bool heldBack = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG);
164 bool heldBack = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG; 170 bool heldLeft = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS);
165 bool heldLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS; 171 bool heldRight = ((controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG || (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG);
166 bool heldRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG;
167 //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; 172 //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT;
168 //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; 173 //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT;
169 bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; 174 bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS;
@@ -182,8 +187,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
182 187
183 // Is the avatar trying to move? 188 // Is the avatar trying to move?
184// bool moving = (move != Vector3.Zero); 189// bool moving = (move != Vector3.Zero);
185 bool jumping = m_animTickJump != 0; 190// rm for jumping bool jumping = m_animTickJump != 0;
186
187 #endregion Inputs 191 #endregion Inputs
188 192
189 #region Flying 193 #region Flying
@@ -192,6 +196,11 @@ namespace OpenSim.Region.Framework.Scenes.Animation
192 { 196 {
193 m_animTickFall = 0; 197 m_animTickFall = 0;
194 m_animTickJump = 0; 198 m_animTickJump = 0;
199 m_jumping = false; //add for jumping
200 m_falling = true; //add for falling
201 m_jumpVelocity = 0f; //add for jumping
202 actor.Selected = false; //add for jumping flag
203 m_fallHeight = actor.Position.Z; // save latest flying height
195 204
196 if (move.X != 0f || move.Y != 0f) 205 if (move.X != 0f || move.Y != 0f)
197 { 206 {
@@ -203,8 +212,11 @@ namespace OpenSim.Region.Framework.Scenes.Animation
203 } 212 }
204 else if (move.Z < 0f) 213 else if (move.Z < 0f)
205 { 214 {
206 if (actor != null && actor.IsColliding) 215 if (actor != null && actor.IsColliding)
216 { //##
217//Console.WriteLine("LAND FLYING"); // ##
207 return "LAND"; 218 return "LAND";
219 } //#
208 else 220 else
209 return "HOVER_DOWN"; 221 return "HOVER_DOWN";
210 } 222 }
@@ -218,19 +230,28 @@ namespace OpenSim.Region.Framework.Scenes.Animation
218 230
219 #region Falling/Floating/Landing 231 #region Falling/Floating/Landing
220 232
221 if (actor == null || !actor.IsColliding) 233// rm for jumping if (actor == null || !actor.IsColliding)
234 if ((actor == null || !actor.IsColliding) && !m_jumping) // add for jumping
222 { 235 {
223 float fallElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; 236// rm float fallElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f;
237 float fallElapsed = (float)(Environment.TickCount - m_animTickFall); // add, in mS
224 float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f; 238 float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f;
239//Console.WriteLine("falling t={0} v={1}", fallElapsed, fallVelocity); //##
240
241// rm for fall if (m_animTickFall == 0 || (fallElapsed > FALL_DELAY && fallVelocity >= 0.0f))
242 if (!m_jumping && (fallVelocity < -3.0f) ) m_falling = true; // add for falling and jumping
225 243
226 if (m_animTickFall == 0 || (fallElapsed > FALL_DELAY && fallVelocity >= 0.0f)) 244 if (m_animTickFall == 0 || (fallVelocity >= 0.0f)) // add for jumping
245 // not falling yet or going up
227 { 246 {
228 // Just started falling 247 // reset start of fall time
229 m_animTickFall = Environment.TickCount; 248 m_animTickFall = Environment.TickCount;
230 } 249 }
231 else if (!jumping && fallElapsed > FALL_DELAY) 250// else if (!jumping && fallElapsed > FALL_DELAY)
251 else if (!m_jumping && (fallElapsed > FALL_DELAY) && (fallVelocity < -3.0f) ) // add for falling and jumping
232 { 252 {
233 // Falling long enough to trigger the animation 253 // Falling long enough to trigger the animation
254//Console.WriteLine("FALLDOWN"); //##
234 return "FALLDOWN"; 255 return "FALLDOWN";
235 } 256 }
236 257
@@ -239,22 +260,97 @@ namespace OpenSim.Region.Framework.Scenes.Animation
239 260
240 #endregion Falling/Floating/Landing 261 #endregion Falling/Floating/Landing
241 262
263
264 #region Jumping // section added for jumping...
265
266 int jumptime;
267 jumptime = Environment.TickCount - m_animTickJump;
268
269
270 if ((move.Z > 0f) && (!m_jumping))
271 {
272//Console.WriteLine("PJ {0}", jumptime); //##
273 // Start jumping, prejump
274 m_animTickFall = 0;
275 m_jumping = true;
276 m_falling = false;
277 actor.Selected = true; // borrowed for jmping flag
278 m_animTickJump = Environment.TickCount;
279 m_jumpVelocity = 0.35f;
280 return "PREJUMP";
281 }
282
283 if(m_jumping)
284 {
285 if ( (jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding)
286 {
287//Console.WriteLine("LA {0}", jumptime); //##
288 // end jumping
289 m_jumping = false;
290 m_falling = false;
291 actor.Selected = false; // borrowed for jumping flag
292 m_jumpVelocity = 0f;
293 m_animTickFall = Environment.TickCount;
294 return "LAND";
295 }
296 else if (jumptime > JUMP_PERIOD)
297 {
298//Console.WriteLine("JD {0}", jumptime); //##
299 // jump down
300 m_jumpVelocity = 0f;
301 return "JUMP";
302 }
303 else if (jumptime > PREJUMP_DELAY)
304 {
305//Console.WriteLine("JU {0}", jumptime); //##
306 // jump up
307 m_jumping = true;
308 m_jumpVelocity = 10f;
309 return "JUMP";
310 }
311 }
312
313 #endregion Jumping // end added section
314
242 #region Ground Movement 315 #region Ground Movement
243 316
244 if (m_movementAnimation == "FALLDOWN") 317 if (m_movementAnimation == "FALLDOWN")
245 { 318 {
319 m_falling = false;
246 m_animTickFall = Environment.TickCount; 320 m_animTickFall = Environment.TickCount;
247
248 // TODO: SOFT_LAND support 321 // TODO: SOFT_LAND support
249 return "LAND"; 322 float fallHeight = m_fallHeight - actor.Position.Z;
323//Console.WriteLine("Hit from {0}", fallHeight); //##
324 if (fallHeight > 15.0f) // add for falling
325 return "STANDUP";
326 else if (fallHeight > 8.0f) // add for falling
327 return "SOFT_LAND"; // add for falling
328 else // add for falling
329 return "LAND"; // add for falling
250 } 330 }
251 else if (m_movementAnimation == "LAND") 331// rm jumping float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f;
332// rm jumping if ((m_animTickFall != 0) && (landElapsed <= FALL_DELAY))
333// rm for landing return "LAND";
334 else if ((m_movementAnimation == "LAND") || (m_movementAnimation == "SOFT_LAND") || (m_movementAnimation == "STANDUP"))
252 { 335 {
253 float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; 336 int landElapsed = Environment.TickCount - m_animTickFall; // add for jumping
254 if ((m_animTickFall != 0) && (landElapsed <= FALL_DELAY)) 337 int limit = 1000; // add for jumping
255 return "LAND"; 338 if(m_movementAnimation == "LAND") limit = 350; // add for jumping
256 } 339 // NB if the above is set too long a weird anim reset from some place prevents STAND from being sent to client
257 340
341 if ((m_animTickFall != 0) && (landElapsed <= limit)) // add for jumping
342 {
343//Console.WriteLine("Lelapse {0}", m_movementAnimation); //##
344 return m_movementAnimation;
345 }
346 else
347 {
348//Console.WriteLine("end/STAND"); //##
349 m_fallHeight = actor.Position.Z; // save latest flying height
350 return "STAND";
351 }
352 }
353/* This section removed, replaced by jumping section
258 m_animTickFall = 0; 354 m_animTickFall = 0;
259 355
260 if (move.Z > 0f) 356 if (move.Z > 0f)
@@ -266,7 +362,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
266 m_animTickJump = Environment.TickCount; 362 m_animTickJump = Environment.TickCount;
267 return "PREJUMP"; 363 return "PREJUMP";
268 } 364 }
269 else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 1000.0f) 365 else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 800.0f)
270 { 366 {
271 // Start actual jump 367 // Start actual jump
272 if (m_animTickJump == -1) 368 if (m_animTickJump == -1)
@@ -284,29 +380,34 @@ namespace OpenSim.Region.Framework.Scenes.Animation
284 { 380 {
285 // Not jumping 381 // Not jumping
286 m_animTickJump = 0; 382 m_animTickJump = 0;
287 383 */
288 if (move.X != 0f || move.Y != 0f) 384 // next section moved outside paren. and realigned for jumping
289 { 385 if (move.X != 0f || move.Y != 0f)
290 // Walking / crouchwalking / running 386 {
291 if (move.Z < 0f) 387 m_fallHeight = actor.Position.Z; // save latest flying height
292 return "CROUCHWALK"; 388 m_falling = false; // Add for falling
293 else if (m_scenePresence.SetAlwaysRun) 389 // Walking / crouchwalking / running
294 return "RUN"; 390 if (move.Z < 0f)
295 else 391 return "CROUCHWALK";
296 return "WALK"; 392 else if (m_scenePresence.SetAlwaysRun)
297 } 393 return "RUN";
298 else 394 else
299 { 395 return "WALK";
300 // Not walking
301 if (move.Z < 0f)
302 return "CROUCH";
303 else
304 return "STAND";
305 }
306 } 396 }
307 397// rm for jumping else
398 else if (!m_jumping) // add for jumping
399 {
400 m_falling = false; // Add for falling
401 // Not walking
402 if (move.Z < 0f)
403 return "CROUCH";
404 else
405 return "STAND";
406 }
407 // end section realign for jumping
308 #endregion Ground Movement 408 #endregion Ground Movement
309 409
410 m_falling = false; // Add for falling
310 return m_movementAnimation; 411 return m_movementAnimation;
311 } 412 }
312 413
@@ -316,16 +417,15 @@ namespace OpenSim.Region.Framework.Scenes.Animation
316 public void UpdateMovementAnimations() 417 public void UpdateMovementAnimations()
317 { 418 {
318 m_movementAnimation = GetMovementAnimation(); 419 m_movementAnimation = GetMovementAnimation();
319 420/* if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump)
320 if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump)
321 { 421 {
322 // This was the previous behavior before PREJUMP 422 // This was the previous behavior before PREJUMP
323 TrySetMovementAnimation("JUMP"); 423 TrySetMovementAnimation("JUMP");
324 } 424 }
325 else 425 else
326 { 426 { removed for jumping */
327 TrySetMovementAnimation(m_movementAnimation); 427 TrySetMovementAnimation(m_movementAnimation);
328 } 428// rm for jumping }
329 } 429 }
330 430
331 public UUID[] GetAnimationArray() 431 public UUID[] GetAnimationArray()
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
index 64567db..a8d24fd 100644
--- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
+++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
@@ -104,8 +104,15 @@ namespace OpenSim.Region.Framework.Scenes
104 // better than losing the object for now. 104 // better than losing the object for now.
105 if (permissionToDelete) 105 if (permissionToDelete)
106 { 106 {
107 List<uint> killIDs = new List<uint>();
108
107 foreach (SceneObjectGroup g in objectGroups) 109 foreach (SceneObjectGroup g in objectGroups)
110 {
111 killIDs.Add(g.LocalId);
108 g.DeleteGroupFromScene(false); 112 g.DeleteGroupFromScene(false);
113 }
114
115 m_scene.SendKillObject(killIDs);
109 } 116 }
110 } 117 }
111 118
@@ -137,7 +144,7 @@ namespace OpenSim.Region.Framework.Scenes
137 x = m_inventoryDeletes.Dequeue(); 144 x = m_inventoryDeletes.Dequeue();
138 145
139 m_log.DebugFormat( 146 m_log.DebugFormat(
140 "[ASYNC DELETER]: Sending object to user's inventory, {0} item(s) remaining.", left); 147 "[ASYNC DELETER]: Sending object to user's inventory, action {1}, count {2}, {0} item(s) remaining.", left, x.action, x.objectGroups.Count);
141 148
142 try 149 try
143 { 150 {
@@ -177,4 +184,4 @@ namespace OpenSim.Region.Framework.Scenes
177 return false; 184 return false;
178 } 185 }
179 } 186 }
180} \ No newline at end of file 187}
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 437b91a..e923932 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -55,8 +55,12 @@ namespace OpenSim.Region.Framework.Scenes
55 55
56 public delegate void OnTerrainTickDelegate(); 56 public delegate void OnTerrainTickDelegate();
57 57
58 public delegate void OnTerrainUpdateDelegate();
59
58 public event OnTerrainTickDelegate OnTerrainTick; 60 public event OnTerrainTickDelegate OnTerrainTick;
59 61
62 public event OnTerrainUpdateDelegate OnTerrainUpdate;
63
60 public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup); 64 public delegate void OnBackupDelegate(ISimulationDataService datastore, bool forceBackup);
61 65
62 public event OnBackupDelegate OnBackup; 66 public event OnBackupDelegate OnBackup;
@@ -746,6 +750,26 @@ namespace OpenSim.Region.Framework.Scenes
746 } 750 }
747 } 751 }
748 } 752 }
753 public void TriggerTerrainUpdate()
754 {
755 OnTerrainUpdateDelegate handlerTerrainUpdate = OnTerrainUpdate;
756 if (handlerTerrainUpdate != null)
757 {
758 foreach (OnTerrainUpdateDelegate d in handlerTerrainUpdate.GetInvocationList())
759 {
760 try
761 {
762 d();
763 }
764 catch (Exception e)
765 {
766 m_log.ErrorFormat(
767 "[EVENT MANAGER]: Delegate for TriggerTerrainUpdate failed - continuing. {0} {1}",
768 e.Message, e.StackTrace);
769 }
770 }
771 }
772 }
749 773
750 public void TriggerTerrainTick() 774 public void TriggerTerrainTick()
751 { 775 {
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 19f8180..c75f8ba 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -167,6 +167,7 @@ namespace OpenSim.Region.Framework.Scenes
167 167
168 private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) 168 private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
169 { 169 {
170 if (entity == null) return double.NaN;
170 ScenePresence presence = m_scene.GetScenePresence(client.AgentId); 171 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
171 if (presence != null) 172 if (presence != null)
172 { 173 {
@@ -226,9 +227,9 @@ namespace OpenSim.Region.Framework.Scenes
226 return 0.0; 227 return 0.0;
227 228
228 // Use group position for child prims 229 // Use group position for child prims
229 Vector3 entityPos = entity.AbsolutePosition; 230 Vector3 entityPos;
230 if (entity is SceneObjectPart) 231 if (entity is SceneObjectPart)
231 entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; 232 entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
232 else 233 else
233 entityPos = entity.AbsolutePosition; 234 entityPos = entity.AbsolutePosition;
234 235
@@ -251,12 +252,19 @@ namespace OpenSim.Region.Framework.Scenes
251 252
252 if (entity is SceneObjectPart) 253 if (entity is SceneObjectPart)
253 { 254 {
254 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
255 if (physActor == null || !physActor.IsPhysical)
256 priority += 100;
257
258 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) 255 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
256 {
259 priority = 1.0; 257 priority = 1.0;
258 }
259 else
260 {
261 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
262 if (physActor == null || !physActor.IsPhysical)
263 priority += 100;
264 }
265
266 if (((SceneObjectPart)entity).ParentGroup.RootPart != (SceneObjectPart)entity)
267 priority +=1;
260 } 268 }
261 return priority; 269 return priority;
262 } 270 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 4cc797b..1d8b988 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -99,34 +99,22 @@ namespace OpenSim.Region.Framework.Scenes
99 /// <param name="item"></param> 99 /// <param name="item"></param>
100 public bool AddInventoryItem(InventoryItemBase item) 100 public bool AddInventoryItem(InventoryItemBase item)
101 { 101 {
102 if (UUID.Zero == item.Folder) 102 InventoryFolderBase folder;
103
104 if (item.Folder == UUID.Zero)
103 { 105 {
104 InventoryFolderBase f = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType); 106 folder = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType);
105 if (f != null) 107 if (folder == null)
106 {
107// m_log.DebugFormat(
108// "[LOCAL INVENTORY SERVICES CONNECTOR]: Found folder {0} type {1} for item {2}",
109// f.Name, (AssetType)f.Type, item.Name);
110
111 item.Folder = f.ID;
112 }
113 else
114 { 108 {
115 f = InventoryService.GetRootFolder(item.Owner); 109 folder = InventoryService.GetRootFolder(item.Owner);
116 if (f != null) 110
117 { 111 if (folder == null)
118 item.Folder = f.ID;
119 }
120 else
121 {
122 m_log.WarnFormat(
123 "[AGENT INVENTORY]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
124 item.Owner, item.Name);
125 return false; 112 return false;
126 }
127 } 113 }
114
115 item.Folder = folder.ID;
128 } 116 }
129 117
130 if (InventoryService.AddItem(item)) 118 if (InventoryService.AddItem(item))
131 { 119 {
132 int userlevel = 0; 120 int userlevel = 0;
@@ -252,8 +240,7 @@ namespace OpenSim.Region.Framework.Scenes
252 240
253 // Update item with new asset 241 // Update item with new asset
254 item.AssetID = asset.FullID; 242 item.AssetID = asset.FullID;
255 if (group.UpdateInventoryItem(item)) 243 group.UpdateInventoryItem(item);
256 remoteClient.SendAgentAlertMessage("Script saved", false);
257 244
258 part.GetProperties(remoteClient); 245 part.GetProperties(remoteClient);
259 246
@@ -264,12 +251,7 @@ namespace OpenSim.Region.Framework.Scenes
264 { 251 {
265 // Needs to determine which engine was running it and use that 252 // Needs to determine which engine was running it and use that
266 // 253 //
267 part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); 254 errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 0);
268 errors = part.Inventory.GetScriptErrors(item.ItemID);
269 }
270 else
271 {
272 remoteClient.SendAgentAlertMessage("Script saved", false);
273 } 255 }
274 part.ParentGroup.ResumeScripts(); 256 part.ParentGroup.ResumeScripts();
275 return errors; 257 return errors;
@@ -683,6 +665,8 @@ namespace OpenSim.Region.Framework.Scenes
683 return; 665 return;
684 } 666 }
685 667
668 if (newName == null) newName = item.Name;
669
686 AssetBase asset = AssetService.Get(item.AssetID.ToString()); 670 AssetBase asset = AssetService.Get(item.AssetID.ToString());
687 671
688 if (asset != null) 672 if (asset != null)
@@ -730,6 +714,24 @@ namespace OpenSim.Region.Framework.Scenes
730 } 714 }
731 715
732 /// <summary> 716 /// <summary>
717 /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit)
718 /// </summary>
719 public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List<InventoryItemBase> items, UUID destfolder)
720 {
721 List<InventoryItemBase> moveitems = new List<InventoryItemBase>();
722 foreach (InventoryItemBase b in items)
723 {
724 CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null);
725 InventoryItemBase n = InventoryService.GetItem(b);
726 n.Folder = destfolder;
727 moveitems.Add(n);
728 remoteClient.SendInventoryItemCreateUpdate(n, 0);
729 }
730
731 MoveInventoryItem(remoteClient, moveitems);
732 }
733
734 /// <summary>
733 /// Move an item within the agent's inventory. 735 /// Move an item within the agent's inventory.
734 /// </summary> 736 /// </summary>
735 /// <param name="remoteClient"></param> 737 /// <param name="remoteClient"></param>
@@ -972,8 +974,12 @@ namespace OpenSim.Region.Framework.Scenes
972 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID) 974 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
973 { 975 {
974 SceneObjectPart part = GetSceneObjectPart(localID); 976 SceneObjectPart part = GetSceneObjectPart(localID);
975 SceneObjectGroup group = part.ParentGroup; 977 SceneObjectGroup group = null;
976 if (group != null) 978 if (part != null)
979 {
980 group = part.ParentGroup;
981 }
982 if (part != null && group != null)
977 { 983 {
978 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)) 984 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
979 return; 985 return;
@@ -1420,13 +1426,6 @@ namespace OpenSim.Region.Framework.Scenes
1420 { 1426 {
1421 agentTransactions.HandleTaskItemUpdateFromTransaction( 1427 agentTransactions.HandleTaskItemUpdateFromTransaction(
1422 remoteClient, part, transactionID, currentItem); 1428 remoteClient, part, transactionID, currentItem);
1423
1424 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1425 remoteClient.SendAgentAlertMessage("Notecard saved", false);
1426 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1427 remoteClient.SendAgentAlertMessage("Script saved", false);
1428 else
1429 remoteClient.SendAgentAlertMessage("Item saved", false);
1430 } 1429 }
1431 1430
1432 // Base ALWAYS has move 1431 // Base ALWAYS has move
@@ -1544,7 +1543,7 @@ namespace OpenSim.Region.Framework.Scenes
1544 return; 1543 return;
1545 1544
1546 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1545 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
1547 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), 1546 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"),
1548 remoteClient.AgentId); 1547 remoteClient.AgentId);
1549 AssetService.Store(asset); 1548 AssetService.Store(asset);
1550 1549
@@ -1696,23 +1695,32 @@ namespace OpenSim.Region.Framework.Scenes
1696 // build a list of eligible objects 1695 // build a list of eligible objects
1697 List<uint> deleteIDs = new List<uint>(); 1696 List<uint> deleteIDs = new List<uint>();
1698 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>(); 1697 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>();
1699 1698 List<SceneObjectGroup> takeGroups = new List<SceneObjectGroup>();
1700 // Start with true for both, then remove the flags if objects
1701 // that we can't derez are part of the selection
1702 bool permissionToTake = true;
1703 bool permissionToTakeCopy = true;
1704 bool permissionToDelete = true;
1705 1699
1706 foreach (uint localID in localIDs) 1700 foreach (uint localID in localIDs)
1707 { 1701 {
1702 // Start with true for both, then remove the flags if objects
1703 // that we can't derez are part of the selection
1704 bool permissionToTake = true;
1705 bool permissionToTakeCopy = true;
1706 bool permissionToDelete = true;
1707
1708 // Invalid id 1708 // Invalid id
1709 SceneObjectPart part = GetSceneObjectPart(localID); 1709 SceneObjectPart part = GetSceneObjectPart(localID);
1710 if (part == null) 1710 if (part == null)
1711 {
1712 //Client still thinks the object exists, kill it
1713 deleteIDs.Add(localID);
1711 continue; 1714 continue;
1715 }
1712 1716
1713 // Already deleted by someone else 1717 // Already deleted by someone else
1714 if (part.ParentGroup == null || part.ParentGroup.IsDeleted) 1718 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
1719 {
1720 //Client still thinks the object exists, kill it
1721 deleteIDs.Add(localID);
1715 continue; 1722 continue;
1723 }
1716 1724
1717 // Can't delete child prims 1725 // Can't delete child prims
1718 if (part != part.ParentGroup.RootPart) 1726 if (part != part.ParentGroup.RootPart)
@@ -1720,9 +1728,6 @@ namespace OpenSim.Region.Framework.Scenes
1720 1728
1721 SceneObjectGroup grp = part.ParentGroup; 1729 SceneObjectGroup grp = part.ParentGroup;
1722 1730
1723 deleteIDs.Add(localID);
1724 deleteGroups.Add(grp);
1725
1726 if (remoteClient == null) 1731 if (remoteClient == null)
1727 { 1732 {
1728 // Autoreturn has a null client. Nothing else does. So 1733 // Autoreturn has a null client. Nothing else does. So
@@ -1734,8 +1739,15 @@ namespace OpenSim.Region.Framework.Scenes
1734 } 1739 }
1735 else 1740 else
1736 { 1741 {
1737 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId)) 1742 if (action == DeRezAction.TakeCopy)
1743 {
1744 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId))
1745 permissionToTakeCopy = false;
1746 }
1747 else
1748 {
1738 permissionToTakeCopy = false; 1749 permissionToTakeCopy = false;
1750 }
1739 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId)) 1751 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId))
1740 permissionToTake = false; 1752 permissionToTake = false;
1741 1753
@@ -1743,71 +1755,88 @@ namespace OpenSim.Region.Framework.Scenes
1743 permissionToDelete = false; 1755 permissionToDelete = false;
1744 } 1756 }
1745 1757
1746 } 1758 // Handle god perms
1747 1759 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId))
1748 // Handle god perms 1760 {
1749 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) 1761 permissionToTake = true;
1750 { 1762 permissionToTakeCopy = true;
1751 permissionToTake = true; 1763 permissionToDelete = true;
1752 permissionToTakeCopy = true; 1764 }
1753 permissionToDelete = true;
1754 }
1755 1765
1756 // If we're re-saving, we don't even want to delete 1766 // If we're re-saving, we don't even want to delete
1757 if (action == DeRezAction.SaveToExistingUserInventoryItem) 1767 if (action == DeRezAction.SaveToExistingUserInventoryItem)
1758 permissionToDelete = false; 1768 permissionToDelete = false;
1759 1769
1760 // if we want to take a copy, we also don't want to delete 1770 // if we want to take a copy, we also don't want to delete
1761 // Note: after this point, the permissionToTakeCopy flag 1771 // Note: after this point, the permissionToTakeCopy flag
1762 // becomes irrelevant. It already includes the permissionToTake 1772 // becomes irrelevant. It already includes the permissionToTake
1763 // permission and after excluding no copy items here, we can 1773 // permission and after excluding no copy items here, we can
1764 // just use that. 1774 // just use that.
1765 if (action == DeRezAction.TakeCopy) 1775 if (action == DeRezAction.TakeCopy)
1766 { 1776 {
1767 // If we don't have permission, stop right here 1777 // If we don't have permission, stop right here
1768 if (!permissionToTakeCopy) 1778 if (!permissionToTakeCopy)
1769 return; 1779 return;
1770 1780
1771 permissionToTake = true; 1781 permissionToTake = true;
1772 // Don't delete 1782 // Don't delete
1773 permissionToDelete = false; 1783 permissionToDelete = false;
1774 } 1784 }
1775 1785
1776 if (action == DeRezAction.Return) 1786 if (action == DeRezAction.Return)
1777 {
1778 if (remoteClient != null)
1779 { 1787 {
1780 if (Permissions.CanReturnObjects( 1788 if (remoteClient != null)
1781 null,
1782 remoteClient.AgentId,
1783 deleteGroups))
1784 { 1789 {
1785 permissionToTake = true; 1790 if (Permissions.CanReturnObjects(
1786 permissionToDelete = true; 1791 null,
1787 1792 remoteClient.AgentId,
1788 foreach (SceneObjectGroup g in deleteGroups) 1793 deleteGroups))
1789 { 1794 {
1790 AddReturn(g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return"); 1795 permissionToTake = true;
1796 permissionToDelete = true;
1797
1798 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
1791 } 1799 }
1792 } 1800 }
1801 else // Auto return passes through here with null agent
1802 {
1803 permissionToTake = true;
1804 permissionToDelete = true;
1805 }
1793 } 1806 }
1794 else // Auto return passes through here with null agent 1807
1808 if (permissionToTake && (!permissionToDelete))
1809 takeGroups.Add(grp);
1810
1811 if (permissionToDelete)
1795 { 1812 {
1796 permissionToTake = true; 1813 if (permissionToTake)
1797 permissionToDelete = true; 1814 deleteGroups.Add(grp);
1815 deleteIDs.Add(grp.LocalId);
1798 } 1816 }
1799 } 1817 }
1800 1818
1801 if (permissionToTake) 1819 SendKillObject(deleteIDs);
1820
1821 if (deleteGroups.Count > 0)
1802 { 1822 {
1823 foreach (SceneObjectGroup g in deleteGroups)
1824 deleteIDs.Remove(g.LocalId);
1825
1803 m_asyncSceneObjectDeleter.DeleteToInventory( 1826 m_asyncSceneObjectDeleter.DeleteToInventory(
1804 action, destinationID, deleteGroups, remoteClient, 1827 action, destinationID, deleteGroups, remoteClient,
1805 permissionToDelete); 1828 true);
1829 }
1830 if (takeGroups.Count > 0)
1831 {
1832 m_asyncSceneObjectDeleter.DeleteToInventory(
1833 action, destinationID, takeGroups, remoteClient,
1834 false);
1806 } 1835 }
1807 else if (permissionToDelete) 1836 if (deleteIDs.Count > 0)
1808 { 1837 {
1809 foreach (SceneObjectGroup g in deleteGroups) 1838 foreach (SceneObjectGroup g in deleteGroups)
1810 DeleteSceneObject(g, false); 1839 DeleteSceneObject(g, true);
1811 } 1840 }
1812 } 1841 }
1813 1842
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 0cfc235..48ae4ca 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -102,6 +102,7 @@ namespace OpenSim.Region.Framework.Scenes
102 protected ModuleLoader m_moduleLoader; 102 protected ModuleLoader m_moduleLoader;
103 protected AgentCircuitManager m_authenticateHandler; 103 protected AgentCircuitManager m_authenticateHandler;
104 protected SceneCommunicationService m_sceneGridService; 104 protected SceneCommunicationService m_sceneGridService;
105 protected ISnmpModule m_snmpService = null;
105 106
106 protected ISimulationDataService m_SimulationDataService; 107 protected ISimulationDataService m_SimulationDataService;
107 protected IEstateDataService m_EstateDataService; 108 protected IEstateDataService m_EstateDataService;
@@ -163,6 +164,7 @@ namespace OpenSim.Region.Framework.Scenes
163 private int landMS; 164 private int landMS;
164 private int lastCompletedFrame; 165 private int lastCompletedFrame;
165 166
167 public bool CombineRegions = false;
166 private bool m_physics_enabled = true; 168 private bool m_physics_enabled = true;
167 private bool m_scripts_enabled = true; 169 private bool m_scripts_enabled = true;
168 private string m_defaultScriptEngine; 170 private string m_defaultScriptEngine;
@@ -174,6 +176,7 @@ namespace OpenSim.Region.Framework.Scenes
174 private bool m_firstHeartbeat = true; 176 private bool m_firstHeartbeat = true;
175 177
176 private object m_deleting_scene_object = new object(); 178 private object m_deleting_scene_object = new object();
179 private object m_cleaningAttachments = new object();
177 180
178 private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time; 181 private UpdatePrioritizationSchemes m_priorityScheme = UpdatePrioritizationSchemes.Time;
179 private bool m_reprioritizationEnabled = true; 182 private bool m_reprioritizationEnabled = true;
@@ -217,6 +220,19 @@ namespace OpenSim.Region.Framework.Scenes
217 get { return m_sceneGridService; } 220 get { return m_sceneGridService; }
218 } 221 }
219 222
223 public ISnmpModule SnmpService
224 {
225 get
226 {
227 if (m_snmpService == null)
228 {
229 m_snmpService = RequestModuleInterface<ISnmpModule>();
230 }
231
232 return m_snmpService;
233 }
234 }
235
220 public ISimulationDataService SimulationDataService 236 public ISimulationDataService SimulationDataService
221 { 237 {
222 get 238 get
@@ -561,6 +577,8 @@ namespace OpenSim.Region.Framework.Scenes
561 #region Region Settings 577 #region Region Settings
562 578
563 // Load region settings 579 // Load region settings
580 m_regInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(m_regInfo.RegionID);
581
564 m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID); 582 m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID);
565 if (estateDataService != null) 583 if (estateDataService != null)
566 m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); 584 m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false);
@@ -622,9 +640,10 @@ namespace OpenSim.Region.Framework.Scenes
622 //Animation states 640 //Animation states
623 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); 641 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
624 // TODO: Change default to true once the feature is supported 642 // TODO: Change default to true once the feature is supported
625 m_usePreJump = startupConfig.GetBoolean("enableprejump", false); 643 m_usePreJump = startupConfig.GetBoolean("enableprejump", true);
626
627 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys); 644 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
645
646 m_log.DebugFormat("[SCENE]: prejump is {0}", m_usePreJump ? "ON" : "OFF");
628 if (RegionInfo.NonphysPrimMax > 0) 647 if (RegionInfo.NonphysPrimMax > 0)
629 { 648 {
630 m_maxNonphys = RegionInfo.NonphysPrimMax; 649 m_maxNonphys = RegionInfo.NonphysPrimMax;
@@ -656,6 +675,7 @@ namespace OpenSim.Region.Framework.Scenes
656 m_persistAfter *= 10000000; 675 m_persistAfter *= 10000000;
657 676
658 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 677 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
678 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
659 679
660 IConfig packetConfig = m_config.Configs["PacketPool"]; 680 IConfig packetConfig = m_config.Configs["PacketPool"];
661 if (packetConfig != null) 681 if (packetConfig != null)
@@ -665,6 +685,7 @@ namespace OpenSim.Region.Framework.Scenes
665 } 685 }
666 686
667 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 687 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
688 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
668 689
669 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); 690 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
670 if (m_generateMaptiles) 691 if (m_generateMaptiles)
@@ -689,9 +710,9 @@ namespace OpenSim.Region.Framework.Scenes
689 } 710 }
690 } 711 }
691 } 712 }
692 catch 713 catch (Exception e)
693 { 714 {
694 m_log.Warn("[SCENE]: Failed to load StartupConfig"); 715 m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString());
695 } 716 }
696 717
697 #endregion Region Config 718 #endregion Region Config
@@ -928,6 +949,15 @@ namespace OpenSim.Region.Framework.Scenes
928 /// <param name="seconds">float indicating duration before restart.</param> 949 /// <param name="seconds">float indicating duration before restart.</param>
929 public virtual void Restart(float seconds) 950 public virtual void Restart(float seconds)
930 { 951 {
952 Restart(seconds, true);
953 }
954
955 /// <summary>
956 /// Given float seconds, this will restart the region. showDialog will optionally alert the users.
957 /// </summary>
958 /// <param name="seconds">float indicating duration before restart.</param>
959 public virtual void Restart(float seconds, bool showDialog)
960 {
931 // notifications are done in 15 second increments 961 // notifications are done in 15 second increments
932 // so .. if the number of seconds is less then 15 seconds, it's not really a restart request 962 // so .. if the number of seconds is less then 15 seconds, it's not really a restart request
933 // It's a 'Cancel restart' request. 963 // It's a 'Cancel restart' request.
@@ -948,8 +978,11 @@ namespace OpenSim.Region.Framework.Scenes
948 m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed); 978 m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed);
949 m_log.Info("[REGION]: Restarting Region in " + (seconds / 60) + " minutes"); 979 m_log.Info("[REGION]: Restarting Region in " + (seconds / 60) + " minutes");
950 m_restartTimer.Start(); 980 m_restartTimer.Start();
951 m_dialogModule.SendNotificationToUsersInRegion( 981 if (showDialog)
982 {
983 m_dialogModule.SendNotificationToUsersInRegion(
952 UUID.Random(), String.Empty, RegionInfo.RegionName + String.Format(": Restarting in {0} Minutes", (int)(seconds / 60.0))); 984 UUID.Random(), String.Empty, RegionInfo.RegionName + String.Format(": Restarting in {0} Minutes", (int)(seconds / 60.0)));
985 }
953 } 986 }
954 } 987 }
955 988
@@ -1145,6 +1178,7 @@ namespace OpenSim.Region.Framework.Scenes
1145 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat); 1178 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
1146 if (HeartbeatThread != null) 1179 if (HeartbeatThread != null)
1147 { 1180 {
1181 m_log.ErrorFormat("[SCENE]: Restarting heartbeat thread because it hasn't reported in in region {0}", RegionInfo.RegionName);
1148 HeartbeatThread.Abort(); 1182 HeartbeatThread.Abort();
1149 HeartbeatThread = null; 1183 HeartbeatThread = null;
1150 } 1184 }
@@ -1816,14 +1850,24 @@ namespace OpenSim.Region.Framework.Scenes
1816 /// <returns></returns> 1850 /// <returns></returns>
1817 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) 1851 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1818 { 1852 {
1853
1854 float wheight = (float)RegionInfo.RegionSettings.WaterHeight;
1855 Vector3 wpos = Vector3.Zero;
1856 // Check for water surface intersection from above
1857 if ( (RayStart.Z > wheight) && (RayEnd.Z < wheight) )
1858 {
1859 float ratio = (RayStart.Z - wheight) / (RayStart.Z - RayEnd.Z);
1860 wpos.X = RayStart.X - (ratio * (RayStart.X - RayEnd.X));
1861 wpos.Y = RayStart.Y - (ratio * (RayStart.Y - RayEnd.Y));
1862 wpos.Z = wheight;
1863 }
1864
1819 Vector3 pos = Vector3.Zero; 1865 Vector3 pos = Vector3.Zero;
1820 if (RayEndIsIntersection == (byte)1) 1866 if (RayEndIsIntersection == (byte)1)
1821 { 1867 {
1822 pos = RayEnd; 1868 pos = RayEnd;
1823 return pos;
1824 } 1869 }
1825 1870 else if (RayTargetID != UUID.Zero)
1826 if (RayTargetID != UUID.Zero)
1827 { 1871 {
1828 SceneObjectPart target = GetSceneObjectPart(RayTargetID); 1872 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1829 1873
@@ -1845,7 +1889,7 @@ namespace OpenSim.Region.Framework.Scenes
1845 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); 1889 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1846 1890
1847 // Un-comment out the following line to Get Raytrace results printed to the console. 1891 // Un-comment out the following line to Get Raytrace results printed to the console.
1848 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 1892 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1849 float ScaleOffset = 0.5f; 1893 float ScaleOffset = 0.5f;
1850 1894
1851 // If we hit something 1895 // If we hit something
@@ -1868,13 +1912,10 @@ namespace OpenSim.Region.Framework.Scenes
1868 //pos.Z -= 0.25F; 1912 //pos.Z -= 0.25F;
1869 1913
1870 } 1914 }
1871
1872 return pos;
1873 } 1915 }
1874 else 1916 else
1875 { 1917 {
1876 // We don't have a target here, so we're going to raytrace all the objects in the scene. 1918 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1877
1878 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); 1919 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1879 1920
1880 // Un-comment the following line to print the raytrace results to the console. 1921 // Un-comment the following line to print the raytrace results to the console.
@@ -1883,13 +1924,12 @@ namespace OpenSim.Region.Framework.Scenes
1883 if (ei.HitTF) 1924 if (ei.HitTF)
1884 { 1925 {
1885 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 1926 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1886 } else 1927 }
1928 else
1887 { 1929 {
1888 // fall back to our stupid functionality 1930 // fall back to our stupid functionality
1889 pos = RayEnd; 1931 pos = RayEnd;
1890 } 1932 }
1891
1892 return pos;
1893 } 1933 }
1894 } 1934 }
1895 else 1935 else
@@ -1900,8 +1940,12 @@ namespace OpenSim.Region.Framework.Scenes
1900 //increase height so its above the ground. 1940 //increase height so its above the ground.
1901 //should be getting the normal of the ground at the rez point and using that? 1941 //should be getting the normal of the ground at the rez point and using that?
1902 pos.Z += scale.Z / 2f; 1942 pos.Z += scale.Z / 2f;
1903 return pos; 1943// return pos;
1904 } 1944 }
1945
1946 // check against posible water intercept
1947 if (wpos.Z > pos.Z) pos = wpos;
1948 return pos;
1905 } 1949 }
1906 1950
1907 1951
@@ -1981,7 +2025,10 @@ namespace OpenSim.Region.Framework.Scenes
1981 public bool AddRestoredSceneObject( 2025 public bool AddRestoredSceneObject(
1982 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 2026 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
1983 { 2027 {
1984 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 2028 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates);
2029 if (result)
2030 sceneObject.IsDeleted = false;
2031 return result;
1985 } 2032 }
1986 2033
1987 /// <summary> 2034 /// <summary>
@@ -2058,6 +2105,15 @@ namespace OpenSim.Region.Framework.Scenes
2058 /// </summary> 2105 /// </summary>
2059 public void DeleteAllSceneObjects() 2106 public void DeleteAllSceneObjects()
2060 { 2107 {
2108 DeleteAllSceneObjects(false);
2109 }
2110
2111 /// <summary>
2112 /// Delete every object from the scene. This does not include attachments worn by avatars.
2113 /// </summary>
2114 public void DeleteAllSceneObjects(bool exceptNoCopy)
2115 {
2116 List<SceneObjectGroup> toReturn = new List<SceneObjectGroup>();
2061 lock (Entities) 2117 lock (Entities)
2062 { 2118 {
2063 EntityBase[] entities = Entities.GetEntities(); 2119 EntityBase[] entities = Entities.GetEntities();
@@ -2066,11 +2122,24 @@ namespace OpenSim.Region.Framework.Scenes
2066 if (e is SceneObjectGroup) 2122 if (e is SceneObjectGroup)
2067 { 2123 {
2068 SceneObjectGroup sog = (SceneObjectGroup)e; 2124 SceneObjectGroup sog = (SceneObjectGroup)e;
2069 if (!sog.IsAttachment) 2125 if (sog != null && !sog.IsAttachment)
2070 DeleteSceneObject((SceneObjectGroup)e, false); 2126 {
2127 if (!exceptNoCopy || ((sog.GetEffectivePermissions() & (uint)PermissionMask.Copy) != 0))
2128 {
2129 DeleteSceneObject((SceneObjectGroup)e, false);
2130 }
2131 else
2132 {
2133 toReturn.Add((SceneObjectGroup)e);
2134 }
2135 }
2071 } 2136 }
2072 } 2137 }
2073 } 2138 }
2139 if (toReturn.Count > 0)
2140 {
2141 returnObjects(toReturn.ToArray(), UUID.Zero);
2142 }
2074 } 2143 }
2075 2144
2076 /// <summary> 2145 /// <summary>
@@ -2119,6 +2188,8 @@ namespace OpenSim.Region.Framework.Scenes
2119 } 2188 }
2120 2189
2121 group.DeleteGroupFromScene(silent); 2190 group.DeleteGroupFromScene(silent);
2191 if (!silent)
2192 SendKillObject(new List<uint>() { group.LocalId });
2122 2193
2123// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2194// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2124 } 2195 }
@@ -2448,6 +2519,12 @@ namespace OpenSim.Region.Framework.Scenes
2448 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns> 2519 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2449 public bool AddSceneObject(SceneObjectGroup sceneObject) 2520 public bool AddSceneObject(SceneObjectGroup sceneObject)
2450 { 2521 {
2522 if (sceneObject.OwnerID == UUID.Zero)
2523 {
2524 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero", sceneObject.UUID);
2525 return false;
2526 }
2527
2451 // If the user is banned, we won't let any of their objects 2528 // If the user is banned, we won't let any of their objects
2452 // enter. Period. 2529 // enter. Period.
2453 // 2530 //
@@ -2495,15 +2572,28 @@ namespace OpenSim.Region.Framework.Scenes
2495 2572
2496 if (AttachmentsModule != null) 2573 if (AttachmentsModule != null)
2497 AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false); 2574 AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false);
2575
2576 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was found, attaching", sceneObject.UUID);
2498 } 2577 }
2499 else 2578 else
2500 { 2579 {
2580 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was not found, setting to temp", sceneObject.UUID);
2501 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2581 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2502 RootPrim.AddFlag(PrimFlags.TemporaryOnRez); 2582 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2503 } 2583 }
2584 if (sceneObject.OwnerID == UUID.Zero)
2585 {
2586 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero after attachment processing. BUG!", sceneObject.UUID);
2587 return false;
2588 }
2504 } 2589 }
2505 else 2590 else
2506 { 2591 {
2592 if (sceneObject.OwnerID == UUID.Zero)
2593 {
2594 m_log.ErrorFormat("[SCENE]: Owner ID for non-attachment {0} was zero", sceneObject.UUID);
2595 return false;
2596 }
2507 AddRestoredSceneObject(sceneObject, true, false); 2597 AddRestoredSceneObject(sceneObject, true, false);
2508 2598
2509 if (!Permissions.CanObjectEntry(sceneObject.UUID, 2599 if (!Permissions.CanObjectEntry(sceneObject.UUID,
@@ -2776,6 +2866,7 @@ namespace OpenSim.Region.Framework.Scenes
2776 client.OnFetchInventory += HandleFetchInventory; 2866 client.OnFetchInventory += HandleFetchInventory;
2777 client.OnUpdateInventoryItem += UpdateInventoryItemAsset; 2867 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2778 client.OnCopyInventoryItem += CopyInventoryItem; 2868 client.OnCopyInventoryItem += CopyInventoryItem;
2869 client.OnMoveItemsAndLeaveCopy += MoveInventoryItemsLeaveCopy;
2779 client.OnMoveInventoryItem += MoveInventoryItem; 2870 client.OnMoveInventoryItem += MoveInventoryItem;
2780 client.OnRemoveInventoryItem += RemoveInventoryItem; 2871 client.OnRemoveInventoryItem += RemoveInventoryItem;
2781 client.OnRemoveInventoryFolder += RemoveInventoryFolder; 2872 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
@@ -2954,15 +3045,16 @@ namespace OpenSim.Region.Framework.Scenes
2954 /// </summary> 3045 /// </summary>
2955 /// <param name="agentId">The avatar's Unique ID</param> 3046 /// <param name="agentId">The avatar's Unique ID</param>
2956 /// <param name="client">The IClientAPI for the client</param> 3047 /// <param name="client">The IClientAPI for the client</param>
2957 public virtual void TeleportClientHome(UUID agentId, IClientAPI client) 3048 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
2958 { 3049 {
2959 if (m_teleportModule != null) 3050 if (m_teleportModule != null)
2960 m_teleportModule.TeleportHome(agentId, client); 3051 return m_teleportModule.TeleportHome(agentId, client);
2961 else 3052 else
2962 { 3053 {
2963 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 3054 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
2964 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 3055 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
2965 } 3056 }
3057 return false;
2966 } 3058 }
2967 3059
2968 /// <summary> 3060 /// <summary>
@@ -3061,6 +3153,16 @@ namespace OpenSim.Region.Framework.Scenes
3061 /// <param name="flags"></param> 3153 /// <param name="flags"></param>
3062 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) 3154 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
3063 { 3155 {
3156 //Add half the avatar's height so that the user doesn't fall through prims
3157 ScenePresence presence;
3158 if (TryGetScenePresence(remoteClient.AgentId, out presence))
3159 {
3160 if (presence.Appearance != null)
3161 {
3162 position.Z = position.Z + (presence.Appearance.AvatarHeight / 2);
3163 }
3164 }
3165
3064 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) 3166 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
3065 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. 3167 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
3066 m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); 3168 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
@@ -3155,7 +3257,9 @@ namespace OpenSim.Region.Framework.Scenes
3155 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3257 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3156 3258
3157 } 3259 }
3260 m_log.Debug("[Scene] Beginning ClientClosed");
3158 m_eventManager.TriggerClientClosed(agentID, this); 3261 m_eventManager.TriggerClientClosed(agentID, this);
3262 m_log.Debug("[Scene] Finished ClientClosed");
3159 } 3263 }
3160 catch (NullReferenceException) 3264 catch (NullReferenceException)
3161 { 3265 {
@@ -3163,12 +3267,15 @@ namespace OpenSim.Region.Framework.Scenes
3163 // Avatar is already disposed :/ 3267 // Avatar is already disposed :/
3164 } 3268 }
3165 3269
3270 m_log.Debug("[Scene] Beginning OnRemovePresence");
3166 m_eventManager.TriggerOnRemovePresence(agentID); 3271 m_eventManager.TriggerOnRemovePresence(agentID);
3272 m_log.Debug("[Scene] Finished OnRemovePresence");
3273
3167 ForEachClient( 3274 ForEachClient(
3168 delegate(IClientAPI client) 3275 delegate(IClientAPI client)
3169 { 3276 {
3170 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3277 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3171 try { client.SendKillObject(avatar.RegionHandle, avatar.LocalId); } 3278 try { client.SendKillObject(avatar.RegionHandle, new List<uint>() { avatar.LocalId}); }
3172 catch (NullReferenceException) { } 3279 catch (NullReferenceException) { }
3173 }); 3280 });
3174 3281
@@ -3179,8 +3286,11 @@ namespace OpenSim.Region.Framework.Scenes
3179 } 3286 }
3180 3287
3181 // Remove the avatar from the scene 3288 // Remove the avatar from the scene
3289 m_log.Debug("[Scene] Begin RemoveScenePresence");
3182 m_sceneGraph.RemoveScenePresence(agentID); 3290 m_sceneGraph.RemoveScenePresence(agentID);
3291 m_log.Debug("[Scene] Finished RemoveScenePresence. Removing the client manager");
3183 m_clientManager.Remove(agentID); 3292 m_clientManager.Remove(agentID);
3293 m_log.Debug("[Scene] Removed the client manager. Firing avatar.close");
3184 3294
3185 try 3295 try
3186 { 3296 {
@@ -3194,8 +3304,10 @@ namespace OpenSim.Region.Framework.Scenes
3194 { 3304 {
3195 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString()); 3305 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString());
3196 } 3306 }
3197 3307 m_log.Debug("[Scene] Done. Firing RemoveCircuit");
3198 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3308 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
3309 CleanDroppedAttachments();
3310 m_log.Debug("[Scene] The avatar has left the building");
3199 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 3311 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3200 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); 3312 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3201 } 3313 }
@@ -3226,18 +3338,24 @@ namespace OpenSim.Region.Framework.Scenes
3226 3338
3227 #region Entities 3339 #region Entities
3228 3340
3229 public void SendKillObject(uint localID) 3341 public void SendKillObject(List<uint> localIDs)
3230 { 3342 {
3231 SceneObjectPart part = GetSceneObjectPart(localID); 3343 List<uint> deleteIDs = new List<uint>();
3232 if (part != null) // It is a prim 3344
3345 foreach (uint localID in localIDs)
3233 { 3346 {
3234 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid 3347 SceneObjectPart part = GetSceneObjectPart(localID);
3348 if (part != null) // It is a prim
3235 { 3349 {
3236 if (part.ParentGroup.RootPart != part) // Child part 3350 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
3237 return; 3351 {
3352 if (part.ParentGroup.RootPart != part) // Child part
3353 continue;
3354 }
3238 } 3355 }
3356 deleteIDs.Add(localID);
3239 } 3357 }
3240 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); 3358 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); });
3241 } 3359 }
3242 3360
3243 #endregion 3361 #endregion
@@ -3255,7 +3373,6 @@ namespace OpenSim.Region.Framework.Scenes
3255 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate; 3373 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
3256 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar; 3374 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar;
3257 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid; 3375 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid;
3258 m_sceneGridService.KiPrimitive += SendKillObject;
3259 m_sceneGridService.OnGetLandData += GetLandData; 3376 m_sceneGridService.OnGetLandData += GetLandData;
3260 } 3377 }
3261 3378
@@ -3264,7 +3381,6 @@ namespace OpenSim.Region.Framework.Scenes
3264 /// </summary> 3381 /// </summary>
3265 public void UnRegisterRegionWithComms() 3382 public void UnRegisterRegionWithComms()
3266 { 3383 {
3267 m_sceneGridService.KiPrimitive -= SendKillObject;
3268 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid; 3384 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid;
3269 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar; 3385 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar;
3270 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate; 3386 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
@@ -3335,6 +3451,7 @@ namespace OpenSim.Region.Framework.Scenes
3335 { 3451 {
3336 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3452 if (land != null && !TestLandRestrictions(agent, land, out reason))
3337 { 3453 {
3454 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3338 return false; 3455 return false;
3339 } 3456 }
3340 } 3457 }
@@ -3392,6 +3509,8 @@ namespace OpenSim.Region.Framework.Scenes
3392 3509
3393 if (vialogin) 3510 if (vialogin)
3394 { 3511 {
3512 CleanDroppedAttachments();
3513
3395 if (TestBorderCross(agent.startpos, Cardinals.E)) 3514 if (TestBorderCross(agent.startpos, Cardinals.E))
3396 { 3515 {
3397 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); 3516 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E);
@@ -3448,6 +3567,8 @@ namespace OpenSim.Region.Framework.Scenes
3448 } 3567 }
3449 } 3568 }
3450 // Honor parcel landing type and position. 3569 // Honor parcel landing type and position.
3570 /*
3571 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3451 if (land != null) 3572 if (land != null)
3452 { 3573 {
3453 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3574 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
@@ -3455,6 +3576,7 @@ namespace OpenSim.Region.Framework.Scenes
3455 agent.startpos = land.LandData.UserLocation; 3576 agent.startpos = land.LandData.UserLocation;
3456 } 3577 }
3457 } 3578 }
3579 */// This is now handled properly in ScenePresence.MakeRootAgent
3458 } 3580 }
3459 3581
3460 return true; 3582 return true;
@@ -3740,6 +3862,14 @@ namespace OpenSim.Region.Framework.Scenes
3740 3862
3741 // We have to wait until the viewer contacts this region after receiving EAC. 3863 // We have to wait until the viewer contacts this region after receiving EAC.
3742 // That calls AddNewClient, which finally creates the ScenePresence 3864 // That calls AddNewClient, which finally creates the ScenePresence
3865 int num = m_sceneGraph.GetNumberOfScenePresences();
3866
3867 if (num >= RegionInfo.RegionSettings.AgentLimit)
3868 {
3869 if (!Permissions.IsAdministrator(cAgentData.AgentID))
3870 return false;
3871 }
3872
3743 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); 3873 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
3744 if (childAgentUpdate != null) 3874 if (childAgentUpdate != null)
3745 { 3875 {
@@ -3805,12 +3935,22 @@ namespace OpenSim.Region.Framework.Scenes
3805 return false; 3935 return false;
3806 } 3936 }
3807 3937
3938 public bool IncomingCloseAgent(UUID agentID)
3939 {
3940 return IncomingCloseAgent(agentID, false);
3941 }
3942
3943 public bool IncomingCloseChildAgent(UUID agentID)
3944 {
3945 return IncomingCloseAgent(agentID, true);
3946 }
3947
3808 /// <summary> 3948 /// <summary>
3809 /// Tell a single agent to disconnect from the region. 3949 /// Tell a single agent to disconnect from the region.
3810 /// </summary> 3950 /// </summary>
3811 /// <param name="regionHandle"></param>
3812 /// <param name="agentID"></param> 3951 /// <param name="agentID"></param>
3813 public bool IncomingCloseAgent(UUID agentID) 3952 /// <param name="childOnly"></param>
3953 public bool IncomingCloseAgent(UUID agentID, bool childOnly)
3814 { 3954 {
3815 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 3955 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
3816 3956
@@ -3822,7 +3962,7 @@ namespace OpenSim.Region.Framework.Scenes
3822 { 3962 {
3823 m_sceneGraph.removeUserCount(false); 3963 m_sceneGraph.removeUserCount(false);
3824 } 3964 }
3825 else 3965 else if (!childOnly)
3826 { 3966 {
3827 m_sceneGraph.removeUserCount(true); 3967 m_sceneGraph.removeUserCount(true);
3828 } 3968 }
@@ -3838,9 +3978,12 @@ namespace OpenSim.Region.Framework.Scenes
3838 } 3978 }
3839 else 3979 else
3840 presence.ControllingClient.SendShutdownConnectionNotice(); 3980 presence.ControllingClient.SendShutdownConnectionNotice();
3981 presence.ControllingClient.Close(false);
3982 }
3983 else if (!childOnly)
3984 {
3985 presence.ControllingClient.Close(true);
3841 } 3986 }
3842
3843 presence.ControllingClient.Close();
3844 return true; 3987 return true;
3845 } 3988 }
3846 3989
@@ -4462,7 +4605,7 @@ namespace OpenSim.Region.Framework.Scenes
4462 // 4605 //
4463 int health=1; // Start at 1, means we're up 4606 int health=1; // Start at 1, means we're up
4464 4607
4465 if ((Util.EnvironmentTickCountSubtract(m_lastUpdate)) < 1000) 4608 if (m_firstHeartbeat || ((Util.EnvironmentTickCountSubtract(m_lastUpdate)) < 1000))
4466 health+=1; 4609 health+=1;
4467 else 4610 else
4468 return health; 4611 return health;
@@ -4926,8 +5069,17 @@ namespace OpenSim.Region.Framework.Scenes
4926 { 5069 {
4927 float ominX, ominY, ominZ, omaxX, omaxY, omaxZ; 5070 float ominX, ominY, ominZ, omaxX, omaxY, omaxZ;
4928 5071
5072 Vector3 vec = g.AbsolutePosition;
5073
4929 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); 5074 g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ);
4930 5075
5076 ominX += vec.X;
5077 omaxX += vec.X;
5078 ominY += vec.Y;
5079 omaxY += vec.Y;
5080 ominZ += vec.Z;
5081 omaxZ += vec.Z;
5082
4931 if (minX > ominX) 5083 if (minX > ominX)
4932 minX = ominX; 5084 minX = ominX;
4933 if (minY > ominY) 5085 if (minY > ominY)
@@ -4968,5 +5120,45 @@ namespace OpenSim.Region.Framework.Scenes
4968 throw new Exception(error); 5120 throw new Exception(error);
4969 } 5121 }
4970 } 5122 }
5123
5124 public void CleanDroppedAttachments()
5125 {
5126 List<SceneObjectGroup> objectsToDelete =
5127 new List<SceneObjectGroup>();
5128
5129 lock (m_cleaningAttachments)
5130 {
5131 ForEachSOG(delegate (SceneObjectGroup grp)
5132 {
5133 if (grp.RootPart.Shape.PCode == 0 && grp.RootPart.Shape.State != 0 && (!objectsToDelete.Contains(grp)))
5134 {
5135 UUID agentID = grp.OwnerID;
5136 if (agentID == UUID.Zero)
5137 {
5138 objectsToDelete.Add(grp);
5139 return;
5140 }
5141
5142 ScenePresence sp = GetScenePresence(agentID);
5143 if (sp == null)
5144 {
5145 objectsToDelete.Add(grp);
5146 return;
5147 }
5148 }
5149 });
5150 }
5151
5152 if (objectsToDelete.Count > 0)
5153 {
5154 m_log.DebugFormat("[SCENE]: Starting delete of {0} dropped attachments", objectsToDelete.Count);
5155 foreach (SceneObjectGroup grp in objectsToDelete)
5156 {
5157 m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID);
5158 DeleteSceneObject(grp, true);
5159 }
5160 m_log.Debug("[SCENE]: Finished dropped attachment deletion");
5161 }
5162 }
4971 } 5163 }
4972} 5164}
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 88e084e..632646d 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -44,8 +44,6 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion;
44 44
45namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
46{ 46{
47 public delegate void KiPrimitiveDelegate(uint localID);
48
49 public delegate void RemoveKnownRegionsFromAvatarList(UUID avatarID, List<ulong> regionlst); 47 public delegate void RemoveKnownRegionsFromAvatarList(UUID avatarID, List<ulong> regionlst);
50 48
51 /// <summary> 49 /// <summary>
@@ -113,8 +111,6 @@ namespace OpenSim.Region.Framework.Scenes
113// private LogOffUser handlerLogOffUser = null; 111// private LogOffUser handlerLogOffUser = null;
114// private GetLandData handlerGetLandData = null; // OnGetLandData 112// private GetLandData handlerGetLandData = null; // OnGetLandData
115 113
116 public KiPrimitiveDelegate KiPrimitive;
117
118 public SceneCommunicationService() 114 public SceneCommunicationService()
119 { 115 {
120 } 116 }
@@ -168,7 +164,7 @@ namespace OpenSim.Region.Framework.Scenes
168 164
169 if (neighbour != null) 165 if (neighbour != null)
170 { 166 {
171 m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize); 167 // m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize);
172 m_scene.EventManager.TriggerOnRegionUp(neighbour); 168 m_scene.EventManager.TriggerOnRegionUp(neighbour);
173 } 169 }
174 else 170 else
@@ -183,7 +179,7 @@ namespace OpenSim.Region.Framework.Scenes
183 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName); 179 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName);
184 180
185 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); 181 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID);
186 m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count); 182 //m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count);
187 foreach (GridRegion n in neighbours) 183 foreach (GridRegion n in neighbours)
188 { 184 {
189 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync; 185 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
@@ -267,14 +263,14 @@ namespace OpenSim.Region.Framework.Scenes
267 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle) 263 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
268 { 264 {
269 265
270 m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle); 266 //m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
271 // let's do our best, but there's not much we can do if the neighbour doesn't accept. 267 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
272 268
273 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); 269 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
274 uint x = 0, y = 0; 270 uint x = 0, y = 0;
275 Utils.LongToUInts(regionHandle, out x, out y); 271 Utils.LongToUInts(regionHandle, out x, out y);
276 GridRegion destination = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); 272 GridRegion destination = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
277 m_scene.SimulationService.CloseAgent(destination, agentID); 273 m_scene.SimulationService.CloseChildAgent(destination, agentID);
278 } 274 }
279 275
280 private void SendCloseChildAgentCompleted(IAsyncResult iar) 276 private void SendCloseChildAgentCompleted(IAsyncResult iar)
@@ -293,7 +289,7 @@ namespace OpenSim.Region.Framework.Scenes
293 d); 289 d);
294 } 290 }
295 } 291 }
296 292
297 public List<GridRegion> RequestNamedRegions(string name, int maxNumber) 293 public List<GridRegion> RequestNamedRegions(string name, int maxNumber)
298 { 294 {
299 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); 295 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber);
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index f81c551..d4e3717 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -43,6 +43,12 @@ namespace OpenSim.Region.Framework.Scenes
43 43
44 public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone); 44 public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone);
45 45
46 public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
47
48 public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
49
50 public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
51
46 public delegate void ObjectCreateDelegate(EntityBase obj); 52 public delegate void ObjectCreateDelegate(EntityBase obj);
47 53
48 public delegate void ObjectDeleteDelegate(EntityBase obj); 54 public delegate void ObjectDeleteDelegate(EntityBase obj);
@@ -61,6 +67,9 @@ namespace OpenSim.Region.Framework.Scenes
61 private PhysicsCrash handlerPhysicsCrash = null; 67 private PhysicsCrash handlerPhysicsCrash = null;
62 68
63 public event ObjectDuplicateDelegate OnObjectDuplicate; 69 public event ObjectDuplicateDelegate OnObjectDuplicate;
70 public event AttachToBackupDelegate OnAttachToBackup;
71 public event DetachFromBackupDelegate OnDetachFromBackup;
72 public event ChangedBackupDelegate OnChangeBackup;
64 public event ObjectCreateDelegate OnObjectCreate; 73 public event ObjectCreateDelegate OnObjectCreate;
65 public event ObjectDeleteDelegate OnObjectRemove; 74 public event ObjectDeleteDelegate OnObjectRemove;
66 75
@@ -68,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes
68 77
69 #region Fields 78 #region Fields
70 79
71 protected object m_presenceLock = new object(); 80 protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
72 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); 81 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
73 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); 82 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
74 83
@@ -124,13 +133,18 @@ namespace OpenSim.Region.Framework.Scenes
124 133
125 protected internal void Close() 134 protected internal void Close()
126 { 135 {
127 lock (m_presenceLock) 136 m_scenePresencesLock.EnterWriteLock();
137 try
128 { 138 {
129 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); 139 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
130 List<ScenePresence> newlist = new List<ScenePresence>(); 140 List<ScenePresence> newlist = new List<ScenePresence>();
131 m_scenePresenceMap = newmap; 141 m_scenePresenceMap = newmap;
132 m_scenePresenceArray = newlist; 142 m_scenePresenceArray = newlist;
133 } 143 }
144 finally
145 {
146 m_scenePresencesLock.ExitWriteLock();
147 }
134 148
135 lock (SceneObjectGroupsByFullID) 149 lock (SceneObjectGroupsByFullID)
136 SceneObjectGroupsByFullID.Clear(); 150 SceneObjectGroupsByFullID.Clear();
@@ -209,27 +223,8 @@ namespace OpenSim.Region.Framework.Scenes
209 if (sp.IsChildAgent) 223 if (sp.IsChildAgent)
210 return; 224 return;
211 225
212 if (sp.ParentID != 0) 226 coarseLocations.Add(sp.AbsolutePosition);
213 { 227 avatarUUIDs.Add(sp.UUID);
214 // sitting avatar
215 SceneObjectPart sop = m_parentScene.GetSceneObjectPart(sp.ParentID);
216 if (sop != null)
217 {
218 coarseLocations.Add(sop.AbsolutePosition + sp.AbsolutePosition);
219 avatarUUIDs.Add(sp.UUID);
220 }
221 else
222 {
223 // we can't find the parent.. ! arg!
224 coarseLocations.Add(sp.AbsolutePosition);
225 avatarUUIDs.Add(sp.UUID);
226 }
227 }
228 else
229 {
230 coarseLocations.Add(sp.AbsolutePosition);
231 avatarUUIDs.Add(sp.UUID);
232 }
233 } 228 }
234 } 229 }
235 230
@@ -259,6 +254,33 @@ namespace OpenSim.Region.Framework.Scenes
259 protected internal bool AddRestoredSceneObject( 254 protected internal bool AddRestoredSceneObject(
260 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 255 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
261 { 256 {
257 if (!m_parentScene.CombineRegions)
258 {
259 // KF: Check for out-of-region, move inside and make static.
260 Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
261 sceneObject.RootPart.GroupPosition.Y,
262 sceneObject.RootPart.GroupPosition.Z);
263 if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || npos.Z < 0.0 ||
264 npos.X > Constants.RegionSize ||
265 npos.Y > Constants.RegionSize))
266 {
267 if (npos.X < 0.0) npos.X = 1.0f;
268 if (npos.Y < 0.0) npos.Y = 1.0f;
269 if (npos.Z < 0.0) npos.Z = 0.0f;
270 if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f;
271 if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f;
272
273 foreach (SceneObjectPart part in sceneObject.Parts)
274 {
275 part.GroupPosition = npos;
276 }
277 sceneObject.RootPart.Velocity = Vector3.Zero;
278 sceneObject.RootPart.AngularVelocity = Vector3.Zero;
279 sceneObject.RootPart.Acceleration = Vector3.Zero;
280 sceneObject.RootPart.Velocity = Vector3.Zero;
281 }
282 }
283
262 if (!alreadyPersisted) 284 if (!alreadyPersisted)
263 { 285 {
264 sceneObject.ForceInventoryPersistence(); 286 sceneObject.ForceInventoryPersistence();
@@ -453,6 +475,30 @@ namespace OpenSim.Region.Framework.Scenes
453 m_updateList[obj.UUID] = obj; 475 m_updateList[obj.UUID] = obj;
454 } 476 }
455 477
478 public void FireAttachToBackup(SceneObjectGroup obj)
479 {
480 if (OnAttachToBackup != null)
481 {
482 OnAttachToBackup(obj);
483 }
484 }
485
486 public void FireDetachFromBackup(SceneObjectGroup obj)
487 {
488 if (OnDetachFromBackup != null)
489 {
490 OnDetachFromBackup(obj);
491 }
492 }
493
494 public void FireChangeBackup(SceneObjectGroup obj)
495 {
496 if (OnChangeBackup != null)
497 {
498 OnChangeBackup(obj);
499 }
500 }
501
456 /// <summary> 502 /// <summary>
457 /// Process all pending updates 503 /// Process all pending updates
458 /// </summary> 504 /// </summary>
@@ -587,7 +633,8 @@ namespace OpenSim.Region.Framework.Scenes
587 633
588 Entities[presence.UUID] = presence; 634 Entities[presence.UUID] = presence;
589 635
590 lock (m_presenceLock) 636 m_scenePresencesLock.EnterWriteLock();
637 try
591 { 638 {
592 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 639 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
593 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 640 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -611,6 +658,10 @@ namespace OpenSim.Region.Framework.Scenes
611 m_scenePresenceMap = newmap; 658 m_scenePresenceMap = newmap;
612 m_scenePresenceArray = newlist; 659 m_scenePresenceArray = newlist;
613 } 660 }
661 finally
662 {
663 m_scenePresencesLock.ExitWriteLock();
664 }
614 } 665 }
615 666
616 /// <summary> 667 /// <summary>
@@ -625,7 +676,8 @@ namespace OpenSim.Region.Framework.Scenes
625 agentID); 676 agentID);
626 } 677 }
627 678
628 lock (m_presenceLock) 679 m_scenePresencesLock.EnterWriteLock();
680 try
629 { 681 {
630 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 682 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
631 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 683 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -647,6 +699,10 @@ namespace OpenSim.Region.Framework.Scenes
647 m_log.WarnFormat("[SCENE]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); 699 m_log.WarnFormat("[SCENE]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
648 } 700 }
649 } 701 }
702 finally
703 {
704 m_scenePresencesLock.ExitWriteLock();
705 }
650 } 706 }
651 707
652 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) 708 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
@@ -770,6 +826,11 @@ namespace OpenSim.Region.Framework.Scenes
770 return m_scenePresenceArray; 826 return m_scenePresenceArray;
771 } 827 }
772 828
829 public int GetNumberOfScenePresences()
830 {
831 return m_scenePresenceArray.Count;
832 }
833
773 /// <summary> 834 /// <summary>
774 /// Request a scene presence by UUID. Fast, indexed lookup. 835 /// Request a scene presence by UUID. Fast, indexed lookup.
775 /// </summary> 836 /// </summary>
@@ -1063,9 +1124,11 @@ namespace OpenSim.Region.Framework.Scenes
1063 /// <param name="action"></param> 1124 /// <param name="action"></param>
1064 protected internal void ForEachSOG(Action<SceneObjectGroup> action) 1125 protected internal void ForEachSOG(Action<SceneObjectGroup> action)
1065 { 1126 {
1066 List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); 1127 EntityBase[] objlist = Entities.GetAllByType<SceneObjectGroup>();
1067 foreach (SceneObjectGroup obj in objlist) 1128 foreach (EntityBase ent in objlist)
1068 { 1129 {
1130 SceneObjectGroup obj = (SceneObjectGroup)ent;
1131
1069 try 1132 try
1070 { 1133 {
1071 action(obj); 1134 action(obj);
@@ -1521,10 +1584,13 @@ namespace OpenSim.Region.Framework.Scenes
1521 /// <param name="childPrims"></param> 1584 /// <param name="childPrims"></param>
1522 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1585 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1523 { 1586 {
1587 SceneObjectGroup parentGroup = root.ParentGroup;
1588 if (parentGroup == null) return;
1524 Monitor.Enter(m_updateLock); 1589 Monitor.Enter(m_updateLock);
1590
1525 try 1591 try
1526 { 1592 {
1527 SceneObjectGroup parentGroup = root.ParentGroup; 1593 parentGroup.areUpdatesSuspended = true;
1528 1594
1529 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1595 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1530 if (parentGroup != null) 1596 if (parentGroup != null)
@@ -1536,11 +1602,6 @@ namespace OpenSim.Region.Framework.Scenes
1536 1602
1537 if (child != null) 1603 if (child != null)
1538 { 1604 {
1539 // Make sure no child prim is set for sale
1540 // So that, on delink, no prims are unwittingly
1541 // left for sale and sold off
1542 child.RootPart.ObjectSaleType = 0;
1543 child.RootPart.SalePrice = 10;
1544 childGroups.Add(child); 1605 childGroups.Add(child);
1545 } 1606 }
1546 } 1607 }
@@ -1563,12 +1624,12 @@ namespace OpenSim.Region.Framework.Scenes
1563 // occur on link to invoke this elsewhere (such as object selection) 1624 // occur on link to invoke this elsewhere (such as object selection)
1564 parentGroup.RootPart.CreateSelected = true; 1625 parentGroup.RootPart.CreateSelected = true;
1565 parentGroup.TriggerScriptChangedEvent(Changed.LINK); 1626 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1566 parentGroup.HasGroupChanged = true;
1567 parentGroup.ScheduleGroupForFullUpdate();
1568
1569 } 1627 }
1570 finally 1628 finally
1571 { 1629 {
1630 parentGroup.areUpdatesSuspended = false;
1631 parentGroup.HasGroupChanged = true;
1632 parentGroup.ScheduleGroupForFullUpdate();
1572 Monitor.Exit(m_updateLock); 1633 Monitor.Exit(m_updateLock);
1573 } 1634 }
1574 } 1635 }
@@ -1600,21 +1661,24 @@ namespace OpenSim.Region.Framework.Scenes
1600 1661
1601 SceneObjectGroup group = part.ParentGroup; 1662 SceneObjectGroup group = part.ParentGroup;
1602 if (!affectedGroups.Contains(group)) 1663 if (!affectedGroups.Contains(group))
1664 {
1665 group.areUpdatesSuspended = true;
1603 affectedGroups.Add(group); 1666 affectedGroups.Add(group);
1667 }
1604 } 1668 }
1605 } 1669 }
1606 } 1670 }
1607 1671
1608 foreach (SceneObjectPart child in childParts) 1672 if (childParts.Count > 0)
1609 { 1673 {
1610 // Unlink all child parts from their groups 1674 foreach (SceneObjectPart child in childParts)
1611 // 1675 {
1612 child.ParentGroup.DelinkFromGroup(child, true); 1676 // Unlink all child parts from their groups
1613 1677 //
1614 // These are not in affected groups and will not be 1678 child.ParentGroup.DelinkFromGroup(child, true);
1615 // handled further. Do the honors here. 1679 child.ParentGroup.HasGroupChanged = true;
1616 child.ParentGroup.HasGroupChanged = true; 1680 child.ParentGroup.ScheduleGroupForFullUpdate();
1617 child.ParentGroup.ScheduleGroupForFullUpdate(); 1681 }
1618 } 1682 }
1619 1683
1620 foreach (SceneObjectPart root in rootParts) 1684 foreach (SceneObjectPart root in rootParts)
@@ -1624,56 +1688,68 @@ namespace OpenSim.Region.Framework.Scenes
1624 // However, editing linked parts and unlinking may be different 1688 // However, editing linked parts and unlinking may be different
1625 // 1689 //
1626 SceneObjectGroup group = root.ParentGroup; 1690 SceneObjectGroup group = root.ParentGroup;
1691 group.areUpdatesSuspended = true;
1627 1692
1628 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1693 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1629 int numChildren = newSet.Count; 1694 int numChildren = newSet.Count;
1630 1695
1696 if (numChildren == 1)
1697 break;
1698
1631 // If there are prims left in a link set, but the root is 1699 // If there are prims left in a link set, but the root is
1632 // slated for unlink, we need to do this 1700 // slated for unlink, we need to do this
1701 // Unlink the remaining set
1633 // 1702 //
1634 if (numChildren != 1) 1703 bool sendEventsToRemainder = true;
1635 { 1704 if (numChildren > 1)
1636 // Unlink the remaining set 1705 sendEventsToRemainder = false;
1637 //
1638 bool sendEventsToRemainder = true;
1639 if (numChildren > 1)
1640 sendEventsToRemainder = false;
1641 1706
1642 foreach (SceneObjectPart p in newSet) 1707 foreach (SceneObjectPart p in newSet)
1708 {
1709 if (p != group.RootPart)
1643 { 1710 {
1644 if (p != group.RootPart) 1711 group.DelinkFromGroup(p, sendEventsToRemainder);
1645 group.DelinkFromGroup(p, sendEventsToRemainder); 1712 if (numChildren > 2)
1713 {
1714 p.ParentGroup.areUpdatesSuspended = true;
1715 }
1716 else
1717 {
1718 p.ParentGroup.HasGroupChanged = true;
1719 p.ParentGroup.ScheduleGroupForFullUpdate();
1720 }
1646 } 1721 }
1722 }
1723
1724 // If there is more than one prim remaining, we
1725 // need to re-link
1726 //
1727 if (numChildren > 2)
1728 {
1729 // Remove old root
1730 //
1731 if (newSet.Contains(root))
1732 newSet.Remove(root);
1647 1733
1648 // If there is more than one prim remaining, we 1734 // Preserve link ordering
1649 // need to re-link
1650 // 1735 //
1651 if (numChildren > 2) 1736 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1652 { 1737 {
1653 // Remove old root 1738 return a.LinkNum.CompareTo(b.LinkNum);
1654 // 1739 });
1655 if (newSet.Contains(root))
1656 newSet.Remove(root);
1657
1658 // Preserve link ordering
1659 //
1660 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1661 {
1662 return a.LinkNum.CompareTo(b.LinkNum);
1663 });
1664 1740
1665 // Determine new root 1741 // Determine new root
1666 // 1742 //
1667 SceneObjectPart newRoot = newSet[0]; 1743 SceneObjectPart newRoot = newSet[0];
1668 newSet.RemoveAt(0); 1744 newSet.RemoveAt(0);
1669 1745
1670 foreach (SceneObjectPart newChild in newSet) 1746 foreach (SceneObjectPart newChild in newSet)
1671 newChild.UpdateFlag = 0; 1747 newChild.UpdateFlag = 0;
1672 1748
1673 LinkObjects(newRoot, newSet); 1749 newRoot.ParentGroup.areUpdatesSuspended = true;
1674 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1750 LinkObjects(newRoot, newSet);
1675 affectedGroups.Add(newRoot.ParentGroup); 1751 if (!affectedGroups.Contains(newRoot.ParentGroup))
1676 } 1752 affectedGroups.Add(newRoot.ParentGroup);
1677 } 1753 }
1678 } 1754 }
1679 1755
@@ -1683,6 +1759,7 @@ namespace OpenSim.Region.Framework.Scenes
1683 { 1759 {
1684 g.TriggerScriptChangedEvent(Changed.LINK); 1760 g.TriggerScriptChangedEvent(Changed.LINK);
1685 g.HasGroupChanged = true; // Persist 1761 g.HasGroupChanged = true; // Persist
1762 g.areUpdatesSuspended = false;
1686 g.ScheduleGroupForFullUpdate(); 1763 g.ScheduleGroupForFullUpdate();
1687 } 1764 }
1688 } 1765 }
@@ -1797,9 +1874,6 @@ namespace OpenSim.Region.Framework.Scenes
1797 child.ApplyNextOwnerPermissions(); 1874 child.ApplyNextOwnerPermissions();
1798 } 1875 }
1799 } 1876 }
1800
1801 copy.RootPart.ObjectSaleType = 0;
1802 copy.RootPart.SalePrice = 10;
1803 } 1877 }
1804 1878
1805 Entities.Add(copy); 1879 Entities.Add(copy);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index a86223c..6cc7231 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -69,10 +69,6 @@ namespace OpenSim.Region.Framework.Scenes
69 /// <summary> 69 /// <summary>
70 /// Stop the scripts contained in all the prims in this group 70 /// Stop the scripts contained in all the prims in this group
71 /// </summary> 71 /// </summary>
72 /// <param name="sceneObjectBeingDeleted">
73 /// Should be true if these scripts are being removed because the scene
74 /// object is being deleted. This will prevent spurious updates to the client.
75 /// </param>
76 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 72 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
77 { 73 {
78 SceneObjectPart[] parts = m_parts.GetArray(); 74 SceneObjectPart[] parts = m_parts.GetArray();
@@ -419,6 +415,9 @@ namespace OpenSim.Region.Framework.Scenes
419 415
420 public void ResumeScripts() 416 public void ResumeScripts()
421 { 417 {
418 if (m_scene.RegionInfo.RegionSettings.DisableScripts)
419 return;
420
422 SceneObjectPart[] parts = m_parts.GetArray(); 421 SceneObjectPart[] parts = m_parts.GetArray();
423 for (int i = 0; i < parts.Length; i++) 422 for (int i = 0; i < parts.Length; i++)
424 parts[i].Inventory.ResumeScripts(); 423 parts[i].Inventory.ResumeScripts();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 5f00f84..c870797 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -29,6 +29,7 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -105,8 +106,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 106 /// since the group's last persistent backup
106 /// </summary> 107 /// </summary>
107 private bool m_hasGroupChanged = false; 108 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 109 private long timeFirstChanged = 0;
109 private long timeLastChanged; 110 private long timeLastChanged = 0;
111 private long m_maxPersistTime = 0;
112 private long m_minPersistTime = 0;
113 private Random m_rand;
114 private bool m_suspendUpdates;
115 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
116
117 public bool areUpdatesSuspended
118 {
119 get
120 {
121 return m_suspendUpdates;
122 }
123 set
124 {
125 m_suspendUpdates = value;
126 if (!value)
127 {
128 QueueForUpdateCheck();
129 }
130 }
131 }
110 132
111 public bool HasGroupChanged 133 public bool HasGroupChanged
112 { 134 {
@@ -114,9 +136,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 136 {
115 if (value) 137 if (value)
116 { 138 {
139 if (m_isBackedUp)
140 {
141 m_scene.SceneGraph.FireChangeBackup(this);
142 }
117 timeLastChanged = DateTime.Now.Ticks; 143 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 144 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 145 timeFirstChanged = DateTime.Now.Ticks;
146 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
147 {
148 if (m_rand == null)
149 {
150 byte[] val = new byte[16];
151 m_rootPart.UUID.ToBytes(val, 0);
152 m_rand = new Random(BitConverter.ToInt32(val, 0));
153 }
154
155 if (m_scene.GetRootAgentCount() == 0)
156 {
157 //If the region is empty, this change has been made by an automated process
158 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
159
160 float factor = 1.5f + (float)(m_rand.NextDouble());
161 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
162 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
163 }
164 else
165 {
166 //If the region is not empty, we want to obey the minimum and maximum persist times
167 //but add a random factor so we stagger the object persistance a little
168 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
169 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
170 }
171 }
120 } 172 }
121 m_hasGroupChanged = value; 173 m_hasGroupChanged = value;
122 } 174 }
@@ -132,8 +184,19 @@ namespace OpenSim.Region.Framework.Scenes
132 return false; 184 return false;
133 if (m_scene.ShuttingDown) 185 if (m_scene.ShuttingDown)
134 return true; 186 return true;
187
188 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
189 {
190 m_maxPersistTime = m_scene.m_persistAfter;
191 m_minPersistTime = m_scene.m_dontPersistBefore;
192 }
193
135 long currentTime = DateTime.Now.Ticks; 194 long currentTime = DateTime.Now.Ticks;
136 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 195
196 if (timeLastChanged == 0) timeLastChanged = currentTime;
197 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
198
199 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
137 return true; 200 return true;
138 return false; 201 return false;
139 } 202 }
@@ -176,10 +239,10 @@ namespace OpenSim.Region.Framework.Scenes
176 239
177 private bool m_scriptListens_atTarget; 240 private bool m_scriptListens_atTarget;
178 private bool m_scriptListens_notAtTarget; 241 private bool m_scriptListens_notAtTarget;
179
180 private bool m_scriptListens_atRotTarget; 242 private bool m_scriptListens_atRotTarget;
181 private bool m_scriptListens_notAtRotTarget; 243 private bool m_scriptListens_notAtRotTarget;
182 244
245 public bool m_dupeInProgress = false;
183 internal Dictionary<UUID, string> m_savedScriptState; 246 internal Dictionary<UUID, string> m_savedScriptState;
184 247
185 #region Properties 248 #region Properties
@@ -219,7 +282,13 @@ namespace OpenSim.Region.Framework.Scenes
219 public virtual Quaternion Rotation 282 public virtual Quaternion Rotation
220 { 283 {
221 get { return m_rotation; } 284 get { return m_rotation; }
222 set { m_rotation = value; } 285 set {
286 foreach(SceneObjectPart p in m_parts.GetArray())
287 {
288 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
289 }
290 m_rotation = value;
291 }
223 } 292 }
224 293
225 public Quaternion GroupRotation 294 public Quaternion GroupRotation
@@ -293,7 +362,11 @@ namespace OpenSim.Region.Framework.Scenes
293 { 362 {
294 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 363 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
295 } 364 }
296 365
366 foreach (SceneObjectPart part in m_parts.GetArray())
367 {
368 part.IgnoreUndoUpdate = true;
369 }
297 if (RootPart.GetStatusSandbox()) 370 if (RootPart.GetStatusSandbox())
298 { 371 {
299 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 372 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -304,10 +377,31 @@ namespace OpenSim.Region.Framework.Scenes
304 return; 377 return;
305 } 378 }
306 } 379 }
307
308 SceneObjectPart[] parts = m_parts.GetArray(); 380 SceneObjectPart[] parts = m_parts.GetArray();
309 for (int i = 0; i < parts.Length; i++) 381 foreach (SceneObjectPart part in parts)
310 parts[i].GroupPosition = val; 382 {
383 part.IgnoreUndoUpdate = false;
384 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
385 part.GroupPosition = val;
386 if (!m_dupeInProgress)
387 {
388 part.TriggerScriptChangedEvent(Changed.POSITION);
389 }
390 }
391 if (!m_dupeInProgress)
392 {
393 foreach (ScenePresence av in m_linkedAvatars)
394 {
395 SceneObjectPart p;
396 if (m_parts.TryGetValue(av.LinkedPrim, out p))
397 {
398 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
399 av.AbsolutePosition += offset;
400 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
401 av.SendFullUpdateToAllClients();
402 }
403 }
404 }
311 405
312 //if (m_rootPart.PhysActor != null) 406 //if (m_rootPart.PhysActor != null)
313 //{ 407 //{
@@ -458,6 +552,7 @@ namespace OpenSim.Region.Framework.Scenes
458 /// </summary> 552 /// </summary>
459 public SceneObjectGroup() 553 public SceneObjectGroup()
460 { 554 {
555
461 } 556 }
462 557
463 /// <summary> 558 /// <summary>
@@ -474,7 +569,7 @@ namespace OpenSim.Region.Framework.Scenes
474 /// Constructor. This object is added to the scene later via AttachToScene() 569 /// Constructor. This object is added to the scene later via AttachToScene()
475 /// </summary> 570 /// </summary>
476 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 571 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
477 { 572 {
478 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 573 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
479 } 574 }
480 575
@@ -520,6 +615,9 @@ namespace OpenSim.Region.Framework.Scenes
520 /// </summary> 615 /// </summary>
521 public virtual void AttachToBackup() 616 public virtual void AttachToBackup()
522 { 617 {
618 if (IsAttachment) return;
619 m_scene.SceneGraph.FireAttachToBackup(this);
620
523 if (InSceneBackup) 621 if (InSceneBackup)
524 { 622 {
525 //m_log.DebugFormat( 623 //m_log.DebugFormat(
@@ -635,9 +733,9 @@ namespace OpenSim.Region.Framework.Scenes
635 result.normal = inter.normal; 733 result.normal = inter.normal;
636 result.distance = inter.distance; 734 result.distance = inter.distance;
637 } 735 }
736
638 } 737 }
639 } 738 }
640
641 return result; 739 return result;
642 } 740 }
643 741
@@ -657,17 +755,19 @@ namespace OpenSim.Region.Framework.Scenes
657 minZ = 8192f; 755 minZ = 8192f;
658 756
659 SceneObjectPart[] parts = m_parts.GetArray(); 757 SceneObjectPart[] parts = m_parts.GetArray();
660 for (int i = 0; i < parts.Length; i++) 758 foreach (SceneObjectPart part in parts)
661 { 759 {
662 SceneObjectPart part = parts[i];
663
664 Vector3 worldPos = part.GetWorldPosition(); 760 Vector3 worldPos = part.GetWorldPosition();
665 Vector3 offset = worldPos - AbsolutePosition; 761 Vector3 offset = worldPos - AbsolutePosition;
666 Quaternion worldRot; 762 Quaternion worldRot;
667 if (part.ParentID == 0) 763 if (part.ParentID == 0)
764 {
668 worldRot = part.RotationOffset; 765 worldRot = part.RotationOffset;
766 }
669 else 767 else
768 {
670 worldRot = part.GetWorldRotation(); 769 worldRot = part.GetWorldRotation();
770 }
671 771
672 Vector3 frontTopLeft; 772 Vector3 frontTopLeft;
673 Vector3 frontTopRight; 773 Vector3 frontTopRight;
@@ -679,6 +779,8 @@ namespace OpenSim.Region.Framework.Scenes
679 Vector3 backBottomLeft; 779 Vector3 backBottomLeft;
680 Vector3 backBottomRight; 780 Vector3 backBottomRight;
681 781
782 // Vector3[] corners = new Vector3[8];
783
682 Vector3 orig = Vector3.Zero; 784 Vector3 orig = Vector3.Zero;
683 785
684 frontTopLeft.X = orig.X - (part.Scale.X / 2); 786 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -713,6 +815,38 @@ namespace OpenSim.Region.Framework.Scenes
713 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 815 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
714 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 816 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
715 817
818
819
820 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
821 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
822 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
823 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
824 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
825 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
826 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
827 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
828
829 //for (int i = 0; i < 8; i++)
830 //{
831 // corners[i] = corners[i] * worldRot;
832 // corners[i] += offset;
833
834 // if (corners[i].X > maxX)
835 // maxX = corners[i].X;
836 // if (corners[i].X < minX)
837 // minX = corners[i].X;
838
839 // if (corners[i].Y > maxY)
840 // maxY = corners[i].Y;
841 // if (corners[i].Y < minY)
842 // minY = corners[i].Y;
843
844 // if (corners[i].Z > maxZ)
845 // maxZ = corners[i].Y;
846 // if (corners[i].Z < minZ)
847 // minZ = corners[i].Z;
848 //}
849
716 frontTopLeft = frontTopLeft * worldRot; 850 frontTopLeft = frontTopLeft * worldRot;
717 frontTopRight = frontTopRight * worldRot; 851 frontTopRight = frontTopRight * worldRot;
718 frontBottomLeft = frontBottomLeft * worldRot; 852 frontBottomLeft = frontBottomLeft * worldRot;
@@ -734,6 +868,15 @@ namespace OpenSim.Region.Framework.Scenes
734 backTopLeft += offset; 868 backTopLeft += offset;
735 backTopRight += offset; 869 backTopRight += offset;
736 870
871 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
872 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
873 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
874 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
875 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
876 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
877 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
878 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
879
737 if (frontTopRight.X > maxX) 880 if (frontTopRight.X > maxX)
738 maxX = frontTopRight.X; 881 maxX = frontTopRight.X;
739 if (frontTopLeft.X > maxX) 882 if (frontTopLeft.X > maxX)
@@ -879,15 +1022,20 @@ namespace OpenSim.Region.Framework.Scenes
879 1022
880 public void SaveScriptedState(XmlTextWriter writer) 1023 public void SaveScriptedState(XmlTextWriter writer)
881 { 1024 {
1025 SaveScriptedState(writer, false);
1026 }
1027
1028 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1029 {
882 XmlDocument doc = new XmlDocument(); 1030 XmlDocument doc = new XmlDocument();
883 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1031 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
884 1032
885 SceneObjectPart[] parts = m_parts.GetArray(); 1033 SceneObjectPart[] parts = m_parts.GetArray();
886 for (int i = 0; i < parts.Length; i++) 1034 for (int i = 0; i < parts.Length; i++)
887 { 1035 {
888 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1036 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
889 foreach (KeyValuePair<UUID, string> kvp in pstates) 1037 foreach (KeyValuePair<UUID, string> kvp in pstates)
890 states.Add(kvp.Key, kvp.Value); 1038 states[kvp.Key] = kvp.Value;
891 } 1039 }
892 1040
893 if (states.Count > 0) 1041 if (states.Count > 0)
@@ -906,6 +1054,118 @@ namespace OpenSim.Region.Framework.Scenes
906 } 1054 }
907 } 1055 }
908 1056
1057 /// <summary>
1058 /// Add the avatar to this linkset (avatar is sat).
1059 /// </summary>
1060 /// <param name="agentID"></param>
1061 public void AddAvatar(UUID agentID)
1062 {
1063 ScenePresence presence;
1064 if (m_scene.TryGetScenePresence(agentID, out presence))
1065 {
1066 if (!m_linkedAvatars.Contains(presence))
1067 {
1068 m_linkedAvatars.Add(presence);
1069 }
1070 }
1071 }
1072
1073 /// <summary>
1074 /// Delete the avatar from this linkset (avatar is unsat).
1075 /// </summary>
1076 /// <param name="agentID"></param>
1077 public void DeleteAvatar(UUID agentID)
1078 {
1079 ScenePresence presence;
1080 if (m_scene.TryGetScenePresence(agentID, out presence))
1081 {
1082 if (m_linkedAvatars.Contains(presence))
1083 {
1084 m_linkedAvatars.Remove(presence);
1085 }
1086 }
1087 }
1088
1089 /// <summary>
1090 /// Returns the list of linked presences (avatars sat on this group)
1091 /// </summary>
1092 /// <param name="agentID"></param>
1093 public List<ScenePresence> GetLinkedAvatars()
1094 {
1095 return m_linkedAvatars;
1096 }
1097
1098 /// <summary>
1099 /// Attach this scene object to the given avatar.
1100 /// </summary>
1101 /// <param name="agentID"></param>
1102 /// <param name="attachmentpoint"></param>
1103 /// <param name="AttachOffset"></param>
1104 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1105 {
1106 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1107 if (avatar != null)
1108 {
1109 // don't attach attachments to child agents
1110 if (avatar.IsChildAgent) return;
1111
1112// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1113
1114 DetachFromBackup();
1115
1116 // Remove from database and parcel prim count
1117 m_scene.DeleteFromStorage(UUID);
1118 m_scene.EventManager.TriggerParcelPrimCountTainted();
1119
1120 m_rootPart.AttachedAvatar = agentID;
1121
1122 //Anakin Lohner bug #3839
1123 lock (m_parts)
1124 {
1125 foreach (SceneObjectPart p in m_parts.GetArray())
1126 {
1127 p.AttachedAvatar = agentID;
1128 }
1129 }
1130
1131 if (m_rootPart.PhysActor != null)
1132 {
1133 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1134 m_rootPart.PhysActor = null;
1135 }
1136
1137 AbsolutePosition = AttachOffset;
1138 m_rootPart.AttachedPos = AttachOffset;
1139 m_rootPart.IsAttachment = true;
1140
1141 m_rootPart.SetParentLocalId(avatar.LocalId);
1142 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1143
1144 avatar.AddAttachment(this);
1145
1146 if (!silent)
1147 {
1148 // Killing it here will cause the client to deselect it
1149 // It then reappears on the avatar, deselected
1150 // through the full update below
1151 //
1152 if (IsSelected)
1153 {
1154 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1155 }
1156
1157 IsSelected = false; // fudge....
1158 ScheduleGroupForFullUpdate();
1159 }
1160 }
1161 else
1162 {
1163 m_log.WarnFormat(
1164 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1165 UUID, agentID, Scene.RegionInfo.RegionName);
1166 }
1167 }
1168
909 public byte GetAttachmentPoint() 1169 public byte GetAttachmentPoint()
910 { 1170 {
911 return m_rootPart.Shape.State; 1171 return m_rootPart.Shape.State;
@@ -1032,7 +1292,10 @@ namespace OpenSim.Region.Framework.Scenes
1032 public void AddPart(SceneObjectPart part) 1292 public void AddPart(SceneObjectPart part)
1033 { 1293 {
1034 part.SetParent(this); 1294 part.SetParent(this);
1035 part.LinkNum = m_parts.Add(part.UUID, part); 1295 m_parts.Add(part.UUID, part);
1296
1297 part.LinkNum = m_parts.Count;
1298
1036 if (part.LinkNum == 2 && RootPart != null) 1299 if (part.LinkNum == 2 && RootPart != null)
1037 RootPart.LinkNum = 1; 1300 RootPart.LinkNum = 1;
1038 } 1301 }
@@ -1116,7 +1379,7 @@ namespace OpenSim.Region.Framework.Scenes
1116 1379
1117 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1380 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1118 { 1381 {
1119 part.StoreUndoState(); 1382 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1120 part.OnGrab(offsetPos, remoteClient); 1383 part.OnGrab(offsetPos, remoteClient);
1121 } 1384 }
1122 1385
@@ -1136,6 +1399,11 @@ namespace OpenSim.Region.Framework.Scenes
1136 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1399 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1137 public void DeleteGroupFromScene(bool silent) 1400 public void DeleteGroupFromScene(bool silent)
1138 { 1401 {
1402 // We need to keep track of this state in case this group is still queued for backup.
1403 m_isDeleted = true;
1404
1405 DetachFromBackup();
1406
1139 SceneObjectPart[] parts = m_parts.GetArray(); 1407 SceneObjectPart[] parts = m_parts.GetArray();
1140 for (int i = 0; i < parts.Length; i++) 1408 for (int i = 0; i < parts.Length; i++)
1141 { 1409 {
@@ -1147,13 +1415,11 @@ namespace OpenSim.Region.Framework.Scenes
1147 avatar.StandUp(); 1415 avatar.StandUp();
1148 1416
1149 if (!silent) 1417 if (!silent)
1150 {
1151 part.UpdateFlag = 0; 1418 part.UpdateFlag = 0;
1152 if (part == m_rootPart)
1153 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1154 }
1155 }); 1419 });
1156 } 1420 }
1421
1422
1157 } 1423 }
1158 1424
1159 public void AddScriptLPS(int count) 1425 public void AddScriptLPS(int count)
@@ -1250,7 +1516,12 @@ namespace OpenSim.Region.Framework.Scenes
1250 1516
1251 public void SetOwnerId(UUID userId) 1517 public void SetOwnerId(UUID userId)
1252 { 1518 {
1253 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1519 ForEachPart(delegate(SceneObjectPart part)
1520 {
1521
1522 part.OwnerID = userId;
1523
1524 });
1254 } 1525 }
1255 1526
1256 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1527 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1286,7 +1557,10 @@ namespace OpenSim.Region.Framework.Scenes
1286 // any exception propogate upwards. 1557 // any exception propogate upwards.
1287 try 1558 try
1288 { 1559 {
1289 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1560 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1561 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1562 m_scene.LoadingPrims) // Land may not be valid yet
1563
1290 { 1564 {
1291 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1565 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1292 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1566 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1311,6 +1585,7 @@ namespace OpenSim.Region.Framework.Scenes
1311 } 1585 }
1312 } 1586 }
1313 } 1587 }
1588
1314 } 1589 }
1315 1590
1316 if (HasGroupChanged) 1591 if (HasGroupChanged)
@@ -1318,6 +1593,20 @@ namespace OpenSim.Region.Framework.Scenes
1318 // don't backup while it's selected or you're asking for changes mid stream. 1593 // don't backup while it's selected or you're asking for changes mid stream.
1319 if (isTimeToPersist() || forcedBackup) 1594 if (isTimeToPersist() || forcedBackup)
1320 { 1595 {
1596 if (m_rootPart.PhysActor != null &&
1597 (!m_rootPart.PhysActor.IsPhysical))
1598 {
1599 // Possible ghost prim
1600 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1601 {
1602 foreach (SceneObjectPart part in m_parts.GetArray())
1603 {
1604 // Re-set physics actor positions and
1605 // orientations
1606 part.GroupPosition = m_rootPart.GroupPosition;
1607 }
1608 }
1609 }
1321// m_log.DebugFormat( 1610// m_log.DebugFormat(
1322// "[SCENE]: Storing {0}, {1} in {2}", 1611// "[SCENE]: Storing {0}, {1} in {2}",
1323// Name, UUID, m_scene.RegionInfo.RegionName); 1612// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1380,81 +1669,106 @@ namespace OpenSim.Region.Framework.Scenes
1380 /// <returns></returns> 1669 /// <returns></returns>
1381 public SceneObjectGroup Copy(bool userExposed) 1670 public SceneObjectGroup Copy(bool userExposed)
1382 { 1671 {
1383 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1672 SceneObjectGroup dupe;
1384 dupe.m_isBackedUp = false; 1673 try
1385 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1674 {
1675 m_dupeInProgress = true;
1676 dupe = (SceneObjectGroup)MemberwiseClone();
1677 dupe.m_isBackedUp = false;
1678 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1386 1679
1387 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1680 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1388 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1681 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1389 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1682 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1390 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state 1683 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1391 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, 1684 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1392 // then restore it's attachment state 1685 // then restore it's attachment state
1393 1686
1394 // This is only necessary when userExposed is false! 1687 // This is only necessary when userExposed is false!
1395 1688
1396 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1689 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1397
1398 if (!userExposed)
1399 dupe.RootPart.IsAttachment = true;
1400 1690
1401 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1691 if (!userExposed)
1692 dupe.RootPart.IsAttachment = true;
1402 1693
1403 if (!userExposed) 1694 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1404 { 1695
1405 dupe.RootPart.IsAttachment = previousAttachmentStatus; 1696 if (!userExposed)
1406 } 1697 {
1698 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1699 }
1407 1700
1408 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1701 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1409 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1702 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1410 1703
1411 if (userExposed) 1704 if (userExposed)
1412 dupe.m_rootPart.TrimPermissions(); 1705 dupe.m_rootPart.TrimPermissions();
1413 1706
1414 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1707 /// may need to create a new Physics actor.
1415 1708 if (dupe.RootPart.PhysActor != null && userExposed)
1416 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1417 { 1709 {
1418 return p1.LinkNum.CompareTo(p2.LinkNum); 1710 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1711
1712 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1713 dupe.RootPart.Name,
1714 pbs,
1715 dupe.RootPart.AbsolutePosition,
1716 dupe.RootPart.Scale,
1717 dupe.RootPart.RotationOffset,
1718 dupe.RootPart.PhysActor.IsPhysical);
1719
1720 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1721 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1419 } 1722 }
1420 );
1421 1723
1422 foreach (SceneObjectPart part in partList) 1724 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1423 { 1725
1424 if (part.UUID != m_rootPart.UUID) 1726 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1727 {
1728 return p1.LinkNum.CompareTo(p2.LinkNum);
1729 }
1730 );
1731
1732 foreach (SceneObjectPart part in partList)
1425 { 1733 {
1426 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1734 if (part.UUID != m_rootPart.UUID)
1427 newPart.LinkNum = part.LinkNum; 1735 {
1428 } 1736 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1737
1738 newPart.LinkNum = part.LinkNum;
1739 }
1429 1740
1430 // Need to duplicate the physics actor as well 1741 // Need to duplicate the physics actor as well
1431 if (part.PhysActor != null && userExposed) 1742 if (part.PhysActor != null && userExposed)
1743 {
1744 PrimitiveBaseShape pbs = part.Shape;
1745
1746 part.PhysActor
1747 = m_scene.PhysicsScene.AddPrimShape(
1748 string.Format("{0}/{1}", part.Name, part.UUID),
1749 pbs,
1750 part.AbsolutePosition,
1751 part.Scale,
1752 part.RotationOffset,
1753 part.PhysActor.IsPhysical);
1754
1755 part.PhysActor.LocalID = part.LocalId;
1756 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1757 }
1758 }
1759 if (userExposed)
1432 { 1760 {
1433 PrimitiveBaseShape pbs = part.Shape; 1761 dupe.UpdateParentIDs();
1434 1762 dupe.HasGroupChanged = true;
1435 part.PhysActor 1763 dupe.AttachToBackup();
1436 = m_scene.PhysicsScene.AddPrimShape( 1764
1437 string.Format("{0}/{1}", part.Name, part.UUID), 1765 ScheduleGroupForFullUpdate();
1438 pbs,
1439 part.AbsolutePosition,
1440 part.Scale,
1441 part.RotationOffset,
1442 part.PhysActor.IsPhysical);
1443
1444 part.PhysActor.LocalID = part.LocalId;
1445 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1446 } 1766 }
1447 } 1767 }
1448 1768 finally
1449 if (userExposed)
1450 { 1769 {
1451 dupe.UpdateParentIDs(); 1770 m_dupeInProgress = false;
1452 dupe.HasGroupChanged = true;
1453 dupe.AttachToBackup();
1454
1455 ScheduleGroupForFullUpdate();
1456 } 1771 }
1457
1458 return dupe; 1772 return dupe;
1459 } 1773 }
1460 1774
@@ -1645,13 +1959,40 @@ namespace OpenSim.Region.Framework.Scenes
1645 } 1959 }
1646 } 1960 }
1647 1961
1962 public void rotLookAt(Quaternion target, float strength, float damping)
1963 {
1964 SceneObjectPart rootpart = m_rootPart;
1965 if (rootpart != null)
1966 {
1967 if (IsAttachment)
1968 {
1969 /*
1970 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1971 if (avatar != null)
1972 {
1973 Rotate the Av?
1974 } */
1975 }
1976 else
1977 {
1978 if (rootpart.PhysActor != null)
1979 { // APID must be implemented in your physics system for this to function.
1980 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1981 rootpart.PhysActor.APIDStrength = strength;
1982 rootpart.PhysActor.APIDDamping = damping;
1983 rootpart.PhysActor.APIDActive = true;
1984 }
1985 }
1986 }
1987 }
1988
1648 public void stopLookAt() 1989 public void stopLookAt()
1649 { 1990 {
1650 SceneObjectPart rootpart = m_rootPart; 1991 SceneObjectPart rootpart = m_rootPart;
1651 if (rootpart != null) 1992 if (rootpart != null)
1652 { 1993 {
1653 if (rootpart.PhysActor != null) 1994 if (rootpart.PhysActor != null)
1654 { 1995 { // APID must be implemented in your physics system for this to function.
1655 rootpart.PhysActor.APIDActive = false; 1996 rootpart.PhysActor.APIDActive = false;
1656 } 1997 }
1657 } 1998 }
@@ -1717,6 +2058,8 @@ namespace OpenSim.Region.Framework.Scenes
1717 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2058 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1718 { 2059 {
1719 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2060 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2061 newPart.SetParent(this);
2062
1720 AddPart(newPart); 2063 AddPart(newPart);
1721 2064
1722 SetPartAsNonRoot(newPart); 2065 SetPartAsNonRoot(newPart);
@@ -1863,11 +2206,11 @@ namespace OpenSim.Region.Framework.Scenes
1863 /// Immediately send a full update for this scene object. 2206 /// Immediately send a full update for this scene object.
1864 /// </summary> 2207 /// </summary>
1865 public void SendGroupFullUpdate() 2208 public void SendGroupFullUpdate()
1866 { 2209 {
1867 if (IsDeleted) 2210 if (IsDeleted)
1868 return; 2211 return;
1869 2212
1870// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2213// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1871 2214
1872 RootPart.SendFullUpdateToAllClients(); 2215 RootPart.SendFullUpdateToAllClients();
1873 2216
@@ -2056,12 +2399,15 @@ namespace OpenSim.Region.Framework.Scenes
2056 part.LinkNum += objectGroup.PrimCount; 2399 part.LinkNum += objectGroup.PrimCount;
2057 } 2400 }
2058 } 2401 }
2402 }
2059 2403
2060 linkPart.LinkNum = 2; 2404 linkPart.LinkNum = 2;
2061 2405
2062 linkPart.SetParent(this); 2406 linkPart.SetParent(this);
2063 linkPart.CreateSelected = true; 2407 linkPart.CreateSelected = true;
2064 2408
2409 lock (m_parts.SyncRoot)
2410 {
2065 //if (linkPart.PhysActor != null) 2411 //if (linkPart.PhysActor != null)
2066 //{ 2412 //{
2067 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2413 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2218,6 +2564,8 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2564 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2565 public virtual void DetachFromBackup()
2220 { 2566 {
2567 m_scene.SceneGraph.FireDetachFromBackup(this);
2568
2221 if (m_isBackedUp) 2569 if (m_isBackedUp)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2570 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2571
@@ -2522,6 +2870,17 @@ namespace OpenSim.Region.Framework.Scenes
2522 } 2870 }
2523 } 2871 }
2524 2872
2873
2874
2875 /// <summary>
2876 /// Gets the number of parts
2877 /// </summary>
2878 /// <returns></returns>
2879 public int GetPartCount()
2880 {
2881 return Parts.Count();
2882 }
2883
2525 /// <summary> 2884 /// <summary>
2526 /// Update the texture entry for this part 2885 /// Update the texture entry for this part
2527 /// </summary> 2886 /// </summary>
@@ -2583,11 +2942,9 @@ namespace OpenSim.Region.Framework.Scenes
2583 scale.Y = m_scene.m_maxNonphys; 2942 scale.Y = m_scene.m_maxNonphys;
2584 if (scale.Z > m_scene.m_maxNonphys) 2943 if (scale.Z > m_scene.m_maxNonphys)
2585 scale.Z = m_scene.m_maxNonphys; 2944 scale.Z = m_scene.m_maxNonphys;
2586
2587 SceneObjectPart part = GetChildPart(localID); 2945 SceneObjectPart part = GetChildPart(localID);
2588 if (part != null) 2946 if (part != null)
2589 { 2947 {
2590 part.Resize(scale);
2591 if (part.PhysActor != null) 2948 if (part.PhysActor != null)
2592 { 2949 {
2593 if (part.PhysActor.IsPhysical) 2950 if (part.PhysActor.IsPhysical)
@@ -2602,7 +2959,7 @@ namespace OpenSim.Region.Framework.Scenes
2602 part.PhysActor.Size = scale; 2959 part.PhysActor.Size = scale;
2603 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2960 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2604 } 2961 }
2605 //if (part.UUID != m_rootPart.UUID) 2962 part.Resize(scale);
2606 2963
2607 HasGroupChanged = true; 2964 HasGroupChanged = true;
2608 ScheduleGroupForFullUpdate(); 2965 ScheduleGroupForFullUpdate();
@@ -2624,7 +2981,6 @@ namespace OpenSim.Region.Framework.Scenes
2624 SceneObjectPart part = GetChildPart(localID); 2981 SceneObjectPart part = GetChildPart(localID);
2625 if (part != null) 2982 if (part != null)
2626 { 2983 {
2627 part.IgnoreUndoUpdate = true;
2628 if (scale.X > m_scene.m_maxNonphys) 2984 if (scale.X > m_scene.m_maxNonphys)
2629 scale.X = m_scene.m_maxNonphys; 2985 scale.X = m_scene.m_maxNonphys;
2630 if (scale.Y > m_scene.m_maxNonphys) 2986 if (scale.Y > m_scene.m_maxNonphys)
@@ -2661,7 +3017,7 @@ namespace OpenSim.Region.Framework.Scenes
2661 3017
2662 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3018 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2663 { 3019 {
2664 if (oldSize.X * x > m_scene.m_maxPhys) 3020 if (oldSize.X*x > m_scene.m_maxPhys)
2665 { 3021 {
2666 f = m_scene.m_maxPhys / oldSize.X; 3022 f = m_scene.m_maxPhys / oldSize.X;
2667 a = f / x; 3023 a = f / x;
@@ -2669,7 +3025,7 @@ namespace OpenSim.Region.Framework.Scenes
2669 y *= a; 3025 y *= a;
2670 z *= a; 3026 z *= a;
2671 } 3027 }
2672 if (oldSize.Y * y > m_scene.m_maxPhys) 3028 if (oldSize.Y*y > m_scene.m_maxPhys)
2673 { 3029 {
2674 f = m_scene.m_maxPhys / oldSize.Y; 3030 f = m_scene.m_maxPhys / oldSize.Y;
2675 a = f / y; 3031 a = f / y;
@@ -2677,7 +3033,7 @@ namespace OpenSim.Region.Framework.Scenes
2677 y *= a; 3033 y *= a;
2678 z *= a; 3034 z *= a;
2679 } 3035 }
2680 if (oldSize.Z * z > m_scene.m_maxPhys) 3036 if (oldSize.Z*z > m_scene.m_maxPhys)
2681 { 3037 {
2682 f = m_scene.m_maxPhys / oldSize.Z; 3038 f = m_scene.m_maxPhys / oldSize.Z;
2683 a = f / z; 3039 a = f / z;
@@ -2688,7 +3044,7 @@ namespace OpenSim.Region.Framework.Scenes
2688 } 3044 }
2689 else 3045 else
2690 { 3046 {
2691 if (oldSize.X * x > m_scene.m_maxNonphys) 3047 if (oldSize.X*x > m_scene.m_maxNonphys)
2692 { 3048 {
2693 f = m_scene.m_maxNonphys / oldSize.X; 3049 f = m_scene.m_maxNonphys / oldSize.X;
2694 a = f / x; 3050 a = f / x;
@@ -2696,7 +3052,7 @@ namespace OpenSim.Region.Framework.Scenes
2696 y *= a; 3052 y *= a;
2697 z *= a; 3053 z *= a;
2698 } 3054 }
2699 if (oldSize.Y * y > m_scene.m_maxNonphys) 3055 if (oldSize.Y*y > m_scene.m_maxNonphys)
2700 { 3056 {
2701 f = m_scene.m_maxNonphys / oldSize.Y; 3057 f = m_scene.m_maxNonphys / oldSize.Y;
2702 a = f / y; 3058 a = f / y;
@@ -2704,7 +3060,7 @@ namespace OpenSim.Region.Framework.Scenes
2704 y *= a; 3060 y *= a;
2705 z *= a; 3061 z *= a;
2706 } 3062 }
2707 if (oldSize.Z * z > m_scene.m_maxNonphys) 3063 if (oldSize.Z*z > m_scene.m_maxNonphys)
2708 { 3064 {
2709 f = m_scene.m_maxNonphys / oldSize.Z; 3065 f = m_scene.m_maxNonphys / oldSize.Z;
2710 a = f / z; 3066 a = f / z;
@@ -2714,7 +3070,6 @@ namespace OpenSim.Region.Framework.Scenes
2714 } 3070 }
2715 } 3071 }
2716 obPart.IgnoreUndoUpdate = false; 3072 obPart.IgnoreUndoUpdate = false;
2717 obPart.StoreUndoState();
2718 } 3073 }
2719 } 3074 }
2720 } 3075 }
@@ -2722,8 +3077,13 @@ namespace OpenSim.Region.Framework.Scenes
2722 Vector3 prevScale = part.Scale; 3077 Vector3 prevScale = part.Scale;
2723 prevScale.X *= x; 3078 prevScale.X *= x;
2724 prevScale.Y *= y; 3079 prevScale.Y *= y;
2725 prevScale.Z *= z; 3080 prevScale.Z *= z;;
3081
3082 part.IgnoreUndoUpdate = false;
3083 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3084 part.IgnoreUndoUpdate = true;
2726 part.Resize(prevScale); 3085 part.Resize(prevScale);
3086 part.IgnoreUndoUpdate = false;
2727 3087
2728 parts = m_parts.GetArray(); 3088 parts = m_parts.GetArray();
2729 for (int i = 0; i < parts.Length; i++) 3089 for (int i = 0; i < parts.Length; i++)
@@ -2732,19 +3092,26 @@ namespace OpenSim.Region.Framework.Scenes
2732 obPart.IgnoreUndoUpdate = true; 3092 obPart.IgnoreUndoUpdate = true;
2733 if (obPart.UUID != m_rootPart.UUID) 3093 if (obPart.UUID != m_rootPart.UUID)
2734 { 3094 {
2735 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3095 if (obPart.UUID != m_rootPart.UUID)
2736 currentpos.X *= x; 3096 {
2737 currentpos.Y *= y; 3097 obPart.IgnoreUndoUpdate = false;
2738 currentpos.Z *= z; 3098 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2739 Vector3 newSize = new Vector3(obPart.Scale); 3099 obPart.IgnoreUndoUpdate = true;
2740 newSize.X *= x; 3100
2741 newSize.Y *= y; 3101 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2742 newSize.Z *= z; 3102 currentpos.X *= x;
2743 obPart.Resize(newSize); 3103 currentpos.Y *= y;
2744 obPart.UpdateOffSet(currentpos); 3104 currentpos.Z *= z;
3105 Vector3 newSize = new Vector3(obPart.Scale);
3106 newSize.X *= x;
3107 newSize.Y *= y;
3108 newSize.Z *= z;
3109 obPart.Resize(newSize);
3110 obPart.UpdateOffSet(currentpos);
3111 }
3112 obPart.IgnoreUndoUpdate = false;
2745 } 3113 }
2746 obPart.IgnoreUndoUpdate = false; 3114 obPart.IgnoreUndoUpdate = false;
2747 obPart.StoreUndoState();
2748 } 3115 }
2749 3116
2750 if (part.PhysActor != null) 3117 if (part.PhysActor != null)
@@ -2754,7 +3121,6 @@ namespace OpenSim.Region.Framework.Scenes
2754 } 3121 }
2755 3122
2756 part.IgnoreUndoUpdate = false; 3123 part.IgnoreUndoUpdate = false;
2757 part.StoreUndoState();
2758 HasGroupChanged = true; 3124 HasGroupChanged = true;
2759 ScheduleGroupForTerseUpdate(); 3125 ScheduleGroupForTerseUpdate();
2760 } 3126 }
@@ -2770,14 +3136,11 @@ namespace OpenSim.Region.Framework.Scenes
2770 /// <param name="pos"></param> 3136 /// <param name="pos"></param>
2771 public void UpdateGroupPosition(Vector3 pos) 3137 public void UpdateGroupPosition(Vector3 pos)
2772 { 3138 {
2773 SceneObjectPart[] parts = m_parts.GetArray();
2774 for (int i = 0; i < parts.Length; i++)
2775 parts[i].StoreUndoState();
2776
2777 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3139 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2778 { 3140 {
2779 if (IsAttachment) 3141 if (IsAttachment)
2780 { 3142 {
3143 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2781 m_rootPart.AttachedPos = pos; 3144 m_rootPart.AttachedPos = pos;
2782 } 3145 }
2783 if (RootPart.GetStatusSandbox()) 3146 if (RootPart.GetStatusSandbox())
@@ -2811,7 +3174,7 @@ namespace OpenSim.Region.Framework.Scenes
2811 3174
2812 SceneObjectPart[] parts = m_parts.GetArray(); 3175 SceneObjectPart[] parts = m_parts.GetArray();
2813 for (int i = 0; i < parts.Length; i++) 3176 for (int i = 0; i < parts.Length; i++)
2814 parts[i].StoreUndoState(); 3177 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2815 3178
2816 if (part != null) 3179 if (part != null)
2817 { 3180 {
@@ -2836,7 +3199,7 @@ namespace OpenSim.Region.Framework.Scenes
2836 { 3199 {
2837 SceneObjectPart[] parts = m_parts.GetArray(); 3200 SceneObjectPart[] parts = m_parts.GetArray();
2838 for (int i = 0; i < parts.Length; i++) 3201 for (int i = 0; i < parts.Length; i++)
2839 parts[i].StoreUndoState(); 3202 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2840 3203
2841 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3204 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2842 Vector3 oldPos = 3205 Vector3 oldPos =
@@ -2857,10 +3220,27 @@ namespace OpenSim.Region.Framework.Scenes
2857 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3220 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2858 } 3221 }
2859 3222
2860 AbsolutePosition = newPos; 3223 //We have to set undoing here because otherwise an undo state will be saved
3224 if (!m_rootPart.Undoing)
3225 {
3226 m_rootPart.Undoing = true;
3227 AbsolutePosition = newPos;
3228 m_rootPart.Undoing = false;
3229 }
3230 else
3231 {
3232 AbsolutePosition = newPos;
3233 }
2861 3234
2862 HasGroupChanged = true; 3235 HasGroupChanged = true;
2863 ScheduleGroupForTerseUpdate(); 3236 if (m_rootPart.Undoing)
3237 {
3238 ScheduleGroupForFullUpdate();
3239 }
3240 else
3241 {
3242 ScheduleGroupForTerseUpdate();
3243 }
2864 } 3244 }
2865 3245
2866 public void OffsetForNewRegion(Vector3 offset) 3246 public void OffsetForNewRegion(Vector3 offset)
@@ -2880,7 +3260,7 @@ namespace OpenSim.Region.Framework.Scenes
2880 { 3260 {
2881 SceneObjectPart[] parts = m_parts.GetArray(); 3261 SceneObjectPart[] parts = m_parts.GetArray();
2882 for (int i = 0; i < parts.Length; i++) 3262 for (int i = 0; i < parts.Length; i++)
2883 parts[i].StoreUndoState(); 3263 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2884 3264
2885 m_rootPart.UpdateRotation(rot); 3265 m_rootPart.UpdateRotation(rot);
2886 3266
@@ -2904,7 +3284,7 @@ namespace OpenSim.Region.Framework.Scenes
2904 { 3284 {
2905 SceneObjectPart[] parts = m_parts.GetArray(); 3285 SceneObjectPart[] parts = m_parts.GetArray();
2906 for (int i = 0; i < parts.Length; i++) 3286 for (int i = 0; i < parts.Length; i++)
2907 parts[i].StoreUndoState(); 3287 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2908 3288
2909 m_rootPart.UpdateRotation(rot); 3289 m_rootPart.UpdateRotation(rot);
2910 3290
@@ -2929,10 +3309,9 @@ namespace OpenSim.Region.Framework.Scenes
2929 public void UpdateSingleRotation(Quaternion rot, uint localID) 3309 public void UpdateSingleRotation(Quaternion rot, uint localID)
2930 { 3310 {
2931 SceneObjectPart part = GetChildPart(localID); 3311 SceneObjectPart part = GetChildPart(localID);
2932
2933 SceneObjectPart[] parts = m_parts.GetArray(); 3312 SceneObjectPart[] parts = m_parts.GetArray();
2934 for (int i = 0; i < parts.Length; i++) 3313 for (int i = 0; i < parts.Length; i++)
2935 parts[i].StoreUndoState(); 3314 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2936 3315
2937 if (part != null) 3316 if (part != null)
2938 { 3317 {
@@ -2960,15 +3339,24 @@ namespace OpenSim.Region.Framework.Scenes
2960 if (part.UUID == m_rootPart.UUID) 3339 if (part.UUID == m_rootPart.UUID)
2961 { 3340 {
2962 UpdateRootRotation(rot); 3341 UpdateRootRotation(rot);
2963 AbsolutePosition = pos; 3342 if (!m_rootPart.Undoing)
3343 {
3344 m_rootPart.Undoing = true;
3345 AbsolutePosition = pos;
3346 m_rootPart.Undoing = false;
3347 }
3348 else
3349 {
3350 AbsolutePosition = pos;
3351 }
2964 } 3352 }
2965 else 3353 else
2966 { 3354 {
3355 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2967 part.IgnoreUndoUpdate = true; 3356 part.IgnoreUndoUpdate = true;
2968 part.UpdateRotation(rot); 3357 part.UpdateRotation(rot);
2969 part.OffsetPosition = pos; 3358 part.OffsetPosition = pos;
2970 part.IgnoreUndoUpdate = false; 3359 part.IgnoreUndoUpdate = false;
2971 part.StoreUndoState();
2972 } 3360 }
2973 } 3361 }
2974 } 3362 }
@@ -2982,7 +3370,13 @@ namespace OpenSim.Region.Framework.Scenes
2982 Quaternion axRot = rot; 3370 Quaternion axRot = rot;
2983 Quaternion oldParentRot = m_rootPart.RotationOffset; 3371 Quaternion oldParentRot = m_rootPart.RotationOffset;
2984 3372
2985 m_rootPart.StoreUndoState(); 3373 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3374 bool cancelUndo = false;
3375 if (!m_rootPart.Undoing)
3376 {
3377 m_rootPart.Undoing = true;
3378 cancelUndo = true;
3379 }
2986 m_rootPart.UpdateRotation(rot); 3380 m_rootPart.UpdateRotation(rot);
2987 if (m_rootPart.PhysActor != null) 3381 if (m_rootPart.PhysActor != null)
2988 { 3382 {
@@ -3006,17 +3400,12 @@ namespace OpenSim.Region.Framework.Scenes
3006 newRot *= Quaternion.Inverse(axRot); 3400 newRot *= Quaternion.Inverse(axRot);
3007 prim.RotationOffset = newRot; 3401 prim.RotationOffset = newRot;
3008 prim.ScheduleTerseUpdate(); 3402 prim.ScheduleTerseUpdate();
3403 prim.IgnoreUndoUpdate = false;
3009 } 3404 }
3010 } 3405 }
3011 3406 if (cancelUndo == true)
3012 for (int i = 0; i < parts.Length; i++)
3013 { 3407 {
3014 SceneObjectPart childpart = parts[i]; 3408 m_rootPart.Undoing = false;
3015 if (childpart != m_rootPart)
3016 {
3017 childpart.IgnoreUndoUpdate = false;
3018 childpart.StoreUndoState();
3019 }
3020 } 3409 }
3021 3410
3022 m_rootPart.ScheduleTerseUpdate(); 3411 m_rootPart.ScheduleTerseUpdate();
@@ -3242,7 +3631,6 @@ namespace OpenSim.Region.Framework.Scenes
3242 public float GetMass() 3631 public float GetMass()
3243 { 3632 {
3244 float retmass = 0f; 3633 float retmass = 0f;
3245
3246 SceneObjectPart[] parts = m_parts.GetArray(); 3634 SceneObjectPart[] parts = m_parts.GetArray();
3247 for (int i = 0; i < parts.Length; i++) 3635 for (int i = 0; i < parts.Length; i++)
3248 retmass += parts[i].GetMass(); 3636 retmass += parts[i].GetMass();
@@ -3358,6 +3746,14 @@ namespace OpenSim.Region.Framework.Scenes
3358 SetFromItemID(uuid); 3746 SetFromItemID(uuid);
3359 } 3747 }
3360 3748
3749 public void ResetOwnerChangeFlag()
3750 {
3751 ForEachPart(delegate(SceneObjectPart part)
3752 {
3753 part.ResetOwnerChangeFlag();
3754 });
3755 }
3756
3361 #endregion 3757 #endregion
3362 } 3758 }
3363} 3759}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 39b109b..f0740f8 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -60,7 +60,8 @@ namespace OpenSim.Region.Framework.Scenes
60 TELEPORT = 512, 60 TELEPORT = 512,
61 REGION_RESTART = 1024, 61 REGION_RESTART = 1024,
62 MEDIA = 2048, 62 MEDIA = 2048,
63 ANIMATION = 16384 63 ANIMATION = 16384,
64 POSITION = 32768
64 } 65 }
65 66
66 // I don't really know where to put this except here. 67 // I don't really know where to put this except here.
@@ -149,8 +150,8 @@ namespace OpenSim.Region.Framework.Scenes
149 150
150 // TODO: This needs to be persisted in next XML version update! 151 // TODO: This needs to be persisted in next XML version update!
151 [XmlIgnore] 152 [XmlIgnore]
152 public readonly int[] PayPrice = {-2,-2,-2,-2,-2}; 153 public int[] PayPrice = {-2,-2,-2,-2,-2};
153 154
154 [XmlIgnore] 155 [XmlIgnore]
155 public PhysicsActor PhysActor 156 public PhysicsActor PhysActor
156 { 157 {
@@ -193,6 +194,14 @@ namespace OpenSim.Region.Framework.Scenes
193 [XmlIgnore] 194 [XmlIgnore]
194 public UUID FromFolderID; 195 public UUID FromFolderID;
195 196
197 // The following two are to hold the attachment data
198 // while an object is inworld
199 [XmlIgnore]
200 public byte AttachPoint = 0;
201
202 [XmlIgnore]
203 public Vector3 AttachOffset = Vector3.Zero;
204
196 [XmlIgnore] 205 [XmlIgnore]
197 public int STATUS_ROTATE_X; 206 public int STATUS_ROTATE_X;
198 207
@@ -288,6 +297,7 @@ namespace OpenSim.Region.Framework.Scenes
288 private Quaternion m_sitTargetOrientation = Quaternion.Identity; 297 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
289 private Vector3 m_sitTargetPosition; 298 private Vector3 m_sitTargetPosition;
290 private string m_sitAnimation = "SIT"; 299 private string m_sitAnimation = "SIT";
300 private bool m_occupied; // KF if any av is sitting on this prim
291 private string m_text = String.Empty; 301 private string m_text = String.Empty;
292 private string m_touchName = String.Empty; 302 private string m_touchName = String.Empty;
293 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); 303 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5);
@@ -377,7 +387,7 @@ namespace OpenSim.Region.Framework.Scenes
377 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, 387 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
378 Quaternion rotationOffset, Vector3 offsetPosition) 388 Quaternion rotationOffset, Vector3 offsetPosition)
379 { 389 {
380 m_name = "Primitive"; 390 m_name = "Object";
381 391
382 Rezzed = DateTime.UtcNow; 392 Rezzed = DateTime.UtcNow;
383 _creationDate = (int)Utils.DateTimeToUnixTime(Rezzed); 393 _creationDate = (int)Utils.DateTimeToUnixTime(Rezzed);
@@ -433,7 +443,7 @@ namespace OpenSim.Region.Framework.Scenes
433 private uint _ownerMask = (uint)PermissionMask.All; 443 private uint _ownerMask = (uint)PermissionMask.All;
434 private uint _groupMask = (uint)PermissionMask.None; 444 private uint _groupMask = (uint)PermissionMask.None;
435 private uint _everyoneMask = (uint)PermissionMask.None; 445 private uint _everyoneMask = (uint)PermissionMask.None;
436 private uint _nextOwnerMask = (uint)PermissionMask.All; 446 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
437 private PrimFlags _flags = PrimFlags.None; 447 private PrimFlags _flags = PrimFlags.None;
438 private DateTime m_expires; 448 private DateTime m_expires;
439 private DateTime m_rezzed; 449 private DateTime m_rezzed;
@@ -473,12 +483,16 @@ namespace OpenSim.Region.Framework.Scenes
473 } 483 }
474 484
475 /// <value> 485 /// <value>
476 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes 486 /// Get the inventory list
477 /// </value> 487 /// </value>
478 public TaskInventoryDictionary TaskInventory 488 public TaskInventoryDictionary TaskInventory
479 { 489 {
480 get { return m_inventory.Items; } 490 get {
481 set { m_inventory.Items = value; } 491 return m_inventory.Items;
492 }
493 set {
494 m_inventory.Items = value;
495 }
482 } 496 }
483 497
484 /// <summary> 498 /// <summary>
@@ -618,14 +632,12 @@ namespace OpenSim.Region.Framework.Scenes
618 set { m_LoopSoundSlavePrims = value; } 632 set { m_LoopSoundSlavePrims = value; }
619 } 633 }
620 634
621 [XmlIgnore]
622 public Byte[] TextureAnimation 635 public Byte[] TextureAnimation
623 { 636 {
624 get { return m_TextureAnimation; } 637 get { return m_TextureAnimation; }
625 set { m_TextureAnimation = value; } 638 set { m_TextureAnimation = value; }
626 } 639 }
627 640
628 [XmlIgnore]
629 public Byte[] ParticleSystem 641 public Byte[] ParticleSystem
630 { 642 {
631 get { return m_particleSystem; } 643 get { return m_particleSystem; }
@@ -679,7 +691,6 @@ namespace OpenSim.Region.Framework.Scenes
679 set 691 set
680 { 692 {
681 m_groupPosition = value; 693 m_groupPosition = value;
682
683 PhysicsActor actor = PhysActor; 694 PhysicsActor actor = PhysActor;
684 if (actor != null) 695 if (actor != null)
685 { 696 {
@@ -699,25 +710,13 @@ namespace OpenSim.Region.Framework.Scenes
699 710
700 // Tell the physics engines that this prim changed. 711 // Tell the physics engines that this prim changed.
701 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 712 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
713
702 } 714 }
703 catch (Exception e) 715 catch (Exception e)
704 { 716 {
705 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); 717 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
706 } 718 }
707 } 719 }
708
709 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
710 if (m_sitTargetAvatar != UUID.Zero)
711 {
712 if (m_parentGroup != null) // TODO can there be a SOP without a SOG?
713 {
714 ScenePresence avatar;
715 if (m_parentGroup.Scene.TryGetScenePresence(m_sitTargetAvatar, out avatar))
716 {
717 avatar.ParentPosition = GetWorldPosition();
718 }
719 }
720 }
721 } 720 }
722 } 721 }
723 722
@@ -726,7 +725,8 @@ namespace OpenSim.Region.Framework.Scenes
726 get { return m_offsetPosition; } 725 get { return m_offsetPosition; }
727 set 726 set
728 { 727 {
729 StoreUndoState(); 728 Vector3 oldpos = m_offsetPosition;
729 StoreUndoState(UndoType.STATE_PRIM_POSITION);
730 m_offsetPosition = value; 730 m_offsetPosition = value;
731 731
732 if (ParentGroup != null && !ParentGroup.IsDeleted) 732 if (ParentGroup != null && !ParentGroup.IsDeleted)
@@ -740,7 +740,22 @@ namespace OpenSim.Region.Framework.Scenes
740 // Tell the physics engines that this prim changed. 740 // Tell the physics engines that this prim changed.
741 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 741 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
742 } 742 }
743
744 if (!m_parentGroup.m_dupeInProgress)
745 {
746 List<ScenePresence> avs = ParentGroup.GetLinkedAvatars();
747 foreach (ScenePresence av in avs)
748 {
749 if (av.LinkedPrim == m_uuid)
750 {
751 Vector3 offset = (m_offsetPosition - oldpos);
752 av.OffsetPosition += offset;
753 av.SendFullUpdateToAllClients();
754 }
755 }
756 }
743 } 757 }
758 TriggerScriptChangedEvent(Changed.POSITION);
744 } 759 }
745 } 760 }
746 761
@@ -782,7 +797,7 @@ namespace OpenSim.Region.Framework.Scenes
782 797
783 set 798 set
784 { 799 {
785 StoreUndoState(); 800 StoreUndoState(UndoType.STATE_PRIM_ROTATION);
786 m_rotationOffset = value; 801 m_rotationOffset = value;
787 802
788 PhysicsActor actor = PhysActor; 803 PhysicsActor actor = PhysActor;
@@ -866,7 +881,16 @@ namespace OpenSim.Region.Framework.Scenes
866 /// <summary></summary> 881 /// <summary></summary>
867 public Vector3 Acceleration 882 public Vector3 Acceleration
868 { 883 {
869 get { return m_acceleration; } 884 get
885 {
886 PhysicsActor actor = PhysActor;
887 if (actor != null)
888 {
889 m_acceleration = actor.Acceleration;
890 }
891 return m_acceleration;
892 }
893
870 set { m_acceleration = value; } 894 set { m_acceleration = value; }
871 } 895 }
872 896
@@ -971,7 +995,7 @@ namespace OpenSim.Region.Framework.Scenes
971 get { return m_shape.Scale; } 995 get { return m_shape.Scale; }
972 set 996 set
973 { 997 {
974 StoreUndoState(); 998 StoreUndoState(UndoType.STATE_PRIM_SCALE);
975 if (m_shape != null) 999 if (m_shape != null)
976 { 1000 {
977 m_shape.Scale = value; 1001 m_shape.Scale = value;
@@ -1041,7 +1065,8 @@ namespace OpenSim.Region.Framework.Scenes
1041 if (IsAttachment) 1065 if (IsAttachment)
1042 return GroupPosition; 1066 return GroupPosition;
1043 1067
1044 return m_offsetPosition + m_groupPosition; } 1068// return m_offsetPosition + m_groupPosition; }
1069 return m_groupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset) ; } //KF: Rotation was ignored!
1045 } 1070 }
1046 1071
1047 public SceneObjectGroup ParentGroup 1072 public SceneObjectGroup ParentGroup
@@ -1200,6 +1225,13 @@ namespace OpenSim.Region.Framework.Scenes
1200 _flags = value; 1225 _flags = value;
1201 } 1226 }
1202 } 1227 }
1228
1229 [XmlIgnore]
1230 public bool IsOccupied // KF If an av is sittingon this prim
1231 {
1232 get { return m_occupied; }
1233 set { m_occupied = value; }
1234 }
1203 1235
1204 [XmlIgnore] 1236 [XmlIgnore]
1205 public UUID SitTargetAvatar 1237 public UUID SitTargetAvatar
@@ -1275,14 +1307,6 @@ namespace OpenSim.Region.Framework.Scenes
1275 } 1307 }
1276 } 1308 }
1277 1309
1278 /// <summary>
1279 /// Clear all pending updates of parts to clients
1280 /// </summary>
1281 private void ClearUpdateSchedule()
1282 {
1283 m_updateFlag = 0;
1284 }
1285
1286 private void SendObjectPropertiesToClient(UUID AgentID) 1310 private void SendObjectPropertiesToClient(UUID AgentID)
1287 { 1311 {
1288 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1312 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
@@ -1533,14 +1557,21 @@ namespace OpenSim.Region.Framework.Scenes
1533 // or flexible 1557 // or flexible
1534 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) 1558 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible))
1535 { 1559 {
1536 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( 1560 try
1537 string.Format("{0}/{1}", Name, UUID), 1561 {
1538 Shape, 1562 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
1539 AbsolutePosition, 1563 string.Format("{0}/{1}", Name, UUID),
1540 Scale, 1564 Shape,
1541 RotationOffset, 1565 AbsolutePosition,
1542 RigidBody); 1566 Scale,
1543 1567 RotationOffset,
1568 RigidBody);
1569 }
1570 catch
1571 {
1572 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom.", m_uuid);
1573 PhysActor = null;
1574 }
1544 // Basic Physics returns null.. joy joy joy. 1575 // Basic Physics returns null.. joy joy joy.
1545 if (PhysActor != null) 1576 if (PhysActor != null)
1546 { 1577 {
@@ -1568,7 +1599,7 @@ namespace OpenSim.Region.Framework.Scenes
1568 { 1599 {
1569 m_redo.Clear(); 1600 m_redo.Clear();
1570 } 1601 }
1571 StoreUndoState(); 1602 StoreUndoState(UndoType.STATE_ALL);
1572 } 1603 }
1573 1604
1574 public byte ConvertScriptUintToByte(uint indata) 1605 public byte ConvertScriptUintToByte(uint indata)
@@ -1637,6 +1668,9 @@ namespace OpenSim.Region.Framework.Scenes
1637 1668
1638 // Move afterwards ResetIDs as it clears the localID 1669 // Move afterwards ResetIDs as it clears the localID
1639 dupe.LocalId = localID; 1670 dupe.LocalId = localID;
1671 if(dupe.PhysActor != null)
1672 dupe.PhysActor.LocalID = localID;
1673
1640 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. 1674 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1641 dupe._lastOwnerID = OwnerID; 1675 dupe._lastOwnerID = OwnerID;
1642 1676
@@ -1680,7 +1714,7 @@ namespace OpenSim.Region.Framework.Scenes
1680 PrimitiveBaseShape shape = PrimitiveBaseShape.Create(); 1714 PrimitiveBaseShape shape = PrimitiveBaseShape.Create();
1681 part.Shape = shape; 1715 part.Shape = shape;
1682 1716
1683 part.Name = "Primitive"; 1717 part.Name = "Object";
1684 part._ownerID = UUID.Random(); 1718 part._ownerID = UUID.Random();
1685 1719
1686 return part; 1720 return part;
@@ -2040,12 +2074,17 @@ namespace OpenSim.Region.Framework.Scenes
2040 public Vector3 GetWorldPosition() 2074 public Vector3 GetWorldPosition()
2041 { 2075 {
2042 Quaternion parentRot = ParentGroup.RootPart.RotationOffset; 2076 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
2043
2044 Vector3 axPos = OffsetPosition; 2077 Vector3 axPos = OffsetPosition;
2045
2046 axPos *= parentRot; 2078 axPos *= parentRot;
2047 Vector3 translationOffsetPosition = axPos; 2079 Vector3 translationOffsetPosition = axPos;
2048 return GroupPosition + translationOffsetPosition; 2080 if(_parentID == 0)
2081 {
2082 return GroupPosition;
2083 }
2084 else
2085 {
2086 return ParentGroup.AbsolutePosition + translationOffsetPosition; //KF: Fix child prim position
2087 }
2049 } 2088 }
2050 2089
2051 /// <summary> 2090 /// <summary>
@@ -2056,7 +2095,7 @@ namespace OpenSim.Region.Framework.Scenes
2056 { 2095 {
2057 Quaternion newRot; 2096 Quaternion newRot;
2058 2097
2059 if (this.LinkNum == 0) 2098 if (this.LinkNum < 2) //KF Single or root prim
2060 { 2099 {
2061 newRot = RotationOffset; 2100 newRot = RotationOffset;
2062 } 2101 }
@@ -2702,17 +2741,18 @@ namespace OpenSim.Region.Framework.Scenes
2702 //Trys to fetch sound id from prim's inventory. 2741 //Trys to fetch sound id from prim's inventory.
2703 //Prim's inventory doesn't support non script items yet 2742 //Prim's inventory doesn't support non script items yet
2704 2743
2705 lock (TaskInventory) 2744 TaskInventory.LockItemsForRead(true);
2745
2746 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2706 { 2747 {
2707 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 2748 if (item.Value.Name == sound)
2708 { 2749 {
2709 if (item.Value.Name == sound) 2750 soundID = item.Value.ItemID;
2710 { 2751 break;
2711 soundID = item.Value.ItemID;
2712 break;
2713 }
2714 } 2752 }
2715 } 2753 }
2754
2755 TaskInventory.LockItemsForRead(false);
2716 } 2756 }
2717 2757
2718 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence sp) 2758 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence sp)
@@ -2772,7 +2812,7 @@ namespace OpenSim.Region.Framework.Scenes
2772 /// <param name="scale"></param> 2812 /// <param name="scale"></param>
2773 public void Resize(Vector3 scale) 2813 public void Resize(Vector3 scale)
2774 { 2814 {
2775 StoreUndoState(); 2815 StoreUndoState(UndoType.STATE_PRIM_SCALE);
2776 m_shape.Scale = scale; 2816 m_shape.Scale = scale;
2777 2817
2778 ParentGroup.HasGroupChanged = true; 2818 ParentGroup.HasGroupChanged = true;
@@ -2781,38 +2821,7 @@ namespace OpenSim.Region.Framework.Scenes
2781 2821
2782 public void RotLookAt(Quaternion target, float strength, float damping) 2822 public void RotLookAt(Quaternion target, float strength, float damping)
2783 { 2823 {
2784 rotLookAt(target, strength, damping); 2824 m_parentGroup.rotLookAt(target, strength, damping); // This calls method in SceneObjectGroup.
2785 }
2786
2787 public void rotLookAt(Quaternion target, float strength, float damping)
2788 {
2789 if (IsAttachment)
2790 {
2791 /*
2792 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2793 if (avatar != null)
2794 {
2795 Rotate the Av?
2796 } */
2797 }
2798 else
2799 {
2800 APIDDamp = damping;
2801 APIDStrength = strength;
2802 APIDTarget = target;
2803 }
2804 }
2805
2806 public void startLookAt(Quaternion rot, float damp, float strength)
2807 {
2808 APIDDamp = damp;
2809 APIDStrength = strength;
2810 APIDTarget = rot;
2811 }
2812
2813 public void stopLookAt()
2814 {
2815 APIDTarget = Quaternion.Identity;
2816 } 2825 }
2817 2826
2818 /// <summary> 2827 /// <summary>
@@ -2824,7 +2833,10 @@ namespace OpenSim.Region.Framework.Scenes
2824 2833
2825 if (m_parentGroup != null) 2834 if (m_parentGroup != null)
2826 { 2835 {
2827 m_parentGroup.QueueForUpdateCheck(); 2836 if (!m_parentGroup.areUpdatesSuspended)
2837 {
2838 m_parentGroup.QueueForUpdateCheck();
2839 }
2828 } 2840 }
2829 2841
2830 int timeNow = Util.UnixTimeSinceEpoch(); 2842 int timeNow = Util.UnixTimeSinceEpoch();
@@ -3041,8 +3053,8 @@ namespace OpenSim.Region.Framework.Scenes
3041 { 3053 {
3042 const float ROTATION_TOLERANCE = 0.01f; 3054 const float ROTATION_TOLERANCE = 0.01f;
3043 const float VELOCITY_TOLERANCE = 0.001f; 3055 const float VELOCITY_TOLERANCE = 0.001f;
3044 const float POSITION_TOLERANCE = 0.05f; 3056 const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary
3045 const int TIME_MS_TOLERANCE = 3000; 3057 const int TIME_MS_TOLERANCE = 200; //llSetPos has a 200ms delay. This should NOT be 3 seconds.
3046 3058
3047 if (m_updateFlag == 1) 3059 if (m_updateFlag == 1)
3048 { 3060 {
@@ -3056,7 +3068,7 @@ namespace OpenSim.Region.Framework.Scenes
3056 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE) 3068 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE)
3057 { 3069 {
3058 AddTerseUpdateToAllAvatars(); 3070 AddTerseUpdateToAllAvatars();
3059 ClearUpdateSchedule(); 3071
3060 3072
3061 // This causes the Scene to 'poll' physical objects every couple of frames 3073 // This causes the Scene to 'poll' physical objects every couple of frames
3062 // bad, so it's been replaced by an event driven method. 3074 // bad, so it's been replaced by an event driven method.
@@ -3074,16 +3086,18 @@ namespace OpenSim.Region.Framework.Scenes
3074 m_lastAngularVelocity = AngularVelocity; 3086 m_lastAngularVelocity = AngularVelocity;
3075 m_lastTerseSent = Environment.TickCount; 3087 m_lastTerseSent = Environment.TickCount;
3076 } 3088 }
3089 //Moved this outside of the if clause so updates don't get blocked.. *sigh*
3090 m_updateFlag = 0; //Why were we calling a function to do this? Inefficient! *screams*
3077 } 3091 }
3078 else 3092 else
3079 { 3093 {
3080 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes 3094 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes
3081 { 3095 {
3082 AddFullUpdateToAllAvatars(); 3096 AddFullUpdateToAllAvatars();
3083 ClearUpdateSchedule(); 3097 m_updateFlag = 0; //Same here
3084 } 3098 }
3085 } 3099 }
3086 ClearUpdateSchedule(); 3100 m_updateFlag = 0;
3087 } 3101 }
3088 3102
3089 /// <summary> 3103 /// <summary>
@@ -3103,6 +3117,15 @@ namespace OpenSim.Region.Framework.Scenes
3103 UUID ownerID = _ownerID; 3117 UUID ownerID = _ownerID;
3104 UUID objectID = ParentGroup.RootPart.UUID; 3118 UUID objectID = ParentGroup.RootPart.UUID;
3105 UUID parentID = GetRootPartUUID(); 3119 UUID parentID = GetRootPartUUID();
3120
3121 if (ParentGroup.IsAttachment && ParentGroup.RootPart.Shape.State > 30)
3122 {
3123 // Use the avatar as the parent for HUDs, since the prims
3124 // are not sent to other avatars
3125 objectID = _ownerID;
3126 parentID = _ownerID;
3127 }
3128
3106 UUID soundID = UUID.Zero; 3129 UUID soundID = UUID.Zero;
3107 Vector3 position = AbsolutePosition; // region local 3130 Vector3 position = AbsolutePosition; // region local
3108 ulong regionHandle = m_parentGroup.Scene.RegionInfo.RegionHandle; 3131 ulong regionHandle = m_parentGroup.Scene.RegionInfo.RegionHandle;
@@ -3110,17 +3133,16 @@ namespace OpenSim.Region.Framework.Scenes
3110 if (!UUID.TryParse(sound, out soundID)) 3133 if (!UUID.TryParse(sound, out soundID))
3111 { 3134 {
3112 // search sound file from inventory 3135 // search sound file from inventory
3113 lock (TaskInventory) 3136 TaskInventory.LockItemsForRead(true);
3137 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
3114 { 3138 {
3115 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 3139 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound)
3116 { 3140 {
3117 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) 3141 soundID = item.Value.ItemID;
3118 { 3142 break;
3119 soundID = item.Value.ItemID;
3120 break;
3121 }
3122 } 3143 }
3123 } 3144 }
3145 TaskInventory.LockItemsForRead(false);
3124 } 3146 }
3125 3147
3126 if (soundID == UUID.Zero) 3148 if (soundID == UUID.Zero)
@@ -3557,7 +3579,7 @@ namespace OpenSim.Region.Framework.Scenes
3557 3579
3558 public void StopLookAt() 3580 public void StopLookAt()
3559 { 3581 {
3560 m_parentGroup.stopLookAt(); 3582 m_parentGroup.stopLookAt(); // This calls method in SceneObjectGroup.
3561 3583
3562 m_parentGroup.ScheduleGroupForTerseUpdate(); 3584 m_parentGroup.ScheduleGroupForTerseUpdate();
3563 } 3585 }
@@ -3584,10 +3606,9 @@ namespace OpenSim.Region.Framework.Scenes
3584 m_parentGroup.ScheduleGroupForTerseUpdate(); 3606 m_parentGroup.ScheduleGroupForTerseUpdate();
3585 //m_parentGroup.ScheduleGroupForFullUpdate(); 3607 //m_parentGroup.ScheduleGroupForFullUpdate();
3586 } 3608 }
3587 3609 public void StoreUndoState(UndoType type)
3588 public void StoreUndoState()
3589 { 3610 {
3590 if (!Undoing) 3611 if (!Undoing && (m_parentGroup == null || m_parentGroup.RootPart == null || !m_parentGroup.RootPart.Undoing))
3591 { 3612 {
3592 if (!IgnoreUndoUpdate) 3613 if (!IgnoreUndoUpdate)
3593 { 3614 {
@@ -3598,17 +3619,25 @@ namespace OpenSim.Region.Framework.Scenes
3598 if (m_undo.Count > 0) 3619 if (m_undo.Count > 0)
3599 { 3620 {
3600 UndoState last = m_undo.Peek(); 3621 UndoState last = m_undo.Peek();
3601 if (last != null) 3622
3602 {
3603 if (last.Compare(this))
3604 return;
3605 }
3606 } 3623 }
3607 3624
3608 if (m_parentGroup.GetSceneMaxUndo() > 0) 3625 if (m_parentGroup.GetSceneMaxUndo() > 0)
3609 { 3626 {
3610 UndoState nUndo = new UndoState(this); 3627 UndoState lastUndo = m_undo.Peek();
3628
3629 UndoState nUndo = new UndoState(this, type);
3611 3630
3631 if (lastUndo != null)
3632 {
3633 TimeSpan ts = DateTime.Now.Subtract(lastUndo.LastUpdated);
3634 if (ts.TotalMilliseconds < 500)
3635 {
3636 //Delete the last entry since it was less than 500 milliseconds ago
3637 nUndo.Merge(lastUndo);
3638 m_undo.Pop();
3639 }
3640 }
3612 m_undo.Push(nUndo); 3641 m_undo.Push(nUndo);
3613 } 3642 }
3614 3643
@@ -4085,11 +4114,13 @@ namespace OpenSim.Region.Framework.Scenes
4085 if (m_undo.Count > 0) 4114 if (m_undo.Count > 0)
4086 { 4115 {
4087 UndoState nUndo = null; 4116 UndoState nUndo = null;
4117 UndoState goback = m_undo.Pop();
4088 if (m_parentGroup.GetSceneMaxUndo() > 0) 4118 if (m_parentGroup.GetSceneMaxUndo() > 0)
4089 { 4119 {
4090 nUndo = new UndoState(this); 4120 nUndo = new UndoState(this, goback.Type);
4091 } 4121 }
4092 UndoState goback = m_undo.Pop(); 4122
4123
4093 if (goback != null) 4124 if (goback != null)
4094 { 4125 {
4095 goback.PlaybackState(this); 4126 goback.PlaybackState(this);
@@ -4104,13 +4135,13 @@ namespace OpenSim.Region.Framework.Scenes
4104 { 4135 {
4105 lock (m_redo) 4136 lock (m_redo)
4106 { 4137 {
4138 UndoState gofwd = m_redo.Pop();
4107 if (m_parentGroup.GetSceneMaxUndo() > 0) 4139 if (m_parentGroup.GetSceneMaxUndo() > 0)
4108 { 4140 {
4109 UndoState nUndo = new UndoState(this); 4141 UndoState nUndo = new UndoState(this, gofwd.Type);
4110 4142
4111 m_undo.Push(nUndo); 4143 m_undo.Push(nUndo);
4112 } 4144 }
4113 UndoState gofwd = m_redo.Pop();
4114 if (gofwd != null) 4145 if (gofwd != null)
4115 gofwd.PlayfwdState(this); 4146 gofwd.PlayfwdState(this);
4116 } 4147 }
@@ -4558,8 +4589,9 @@ namespace OpenSim.Region.Framework.Scenes
4558 { 4589 {
4559 m_shape.TextureEntry = textureEntry; 4590 m_shape.TextureEntry = textureEntry;
4560 TriggerScriptChangedEvent(Changed.TEXTURE); 4591 TriggerScriptChangedEvent(Changed.TEXTURE);
4561 4592 m_updateFlag = 1;
4562 ParentGroup.HasGroupChanged = true; 4593 ParentGroup.HasGroupChanged = true;
4594
4563 //This is madness.. 4595 //This is madness..
4564 //ParentGroup.ScheduleGroupForFullUpdate(); 4596 //ParentGroup.ScheduleGroupForFullUpdate();
4565 //This is sparta 4597 //This is sparta
@@ -4792,5 +4824,17 @@ namespace OpenSim.Region.Framework.Scenes
4792 Color color = Color; 4824 Color color = Color;
4793 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); 4825 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A));
4794 } 4826 }
4827
4828 public void ResetOwnerChangeFlag()
4829 {
4830 List<UUID> inv = Inventory.GetInventoryList();
4831
4832 foreach (UUID itemID in inv)
4833 {
4834 TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
4835 item.OwnerChanged = false;
4836 Inventory.UpdateInventoryItem(item);
4837 }
4838 }
4795 } 4839 }
4796} 4840}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 0c5e62d..522f75e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -47,6 +47,8 @@ namespace OpenSim.Region.Framework.Scenes
47 47
48 private string m_inventoryFileName = String.Empty; 48 private string m_inventoryFileName = String.Empty;
49 private int m_inventoryFileNameSerial = 0; 49 private int m_inventoryFileNameSerial = 0;
50
51 private Dictionary<UUID, ArrayList> m_scriptErrors = new Dictionary<UUID, ArrayList>();
50 52
51 /// <value> 53 /// <value>
52 /// The part to which the inventory belongs. 54 /// The part to which the inventory belongs.
@@ -83,7 +85,9 @@ namespace OpenSim.Region.Framework.Scenes
83 /// </value> 85 /// </value>
84 protected internal TaskInventoryDictionary Items 86 protected internal TaskInventoryDictionary Items
85 { 87 {
86 get { return m_items; } 88 get {
89 return m_items;
90 }
87 set 91 set
88 { 92 {
89 m_items = value; 93 m_items = value;
@@ -119,52 +123,57 @@ namespace OpenSim.Region.Framework.Scenes
119 /// <param name="linkNum">Link number for the part</param> 123 /// <param name="linkNum">Link number for the part</param>
120 public void ResetInventoryIDs() 124 public void ResetInventoryIDs()
121 { 125 {
122 if (null == m_part || null == m_part.ParentGroup) 126 m_items.LockItemsForWrite(true);
123 return; 127
124 128 if (Items.Count == 0)
125 lock (m_items)
126 { 129 {
127 if (0 == m_items.Count) 130 m_items.LockItemsForWrite(false);
128 return; 131 return;
132 }
129 133
130 HasInventoryChanged = true; 134 HasInventoryChanged = true;
135 if (m_part.ParentGroup != null)
136 {
131 m_part.ParentGroup.HasGroupChanged = true; 137 m_part.ParentGroup.HasGroupChanged = true;
132 IList<TaskInventoryItem> items = GetInventoryItems(); 138 }
133 m_items.Clear(); 139
140 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
141 Items.Clear();
134 142
135 foreach (TaskInventoryItem item in items) 143 foreach (TaskInventoryItem item in items)
136 { 144 {
137 item.ResetIDs(m_part.UUID); 145 item.ResetIDs(m_part.UUID);
138 m_items.Add(item.ItemID, item); 146 Items.Add(item.ItemID, item);
139 }
140 } 147 }
148 m_items.LockItemsForWrite(false);
141 } 149 }
142 150
143 public void ResetObjectID() 151 public void ResetObjectID()
144 { 152 {
145 lock (Items) 153 m_items.LockItemsForWrite(true);
154
155 if (Items.Count == 0)
146 { 156 {
147 if (Items.Count == 0) 157 m_items.LockItemsForWrite(false);
148 { 158 return;
149 return;
150 }
151
152 HasInventoryChanged = true;
153 if (m_part.ParentGroup != null)
154 {
155 m_part.ParentGroup.HasGroupChanged = true;
156 }
157
158 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
159 Items.Clear();
160
161 foreach (TaskInventoryItem item in items)
162 {
163 item.ParentPartID = m_part.UUID;
164 item.ParentID = m_part.UUID;
165 Items.Add(item.ItemID, item);
166 }
167 } 159 }
160
161 HasInventoryChanged = true;
162 if (m_part.ParentGroup != null)
163 {
164 m_part.ParentGroup.HasGroupChanged = true;
165 }
166
167 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
168 Items.Clear();
169
170 foreach (TaskInventoryItem item in items)
171 {
172 item.ParentPartID = m_part.UUID;
173 item.ParentID = m_part.UUID;
174 Items.Add(item.ItemID, item);
175 }
176 m_items.LockItemsForWrite(false);
168 } 177 }
169 178
170 /// <summary> 179 /// <summary>
@@ -173,12 +182,11 @@ namespace OpenSim.Region.Framework.Scenes
173 /// <param name="ownerId"></param> 182 /// <param name="ownerId"></param>
174 public void ChangeInventoryOwner(UUID ownerId) 183 public void ChangeInventoryOwner(UUID ownerId)
175 { 184 {
176 lock (Items) 185 m_items.LockItemsForWrite(true);
186 if (0 == Items.Count)
177 { 187 {
178 if (0 == Items.Count) 188 m_items.LockItemsForWrite(false);
179 { 189 return;
180 return;
181 }
182 } 190 }
183 191
184 HasInventoryChanged = true; 192 HasInventoryChanged = true;
@@ -192,6 +200,7 @@ namespace OpenSim.Region.Framework.Scenes
192 item.OwnerID = ownerId; 200 item.OwnerID = ownerId;
193 } 201 }
194 } 202 }
203 m_items.LockItemsForWrite(false);
195 } 204 }
196 205
197 /// <summary> 206 /// <summary>
@@ -200,22 +209,24 @@ namespace OpenSim.Region.Framework.Scenes
200 /// <param name="groupID"></param> 209 /// <param name="groupID"></param>
201 public void ChangeInventoryGroup(UUID groupID) 210 public void ChangeInventoryGroup(UUID groupID)
202 { 211 {
203 lock (Items) 212 m_items.LockItemsForWrite(true);
213 if (0 == Items.Count)
204 { 214 {
205 if (0 == Items.Count) 215 m_items.LockItemsForWrite(false);
206 { 216 return;
207 return;
208 }
209 } 217 }
210 218
211 HasInventoryChanged = true; 219 HasInventoryChanged = true;
212 m_part.ParentGroup.HasGroupChanged = true; 220 m_part.ParentGroup.HasGroupChanged = true;
213 List<TaskInventoryItem> items = GetInventoryItems(); 221 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
214 foreach (TaskInventoryItem item in items) 222 foreach (TaskInventoryItem item in items)
215 { 223 {
216 if (groupID != item.GroupID) 224 if (groupID != item.GroupID)
225 {
217 item.GroupID = groupID; 226 item.GroupID = groupID;
227 }
218 } 228 }
229 m_items.LockItemsForWrite(false);
219 } 230 }
220 231
221 /// <summary> 232 /// <summary>
@@ -223,9 +234,14 @@ namespace OpenSim.Region.Framework.Scenes
223 /// </summary> 234 /// </summary>
224 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) 235 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
225 { 236 {
226 List<TaskInventoryItem> scripts = GetInventoryScripts(); 237 Items.LockItemsForRead(true);
227 foreach (TaskInventoryItem item in scripts) 238 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
228 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 239 Items.LockItemsForRead(false);
240 foreach (TaskInventoryItem item in items)
241 {
242 if ((int)InventoryType.LSL == item.InvType)
243 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
244 }
229 } 245 }
230 246
231 public ArrayList GetScriptErrors(UUID itemID) 247 public ArrayList GetScriptErrors(UUID itemID)
@@ -258,9 +274,18 @@ namespace OpenSim.Region.Framework.Scenes
258 /// </param> 274 /// </param>
259 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 275 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
260 { 276 {
261 List<TaskInventoryItem> scripts = GetInventoryScripts(); 277 Items.LockItemsForRead(true);
262 foreach (TaskInventoryItem item in scripts) 278 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
263 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); 279 Items.LockItemsForRead(false);
280
281 foreach (TaskInventoryItem item in items)
282 {
283 if ((int)InventoryType.LSL == item.InvType)
284 {
285 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
286 m_part.RemoveScriptEvents(item.ItemID);
287 }
288 }
264 } 289 }
265 290
266 /// <summary> 291 /// <summary>
@@ -276,7 +301,10 @@ namespace OpenSim.Region.Framework.Scenes
276 // item.Name, item.ItemID, Name, UUID); 301 // item.Name, item.ItemID, Name, UUID);
277 302
278 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) 303 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
304 {
305 StoreScriptError(item.ItemID, "no permission");
279 return; 306 return;
307 }
280 308
281 m_part.AddFlag(PrimFlags.Scripted); 309 m_part.AddFlag(PrimFlags.Scripted);
282 310
@@ -285,14 +313,13 @@ namespace OpenSim.Region.Framework.Scenes
285 if (stateSource == 2 && // Prim crossing 313 if (stateSource == 2 && // Prim crossing
286 m_part.ParentGroup.Scene.m_trustBinaries) 314 m_part.ParentGroup.Scene.m_trustBinaries)
287 { 315 {
288 lock (m_items) 316 m_items.LockItemsForWrite(true);
289 { 317 m_items[item.ItemID].PermsMask = 0;
290 m_items[item.ItemID].PermsMask = 0; 318 m_items[item.ItemID].PermsGranter = UUID.Zero;
291 m_items[item.ItemID].PermsGranter = UUID.Zero; 319 m_items.LockItemsForWrite(false);
292 }
293
294 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 320 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
295 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); 321 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
322 StoreScriptErrors(item.ItemID, null);
296 m_part.ParentGroup.AddActiveScriptCount(1); 323 m_part.ParentGroup.AddActiveScriptCount(1);
297 m_part.ScheduleFullUpdate(); 324 m_part.ScheduleFullUpdate();
298 return; 325 return;
@@ -301,6 +328,8 @@ namespace OpenSim.Region.Framework.Scenes
301 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); 328 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
302 if (null == asset) 329 if (null == asset)
303 { 330 {
331 string msg = String.Format("asset ID {0} could not be found", item.AssetID);
332 StoreScriptError(item.ItemID, msg);
304 m_log.ErrorFormat( 333 m_log.ErrorFormat(
305 "[PRIM INVENTORY]: " + 334 "[PRIM INVENTORY]: " +
306 "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", 335 "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
@@ -312,15 +341,17 @@ namespace OpenSim.Region.Framework.Scenes
312 if (m_part.ParentGroup.m_savedScriptState != null) 341 if (m_part.ParentGroup.m_savedScriptState != null)
313 RestoreSavedScriptState(item.OldItemID, item.ItemID); 342 RestoreSavedScriptState(item.OldItemID, item.ItemID);
314 343
315 lock (m_items) 344 m_items.LockItemsForWrite(true);
316 { 345
317 m_items[item.ItemID].PermsMask = 0; 346 m_items[item.ItemID].PermsMask = 0;
318 m_items[item.ItemID].PermsGranter = UUID.Zero; 347 m_items[item.ItemID].PermsGranter = UUID.Zero;
319 } 348
349 m_items.LockItemsForWrite(false);
320 350
321 string script = Utils.BytesToString(asset.Data); 351 string script = Utils.BytesToString(asset.Data);
322 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 352 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
323 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); 353 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
354 StoreScriptErrors(item.ItemID, null);
324 m_part.ParentGroup.AddActiveScriptCount(1); 355 m_part.ParentGroup.AddActiveScriptCount(1);
325 m_part.ScheduleFullUpdate(); 356 m_part.ScheduleFullUpdate();
326 } 357 }
@@ -384,21 +415,145 @@ namespace OpenSim.Region.Framework.Scenes
384 415
385 /// <summary> 416 /// <summary>
386 /// Start a script which is in this prim's inventory. 417 /// Start a script which is in this prim's inventory.
418 /// Some processing may occur in the background, but this routine returns asap.
387 /// </summary> 419 /// </summary>
388 /// <param name="itemId"> 420 /// <param name="itemId">
389 /// A <see cref="UUID"/> 421 /// A <see cref="UUID"/>
390 /// </param> 422 /// </param>
391 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) 423 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
392 { 424 {
393 TaskInventoryItem item = GetInventoryItem(itemId); 425 lock (m_scriptErrors)
394 if (item != null) 426 {
395 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 427 // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
428 m_scriptErrors.Remove(itemId);
429 }
430 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
431 }
432
433 private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
434 {
435 m_items.LockItemsForRead(true);
436 if (m_items.ContainsKey(itemId))
437 {
438 if (m_items.ContainsKey(itemId))
439 {
440 m_items.LockItemsForRead(false);
441 CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource);
442 }
443 else
444 {
445 m_items.LockItemsForRead(false);
446 string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID,
447 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
448 StoreScriptError(itemId, msg);
449 m_log.ErrorFormat(
450 "[PRIM INVENTORY]: " +
451 "Couldn't start script with ID {0} since it {1}", itemId, msg);
452 }
453 }
396 else 454 else
455 {
456 m_items.LockItemsForRead(false);
457 string msg = String.Format("couldn't be found for prim {0}, {1}", m_part.Name, m_part.UUID);
458 StoreScriptError(itemId, msg);
397 m_log.ErrorFormat( 459 m_log.ErrorFormat(
398 "[PRIM INVENTORY]: " + 460 "[PRIM INVENTORY]: " +
399 "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", 461 "Couldn't start script with ID {0} since it {1}", itemId, msg);
400 itemId, m_part.Name, m_part.UUID, 462 }
401 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 463
464 }
465
466 /// <summary>
467 /// Start a script which is in this prim's inventory and return any compilation error messages.
468 /// </summary>
469 /// <param name="itemId">
470 /// A <see cref="UUID"/>
471 /// </param>
472 public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
473 {
474 ArrayList errors;
475
476 // Indicate to CreateScriptInstanceInternal() we want it to
477 // post any compilation/loading error messages
478 lock (m_scriptErrors)
479 {
480 m_scriptErrors[itemId] = null;
481 }
482
483 // Perform compilation/loading
484 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
485
486 // Wait for and retrieve any errors
487 lock (m_scriptErrors)
488 {
489 while ((errors = m_scriptErrors[itemId]) == null)
490 {
491 if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
492 {
493 m_log.ErrorFormat(
494 "[PRIM INVENTORY]: " +
495 "timedout waiting for script {0} errors", itemId);
496 errors = m_scriptErrors[itemId];
497 if (errors == null)
498 {
499 errors = new ArrayList(1);
500 errors.Add("timedout waiting for errors");
501 }
502 break;
503 }
504 }
505 m_scriptErrors.Remove(itemId);
506 }
507 return errors;
508 }
509
510 // Signal to CreateScriptInstanceEr() that compilation/loading is complete
511 private void StoreScriptErrors(UUID itemId, ArrayList errors)
512 {
513 lock (m_scriptErrors)
514 {
515 // If compilation/loading initiated via CreateScriptInstance(),
516 // it does not want the errors, so just get out
517 if (!m_scriptErrors.ContainsKey(itemId))
518 {
519 return;
520 }
521
522 // Initiated via CreateScriptInstanceEr(), if we know what the
523 // errors are, save them and wake CreateScriptInstanceEr().
524 if (errors != null)
525 {
526 m_scriptErrors[itemId] = errors;
527 System.Threading.Monitor.PulseAll(m_scriptErrors);
528 return;
529 }
530 }
531
532 // Initiated via CreateScriptInstanceEr() but we don't know what
533 // the errors are yet, so retrieve them from the script engine.
534 // This may involve some waiting internal to GetScriptErrors().
535 errors = GetScriptErrors(itemId);
536
537 // Get a default non-null value to indicate success.
538 if (errors == null)
539 {
540 errors = new ArrayList();
541 }
542
543 // Post to CreateScriptInstanceEr() and wake it up
544 lock (m_scriptErrors)
545 {
546 m_scriptErrors[itemId] = errors;
547 System.Threading.Monitor.PulseAll(m_scriptErrors);
548 }
549 }
550
551 // Like StoreScriptErrors(), but just posts a single string message
552 private void StoreScriptError(UUID itemId, string message)
553 {
554 ArrayList errors = new ArrayList(1);
555 errors.Add(message);
556 StoreScriptErrors(itemId, errors);
402 } 557 }
403 558
404 /// <summary> 559 /// <summary>
@@ -411,15 +566,7 @@ namespace OpenSim.Region.Framework.Scenes
411 /// </param> 566 /// </param>
412 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) 567 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
413 { 568 {
414 bool scriptPresent = false; 569 if (m_items.ContainsKey(itemId))
415
416 lock (m_items)
417 {
418 if (m_items.ContainsKey(itemId))
419 scriptPresent = true;
420 }
421
422 if (scriptPresent)
423 { 570 {
424 if (!sceneObjectBeingDeleted) 571 if (!sceneObjectBeingDeleted)
425 m_part.RemoveScriptEvents(itemId); 572 m_part.RemoveScriptEvents(itemId);
@@ -444,14 +591,16 @@ namespace OpenSim.Region.Framework.Scenes
444 /// <returns></returns> 591 /// <returns></returns>
445 private bool InventoryContainsName(string name) 592 private bool InventoryContainsName(string name)
446 { 593 {
447 lock (m_items) 594 m_items.LockItemsForRead(true);
595 foreach (TaskInventoryItem item in m_items.Values)
448 { 596 {
449 foreach (TaskInventoryItem item in m_items.Values) 597 if (item.Name == name)
450 { 598 {
451 if (item.Name == name) 599 m_items.LockItemsForRead(false);
452 return true; 600 return true;
453 } 601 }
454 } 602 }
603 m_items.LockItemsForRead(false);
455 return false; 604 return false;
456 } 605 }
457 606
@@ -493,8 +642,9 @@ namespace OpenSim.Region.Framework.Scenes
493 /// <param name="item"></param> 642 /// <param name="item"></param>
494 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) 643 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
495 { 644 {
496 List<TaskInventoryItem> il = GetInventoryItems(); 645 m_items.LockItemsForRead(true);
497 646 List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
647 m_items.LockItemsForRead(false);
498 foreach (TaskInventoryItem i in il) 648 foreach (TaskInventoryItem i in il)
499 { 649 {
500 if (i.Name == item.Name) 650 if (i.Name == item.Name)
@@ -532,14 +682,14 @@ namespace OpenSim.Region.Framework.Scenes
532 item.Name = name; 682 item.Name = name;
533 item.GroupID = m_part.GroupID; 683 item.GroupID = m_part.GroupID;
534 684
535 lock (m_items) 685 m_items.LockItemsForWrite(true);
536 m_items.Add(item.ItemID, item); 686 m_items.Add(item.ItemID, item);
537 687 m_items.LockItemsForWrite(false);
538 if (allowedDrop) 688 if (allowedDrop)
539 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); 689 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
540 else 690 else
541 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 691 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
542 692
543 m_inventorySerial++; 693 m_inventorySerial++;
544 //m_inventorySerial += 2; 694 //m_inventorySerial += 2;
545 HasInventoryChanged = true; 695 HasInventoryChanged = true;
@@ -555,15 +705,15 @@ namespace OpenSim.Region.Framework.Scenes
555 /// <param name="items"></param> 705 /// <param name="items"></param>
556 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) 706 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
557 { 707 {
558 lock (m_items) 708 m_items.LockItemsForWrite(true);
709 foreach (TaskInventoryItem item in items)
559 { 710 {
560 foreach (TaskInventoryItem item in items) 711 m_items.Add(item.ItemID, item);
561 { 712// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
562 m_items.Add(item.ItemID, item);
563// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
564 }
565 m_inventorySerial++;
566 } 713 }
714 m_items.LockItemsForWrite(false);
715
716 m_inventorySerial++;
567 } 717 }
568 718
569 /// <summary> 719 /// <summary>
@@ -574,10 +724,9 @@ namespace OpenSim.Region.Framework.Scenes
574 public TaskInventoryItem GetInventoryItem(UUID itemId) 724 public TaskInventoryItem GetInventoryItem(UUID itemId)
575 { 725 {
576 TaskInventoryItem item; 726 TaskInventoryItem item;
577 727 m_items.LockItemsForRead(true);
578 lock (m_items) 728 m_items.TryGetValue(itemId, out item);
579 m_items.TryGetValue(itemId, out item); 729 m_items.LockItemsForRead(false);
580
581 return item; 730 return item;
582 } 731 }
583 732
@@ -593,15 +742,16 @@ namespace OpenSim.Region.Framework.Scenes
593 { 742 {
594 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(); 743 IList<TaskInventoryItem> items = new List<TaskInventoryItem>();
595 744
596 lock (m_items) 745 m_items.LockItemsForRead(true);
746
747 foreach (TaskInventoryItem item in m_items.Values)
597 { 748 {
598 foreach (TaskInventoryItem item in m_items.Values) 749 if (item.Name == name)
599 { 750 items.Add(item);
600 if (item.Name == name)
601 items.Add(item);
602 }
603 } 751 }
604 752
753 m_items.LockItemsForRead(false);
754
605 return items; 755 return items;
606 } 756 }
607 757
@@ -679,8 +829,9 @@ namespace OpenSim.Region.Framework.Scenes
679 829
680 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents) 830 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
681 { 831 {
682 TaskInventoryItem it = GetInventoryItem(item.ItemID); 832 m_items.LockItemsForWrite(true);
683 if (it != null) 833
834 if (m_items.ContainsKey(item.ItemID))
684 { 835 {
685 item.ParentID = m_part.UUID; 836 item.ParentID = m_part.UUID;
686 item.ParentPartID = m_part.UUID; 837 item.ParentPartID = m_part.UUID;
@@ -692,19 +843,15 @@ namespace OpenSim.Region.Framework.Scenes
692 item.GroupID = m_part.GroupID; 843 item.GroupID = m_part.GroupID;
693 844
694 if (item.AssetID == UUID.Zero) 845 if (item.AssetID == UUID.Zero)
695 item.AssetID = it.AssetID; 846 item.AssetID = m_items[item.ItemID].AssetID;
696
697 lock (m_items)
698 {
699 m_items[item.ItemID] = item;
700 m_inventorySerial++;
701 }
702 847
848 m_items[item.ItemID] = item;
849 m_inventorySerial++;
703 if (fireScriptEvents) 850 if (fireScriptEvents)
704 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 851 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
705
706 HasInventoryChanged = true; 852 HasInventoryChanged = true;
707 m_part.ParentGroup.HasGroupChanged = true; 853 m_part.ParentGroup.HasGroupChanged = true;
854 m_items.LockItemsForWrite(false);
708 return true; 855 return true;
709 } 856 }
710 else 857 else
@@ -715,8 +862,9 @@ namespace OpenSim.Region.Framework.Scenes
715 item.ItemID, m_part.Name, m_part.UUID, 862 item.ItemID, m_part.Name, m_part.UUID,
716 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 863 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
717 } 864 }
718 return false; 865 m_items.LockItemsForWrite(false);
719 866
867 return false;
720 } 868 }
721 869
722 /// <summary> 870 /// <summary>
@@ -727,37 +875,53 @@ namespace OpenSim.Region.Framework.Scenes
727 /// in this prim's inventory.</returns> 875 /// in this prim's inventory.</returns>
728 public int RemoveInventoryItem(UUID itemID) 876 public int RemoveInventoryItem(UUID itemID)
729 { 877 {
730 TaskInventoryItem item = GetInventoryItem(itemID); 878 m_items.LockItemsForRead(true);
731 if (item != null) 879
880 if (m_items.ContainsKey(itemID))
732 { 881 {
733 int type = m_items[itemID].InvType; 882 int type = m_items[itemID].InvType;
883 m_items.LockItemsForRead(false);
734 if (type == 10) // Script 884 if (type == 10) // Script
735 { 885 {
736 m_part.RemoveScriptEvents(itemID);
737 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); 886 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
738 } 887 }
888 m_items.LockItemsForWrite(true);
739 m_items.Remove(itemID); 889 m_items.Remove(itemID);
890 m_items.LockItemsForWrite(false);
740 m_inventorySerial++; 891 m_inventorySerial++;
741 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 892 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
742 893
743 HasInventoryChanged = true; 894 HasInventoryChanged = true;
744 m_part.ParentGroup.HasGroupChanged = true; 895 m_part.ParentGroup.HasGroupChanged = true;
745 896
746 if (!ContainsScripts()) 897 int scriptcount = 0;
898 m_items.LockItemsForRead(true);
899 foreach (TaskInventoryItem item in m_items.Values)
900 {
901 if (item.Type == 10)
902 {
903 scriptcount++;
904 }
905 }
906 m_items.LockItemsForRead(false);
907
908
909 if (scriptcount <= 0)
910 {
747 m_part.RemFlag(PrimFlags.Scripted); 911 m_part.RemFlag(PrimFlags.Scripted);
912 }
748 913
749 m_part.ScheduleFullUpdate(); 914 m_part.ScheduleFullUpdate();
750 915
751 return type; 916 return type;
752
753 } 917 }
754 else 918 else
755 { 919 {
920 m_items.LockItemsForRead(false);
756 m_log.ErrorFormat( 921 m_log.ErrorFormat(
757 "[PRIM INVENTORY]: " + 922 "[PRIM INVENTORY]: " +
758 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", 923 "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
759 itemID, m_part.Name, m_part.UUID, 924 itemID, m_part.Name, m_part.UUID);
760 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
761 } 925 }
762 926
763 return -1; 927 return -1;
@@ -865,6 +1029,8 @@ namespace OpenSim.Region.Framework.Scenes
865 invString.AddSectionEnd(); 1029 invString.AddSectionEnd();
866 } 1030 }
867 } 1031 }
1032 int count = m_items.Count;
1033 m_items.LockItemsForRead(false);
868 1034
869 fileData = Utils.StringToBytes(invString.BuildString); 1035 fileData = Utils.StringToBytes(invString.BuildString);
870 1036
@@ -885,10 +1051,11 @@ namespace OpenSim.Region.Framework.Scenes
885 { 1051 {
886 if (HasInventoryChanged) 1052 if (HasInventoryChanged)
887 { 1053 {
888 HasInventoryChanged = false; 1054 Items.LockItemsForRead(true);
889 List<TaskInventoryItem> items = GetInventoryItems(); 1055 datastore.StorePrimInventory(m_part.UUID, Items.Values);
890 datastore.StorePrimInventory(m_part.UUID, items); 1056 Items.LockItemsForRead(false);
891 1057
1058 HasInventoryChanged = false;
892 } 1059 }
893 } 1060 }
894 1061
@@ -955,89 +1122,75 @@ namespace OpenSim.Region.Framework.Scenes
955 { 1122 {
956 uint mask=0x7fffffff; 1123 uint mask=0x7fffffff;
957 1124
958 lock (m_items) 1125 foreach (TaskInventoryItem item in m_items.Values)
959 { 1126 {
960 foreach (TaskInventoryItem item in m_items.Values) 1127 if (item.InvType != (int)InventoryType.Object)
961 { 1128 {
962 if (item.InvType != (int)InventoryType.Object) 1129 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
963 { 1130 mask &= ~((uint)PermissionMask.Copy >> 13);
964 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) 1131 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
965 mask &= ~((uint)PermissionMask.Copy >> 13); 1132 mask &= ~((uint)PermissionMask.Transfer >> 13);
966 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) 1133 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
967 mask &= ~((uint)PermissionMask.Transfer >> 13); 1134 mask &= ~((uint)PermissionMask.Modify >> 13);
968 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) 1135 }
969 mask &= ~((uint)PermissionMask.Modify >> 13); 1136 else
970 } 1137 {
971 else 1138 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
972 { 1139 mask &= ~((uint)PermissionMask.Copy >> 13);
973 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1140 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
974 mask &= ~((uint)PermissionMask.Copy >> 13); 1141 mask &= ~((uint)PermissionMask.Transfer >> 13);
975 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1142 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
976 mask &= ~((uint)PermissionMask.Transfer >> 13); 1143 mask &= ~((uint)PermissionMask.Modify >> 13);
977 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
978 mask &= ~((uint)PermissionMask.Modify >> 13);
979 }
980
981 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
982 mask &= ~(uint)PermissionMask.Copy;
983 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
984 mask &= ~(uint)PermissionMask.Transfer;
985 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
986 mask &= ~(uint)PermissionMask.Modify;
987 } 1144 }
1145
1146 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1147 mask &= ~(uint)PermissionMask.Copy;
1148 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1149 mask &= ~(uint)PermissionMask.Transfer;
1150 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1151 mask &= ~(uint)PermissionMask.Modify;
988 } 1152 }
989
990 return mask; 1153 return mask;
991 } 1154 }
992 1155
993 public void ApplyNextOwnerPermissions() 1156 public void ApplyNextOwnerPermissions()
994 { 1157 {
995 lock (m_items) 1158 foreach (TaskInventoryItem item in m_items.Values)
996 { 1159 {
997 foreach (TaskInventoryItem item in m_items.Values) 1160 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
998 { 1161 {
999 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) 1162 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1000 { 1163 item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
1001 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1164 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1002 item.CurrentPermissions &= ~(uint)PermissionMask.Copy; 1165 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
1003 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1166 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1004 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; 1167 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1005 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1006 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1007 }
1008 item.CurrentPermissions &= item.NextPermissions;
1009 item.BasePermissions &= item.NextPermissions;
1010 item.EveryonePermissions &= item.NextPermissions;
1011 item.OwnerChanged = true;
1012 } 1168 }
1169 item.OwnerChanged = true;
1170 item.CurrentPermissions &= item.NextPermissions;
1171 item.BasePermissions &= item.NextPermissions;
1172 item.EveryonePermissions &= item.NextPermissions;
1013 } 1173 }
1014 } 1174 }
1015 1175
1016 public void ApplyGodPermissions(uint perms) 1176 public void ApplyGodPermissions(uint perms)
1017 { 1177 {
1018 lock (m_items) 1178 foreach (TaskInventoryItem item in m_items.Values)
1019 { 1179 {
1020 foreach (TaskInventoryItem item in m_items.Values) 1180 item.CurrentPermissions = perms;
1021 { 1181 item.BasePermissions = perms;
1022 item.CurrentPermissions = perms;
1023 item.BasePermissions = perms;
1024 }
1025 } 1182 }
1026 } 1183 }
1027 1184
1028 public bool ContainsScripts() 1185 public bool ContainsScripts()
1029 { 1186 {
1030 lock (m_items) 1187 foreach (TaskInventoryItem item in m_items.Values)
1031 { 1188 {
1032 foreach (TaskInventoryItem item in m_items.Values) 1189 if (item.InvType == (int)InventoryType.LSL)
1033 { 1190 {
1034 if (item.InvType == (int)InventoryType.LSL) 1191 return true;
1035 {
1036 return true;
1037 }
1038 } 1192 }
1039 } 1193 }
1040
1041 return false; 1194 return false;
1042 } 1195 }
1043 1196
@@ -1045,11 +1198,8 @@ namespace OpenSim.Region.Framework.Scenes
1045 { 1198 {
1046 List<UUID> ret = new List<UUID>(); 1199 List<UUID> ret = new List<UUID>();
1047 1200
1048 lock (m_items) 1201 foreach (TaskInventoryItem item in m_items.Values)
1049 { 1202 ret.Add(item.ItemID);
1050 foreach (TaskInventoryItem item in m_items.Values)
1051 ret.Add(item.ItemID);
1052 }
1053 1203
1054 return ret; 1204 return ret;
1055 } 1205 }
@@ -1080,31 +1230,46 @@ namespace OpenSim.Region.Framework.Scenes
1080 1230
1081 public Dictionary<UUID, string> GetScriptStates() 1231 public Dictionary<UUID, string> GetScriptStates()
1082 { 1232 {
1233 return GetScriptStates(false);
1234 }
1235
1236 public Dictionary<UUID, string> GetScriptStates(bool oldIDs)
1237 {
1083 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); 1238 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1084 1239
1085 Dictionary<UUID, string> ret = new Dictionary<UUID, string>(); 1240 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1086 if (engines == null) // No engine at all 1241 if (engines == null) // No engine at all
1087 return ret; 1242 return ret;
1088 1243
1089 List<TaskInventoryItem> scripts = GetInventoryScripts(); 1244 Items.LockItemsForRead(true);
1090 1245 foreach (TaskInventoryItem item in m_items.Values)
1091 foreach (TaskInventoryItem item in scripts)
1092 { 1246 {
1093 foreach (IScriptModule e in engines) 1247 if (item.InvType == (int)InventoryType.LSL)
1094 { 1248 {
1095 if (e != null) 1249 foreach (IScriptModule e in engines)
1096 { 1250 {
1097 string n = e.GetXMLState(item.ItemID); 1251 if (e != null)
1098 if (n != String.Empty)
1099 { 1252 {
1100 if (!ret.ContainsKey(item.ItemID)) 1253 string n = e.GetXMLState(item.ItemID);
1101 ret[item.ItemID] = n; 1254 if (n != String.Empty)
1102 break; 1255 {
1256 if (oldIDs)
1257 {
1258 if (!ret.ContainsKey(item.OldItemID))
1259 ret[item.OldItemID] = n;
1260 }
1261 else
1262 {
1263 if (!ret.ContainsKey(item.ItemID))
1264 ret[item.ItemID] = n;
1265 }
1266 break;
1267 }
1103 } 1268 }
1104 } 1269 }
1105 } 1270 }
1106 } 1271 }
1107 1272 Items.LockItemsForRead(false);
1108 return ret; 1273 return ret;
1109 } 1274 }
1110 1275
@@ -1114,21 +1279,27 @@ namespace OpenSim.Region.Framework.Scenes
1114 if (engines == null) 1279 if (engines == null)
1115 return; 1280 return;
1116 1281
1117 List<TaskInventoryItem> scripts = GetInventoryScripts();
1118 1282
1119 foreach (TaskInventoryItem item in scripts) 1283 Items.LockItemsForRead(true);
1284
1285 foreach (TaskInventoryItem item in m_items.Values)
1120 { 1286 {
1121 foreach (IScriptModule engine in engines) 1287 if (item.InvType == (int)InventoryType.LSL)
1122 { 1288 {
1123 if (engine != null) 1289 foreach (IScriptModule engine in engines)
1124 { 1290 {
1125 if (item.OwnerChanged) 1291 if (engine != null)
1126 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); 1292 {
1127 item.OwnerChanged = false; 1293 if (item.OwnerChanged)
1128 engine.ResumeScript(item.ItemID); 1294 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
1295 item.OwnerChanged = false;
1296 engine.ResumeScript(item.ItemID);
1297 }
1129 } 1298 }
1130 } 1299 }
1131 } 1300 }
1301
1302 Items.LockItemsForRead(false);
1132 } 1303 }
1133 } 1304 }
1134} 1305}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 13d9964..618f425 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Xml;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
31using System.Timers; 32using System.Timers;
@@ -72,7 +73,7 @@ namespace OpenSim.Region.Framework.Scenes
72// { 73// {
73// m_log.Debug("[ScenePresence] Destructor called"); 74// m_log.Debug("[ScenePresence] Destructor called");
74// } 75// }
75 76
76 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
77 78
78 private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; 79 private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 };
@@ -88,7 +89,9 @@ namespace OpenSim.Region.Framework.Scenes
88 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis 89 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
89 /// issue #1716 90 /// issue #1716
90 /// </summary> 91 /// </summary>
91 private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f); 92// private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f);
93 // Value revised by KF 091121 by comparison with SL.
94 private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f);
92 95
93 public UUID currentParcelUUID = UUID.Zero; 96 public UUID currentParcelUUID = UUID.Zero;
94 97
@@ -122,8 +125,11 @@ namespace OpenSim.Region.Framework.Scenes
122 public Vector3 lastKnownAllowedPosition; 125 public Vector3 lastKnownAllowedPosition;
123 public bool sentMessageAboutRestrictedParcelFlyingDown; 126 public bool sentMessageAboutRestrictedParcelFlyingDown;
124 public Vector4 CollisionPlane = Vector4.UnitW; 127 public Vector4 CollisionPlane = Vector4.UnitW;
125 128
129 private Vector3 m_avInitialPos; // used to calculate unscripted sit rotation
130 private Vector3 m_avUnscriptedSitPos; // for non-scripted prims
126 private Vector3 m_lastPosition; 131 private Vector3 m_lastPosition;
132 private Vector3 m_lastWorldPosition;
127 private Quaternion m_lastRotation; 133 private Quaternion m_lastRotation;
128 private Vector3 m_lastVelocity; 134 private Vector3 m_lastVelocity;
129 //private int m_lastTerseSent; 135 //private int m_lastTerseSent;
@@ -156,7 +162,6 @@ namespace OpenSim.Region.Framework.Scenes
156 private int m_perfMonMS; 162 private int m_perfMonMS;
157 163
158 private bool m_setAlwaysRun; 164 private bool m_setAlwaysRun;
159
160 private bool m_forceFly; 165 private bool m_forceFly;
161 private bool m_flyDisabled; 166 private bool m_flyDisabled;
162 167
@@ -180,7 +185,8 @@ namespace OpenSim.Region.Framework.Scenes
180 protected RegionInfo m_regionInfo; 185 protected RegionInfo m_regionInfo;
181 protected ulong crossingFromRegion; 186 protected ulong crossingFromRegion;
182 187
183 private readonly Vector3[] Dir_Vectors = new Vector3[9]; 188 private readonly Vector3[] Dir_Vectors = new Vector3[11];
189 private bool m_isNudging = false;
184 190
185 // Position of agent's camera in world (region cordinates) 191 // Position of agent's camera in world (region cordinates)
186 protected Vector3 m_CameraCenter; 192 protected Vector3 m_CameraCenter;
@@ -205,17 +211,25 @@ namespace OpenSim.Region.Framework.Scenes
205 private bool m_autopilotMoving; 211 private bool m_autopilotMoving;
206 private Vector3 m_autoPilotTarget; 212 private Vector3 m_autoPilotTarget;
207 private bool m_sitAtAutoTarget; 213 private bool m_sitAtAutoTarget;
214 private Vector3 m_initialSitTarget = Vector3.Zero; //KF: First estimate of where to sit
208 215
209 private string m_nextSitAnimation = String.Empty; 216 private string m_nextSitAnimation = String.Empty;
210 217
211 //PauPaw:Proper PID Controler for autopilot************ 218 //PauPaw:Proper PID Controler for autopilot************
212 private bool m_moveToPositionInProgress; 219 private bool m_moveToPositionInProgress;
213 private Vector3 m_moveToPositionTarget; 220 private Vector3 m_moveToPositionTarget;
221 private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
214 222
215 private bool m_followCamAuto; 223 private bool m_followCamAuto;
216 224
217 private int m_movementUpdateCount; 225 private int m_movementUpdateCount;
226 private int m_lastColCount = -1; //KF: Look for Collision chnages
227 private int m_updateCount = 0; //KF: Update Anims for a while
228 private static readonly int UPDATE_COUNT = 10; // how many frames to update for
218 private const int NumMovementsBetweenRayCast = 5; 229 private const int NumMovementsBetweenRayCast = 5;
230 private List<uint> m_lastColliders = new List<uint>();
231
232 private object m_syncRoot = new Object();
219 233
220 private bool CameraConstraintActive; 234 private bool CameraConstraintActive;
221 //private int m_moveToPositionStateStatus; 235 //private int m_moveToPositionStateStatus;
@@ -242,7 +256,9 @@ namespace OpenSim.Region.Framework.Scenes
242 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, 256 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
243 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, 257 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
244 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, 258 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS,
245 DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, 259 DIR_CONTROL_FLAG_BACK_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG,
260 DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS,
261 DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG,
246 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG 262 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
247 } 263 }
248 264
@@ -449,9 +465,18 @@ namespace OpenSim.Region.Framework.Scenes
449 get 465 get
450 { 466 {
451 PhysicsActor actor = m_physicsActor; 467 PhysicsActor actor = m_physicsActor;
452 if (actor != null) 468// if (actor != null)
469 if ((actor != null) && (m_parentID == 0)) // KF Do NOT update m_pos here if Av is sitting!
453 m_pos = actor.Position; 470 m_pos = actor.Position;
454 471
472 // If we're sitting, we need to update our position
473 if (m_parentID != 0)
474 {
475 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID);
476 if (part != null)
477 m_parentPosition = part.AbsolutePosition;
478 }
479
455 return m_parentPosition + m_pos; 480 return m_parentPosition + m_pos;
456 } 481 }
457 set 482 set
@@ -470,7 +495,8 @@ namespace OpenSim.Region.Framework.Scenes
470 } 495 }
471 } 496 }
472 497
473 m_pos = value; 498 if (m_parentID == 0) // KF Do NOT update m_pos here if Av is sitting!
499 m_pos = value;
474 m_parentPosition = Vector3.Zero; 500 m_parentPosition = Vector3.Zero;
475 } 501 }
476 } 502 }
@@ -514,10 +540,39 @@ namespace OpenSim.Region.Framework.Scenes
514 } 540 }
515 } 541 }
516 542
543 public Quaternion OffsetRotation
544 {
545 get { return m_offsetRotation; }
546 set { m_offsetRotation = value; }
547 }
548
517 public Quaternion Rotation 549 public Quaternion Rotation
518 { 550 {
519 get { return m_bodyRot; } 551 get {
520 set { m_bodyRot = value; } 552 if (m_parentID != 0)
553 {
554 if (m_offsetRotation != null)
555 {
556 return m_offsetRotation;
557 }
558 else
559 {
560 return new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
561 }
562
563 }
564 else
565 {
566 return m_bodyRot;
567 }
568 }
569 set {
570 m_bodyRot = value;
571 if (m_parentID != 0)
572 {
573 m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
574 }
575 }
521 } 576 }
522 577
523 public Quaternion PreviousRotation 578 public Quaternion PreviousRotation
@@ -542,11 +597,21 @@ namespace OpenSim.Region.Framework.Scenes
542 597
543 private uint m_parentID; 598 private uint m_parentID;
544 599
600
601 private UUID m_linkedPrim;
602
545 public uint ParentID 603 public uint ParentID
546 { 604 {
547 get { return m_parentID; } 605 get { return m_parentID; }
548 set { m_parentID = value; } 606 set { m_parentID = value; }
549 } 607 }
608
609 public UUID LinkedPrim
610 {
611 get { return m_linkedPrim; }
612 set { m_linkedPrim = value; }
613 }
614
550 public float Health 615 public float Health
551 { 616 {
552 get { return m_health; } 617 get { return m_health; }
@@ -668,7 +733,7 @@ namespace OpenSim.Region.Framework.Scenes
668 CreateSceneViewer(); 733 CreateSceneViewer();
669 m_animator = new ScenePresenceAnimator(this); 734 m_animator = new ScenePresenceAnimator(this);
670 } 735 }
671 736
672 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this() 737 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this()
673 { 738 {
674 m_rootRegionHandle = reginfo.RegionHandle; 739 m_rootRegionHandle = reginfo.RegionHandle;
@@ -700,16 +765,16 @@ namespace OpenSim.Region.Framework.Scenes
700 m_reprioritization_timer.AutoReset = false; 765 m_reprioritization_timer.AutoReset = false;
701 766
702 AdjustKnownSeeds(); 767 AdjustKnownSeeds();
703
704 // TODO: I think, this won't send anything, as we are still a child here...
705 Animator.TrySetMovementAnimation("STAND"); 768 Animator.TrySetMovementAnimation("STAND");
706
707 // we created a new ScenePresence (a new child agent) in a fresh region. 769 // we created a new ScenePresence (a new child agent) in a fresh region.
708 // Request info about all the (root) agents in this region 770 // Request info about all the (root) agents in this region
709 // Note: This won't send data *to* other clients in that region (children don't send) 771 // Note: This won't send data *to* other clients in that region (children don't send)
710 SendInitialFullUpdateToAllClients(); 772 SendInitialFullUpdateToAllClients();
711
712 RegisterToEvents(); 773 RegisterToEvents();
774 if (m_controllingClient != null)
775 {
776 m_controllingClient.ProcessPendingPackets();
777 }
713 SetDirectionVectors(); 778 SetDirectionVectors();
714 } 779 }
715 780
@@ -759,25 +824,47 @@ namespace OpenSim.Region.Framework.Scenes
759 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT 824 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT
760 Dir_Vectors[4] = Vector3.UnitZ; //UP 825 Dir_Vectors[4] = Vector3.UnitZ; //UP
761 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN 826 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN
762 Dir_Vectors[8] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge 827 Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE
763 Dir_Vectors[6] = Vector3.UnitX*2; //FORWARD 828 Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE
764 Dir_Vectors[7] = -Vector3.UnitX; //BACK 829 Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE
830 Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE
831 Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge
765 } 832 }
766 833
767 private Vector3[] GetWalkDirectionVectors() 834 private Vector3[] GetWalkDirectionVectors()
768 { 835 {
769 Vector3[] vector = new Vector3[9]; 836 Vector3[] vector = new Vector3[11];
770 vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD 837 vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD
771 vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK 838 vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK
772 vector[2] = Vector3.UnitY; //LEFT 839 vector[2] = Vector3.UnitY; //LEFT
773 vector[3] = -Vector3.UnitY; //RIGHT 840 vector[3] = -Vector3.UnitY; //RIGHT
774 vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP 841 vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP
775 vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN 842 vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN
776 vector[8] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_Nudge 843 vector[6] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD_NUDGE
777 vector[6] = (new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z) * 2); //FORWARD Nudge 844 vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK_NUDGE
778 vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK Nudge 845 vector[8] = Vector3.UnitY; //LEFT_NUDGE
846 vector[9] = -Vector3.UnitY; //RIGHT_NUDGE
847 vector[10] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_NUDGE
779 return vector; 848 return vector;
780 } 849 }
850
851 private bool[] GetDirectionIsNudge()
852 {
853 bool[] isNudge = new bool[11];
854 isNudge[0] = false; //FORWARD
855 isNudge[1] = false; //BACK
856 isNudge[2] = false; //LEFT
857 isNudge[3] = false; //RIGHT
858 isNudge[4] = false; //UP
859 isNudge[5] = false; //DOWN
860 isNudge[6] = true; //FORWARD_NUDGE
861 isNudge[7] = true; //BACK_NUDGE
862 isNudge[8] = true; //LEFT_NUDGE
863 isNudge[9] = true; //RIGHT_NUDGE
864 isNudge[10] = true; //DOWN_Nudge
865 return isNudge;
866 }
867
781 868
782 #endregion 869 #endregion
783 870
@@ -839,6 +926,52 @@ namespace OpenSim.Region.Framework.Scenes
839 pos.Y = crossedBorder.BorderLine.Z - 1; 926 pos.Y = crossedBorder.BorderLine.Z - 1;
840 } 927 }
841 928
929 //If they're TP'ing in or logging in, we haven't had time to add any known child regions yet.
930 //This has the unfortunate consequence that if somebody is TP'ing who is already a child agent,
931 //they'll bypass the landing point. But I can't think of any decent way of fixing this.
932 if (KnownChildRegionHandles.Count == 0)
933 {
934 ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
935 if (land != null)
936 {
937 //Don't restrict gods, estate managers, or land owners to the TP point. This behaviour mimics agni.
938 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero && UserLevel < 200 && !m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid) && land.LandData.OwnerID != m_uuid)
939 {
940 pos = land.LandData.UserLocation;
941 }
942 }
943 }
944
945 if (pos.X < 0 || pos.Y < 0 || pos.Z < 0)
946 {
947 Vector3 emergencyPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 128);
948
949 if (pos.X < 0)
950 {
951 emergencyPos.X = (int)Constants.RegionSize + pos.X;
952 if (!(pos.Y < 0))
953 emergencyPos.Y = pos.Y;
954 if (!(pos.Z < 0))
955 emergencyPos.Z = pos.Z;
956 }
957 if (pos.Y < 0)
958 {
959 emergencyPos.Y = (int)Constants.RegionSize + pos.Y;
960 if (!(pos.X < 0))
961 emergencyPos.X = pos.X;
962 if (!(pos.Z < 0))
963 emergencyPos.Z = pos.Z;
964 }
965 if (pos.Z < 0)
966 {
967 emergencyPos.Z = 128;
968 if (!(pos.Y < 0))
969 emergencyPos.Y = pos.Y;
970 if (!(pos.X < 0))
971 emergencyPos.X = pos.X;
972 }
973 }
974
842 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) 975 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
843 { 976 {
844 m_log.WarnFormat( 977 m_log.WarnFormat(
@@ -960,12 +1093,17 @@ namespace OpenSim.Region.Framework.Scenes
960 { 1093 {
961 if (PhysicsActor != null) 1094 if (PhysicsActor != null)
962 { 1095 {
963 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; 1096 try
964 m_physicsActor.OnOutOfBounds -= OutOfBoundsCall; 1097 {
965 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); 1098 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
966 m_physicsActor.UnSubscribeEvents(); 1099 m_physicsActor.OnOutOfBounds -= OutOfBoundsCall;
967 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; 1100 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
968 PhysicsActor = null; 1101 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
1102 m_physicsActor.UnSubscribeEvents();
1103 PhysicsActor = null;
1104 }
1105 catch
1106 { }
969 } 1107 }
970 } 1108 }
971 1109
@@ -976,9 +1114,10 @@ namespace OpenSim.Region.Framework.Scenes
976 public void Teleport(Vector3 pos) 1114 public void Teleport(Vector3 pos)
977 { 1115 {
978 bool isFlying = false; 1116 bool isFlying = false;
1117
979 if (m_physicsActor != null) 1118 if (m_physicsActor != null)
980 isFlying = m_physicsActor.Flying; 1119 isFlying = m_physicsActor.Flying;
981 1120
982 RemoveFromPhysicalScene(); 1121 RemoveFromPhysicalScene();
983 Velocity = Vector3.Zero; 1122 Velocity = Vector3.Zero;
984 AbsolutePosition = pos; 1123 AbsolutePosition = pos;
@@ -990,6 +1129,7 @@ namespace OpenSim.Region.Framework.Scenes
990 } 1129 }
991 1130
992 SendTerseUpdateToAllClients(); 1131 SendTerseUpdateToAllClients();
1132
993 } 1133 }
994 1134
995 public void TeleportWithMomentum(Vector3 pos) 1135 public void TeleportWithMomentum(Vector3 pos)
@@ -1103,7 +1243,6 @@ namespace OpenSim.Region.Framework.Scenes
1103 pos.Z = ground + 1.5f; 1243 pos.Z = ground + 1.5f;
1104 AbsolutePosition = pos; 1244 AbsolutePosition = pos;
1105 } 1245 }
1106
1107 m_isChildAgent = false; 1246 m_isChildAgent = false;
1108 bool m_flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); 1247 bool m_flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
1109 MakeRootAgent(AbsolutePosition, m_flying); 1248 MakeRootAgent(AbsolutePosition, m_flying);
@@ -1202,6 +1341,7 @@ namespace OpenSim.Region.Framework.Scenes
1202 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); 1341 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902");
1203 1342
1204 m_pos = m_LastFinitePos; 1343 m_pos = m_LastFinitePos;
1344
1205 if (!m_pos.IsFinite()) 1345 if (!m_pos.IsFinite())
1206 { 1346 {
1207 m_pos.X = 127f; 1347 m_pos.X = 127f;
@@ -1268,7 +1408,6 @@ namespace OpenSim.Region.Framework.Scenes
1268 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); 1408 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback);
1269 } 1409 }
1270 } 1410 }
1271
1272 lock (scriptedcontrols) 1411 lock (scriptedcontrols)
1273 { 1412 {
1274 if (scriptedcontrols.Count > 0) 1413 if (scriptedcontrols.Count > 0)
@@ -1283,6 +1422,9 @@ namespace OpenSim.Region.Framework.Scenes
1283 1422
1284 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) 1423 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0)
1285 { 1424 {
1425 m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.
1426 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
1427
1286 // TODO: This doesn't prevent the user from walking yet. 1428 // TODO: This doesn't prevent the user from walking yet.
1287 // Setting parent ID would fix this, if we knew what value 1429 // Setting parent ID would fix this, if we knew what value
1288 // to use. Or we could add a m_isSitting variable. 1430 // to use. Or we could add a m_isSitting variable.
@@ -1331,12 +1473,20 @@ namespace OpenSim.Region.Framework.Scenes
1331 if (actor.Flying != oldflying) 1473 if (actor.Flying != oldflying)
1332 update_movementflag = true; 1474 update_movementflag = true;
1333 1475
1476 if (m_animator.m_jumping) // add for jumping
1477 update_movementflag = true;
1478
1334 if (q != m_bodyRot) 1479 if (q != m_bodyRot)
1335 { 1480 {
1336 m_bodyRot = q; 1481 m_bodyRot = q;
1337 update_rotation = true; 1482 update_rotation = true;
1338 } 1483 }
1339 1484
1485 //guilty until proven innocent..
1486 bool Nudging = true;
1487 //Basically, if there is at least one non-nudge control then we don't need
1488 //to worry about stopping the avatar
1489
1340 if (m_parentID == 0) 1490 if (m_parentID == 0)
1341 { 1491 {
1342 bool bAllowUpdateMoveToPosition = false; 1492 bool bAllowUpdateMoveToPosition = false;
@@ -1351,9 +1501,12 @@ namespace OpenSim.Region.Framework.Scenes
1351 else 1501 else
1352 dirVectors = Dir_Vectors; 1502 dirVectors = Dir_Vectors;
1353 1503
1354 // The fact that m_movementflag is a byte needs to be fixed 1504 bool[] isNudge = GetDirectionIsNudge();
1355 // it really should be a uint 1505
1356 uint nudgehack = 250; 1506
1507
1508
1509
1357 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) 1510 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS)
1358 { 1511 {
1359 if (((uint)flags & (uint)DCF) != 0) 1512 if (((uint)flags & (uint)DCF) != 0)
@@ -1363,40 +1516,28 @@ namespace OpenSim.Region.Framework.Scenes
1363 try 1516 try
1364 { 1517 {
1365 agent_control_v3 += dirVectors[i]; 1518 agent_control_v3 += dirVectors[i];
1366 //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); 1519 if (isNudge[i] == false)
1520 {
1521 Nudging = false;
1522 }
1367 } 1523 }
1368 catch (IndexOutOfRangeException) 1524 catch (IndexOutOfRangeException)
1369 { 1525 {
1370 // Why did I get this? 1526 // Why did I get this?
1371 } 1527 }
1372 1528
1373 if ((m_movementflag & (byte)(uint)DCF) == 0) 1529 if ((m_movementflag & (uint)DCF) == 0)
1374 { 1530 {
1375 if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1376 {
1377 m_movementflag |= (byte)nudgehack;
1378 }
1379 m_movementflag += (byte)(uint)DCF; 1531 m_movementflag += (byte)(uint)DCF;
1380 update_movementflag = true; 1532 update_movementflag = true;
1381 } 1533 }
1382 } 1534 }
1383 else 1535 else
1384 { 1536 {
1385 if ((m_movementflag & (byte)(uint)DCF) != 0 || 1537 if ((m_movementflag & (uint)DCF) != 0)
1386 ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1387 && ((m_movementflag & (byte)nudgehack) == nudgehack))
1388 ) // This or is for Nudge forward
1389 { 1538 {
1390 m_movementflag -= ((byte)(uint)DCF); 1539 m_movementflag -= (byte)(uint)DCF;
1391
1392 update_movementflag = true; 1540 update_movementflag = true;
1393 /*
1394 if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1395 && ((m_movementflag & (byte)nudgehack) == nudgehack))
1396 {
1397 m_log.Debug("Removed Hack flag");
1398 }
1399 */
1400 } 1541 }
1401 else 1542 else
1402 { 1543 {
@@ -1405,7 +1546,6 @@ namespace OpenSim.Region.Framework.Scenes
1405 } 1546 }
1406 i++; 1547 i++;
1407 } 1548 }
1408
1409 //Paupaw:Do Proper PID for Autopilot here 1549 //Paupaw:Do Proper PID for Autopilot here
1410 if (bResetMoveToPosition) 1550 if (bResetMoveToPosition)
1411 { 1551 {
@@ -1440,6 +1580,9 @@ namespace OpenSim.Region.Framework.Scenes
1440 // Ignore z component of vector 1580 // Ignore z component of vector
1441 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); 1581 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f);
1442 LocalVectorToTarget2D.Normalize(); 1582 LocalVectorToTarget2D.Normalize();
1583
1584 //We're not nudging
1585 Nudging = false;
1443 agent_control_v3 += LocalVectorToTarget2D; 1586 agent_control_v3 += LocalVectorToTarget2D;
1444 1587
1445 // update avatar movement flags. the avatar coordinate system is as follows: 1588 // update avatar movement flags. the avatar coordinate system is as follows:
@@ -1530,13 +1673,13 @@ namespace OpenSim.Region.Framework.Scenes
1530 // m_log.DebugFormat( 1673 // m_log.DebugFormat(
1531 // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); 1674 // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3);
1532 1675
1533 AddNewMovement(agent_control_v3, q); 1676 AddNewMovement(agent_control_v3, q, Nudging);
1534 1677
1535 1678
1536 } 1679 }
1537 } 1680 }
1538 1681
1539 if (update_movementflag && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) == 0) && (m_parentID == 0) && !SitGround) 1682 if (update_movementflag && !SitGround)
1540 Animator.UpdateMovementAnimations(); 1683 Animator.UpdateMovementAnimations();
1541 1684
1542 m_scene.EventManager.TriggerOnClientMovement(this); 1685 m_scene.EventManager.TriggerOnClientMovement(this);
@@ -1551,7 +1694,6 @@ namespace OpenSim.Region.Framework.Scenes
1551 m_sitAtAutoTarget = false; 1694 m_sitAtAutoTarget = false;
1552 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; 1695 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default;
1553 //proxy.PCode = (byte)PCode.ParticleSystem; 1696 //proxy.PCode = (byte)PCode.ParticleSystem;
1554
1555 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy); 1697 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy);
1556 proxyObjectGroup.AttachToScene(m_scene); 1698 proxyObjectGroup.AttachToScene(m_scene);
1557 1699
@@ -1593,7 +1735,7 @@ namespace OpenSim.Region.Framework.Scenes
1593 } 1735 }
1594 m_moveToPositionInProgress = true; 1736 m_moveToPositionInProgress = true;
1595 m_moveToPositionTarget = new Vector3(locx, locy, locz); 1737 m_moveToPositionTarget = new Vector3(locx, locy, locz);
1596 } 1738 }
1597 catch (Exception ex) 1739 catch (Exception ex)
1598 { 1740 {
1599 //Why did I get this error? 1741 //Why did I get this error?
@@ -1615,7 +1757,7 @@ namespace OpenSim.Region.Framework.Scenes
1615 Velocity = Vector3.Zero; 1757 Velocity = Vector3.Zero;
1616 SendFullUpdateToAllClients(); 1758 SendFullUpdateToAllClients();
1617 1759
1618 //HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); 1760 HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); //KF ??
1619 } 1761 }
1620 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false); 1762 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false);
1621 m_requestedSitTargetUUID = UUID.Zero; 1763 m_requestedSitTargetUUID = UUID.Zero;
@@ -1652,50 +1794,85 @@ namespace OpenSim.Region.Framework.Scenes
1652 1794
1653 if (m_parentID != 0) 1795 if (m_parentID != 0)
1654 { 1796 {
1655 m_log.Debug("StandupCode Executed"); 1797 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
1656 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID);
1657 if (part != null) 1798 if (part != null)
1658 { 1799 {
1800 part.TaskInventory.LockItemsForRead(true);
1659 TaskInventoryDictionary taskIDict = part.TaskInventory; 1801 TaskInventoryDictionary taskIDict = part.TaskInventory;
1660 if (taskIDict != null) 1802 if (taskIDict != null)
1661 { 1803 {
1662 lock (taskIDict) 1804 foreach (UUID taskID in taskIDict.Keys)
1663 { 1805 {
1664 foreach (UUID taskID in taskIDict.Keys) 1806 UnRegisterControlEventsToScript(LocalId, taskID);
1665 { 1807 taskIDict[taskID].PermsMask &= ~(
1666 UnRegisterControlEventsToScript(LocalId, taskID); 1808 2048 | //PERMISSION_CONTROL_CAMERA
1667 taskIDict[taskID].PermsMask &= ~( 1809 4); // PERMISSION_TAKE_CONTROLS
1668 2048 | //PERMISSION_CONTROL_CAMERA
1669 4); // PERMISSION_TAKE_CONTROLS
1670 }
1671 } 1810 }
1672
1673 } 1811 }
1812 part.TaskInventory.LockItemsForRead(false);
1674 // Reset sit target. 1813 // Reset sit target.
1675 if (part.GetAvatarOnSitTarget() == UUID) 1814 if (part.GetAvatarOnSitTarget() == UUID)
1676 part.SetAvatarOnSitTarget(UUID.Zero); 1815 part.SetAvatarOnSitTarget(UUID.Zero);
1677
1678 m_parentPosition = part.GetWorldPosition(); 1816 m_parentPosition = part.GetWorldPosition();
1679 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 1817 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
1680 } 1818 }
1819 // part.GetWorldRotation() is the rotation of the object being sat on
1820 // Rotation is the sittiing Av's rotation
1821
1822 Quaternion partRot;
1823// if (part.LinkNum == 1)
1824// { // Root prim of linkset
1825// partRot = part.ParentGroup.RootPart.RotationOffset;
1826// }
1827// else
1828// { // single or child prim
1829
1830// }
1831 if (part == null) //CW: Part may be gone. llDie() for example.
1832 {
1833 partRot = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
1834 }
1835 else
1836 {
1837 partRot = part.GetWorldRotation();
1838 }
1839
1840 Quaternion partIRot = Quaternion.Inverse(partRot);
1841
1842 Quaternion avatarRot = Quaternion.Inverse(Quaternion.Inverse(Rotation) * partIRot); // world or. of the av
1843 Vector3 avStandUp = new Vector3(1.0f, 0f, 0f) * avatarRot; // 1M infront of av
1681 1844
1845
1682 if (m_physicsActor == null) 1846 if (m_physicsActor == null)
1683 { 1847 {
1684 AddToPhysicalScene(false); 1848 AddToPhysicalScene(false);
1685 } 1849 }
1686 1850 //CW: If the part isn't null then we can set the current position
1687 m_pos += m_parentPosition + new Vector3(0.0f, 0.0f, 2.0f*m_sitAvatarHeight); 1851 if (part != null)
1688 m_parentPosition = Vector3.Zero; 1852 {
1689 1853 Vector3 avWorldStandUp = avStandUp + part.GetWorldPosition() + ((m_pos - part.OffsetPosition) * partRot); // + av sit offset!
1690 m_parentID = 0; 1854 AbsolutePosition = avWorldStandUp; //KF: Fix stand up.
1855 part.IsOccupied = false;
1856 part.ParentGroup.DeleteAvatar(ControllingClient.AgentId);
1857 }
1858 else
1859 {
1860 //CW: Since the part doesn't exist, a coarse standup position isn't an issue
1861 AbsolutePosition = m_lastWorldPosition;
1862 }
1863
1864 m_parentPosition = Vector3.Zero;
1865 m_parentID = 0;
1866 m_linkedPrim = UUID.Zero;
1867 m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
1691 SendFullUpdateToAllClients(); 1868 SendFullUpdateToAllClients();
1692 m_requestedSitTargetID = 0; 1869 m_requestedSitTargetID = 0;
1870
1693 if ((m_physicsActor != null) && (m_avHeight > 0)) 1871 if ((m_physicsActor != null) && (m_avHeight > 0))
1694 { 1872 {
1695 SetHeight(m_avHeight); 1873 SetHeight(m_avHeight);
1696 } 1874 }
1697 } 1875 }
1698
1699 Animator.TrySetMovementAnimation("STAND"); 1876 Animator.TrySetMovementAnimation("STAND");
1700 } 1877 }
1701 1878
@@ -1726,13 +1903,9 @@ namespace OpenSim.Region.Framework.Scenes
1726 Vector3 avSitOffSet = part.SitTargetPosition; 1903 Vector3 avSitOffSet = part.SitTargetPosition;
1727 Quaternion avSitOrientation = part.SitTargetOrientation; 1904 Quaternion avSitOrientation = part.SitTargetOrientation;
1728 UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); 1905 UUID avOnTargetAlready = part.GetAvatarOnSitTarget();
1729 1906 bool SitTargetOccupied = (avOnTargetAlready != UUID.Zero);
1730 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); 1907 bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored.
1731 bool SitTargetisSet = 1908 if (SitTargetisSet && !SitTargetOccupied)
1732 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && avSitOrientation.W == 1f &&
1733 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f));
1734
1735 if (SitTargetisSet && SitTargetUnOccupied)
1736 { 1909 {
1737 //switch the target to this prim 1910 //switch the target to this prim
1738 return part; 1911 return part;
@@ -1746,84 +1919,164 @@ namespace OpenSim.Region.Framework.Scenes
1746 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation) 1919 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation)
1747 { 1920 {
1748 bool autopilot = true; 1921 bool autopilot = true;
1922 Vector3 autopilotTarget = new Vector3();
1923 Quaternion sitOrientation = Quaternion.Identity;
1749 Vector3 pos = new Vector3(); 1924 Vector3 pos = new Vector3();
1750 Quaternion sitOrientation = pSitOrientation;
1751 Vector3 cameraEyeOffset = Vector3.Zero; 1925 Vector3 cameraEyeOffset = Vector3.Zero;
1752 Vector3 cameraAtOffset = Vector3.Zero; 1926 Vector3 cameraAtOffset = Vector3.Zero;
1753 bool forceMouselook = false; 1927 bool forceMouselook = false;
1754 1928
1755 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); 1929 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
1756 SceneObjectPart part = FindNextAvailableSitTarget(targetID); 1930 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
1757 if (part != null) 1931 if (part == null) return;
1758 { 1932
1759 // TODO: determine position to sit at based on scene geometry; don't trust offset from client 1933 // TODO: determine position to sit at based on scene geometry; don't trust offset from client
1760 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it 1934 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
1761 1935
1762 // Is a sit target available? 1936 // part is the prim to sit on
1763 Vector3 avSitOffSet = part.SitTargetPosition; 1937 // offset is the world-ref vector distance from that prim center to the click-spot
1764 Quaternion avSitOrientation = part.SitTargetOrientation; 1938 // UUID is the UUID of the Avatar doing the clicking
1765 UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); 1939
1766 1940 m_avInitialPos = AbsolutePosition; // saved to calculate unscripted sit rotation
1767 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); 1941
1768 bool SitTargetisSet = 1942 // Is a sit target available?
1769 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && 1943 Vector3 avSitOffSet = part.SitTargetPosition;
1770 ( 1944 Quaternion avSitOrientation = part.SitTargetOrientation;
1771 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 1f // Valid Zero Rotation quaternion 1945
1772 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point 1946 bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored.
1773 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion 1947 // Quaternion partIRot = Quaternion.Inverse(part.GetWorldRotation());
1774 ) 1948 Quaternion partRot;
1775 )); 1949// if (part.LinkNum == 1)
1776 1950// { // Root prim of linkset
1777 if (SitTargetisSet && SitTargetUnOccupied) 1951// partRot = part.ParentGroup.RootPart.RotationOffset;
1778 { 1952// }
1779 part.SetAvatarOnSitTarget(UUID); 1953// else
1780 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); 1954// { // single or child prim
1781 sitOrientation = avSitOrientation; 1955 partRot = part.GetWorldRotation();
1782 autopilot = false; 1956// }
1783 } 1957 Quaternion partIRot = Quaternion.Inverse(partRot);
1784 1958//Console.WriteLine("SendSitResponse offset=" + offset + " Occup=" + part.IsOccupied + " TargSet=" + SitTargetisSet);
1785 pos = part.AbsolutePosition + offset; 1959 // Sit analysis rewritten by KF 091125
1786 //if (Math.Abs(part.AbsolutePosition.Z - AbsolutePosition.Z) > 1) 1960 if (SitTargetisSet) // scipted sit
1787 //{ 1961 {
1788 // offset = pos; 1962 if (!part.IsOccupied)
1789 //autopilot = false; 1963 {
1790 //} 1964//Console.WriteLine("Scripted, unoccupied");
1791 if (m_physicsActor != null) 1965 part.SetAvatarOnSitTarget(UUID); // set that Av will be on it
1792 { 1966 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); // change ofset to the scripted one
1793 // If we're not using the client autopilot, we're immediately warping the avatar to the location 1967
1794 // We can remove the physicsActor until they stand up. 1968 Quaternion nrot = avSitOrientation;
1795 m_sitAvatarHeight = m_physicsActor.Size.Z; 1969 if (!part.IsRoot)
1796
1797 if (autopilot)
1798 { 1970 {
1799 if (Util.GetDistanceTo(AbsolutePosition, pos) < 4.5) 1971 nrot = part.RotationOffset * avSitOrientation;
1800 {
1801 autopilot = false;
1802
1803 RemoveFromPhysicalScene();
1804 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
1805 }
1806 } 1972 }
1807 else 1973 sitOrientation = nrot; // Change rotatione to the scripted one
1974 OffsetRotation = nrot;
1975 autopilot = false; // Jump direct to scripted llSitPos()
1976 }
1977 else
1978 {
1979//Console.WriteLine("Scripted, occupied");
1980 return;
1981 }
1982 }
1983 else // Not Scripted
1984 {
1985 if ( (Math.Abs(offset.X) > 0.5f) || (Math.Abs(offset.Y) > 0.5f) )
1986 {
1987 // large prim & offset, ignore if other Avs sitting
1988// offset.Z -= 0.05f;
1989 m_avUnscriptedSitPos = offset * partIRot; // (non-zero) sit where clicked
1990 autopilotTarget = part.AbsolutePosition + offset; // World location of clicked point
1991
1992//Console.WriteLine(" offset ={0}", offset);
1993//Console.WriteLine(" UnscriptedSitPos={0}", m_avUnscriptedSitPos);
1994//Console.WriteLine(" autopilotTarget={0}", autopilotTarget);
1995
1996 }
1997 else // small offset
1998 {
1999//Console.WriteLine("Small offset");
2000 if (!part.IsOccupied)
2001 {
2002 m_avUnscriptedSitPos = Vector3.Zero; // Zero = Sit on prim center
2003 autopilotTarget = part.AbsolutePosition;
2004//Console.WriteLine("UsSmall autopilotTarget={0}", autopilotTarget);
2005 }
2006 else return; // occupied small
2007 } // end large/small
2008 } // end Scripted/not
2009 cameraAtOffset = part.GetCameraAtOffset();
2010 cameraEyeOffset = part.GetCameraEyeOffset();
2011 forceMouselook = part.GetForceMouselook();
2012 if(cameraAtOffset == Vector3.Zero) cameraAtOffset = new Vector3(0f, 0f, 0.1f); //
2013 if(cameraEyeOffset == Vector3.Zero) cameraEyeOffset = new Vector3(0f, 0f, 0.1f); //
2014
2015 if (m_physicsActor != null)
2016 {
2017 // If we're not using the client autopilot, we're immediately warping the avatar to the location
2018 // We can remove the physicsActor until they stand up.
2019 m_sitAvatarHeight = m_physicsActor.Size.Z;
2020 if (autopilot)
2021 { // its not a scripted sit
2022// if (Util.GetDistanceTo(AbsolutePosition, autopilotTarget) < 4.5)
2023 if( (Math.Abs(AbsolutePosition.X - autopilotTarget.X) < 256.0f) && (Math.Abs(AbsolutePosition.Y - autopilotTarget.Y) < 256.0f) )
1808 { 2024 {
2025 autopilot = false; // close enough
2026 m_lastWorldPosition = m_pos; /* CW - This give us a position to return the avatar to if the part is killed before standup.
2027 Not using the part's position because returning the AV to the last known standing
2028 position is likely to be more friendly, isn't it? */
1809 RemoveFromPhysicalScene(); 2029 RemoveFromPhysicalScene();
1810 } 2030 Velocity = Vector3.Zero;
2031 AbsolutePosition = autopilotTarget + new Vector3(0.0f, 0.0f, (m_sitAvatarHeight / 2.0f)); // Warp av to over sit target
2032 } // else the autopilot will get us close
2033 }
2034 else
2035 { // its a scripted sit
2036 m_lastWorldPosition = part.AbsolutePosition; /* CW - This give us a position to return the avatar to if the part is killed before standup.
2037 I *am* using the part's position this time because we have no real idea how far away
2038 the avatar is from the sit target. */
2039 RemoveFromPhysicalScene();
2040 Velocity = Vector3.Zero;
1811 } 2041 }
1812
1813 cameraAtOffset = part.GetCameraAtOffset();
1814 cameraEyeOffset = part.GetCameraEyeOffset();
1815 forceMouselook = part.GetForceMouselook();
1816 } 2042 }
1817 2043 else return; // physactor is null!
1818 ControllingClient.SendSitResponse(targetID, offset, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook); 2044
1819 m_requestedSitTargetUUID = targetID; 2045 Vector3 offsetr; // = offset * partIRot;
2046 // KF: In a linkset, offsetr needs to be relative to the group root! 091208
2047 // offsetr = (part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) + (offset * partIRot);
2048 // if (part.LinkNum < 2) 091216 All this was necessary because of the GetWorldRotation error.
2049 // { // Single, or Root prim of linkset, target is ClickOffset * RootRot
2050 //offsetr = offset * partIRot;
2051//
2052 // else
2053 // { // Child prim, offset is (ChildOffset * RootRot) + (ClickOffset * ChildRot)
2054 // offsetr = //(part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) +
2055 // (offset * partRot);
2056 // }
2057
2058//Console.WriteLine(" ");
2059//Console.WriteLine("link number ={0}", part.LinkNum);
2060//Console.WriteLine("Prim offset ={0}", part.OffsetPosition );
2061//Console.WriteLine("Root Rotate ={0}", part.ParentGroup.RootPart.RotationOffset);
2062//Console.WriteLine("Click offst ={0}", offset);
2063//Console.WriteLine("Prim Rotate ={0}", part.GetWorldRotation());
2064//Console.WriteLine("offsetr ={0}", offsetr);
2065//Console.WriteLine("Camera At ={0}", cameraAtOffset);
2066//Console.WriteLine("Camera Eye ={0}", cameraEyeOffset);
2067
2068 //NOTE: SendSitResponse should be relative to the GROUP *NOT* THE PRIM if we're sitting on a child
2069 ControllingClient.SendSitResponse(part.ParentGroup.UUID, ((offset * part.RotationOffset) + part.OffsetPosition), sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook);
2070
2071 m_requestedSitTargetUUID = part.UUID; //KF: Correct autopilot target
1820 // This calls HandleAgentSit twice, once from here, and the client calls 2072 // This calls HandleAgentSit twice, once from here, and the client calls
1821 // HandleAgentSit itself after it gets to the location 2073 // HandleAgentSit itself after it gets to the location
1822 // It doesn't get to the location until we've moved them there though 2074 // It doesn't get to the location until we've moved them there though
1823 // which happens in HandleAgentSit :P 2075 // which happens in HandleAgentSit :P
1824 m_autopilotMoving = autopilot; 2076 m_autopilotMoving = autopilot;
1825 m_autoPilotTarget = pos; 2077 m_autoPilotTarget = autopilotTarget;
1826 m_sitAtAutoTarget = autopilot; 2078 m_sitAtAutoTarget = autopilot;
2079 m_initialSitTarget = autopilotTarget;
1827 if (!autopilot) 2080 if (!autopilot)
1828 HandleAgentSit(remoteClient, UUID); 2081 HandleAgentSit(remoteClient, UUID);
1829 } 2082 }
@@ -2118,47 +2371,130 @@ namespace OpenSim.Region.Framework.Scenes
2118 { 2371 {
2119 if (part != null) 2372 if (part != null)
2120 { 2373 {
2374//Console.WriteLine("Link #{0}, Rot {1}", part.LinkNum, part.GetWorldRotation());
2121 if (part.GetAvatarOnSitTarget() == UUID) 2375 if (part.GetAvatarOnSitTarget() == UUID)
2122 { 2376 {
2377//Console.WriteLine("Scripted Sit");
2378 // Scripted sit
2123 Vector3 sitTargetPos = part.SitTargetPosition; 2379 Vector3 sitTargetPos = part.SitTargetPosition;
2124 Quaternion sitTargetOrient = part.SitTargetOrientation; 2380 Quaternion sitTargetOrient = part.SitTargetOrientation;
2125
2126 //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0);
2127 //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w);
2128
2129 //Quaternion result = (sitTargetOrient * vq) * nq;
2130
2131 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z); 2381 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z);
2132 m_pos += SIT_TARGET_ADJUSTMENT; 2382 m_pos += SIT_TARGET_ADJUSTMENT;
2383 if (!part.IsRoot)
2384 {
2385 m_pos *= part.RotationOffset;
2386 }
2133 m_bodyRot = sitTargetOrient; 2387 m_bodyRot = sitTargetOrient;
2134 //Rotation = sitTargetOrient;
2135 m_parentPosition = part.AbsolutePosition; 2388 m_parentPosition = part.AbsolutePosition;
2136 2389 part.IsOccupied = true;
2137 //SendTerseUpdateToAllClients(); 2390 part.ParentGroup.AddAvatar(agentID);
2138 } 2391 }
2139 else 2392 else
2140 { 2393 {
2141 m_pos -= part.AbsolutePosition; 2394 // if m_avUnscriptedSitPos is zero then Av sits above center
2395 // Else Av sits at m_avUnscriptedSitPos
2396
2397 // Non-scripted sit by Kitto Flora 21Nov09
2398 // Calculate angle of line from prim to Av
2399 Quaternion partIRot;
2400// if (part.LinkNum == 1)
2401// { // Root prim of linkset
2402// partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset);
2403// }
2404// else
2405// { // single or child prim
2406 partIRot = Quaternion.Inverse(part.GetWorldRotation());
2407// }
2408 Vector3 sitTargetPos= part.AbsolutePosition + m_avUnscriptedSitPos;
2409 float y_diff = (m_avInitialPos.Y - sitTargetPos.Y);
2410 float x_diff = ( m_avInitialPos.X - sitTargetPos.X);
2411 if(Math.Abs(x_diff) < 0.001f) x_diff = 0.001f; // avoid div by 0
2412 if(Math.Abs(y_diff) < 0.001f) y_diff = 0.001f; // avoid pol flip at 0
2413 float sit_angle = (float)Math.Atan2( (double)y_diff, (double)x_diff);
2414 // NOTE: when sitting m_ pos and m_bodyRot are *relative* to the prim location/rotation, not 'World'.
2415 // Av sits at world euler <0,0, z>, translated by part rotation
2416 m_bodyRot = partIRot * Quaternion.CreateFromEulers(0f, 0f, sit_angle); // sit at 0,0,inv-click
2417
2142 m_parentPosition = part.AbsolutePosition; 2418 m_parentPosition = part.AbsolutePosition;
2143 } 2419 part.IsOccupied = true;
2420 part.ParentGroup.AddAvatar(agentID);
2421 m_pos = new Vector3(0f, 0f, 0.05f) + // corrections to get Sit Animation
2422 (new Vector3(0.0f, 0f, 0.61f) * partIRot) + // located on center
2423 (new Vector3(0.34f, 0f, 0.0f) * m_bodyRot) +
2424 m_avUnscriptedSitPos; // adds click offset, if any
2425 //Set up raytrace to find top surface of prim
2426 Vector3 size = part.Scale;
2427 float mag = 2.0f; // 0.1f + (float)Math.Sqrt((size.X * size.X) + (size.Y * size.Y) + (size.Z * size.Z));
2428 Vector3 start = part.AbsolutePosition + new Vector3(0f, 0f, mag);
2429 Vector3 down = new Vector3(0f, 0f, -1f);
2430//Console.WriteLine("st={0} do={1} ma={2}", start, down, mag);
2431 m_scene.PhysicsScene.RaycastWorld(
2432 start, // Vector3 position,
2433 down, // Vector3 direction,
2434 mag, // float length,
2435 SitAltitudeCallback); // retMethod
2436 } // end scripted/not
2144 } 2437 }
2145 else 2438 else // no Av
2146 { 2439 {
2147 return; 2440 return;
2148 } 2441 }
2149 } 2442 }
2150 m_parentID = m_requestedSitTargetID;
2151 2443
2444 //We want our offsets to reference the root prim, not the child we may have sat on
2445 if (!part.IsRoot)
2446 {
2447 m_parentID = part.ParentGroup.RootPart.LocalId;
2448 m_pos += part.OffsetPosition;
2449 }
2450 else
2451 {
2452 m_parentID = m_requestedSitTargetID;
2453 }
2454
2455 m_linkedPrim = part.UUID;
2456 if (part.GetAvatarOnSitTarget() != UUID)
2457 {
2458 m_offsetRotation = m_offsetRotation / part.RotationOffset;
2459 }
2152 Velocity = Vector3.Zero; 2460 Velocity = Vector3.Zero;
2153 RemoveFromPhysicalScene(); 2461 RemoveFromPhysicalScene();
2154
2155 Animator.TrySetMovementAnimation(sitAnimation); 2462 Animator.TrySetMovementAnimation(sitAnimation);
2156 SendFullUpdateToAllClients(); 2463 SendFullUpdateToAllClients();
2157 // This may seem stupid, but Our Full updates don't send avatar rotation :P 2464 SendTerseUpdateToAllClients();
2158 // So we're also sending a terse update (which has avatar rotation)
2159 // [Update] We do now.
2160 //SendTerseUpdateToAllClients();
2161 } 2465 }
2466
2467 public void SitAltitudeCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal)
2468 {
2469 // KF: 091202 There appears to be a bug in Prim Edit Size - the process sometimes make a prim that RayTrace no longer
2470 // sees. Take/re-rez, or sim restart corrects the condition. Result of bug is incorrect sit height.
2471 if(hitYN)
2472 {
2473 // m_pos = Av offset from prim center to make look like on center
2474 // m_parentPosition = Actual center pos of prim
2475 // collisionPoint = spot on prim where we want to sit
2476 // collisionPoint.Z = global sit surface height
2477 SceneObjectPart part = m_scene.GetSceneObjectPart(localid);
2478 Quaternion partIRot;
2479// if (part.LinkNum == 1)
2480/// { // Root prim of linkset
2481// partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset);
2482// }
2483// else
2484// { // single or child prim
2485 partIRot = Quaternion.Inverse(part.GetWorldRotation());
2486// }
2487 if (m_initialSitTarget != null)
2488 {
2489 float offZ = collisionPoint.Z - m_initialSitTarget.Z;
2490 Vector3 offset = new Vector3(0.0f, 0.0f, offZ) * partIRot; // Altitude correction
2491 //Console.WriteLine("sitPoint={0}, offset={1}", sitPoint, offset);
2492 m_pos += offset;
2493 // ControllingClient.SendClearFollowCamProperties(part.UUID);
2494 }
2495
2496 }
2497 } // End SitAltitudeCallback KF.
2162 2498
2163 /// <summary> 2499 /// <summary>
2164 /// Event handler for the 'Always run' setting on the client 2500 /// Event handler for the 'Always run' setting on the client
@@ -2188,7 +2524,7 @@ namespace OpenSim.Region.Framework.Scenes
2188 /// </summary> 2524 /// </summary>
2189 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> 2525 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
2190 /// <param name="rotation">The direction in which this avatar should now face. 2526 /// <param name="rotation">The direction in which this avatar should now face.
2191 public void AddNewMovement(Vector3 vec, Quaternion rotation) 2527 public void AddNewMovement(Vector3 vec, Quaternion rotation, bool Nudging)
2192 { 2528 {
2193 if (m_isChildAgent) 2529 if (m_isChildAgent)
2194 { 2530 {
@@ -2229,15 +2565,18 @@ namespace OpenSim.Region.Framework.Scenes
2229 Rotation = rotation; 2565 Rotation = rotation;
2230 Vector3 direc = vec * rotation; 2566 Vector3 direc = vec * rotation;
2231 direc.Normalize(); 2567 direc.Normalize();
2568 PhysicsActor actor = m_physicsActor;
2569 if ((vec.Z == 0f) && !actor.Flying) direc.Z = 0f; // Prevent camera WASD up.
2232 2570
2233 direc *= 0.03f * 128f * m_speedModifier; 2571 direc *= 0.03f * 128f * m_speedModifier;
2234 2572
2235 PhysicsActor actor = m_physicsActor;
2236 if (actor != null) 2573 if (actor != null)
2237 { 2574 {
2238 if (actor.Flying) 2575// rm falling if (actor.Flying)
2576 if ((actor.Flying) || Animator.m_falling) // add for falling lateral speed
2239 { 2577 {
2240 direc *= 4.0f; 2578// rm speed mod direc *= 4.0f;
2579 direc *= 5.2f; // for speed mod
2241 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); 2580 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
2242 //bool colliding = (m_physicsActor.IsColliding==true); 2581 //bool colliding = (m_physicsActor.IsColliding==true);
2243 //if (controlland) 2582 //if (controlland)
@@ -2250,22 +2589,30 @@ namespace OpenSim.Region.Framework.Scenes
2250 // m_log.Info("[AGENT]: Stop FLying"); 2589 // m_log.Info("[AGENT]: Stop FLying");
2251 //} 2590 //}
2252 } 2591 }
2592 /* This jumping section removed to SPA
2253 else if (!actor.Flying && actor.IsColliding) 2593 else if (!actor.Flying && actor.IsColliding)
2254 { 2594 {
2255 if (direc.Z > 2.0f) 2595 if (direc.Z > 2.0f)
2256 { 2596 {
2257 direc.Z *= 3.0f; 2597 if(m_animator.m_animTickJump == -1)
2258 2598 {
2259 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. 2599 direc.Z *= 3.0f; // jump
2260 Animator.TrySetMovementAnimation("PREJUMP"); 2600 }
2261 Animator.TrySetMovementAnimation("JUMP"); 2601 else
2602 {
2603 direc.Z *= 0.1f; // prejump
2604 }
2605 / * Animations are controlled via GetMovementAnimation() in ScenePresenceAnimator.cs
2606 Animator.TrySetMovementAnimation("PREJUMP");
2607 Animator.TrySetMovementAnimation("JUMP");
2608 * /
2262 } 2609 }
2263 } 2610 } */
2264 } 2611 }
2265 2612
2266 // TODO: Add the force instead of only setting it to support multiple forces per frame? 2613 // TODO: Add the force instead of only setting it to support multiple forces per frame?
2267 m_forceToApply = direc; 2614 m_forceToApply = direc;
2268 2615 m_isNudging = Nudging;
2269 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2616 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
2270 } 2617 }
2271 2618
@@ -2280,7 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes
2280 const float POSITION_TOLERANCE = 0.05f; 2627 const float POSITION_TOLERANCE = 0.05f;
2281 //const int TIME_MS_TOLERANCE = 3000; 2628 //const int TIME_MS_TOLERANCE = 3000;
2282 2629
2283 SendPrimUpdates(); 2630
2284 2631
2285 if (m_isChildAgent == false) 2632 if (m_isChildAgent == false)
2286 { 2633 {
@@ -2310,6 +2657,9 @@ namespace OpenSim.Region.Framework.Scenes
2310 CheckForBorderCrossing(); 2657 CheckForBorderCrossing();
2311 CheckForSignificantMovement(); // sends update to the modules. 2658 CheckForSignificantMovement(); // sends update to the modules.
2312 } 2659 }
2660
2661 //Sending prim updates AFTER the avatar terse updates are sent
2662 SendPrimUpdates();
2313 } 2663 }
2314 2664
2315 #endregion 2665 #endregion
@@ -2513,66 +2863,69 @@ namespace OpenSim.Region.Framework.Scenes
2513 /// <param name="visualParam"></param> 2863 /// <param name="visualParam"></param>
2514 public void SetAppearance(Primitive.TextureEntry textureEntry, byte[] visualParams) 2864 public void SetAppearance(Primitive.TextureEntry textureEntry, byte[] visualParams)
2515 { 2865 {
2516 if (m_physicsActor != null) 2866 lock (m_syncRoot)
2517 { 2867 {
2518 if (!IsChildAgent) 2868 if (m_physicsActor != null)
2519 { 2869 {
2520 // This may seem like it's redundant, remove the avatar from the physics scene 2870 if (!IsChildAgent)
2521 // just to add it back again, but it saves us from having to update 2871 {
2522 // 3 variables 10 times a second. 2872 // This may seem like it's redundant, remove the avatar from the physics scene
2523 bool flyingTemp = m_physicsActor.Flying; 2873 // just to add it back again, but it saves us from having to update
2524 RemoveFromPhysicalScene(); 2874 // 3 variables 10 times a second.
2525 //m_scene.PhysicsScene.RemoveAvatar(m_physicsActor); 2875 bool flyingTemp = m_physicsActor.Flying;
2876 RemoveFromPhysicalScene();
2877 //m_scene.PhysicsScene.RemoveAvatar(m_physicsActor);
2526 2878
2527 //PhysicsActor = null; 2879 //PhysicsActor = null;
2528 2880
2529 AddToPhysicalScene(flyingTemp); 2881 AddToPhysicalScene(flyingTemp);
2882 }
2530 } 2883 }
2531 }
2532 2884
2533 #region Bake Cache Check 2885 #region Bake Cache Check
2534 2886
2535 if (textureEntry != null) 2887 if (textureEntry != null)
2536 {
2537 for (int i = 0; i < BAKE_INDICES.Length; i++)
2538 { 2888 {
2539 int j = BAKE_INDICES[i]; 2889 for (int i = 0; i < BAKE_INDICES.Length; i++)
2540 Primitive.TextureEntryFace face = textureEntry.FaceTextures[j];
2541
2542 if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
2543 { 2890 {
2544 if (m_scene.AssetService.Get(face.TextureID.ToString()) == null) 2891 int j = BAKE_INDICES[i];
2892 Primitive.TextureEntryFace face = textureEntry.FaceTextures[j];
2893
2894 if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
2545 { 2895 {
2546 m_log.Warn("[APPEARANCE]: Missing baked texture " + face.TextureID + " (" + j + ") for avatar " + this.Name); 2896 if (m_scene.AssetService.Get(face.TextureID.ToString()) == null)
2547 this.ControllingClient.SendRebakeAvatarTextures(face.TextureID); 2897 {
2898 m_log.Warn("[APPEARANCE]: Missing baked texture " + face.TextureID + " (" + j + ") for avatar " + this.Name);
2899 this.ControllingClient.SendRebakeAvatarTextures(face.TextureID);
2900 }
2548 } 2901 }
2549 } 2902 }
2550 }
2551 2903
2552 } 2904 }
2553 2905
2554 2906
2555 #endregion Bake Cache Check 2907 #endregion Bake Cache Check
2556 2908
2557 m_appearance.SetAppearance(textureEntry, visualParams); 2909 m_appearance.SetAppearance(textureEntry, visualParams);
2558 if (m_appearance.AvatarHeight > 0) 2910 if (m_appearance.AvatarHeight > 0)
2559 SetHeight(m_appearance.AvatarHeight); 2911 SetHeight(m_appearance.AvatarHeight);
2560 2912
2561 // This is not needed, because only the transient data changed 2913 // This is not needed, because only the transient data changed
2562 //AvatarData adata = new AvatarData(m_appearance); 2914 //AvatarData adata = new AvatarData(m_appearance);
2563 //m_scene.AvatarService.SetAvatar(m_controllingClient.AgentId, adata); 2915 //m_scene.AvatarService.SetAvatar(m_controllingClient.AgentId, adata);
2564 2916
2565 SendAppearanceToAllOtherAgents(); 2917 SendAppearanceToAllOtherAgents();
2566 if (!m_startAnimationSet) 2918 if (!m_startAnimationSet)
2567 { 2919 {
2568 Animator.UpdateMovementAnimations(); 2920 Animator.UpdateMovementAnimations();
2569 m_startAnimationSet = true; 2921 m_startAnimationSet = true;
2570 } 2922 }
2571 2923
2572 Vector3 pos = m_pos; 2924 Vector3 pos = m_pos;
2573 pos.Z += m_appearance.HipOffset; 2925 pos.Z += m_appearance.HipOffset;
2574 2926
2575 m_controllingClient.SendAvatarDataImmediate(this); 2927 m_controllingClient.SendAvatarDataImmediate(this);
2928 }
2576 } 2929 }
2577 2930
2578 public void SetWearable(int wearableId, AvatarWearable wearable) 2931 public void SetWearable(int wearableId, AvatarWearable wearable)
@@ -3093,6 +3446,7 @@ namespace OpenSim.Region.Framework.Scenes
3093 m_callbackURI = cAgent.CallbackURI; 3446 m_callbackURI = cAgent.CallbackURI;
3094 3447
3095 m_pos = cAgent.Position; 3448 m_pos = cAgent.Position;
3449
3096 m_velocity = cAgent.Velocity; 3450 m_velocity = cAgent.Velocity;
3097 m_CameraCenter = cAgent.Center; 3451 m_CameraCenter = cAgent.Center;
3098 //m_avHeight = cAgent.Size.Z; 3452 //m_avHeight = cAgent.Size.Z;
@@ -3201,17 +3555,46 @@ namespace OpenSim.Region.Framework.Scenes
3201 /// </summary> 3555 /// </summary>
3202 public override void UpdateMovement() 3556 public override void UpdateMovement()
3203 { 3557 {
3204 if (m_forceToApply.HasValue) 3558 if (Animator!=null) // add for jumping
3205 { 3559 { // add for jumping
3206 Vector3 force = m_forceToApply.Value; 3560 // if (!m_animator.m_jumping) // add for jumping
3561 // { // add for jumping
3207 3562
3208 m_updateflag = true; 3563 if (m_forceToApply.HasValue) // this section realigned
3209// movementvector = force; 3564 {
3210 Velocity = force;
3211 3565
3212 m_forceToApply = null; 3566 Vector3 force = m_forceToApply.Value;
3213 } 3567 m_updateflag = true;
3214 } 3568if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3569 Velocity = force;
3570//Console.WriteLine("UM1 {0}", Velocity);
3571 m_forceToApply = null;
3572 }
3573 else
3574 {
3575 if (m_isNudging)
3576 {
3577 Vector3 force = Vector3.Zero;
3578
3579 m_updateflag = true;
3580if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3581 Velocity = force;
3582//Console.WriteLine("UM2 {0}", Velocity);
3583 m_isNudging = false;
3584 m_updateCount = UPDATE_COUNT; //KF: Update anims to pickup "STAND"
3585 }
3586 else // add for jumping
3587 { // add for jumping
3588 Vector3 force = Vector3.Zero; // add for jumping
3589if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3590//Console.WriteLine("UM3 {0}", Velocity);
3591 Velocity = force; // add for jumping
3592 }
3593
3594 }
3595 // } // end realign
3596 } // add for jumping
3597 } // add for jumping
3215 3598
3216 /// <summary> 3599 /// <summary>
3217 /// Adds a physical representation of the avatar to the Physics plugin 3600 /// Adds a physical representation of the avatar to the Physics plugin
@@ -3256,18 +3639,29 @@ namespace OpenSim.Region.Framework.Scenes
3256 { 3639 {
3257 if (e == null) 3640 if (e == null)
3258 return; 3641 return;
3259 3642
3260 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) 3643 // The Physics Scene will send (spam!) updates every 500 ms grep: m_physicsActor.SubscribeEvents(
3261 // The Physics Scene will send updates every 500 ms grep: m_physicsActor.SubscribeEvents(
3262 // as of this comment the interval is set in AddToPhysicalScene 3644 // as of this comment the interval is set in AddToPhysicalScene
3263 if (Animator!=null) 3645 if (Animator!=null)
3264 Animator.UpdateMovementAnimations(); 3646 {
3647 if (m_updateCount > 0) //KF: DO NOT call UpdateMovementAnimations outside of the m_updateCount wrapper,
3648 { // else its will lock out other animation changes, like ground sit.
3649 Animator.UpdateMovementAnimations();
3650 m_updateCount--;
3651 }
3652 }
3265 3653
3266 CollisionEventUpdate collisionData = (CollisionEventUpdate)e; 3654 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3267 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; 3655 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3268 3656
3269 CollisionPlane = Vector4.UnitW; 3657 CollisionPlane = Vector4.UnitW;
3270 3658
3659 if (m_lastColCount != coldata.Count)
3660 {
3661 m_updateCount = UPDATE_COUNT;
3662 m_lastColCount = coldata.Count;
3663 }
3664
3271 if (coldata.Count != 0 && Animator != null) 3665 if (coldata.Count != 0 && Animator != null)
3272 { 3666 {
3273 switch (Animator.CurrentMovementAnimation) 3667 switch (Animator.CurrentMovementAnimation)
@@ -3297,6 +3691,148 @@ namespace OpenSim.Region.Framework.Scenes
3297 } 3691 }
3298 } 3692 }
3299 3693
3694 List<uint> thisHitColliders = new List<uint>();
3695 List<uint> endedColliders = new List<uint>();
3696 List<uint> startedColliders = new List<uint>();
3697
3698 foreach (uint localid in coldata.Keys)
3699 {
3700 thisHitColliders.Add(localid);
3701 if (!m_lastColliders.Contains(localid))
3702 {
3703 startedColliders.Add(localid);
3704 }
3705 //m_log.Debug("[SCENE PRESENCE]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
3706 }
3707
3708 // calculate things that ended colliding
3709 foreach (uint localID in m_lastColliders)
3710 {
3711 if (!thisHitColliders.Contains(localID))
3712 {
3713 endedColliders.Add(localID);
3714 }
3715 }
3716 //add the items that started colliding this time to the last colliders list.
3717 foreach (uint localID in startedColliders)
3718 {
3719 m_lastColliders.Add(localID);
3720 }
3721 // remove things that ended colliding from the last colliders list
3722 foreach (uint localID in endedColliders)
3723 {
3724 m_lastColliders.Remove(localID);
3725 }
3726
3727 // do event notification
3728 if (startedColliders.Count > 0)
3729 {
3730 ColliderArgs StartCollidingMessage = new ColliderArgs();
3731 List<DetectedObject> colliding = new List<DetectedObject>();
3732 foreach (uint localId in startedColliders)
3733 {
3734 if (localId == 0)
3735 continue;
3736
3737 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3738 string data = "";
3739 if (obj != null)
3740 {
3741 DetectedObject detobj = new DetectedObject();
3742 detobj.keyUUID = obj.UUID;
3743 detobj.nameStr = obj.Name;
3744 detobj.ownerUUID = obj.OwnerID;
3745 detobj.posVector = obj.AbsolutePosition;
3746 detobj.rotQuat = obj.GetWorldRotation();
3747 detobj.velVector = obj.Velocity;
3748 detobj.colliderType = 0;
3749 detobj.groupUUID = obj.GroupID;
3750 colliding.Add(detobj);
3751 }
3752 }
3753
3754 if (colliding.Count > 0)
3755 {
3756 StartCollidingMessage.Colliders = colliding;
3757
3758 foreach (SceneObjectGroup att in Attachments)
3759 Scene.EventManager.TriggerScriptCollidingStart(att.LocalId, StartCollidingMessage);
3760 }
3761 }
3762
3763 if (endedColliders.Count > 0)
3764 {
3765 ColliderArgs EndCollidingMessage = new ColliderArgs();
3766 List<DetectedObject> colliding = new List<DetectedObject>();
3767 foreach (uint localId in endedColliders)
3768 {
3769 if (localId == 0)
3770 continue;
3771
3772 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3773 string data = "";
3774 if (obj != null)
3775 {
3776 DetectedObject detobj = new DetectedObject();
3777 detobj.keyUUID = obj.UUID;
3778 detobj.nameStr = obj.Name;
3779 detobj.ownerUUID = obj.OwnerID;
3780 detobj.posVector = obj.AbsolutePosition;
3781 detobj.rotQuat = obj.GetWorldRotation();
3782 detobj.velVector = obj.Velocity;
3783 detobj.colliderType = 0;
3784 detobj.groupUUID = obj.GroupID;
3785 colliding.Add(detobj);
3786 }
3787 }
3788
3789 if (colliding.Count > 0)
3790 {
3791 EndCollidingMessage.Colliders = colliding;
3792
3793 foreach (SceneObjectGroup att in Attachments)
3794 Scene.EventManager.TriggerScriptCollidingEnd(att.LocalId, EndCollidingMessage);
3795 }
3796 }
3797
3798 if (thisHitColliders.Count > 0)
3799 {
3800 ColliderArgs CollidingMessage = new ColliderArgs();
3801 List<DetectedObject> colliding = new List<DetectedObject>();
3802 foreach (uint localId in thisHitColliders)
3803 {
3804 if (localId == 0)
3805 continue;
3806
3807 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3808 string data = "";
3809 if (obj != null)
3810 {
3811 DetectedObject detobj = new DetectedObject();
3812 detobj.keyUUID = obj.UUID;
3813 detobj.nameStr = obj.Name;
3814 detobj.ownerUUID = obj.OwnerID;
3815 detobj.posVector = obj.AbsolutePosition;
3816 detobj.rotQuat = obj.GetWorldRotation();
3817 detobj.velVector = obj.Velocity;
3818 detobj.colliderType = 0;
3819 detobj.groupUUID = obj.GroupID;
3820 colliding.Add(detobj);
3821 }
3822 }
3823
3824 if (colliding.Count > 0)
3825 {
3826 CollidingMessage.Colliders = colliding;
3827
3828 lock (m_attachments)
3829 {
3830 foreach (SceneObjectGroup att in m_attachments)
3831 Scene.EventManager.TriggerScriptColliding(att.LocalId, CollidingMessage);
3832 }
3833 }
3834 }
3835
3300 if (m_invulnerable) 3836 if (m_invulnerable)
3301 return; 3837 return;
3302 3838
@@ -3492,7 +4028,10 @@ namespace OpenSim.Region.Framework.Scenes
3492 m_scene = scene; 4028 m_scene = scene;
3493 4029
3494 RegisterToEvents(); 4030 RegisterToEvents();
3495 4031 if (m_controllingClient != null)
4032 {
4033 m_controllingClient.ProcessPendingPackets();
4034 }
3496 /* 4035 /*
3497 AbsolutePosition = client.StartPos; 4036 AbsolutePosition = client.StartPos;
3498 4037
@@ -3722,6 +4261,39 @@ namespace OpenSim.Region.Framework.Scenes
3722 return; 4261 return;
3723 } 4262 }
3724 4263
4264 XmlDocument doc = new XmlDocument();
4265 string stateData = String.Empty;
4266
4267 IAttachmentsService attServ = m_scene.RequestModuleInterface<IAttachmentsService>();
4268 if (attServ != null)
4269 {
4270 m_log.DebugFormat("[ATTACHMENT]: Loading attachment data from attachment service");
4271 stateData = attServ.Get(ControllingClient.AgentId.ToString());
4272 if (stateData != String.Empty)
4273 {
4274 try
4275 {
4276 doc.LoadXml(stateData);
4277 }
4278 catch { }
4279 }
4280 }
4281
4282 Dictionary<UUID, string> itemData = new Dictionary<UUID, string>();
4283
4284 XmlNodeList nodes = doc.GetElementsByTagName("Attachment");
4285 if (nodes.Count > 0)
4286 {
4287 foreach (XmlNode n in nodes)
4288 {
4289 XmlElement elem = (XmlElement)n;
4290 string itemID = elem.GetAttribute("ItemID");
4291 string xml = elem.InnerXml;
4292
4293 itemData[new UUID(itemID)] = xml;
4294 }
4295 }
4296
3725 List<int> attPoints = m_appearance.GetAttachedPoints(); 4297 List<int> attPoints = m_appearance.GetAttachedPoints();
3726 foreach (int p in attPoints) 4298 foreach (int p in attPoints)
3727 { 4299 {
@@ -3741,7 +4313,30 @@ namespace OpenSim.Region.Framework.Scenes
3741 4313
3742 try 4314 try
3743 { 4315 {
3744 m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p); 4316 string xmlData;
4317 XmlDocument d = new XmlDocument();
4318 UUID asset;
4319 if (itemData.TryGetValue(itemID, out xmlData))
4320 {
4321 d.LoadXml(xmlData);
4322 m_log.InfoFormat("[ATTACHMENT]: Found saved state for item {0}, loading it", itemID);
4323
4324 // Rez from inventory
4325 asset
4326 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p, true, d);
4327
4328 }
4329 else
4330 {
4331 // Rez from inventory (with a null doc to let
4332 // CHANGED_OWNER happen)
4333 asset
4334 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p, true, null);
4335 }
4336
4337 m_log.InfoFormat(
4338 "[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2}",
4339 p, itemID, asset);
3745 } 4340 }
3746 catch (Exception e) 4341 catch (Exception e)
3747 { 4342 {
@@ -3774,5 +4369,16 @@ namespace OpenSim.Region.Framework.Scenes
3774 m_reprioritization_called = false; 4369 m_reprioritization_called = false;
3775 } 4370 }
3776 } 4371 }
4372
4373 private Vector3 Quat2Euler(Quaternion rot){
4374 float x = Utils.RAD_TO_DEG * (float)Math.Atan2((double)((2.0f * rot.X * rot.W) - (2.0f * rot.Y * rot.Z)) ,
4375 (double)(1 - (2.0f * rot.X * rot.X) - (2.0f * rot.Z * rot.Z)));
4376 float y = Utils.RAD_TO_DEG * (float)Math.Asin ((double)((2.0f * rot.X * rot.Y) + (2.0f * rot.Z * rot.W)));
4377 float z = Utils.RAD_TO_DEG * (float)Math.Atan2(((double)(2.0f * rot.Y * rot.W) - (2.0f * rot.X * rot.Z)) ,
4378 (double)(1 - (2.0f * rot.Y * rot.Y) - (2.0f * rot.Z * rot.Z)));
4379 return(new Vector3(x,y,z));
4380 }
4381
4382
3777 } 4383 }
3778} 4384}
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 9a00bea..79619ee 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -107,7 +107,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
107 sceneObject.AddPart(part); 107 sceneObject.AddPart(part);
108 part.LinkNum = linkNum; 108 part.LinkNum = linkNum;
109 part.TrimPermissions(); 109 part.TrimPermissions();
110 part.StoreUndoState(); 110 part.StoreUndoState(UndoType.STATE_ALL);
111 reader.Close(); 111 reader.Close();
112 sr.Close(); 112 sr.Close();
113 } 113 }
@@ -232,7 +232,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
232 if (originalLinkNum != 0) 232 if (originalLinkNum != 0)
233 part.LinkNum = originalLinkNum; 233 part.LinkNum = originalLinkNum;
234 234
235 part.StoreUndoState(); 235 part.StoreUndoState(UndoType.STATE_ALL);
236 reader.Close(); 236 reader.Close();
237 sr.Close(); 237 sr.Close();
238 } 238 }
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs
index 55e407e..f71b507 100644
--- a/OpenSim/Region/Framework/Scenes/UndoState.cs
+++ b/OpenSim/Region/Framework/Scenes/UndoState.cs
@@ -27,48 +27,125 @@
27 27
28using OpenMetaverse; 28using OpenMetaverse;
29using OpenSim.Region.Framework.Interfaces; 29using OpenSim.Region.Framework.Interfaces;
30using System;
30 31
31namespace OpenSim.Region.Framework.Scenes 32namespace OpenSim.Region.Framework.Scenes
32{ 33{
34 [Flags]
35 public enum UndoType
36 {
37 STATE_PRIM_POSITION = 1,
38 STATE_PRIM_ROTATION = 2,
39 STATE_PRIM_SCALE = 4,
40 STATE_PRIM_ALL = 7,
41 STATE_GROUP_POSITION = 8,
42 STATE_GROUP_ROTATION = 16,
43 STATE_GROUP_SCALE = 32,
44 STATE_GROUP_ALL = 56,
45 STATE_ALL = 63
46 }
47
33 public class UndoState 48 public class UndoState
34 { 49 {
35 public Vector3 Position = Vector3.Zero; 50 public Vector3 Position = Vector3.Zero;
36 public Vector3 Scale = Vector3.Zero; 51 public Vector3 Scale = Vector3.Zero;
37 public Quaternion Rotation = Quaternion.Identity; 52 public Quaternion Rotation = Quaternion.Identity;
53 public Vector3 GroupPosition = Vector3.Zero;
54 public Quaternion GroupRotation = Quaternion.Identity;
55 public Vector3 GroupScale = Vector3.Zero;
56 public DateTime LastUpdated = DateTime.Now;
57 public UndoType Type;
38 58
39 public UndoState(SceneObjectPart part) 59 public UndoState(SceneObjectPart part, UndoType type)
40 { 60 {
61 Type = type;
41 if (part != null) 62 if (part != null)
42 { 63 {
43 if (part.ParentID == 0) 64 if (part.ParentID == 0)
44 { 65 {
45 Position = part.ParentGroup.AbsolutePosition; 66 GroupScale = part.ParentGroup.RootPart.Shape.Scale;
67
68 //FUBAR WARNING: Do NOT get the group's absoluteposition here
69 //or you'll experience a loop and/or a stack issue
70 GroupPosition = part.ParentGroup.RootPart.AbsolutePosition;
71 GroupRotation = part.ParentGroup.GroupRotation;
72 Position = part.ParentGroup.RootPart.AbsolutePosition;
46 Rotation = part.RotationOffset; 73 Rotation = part.RotationOffset;
47 Scale = part.Shape.Scale; 74 Scale = part.Shape.Scale;
75 LastUpdated = DateTime.Now;
48 } 76 }
49 else 77 else
50 { 78 {
79 GroupScale = part.Shape.Scale;
80
81 //FUBAR WARNING: Do NOT get the group's absoluteposition here
82 //or you'll experience a loop and/or a stack issue
83 GroupPosition = part.ParentGroup.RootPart.AbsolutePosition;
84 GroupRotation = part.ParentGroup.Rotation;
51 Position = part.OffsetPosition; 85 Position = part.OffsetPosition;
52 Rotation = part.RotationOffset; 86 Rotation = part.RotationOffset;
53 Scale = part.Shape.Scale; 87 Scale = part.Shape.Scale;
88 LastUpdated = DateTime.Now;
54 } 89 }
55 } 90 }
56 } 91 }
57 92 public void Merge(UndoState last)
93 {
94 if ((Type & UndoType.STATE_GROUP_POSITION) == 0 || ((last.Type & UndoType.STATE_GROUP_POSITION) >= (Type & UndoType.STATE_GROUP_POSITION)))
95 {
96 GroupPosition = last.GroupPosition;
97 Position = last.Position;
98 }
99 if ((Type & UndoType.STATE_GROUP_SCALE) == 0 || ((last.Type & UndoType.STATE_GROUP_SCALE) >= (Type & UndoType.STATE_GROUP_SCALE)))
100 {
101 GroupScale = last.GroupScale;
102 Scale = last.Scale;
103 }
104 if ((Type & UndoType.STATE_GROUP_ROTATION) == 0 || ((last.Type & UndoType.STATE_GROUP_ROTATION) >= (Type & UndoType.STATE_GROUP_ROTATION)))
105 {
106 GroupRotation = last.GroupRotation;
107 Rotation = last.Rotation;
108 }
109 if ((Type & UndoType.STATE_PRIM_POSITION) == 0 || ((last.Type & UndoType.STATE_PRIM_POSITION) >= (Type & UndoType.STATE_PRIM_POSITION)))
110 {
111 Position = last.Position;
112 }
113 if ((Type & UndoType.STATE_PRIM_SCALE) == 0 || ((last.Type & UndoType.STATE_PRIM_SCALE) >= (Type & UndoType.STATE_PRIM_SCALE)))
114 {
115 Scale = last.Scale;
116 }
117 if ((Type & UndoType.STATE_PRIM_ROTATION) == 0 || ((last.Type & UndoType.STATE_PRIM_ROTATION) >= (Type & UndoType.STATE_PRIM_ROTATION)))
118 {
119 Rotation = last.Rotation;
120 }
121 Type = Type | last.Type;
122 }
123 public bool Compare(UndoState undo)
124 {
125 if (undo == null || Position == null) return false;
126 if (undo.Position == Position && undo.Rotation == Rotation && undo.Scale == Scale && undo.GroupPosition == GroupPosition && undo.GroupScale == GroupScale && undo.GroupRotation == GroupRotation)
127 {
128 return true;
129 }
130 else
131 {
132 return false;
133 }
134 }
58 public bool Compare(SceneObjectPart part) 135 public bool Compare(SceneObjectPart part)
59 { 136 {
60 if (part != null) 137 if (part != null)
61 { 138 {
62 if (part.ParentID == 0) 139 if (part.ParentID == 0)
63 { 140 {
64 if (Position == part.ParentGroup.AbsolutePosition && Rotation == part.ParentGroup.Rotation) 141 if (Position == part.ParentGroup.RootPart.AbsolutePosition && Rotation == part.ParentGroup.Rotation && GroupPosition == part.ParentGroup.RootPart.AbsolutePosition && part.ParentGroup.Rotation == GroupRotation && part.Shape.Scale == GroupScale)
65 return true; 142 return true;
66 else 143 else
67 return false; 144 return false;
68 } 145 }
69 else 146 else
70 { 147 {
71 if (Position == part.OffsetPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale) 148 if (Position == part.OffsetPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale && GroupPosition == part.ParentGroup.RootPart.AbsolutePosition && part.ParentGroup.Rotation == GroupRotation && part.Shape.Scale == GroupScale)
72 return true; 149 return true;
73 else 150 else
74 return false; 151 return false;
@@ -78,62 +155,70 @@ namespace OpenSim.Region.Framework.Scenes
78 return false; 155 return false;
79 } 156 }
80 157
81 public void PlaybackState(SceneObjectPart part) 158 private void RestoreState(SceneObjectPart part)
82 { 159 {
160 bool GroupChange = false;
161 if ((Type & UndoType.STATE_GROUP_POSITION) != 0
162 || (Type & UndoType.STATE_GROUP_ROTATION) != 0
163 || (Type & UndoType.STATE_GROUP_SCALE) != 0)
164 {
165 GroupChange = true;
166 }
167
83 if (part != null) 168 if (part != null)
84 { 169 {
85 part.Undoing = true; 170 part.Undoing = true;
86 171
87 if (part.ParentID == 0) 172 if (part.ParentID == 0 && GroupChange == false)
88 { 173 {
89 if (Position != Vector3.Zero) 174 if (Position != Vector3.Zero)
90 part.ParentGroup.AbsolutePosition = Position; 175
91 part.RotationOffset = Rotation; 176 part.ParentGroup.UpdateSinglePosition(Position, part.LocalId);
177 part.ParentGroup.UpdateSingleRotation(Rotation, part.LocalId);
92 if (Scale != Vector3.Zero) 178 if (Scale != Vector3.Zero)
93 part.Resize(Scale); 179 part.Resize(Scale);
94 part.ParentGroup.ScheduleGroupForTerseUpdate(); 180 part.ParentGroup.ScheduleGroupForTerseUpdate();
95 } 181 }
96 else 182 else
97 { 183 {
98 if (Position != Vector3.Zero) 184 if (GroupChange)
99 part.OffsetPosition = Position; 185 {
100 part.UpdateRotation(Rotation); 186 part.ParentGroup.RootPart.Undoing = true;
101 if (Scale != Vector3.Zero) 187 if (GroupPosition != Vector3.Zero)
102 part.Resize(Scale); part.ScheduleTerseUpdate(); 188 {
189 //Calculate the scale...
190 Vector3 gs = part.Shape.Scale;
191 float scale = GroupScale.Z / gs.Z;
192
193 //Scale first since it can affect our position
194 part.ParentGroup.GroupResize(gs * scale, part.LocalId);
195 part.ParentGroup.AbsolutePosition = GroupPosition;
196 part.ParentGroup.UpdateGroupRotationR(GroupRotation);
197
198 }
199 part.ParentGroup.RootPart.Undoing = false;
200 }
201 else
202 {
203 if (Position != Vector3.Zero) //We can use this for all the updates since all are set
204 {
205 part.OffsetPosition = Position;
206 part.UpdateRotation(Rotation);
207 part.Resize(Scale); part.ScheduleTerseUpdate();
208 }
209 }
103 } 210 }
104 part.Undoing = false; 211 part.Undoing = false;
105 212
106 } 213 }
107 } 214 }
215 public void PlaybackState(SceneObjectPart part)
216 {
217 RestoreState(part);
218 }
108 public void PlayfwdState(SceneObjectPart part) 219 public void PlayfwdState(SceneObjectPart part)
109 { 220 {
110 if (part != null) 221 RestoreState(part);
111 {
112 part.Undoing = true;
113
114 if (part.ParentID == 0)
115 {
116 if (Position != Vector3.Zero)
117 part.ParentGroup.AbsolutePosition = Position;
118 if (Rotation != Quaternion.Identity)
119 part.UpdateRotation(Rotation);
120 if (Scale != Vector3.Zero)
121 part.Resize(Scale);
122 part.ParentGroup.ScheduleGroupForTerseUpdate();
123 }
124 else
125 {
126 if (Position != Vector3.Zero)
127 part.OffsetPosition = Position;
128 if (Rotation != Quaternion.Identity)
129 part.UpdateRotation(Rotation);
130 if (Scale != Vector3.Zero)
131 part.Resize(Scale);
132 part.ScheduleTerseUpdate();
133 }
134 part.Undoing = false;
135
136 }
137 } 222 }
138 } 223 }
139 public class LandUndoState 224 public class LandUndoState
@@ -161,3 +246,4 @@ namespace OpenSim.Region.Framework.Scenes
161 } 246 }
162 } 247 }
163} 248}
249
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 159af79..72e5ebd 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -813,6 +813,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
813 public event ObjectOwner OnObjectOwner; 813 public event ObjectOwner OnObjectOwner;
814 public event DirPlacesQuery OnDirPlacesQuery; 814 public event DirPlacesQuery OnDirPlacesQuery;
815 public event DirFindQuery OnDirFindQuery; 815 public event DirFindQuery OnDirFindQuery;
816 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
816 public event DirLandQuery OnDirLandQuery; 817 public event DirLandQuery OnDirLandQuery;
817 public event DirPopularQuery OnDirPopularQuery; 818 public event DirPopularQuery OnDirPopularQuery;
818 public event DirClassifiedQuery OnDirClassifiedQuery; 819 public event DirClassifiedQuery OnDirClassifiedQuery;
@@ -876,6 +877,10 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
876 877
877 } 878 }
878 879
880 public void ProcessPendingPackets()
881 {
882 }
883
879 public void ProcessInPacket(Packet NewPack) 884 public void ProcessInPacket(Packet NewPack)
880 { 885 {
881 886
@@ -883,6 +888,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
883 888
884 public void Close() 889 public void Close()
885 { 890 {
891 Close(true);
892 }
893
894 public void Close(bool sendStop)
895 {
886 Disconnect(); 896 Disconnect();
887 } 897 }
888 898
@@ -937,7 +947,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
937 947
938 } 948 }
939 949
940 public void SendKillObject(ulong regionHandle, uint localID) 950 public void SendKillObject(ulong regionHandle, List<uint> localID)
941 { 951 {
942 952
943 } 953 }
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
index 3a6996e..84c7f29 100644
--- a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs
@@ -259,9 +259,10 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
259 // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles. 259 // I thought that the DeleteGroup() function would handle all of this, but it doesn't. I'm not sure WHAT it handles.
260 ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup(); 260 ((SceneObjectGroup)scene.Entities[uuid]).DetachFromBackup();
261 scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor); 261 scene.PhysicsScene.RemovePrim(((SceneObjectGroup)scene.Entities[uuid]).RootPart.PhysActor);
262 scene.SendKillObject(scene.Entities[uuid].LocalId); 262 scene.SendKillObject(new List<uint>() { scene.Entities[uuid].LocalId });
263 scene.SceneGraph.DeleteSceneObject(uuid, false); 263 scene.SceneGraph.DeleteSceneObject(uuid, false);
264 ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroupFromScene(false); 264 ((SceneObjectGroup)scene.Entities[uuid]).DeleteGroupFromScene(false);
265 scene.SendKillObject(new List<uint>() { ((SceneObjectGroup)scene.Entities[uuid]).LocalId });
265 } 266 }
266 catch(Exception e) 267 catch(Exception e)
267 { 268 {
diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
index c7b1ed7..cd60f4b 100644
--- a/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
+++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/MetaEntity.cs
@@ -175,7 +175,7 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
175 //This is important because we are not IN any database. 175 //This is important because we are not IN any database.
176 //m_Entity.FakeDeleteGroup(); 176 //m_Entity.FakeDeleteGroup();
177 foreach (SceneObjectPart part in m_Entity.Parts) 177 foreach (SceneObjectPart part in m_Entity.Parts)
178 client.SendKillObject(m_Entity.RegionHandle, part.LocalId); 178 client.SendKillObject(m_Entity.RegionHandle, new List<uint>() { part.LocalId });
179 } 179 }
180 180
181 /// <summary> 181 /// <summary>
@@ -187,7 +187,7 @@ namespace OpenSim.Region.OptionalModules.ContentManagement
187 { 187 {
188 m_Entity.Scene.ForEachClient( 188 m_Entity.Scene.ForEachClient(
189 delegate(IClientAPI controller) 189 delegate(IClientAPI controller)
190 { controller.SendKillObject(m_Entity.RegionHandle, part.LocalId); } 190 { controller.SendKillObject(m_Entity.RegionHandle, new List<uint>() { part.LocalId }); }
191 ); 191 );
192 } 192 }
193 } 193 }
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
index 32659c8..11c87f8 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcRouterModule.cs
@@ -42,17 +42,22 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
42 public class XmlRpcRouter : IRegionModule, IXmlRpcRouter 42 public class XmlRpcRouter : IRegionModule, IXmlRpcRouter
43 { 43 {
44 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 45 private bool m_enabled = false;
46 public void Initialise(Scene scene, IConfigSource config) 46 public void Initialise(Scene scene, IConfigSource config)
47 { 47 {
48 IConfig startupConfig = config.Configs["Startup"]; 48 IConfig startupConfig = config.Configs["XMLRPC"];
49 if (startupConfig == null) 49 if (startupConfig == null)
50 return; 50 return;
51 51
52 if (startupConfig.GetString("XmlRpcRouterModule", 52 if (startupConfig.GetString("XmlRpcRouterModule",
53 "XmlRpcRouterModule") == "XmlRpcRouterModule") 53 "") == "XmlRpcRouterModule")
54 { 54 {
55 scene.RegisterModuleInterface<IXmlRpcRouter>(this); 55 scene.RegisterModuleInterface<IXmlRpcRouter>(this);
56 m_enabled = true;
57 }
58 else
59 {
60 m_enabled = false;
56 } 61 }
57 } 62 }
58 63
@@ -76,7 +81,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.XmlRpcRouterModule
76 81
77 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri) 82 public void RegisterNewReceiver(IScriptModule scriptEngine, UUID channel, UUID objectID, UUID itemID, string uri)
78 { 83 {
79 scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] {uri}); 84 if (m_enabled)
85 {
86 scriptEngine.PostScriptEvent(itemID, "xmlrpc_uri", new Object[] { uri });
87 }
80 } 88 }
81 89
82 public void ScriptRemoved(UUID itemID) 90 public void ScriptRemoved(UUID itemID)
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index fae12b6..3cbe391 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -156,7 +156,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
156#pragma warning disable 67 156#pragma warning disable 67
157 public event Action<IClientAPI> OnLogout; 157 public event Action<IClientAPI> OnLogout;
158 public event ObjectPermissions OnObjectPermissions; 158 public event ObjectPermissions OnObjectPermissions;
159 159 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
160 public event MoneyTransferRequest OnMoneyTransferRequest; 160 public event MoneyTransferRequest OnMoneyTransferRequest;
161 public event ParcelBuy OnParcelBuy; 161 public event ParcelBuy OnParcelBuy;
162 public event Action<IClientAPI> OnConnectionClosed; 162 public event Action<IClientAPI> OnConnectionClosed;
@@ -519,7 +519,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
519 519
520 } 520 }
521 521
522 public virtual void SendKillObject(ulong regionHandle, uint localID) 522 public virtual void SendKillObject(ulong regionHandle, List<uint> localID)
523 { 523 {
524 } 524 }
525 525
@@ -836,12 +836,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC
836 { 836 {
837 } 837 }
838 838
839 public void ProcessPendingPackets()
840 {
841 }
842
839 public void ProcessInPacket(Packet NewPack) 843 public void ProcessInPacket(Packet NewPack)
840 { 844 {
841 } 845 }
842 846
843 public void Close() 847 public void Close()
844 { 848 {
849 Close(true);
850 }
851
852 public void Close(bool sendStop)
853 {
845 } 854 }
846 855
847 public void Start() 856 public void Start()
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
index 421da36..2563361 100644
--- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -386,7 +386,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
386 m_scene.ForEachClient(delegate(IClientAPI controller) 386 m_scene.ForEachClient(delegate(IClientAPI controller)
387 { 387 {
388 controller.SendKillObject(m_scene.RegionInfo.RegionHandle, 388 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
389 selectedTree.LocalId); 389 new List<uint>() { selectedTree.LocalId });
390 }); 390 });
391 } 391 }
392 else 392 else
@@ -727,7 +727,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
727 m_scene.ForEachClient(delegate(IClientAPI controller) 727 m_scene.ForEachClient(delegate(IClientAPI controller)
728 { 728 {
729 controller.SendKillObject(m_scene.RegionInfo.RegionHandle, 729 controller.SendKillObject(m_scene.RegionInfo.RegionHandle,
730 selectedTree.LocalId); 730 new List<uint>() { selectedTree.LocalId });
731 }); 731 });
732 732
733 break; 733 break;
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs
index ac4e2b9..f13c323 100644
--- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs
+++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs
@@ -624,8 +624,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin
624 { 624 {
625 set { return; } 625 set { return; }
626 } 626 }
627 627
628
629 public override Quaternion APIDTarget 628 public override Quaternion APIDTarget
630 { 629 {
631 set { return; } 630 set { return; }
diff --git a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs
index e2a6a2e..f4245b6 100644
--- a/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs
+++ b/OpenSim/Region/Physics/BulletXPlugin/BulletXPlugin.cs
@@ -996,7 +996,7 @@ namespace OpenSim.Region.Physics.BulletXPlugin
996 { 996 {
997 997
998 } 998 }
999 999
1000 public override void VehicleFlags(int param, bool remove) 1000 public override void VehicleFlags(int param, bool remove)
1001 { 1001 {
1002 1002
diff --git a/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs
new file mode 100644
index 0000000..d65929a
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs
@@ -0,0 +1,58 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("OdePlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("OdePlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.6.5.*")]
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
new file mode 100644
index 0000000..505d455
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
@@ -0,0 +1,1437 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using Ode.NET;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using log4net;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 /// <summary>
40 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
41 /// </summary>
42
43 public enum dParam : int
44 {
45 LowStop = 0,
46 HiStop = 1,
47 Vel = 2,
48 FMax = 3,
49 FudgeFactor = 4,
50 Bounce = 5,
51 CFM = 6,
52 StopERP = 7,
53 StopCFM = 8,
54 LoStop2 = 256,
55 HiStop2 = 257,
56 Vel2 = 258,
57 FMax2 = 259,
58 StopERP2 = 7 + 256,
59 StopCFM2 = 8 + 256,
60 LoStop3 = 512,
61 HiStop3 = 513,
62 Vel3 = 514,
63 FMax3 = 515,
64 StopERP3 = 7 + 512,
65 StopCFM3 = 8 + 512
66 }
67 public class OdeCharacter : PhysicsActor
68 {
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private Vector3 _position;
72 private d.Vector3 _zeroPosition;
73 // private d.Matrix3 m_StandUpRotation;
74 private bool _zeroFlag = false;
75 private bool m_lastUpdateSent = false;
76 private Vector3 _velocity;
77 private Vector3 _target_velocity;
78 private Vector3 _acceleration;
79 private Vector3 m_rotationalVelocity;
80 private float m_mass = 80f;
81 public float m_density = 60f;
82 private bool m_pidControllerActive = true;
83 public float PID_D = 800.0f;
84 public float PID_P = 900.0f;
85 //private static float POSTURE_SERVO = 10000.0f;
86 public float CAPSULE_RADIUS = 0.37f;
87 public float CAPSULE_LENGTH = 2.140599f;
88 public float m_tensor = 3800000f;
89 public float heightFudgeFactor = 0.52f;
90 public float walkDivisor = 1.3f;
91 public float runDivisor = 0.8f;
92 private bool flying = false;
93 private bool jumping = false; // add for jumping
94 private bool m_iscolliding = false;
95 private bool m_iscollidingGround = false;
96 private bool m_wascolliding = false;
97 private bool m_wascollidingGround = false;
98 private bool m_iscollidingObj = false;
99 private bool m_alwaysRun = false;
100 private bool m_hackSentFall = false;
101 private bool m_hackSentFly = false;
102 private int m_requestedUpdateFrequency = 0;
103 private Vector3 m_taintPosition = Vector3.Zero;
104 public uint m_localID = 0;
105 public bool m_returnCollisions = false;
106 // taints and their non-tainted counterparts
107 public bool m_isPhysical = false; // the current physical status
108 public bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
109 public float MinimumGroundFlightOffset = 3f;
110
111 private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes.
112 private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f; // used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider
113
114
115 private float m_buoyancy = 0f;
116
117 // private CollisionLocker ode;
118
119 private string m_name = String.Empty;
120
121 private bool[] m_colliderarr = new bool[11];
122 private bool[] m_colliderGroundarr = new bool[11];
123
124 // Default we're a Character
125 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
126
127 // Default, Collide with Other Geometries, spaces, bodies and characters.
128 private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
129 | CollisionCategories.Space
130 | CollisionCategories.Body
131 | CollisionCategories.Character
132 | CollisionCategories.Land);
133 public IntPtr Body = IntPtr.Zero;
134 private OdeScene _parent_scene;
135 public IntPtr Shell = IntPtr.Zero;
136 public IntPtr Amotor = IntPtr.Zero;
137 public d.Mass ShellMass;
138 public bool collidelock = false;
139
140 public int m_eventsubscription = 0;
141 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
142
143 // unique UUID of this character object
144 public UUID m_uuid;
145 public bool bad = false;
146 private Object m_syncRoot = new Object();
147
148 public OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, CollisionLocker dode, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float height_fudge_factor, float walk_divisor, float rundivisor)
149 {
150 m_uuid = UUID.Random();
151
152 if (pos.IsFinite())
153 {
154 if (pos.Z > 9999999f)
155 {
156 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
157 }
158 if (pos.Z < -90000f)
159 {
160 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
161 }
162 _position = pos;
163 m_taintPosition.X = pos.X;
164 m_taintPosition.Y = pos.Y;
165 m_taintPosition.Z = pos.Z;
166 }
167 else
168 {
169 _position = new Vector3(((float)_parent_scene.WorldExtents.X * 0.5f), ((float)_parent_scene.WorldExtents.Y * 0.5f), parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
170 m_taintPosition.X = _position.X;
171 m_taintPosition.Y = _position.Y;
172 m_taintPosition.Z = _position.Z;
173 m_log.Warn("[PHYSICS]: Got NaN Position on Character Create");
174 }
175
176 _parent_scene = parent_scene;
177
178 PID_D = pid_d;
179 PID_P = pid_p;
180 CAPSULE_RADIUS = capsule_radius;
181 m_tensor = tensor;
182 m_density = density;
183 heightFudgeFactor = height_fudge_factor;
184 walkDivisor = walk_divisor;
185 runDivisor = rundivisor;
186
187 // m_StandUpRotation =
188 // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
189 // 0.5f);
190
191 for (int i = 0; i < 11; i++)
192 {
193 m_colliderarr[i] = false;
194 }
195 CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f;
196 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
197 m_tainted_CAPSULE_LENGTH = CAPSULE_LENGTH;
198
199 m_isPhysical = false; // current status: no ODE information exists
200 m_tainted_isPhysical = true; // new tainted status: need to create ODE information
201
202 _parent_scene.AddPhysicsActorTaint(this);
203
204 m_name = avName;
205 }
206
207 public override int PhysicsActorType
208 {
209 get { return (int) ActorTypes.Agent; }
210 set { return; }
211 }
212
213 /// <summary>
214 /// If this is set, the avatar will move faster
215 /// </summary>
216 public override bool SetAlwaysRun
217 {
218 get { return m_alwaysRun; }
219 set { m_alwaysRun = value; }
220 }
221
222 public override uint LocalID
223 {
224 set { m_localID = value; }
225 }
226
227 public override bool Grabbed
228 {
229 set { return; }
230 }
231
232 public override bool Selected
233 {
234// set { return; }
235 set { jumping = value; } // add for jumping flag
236 }
237
238 public override float Buoyancy
239 {
240 get { return m_buoyancy; }
241 set { m_buoyancy = value; }
242 }
243
244 public override bool FloatOnWater
245 {
246 set { return; }
247 }
248
249 public override bool IsPhysical
250 {
251 get { return false; }
252 set { return; }
253 }
254
255 public override bool ThrottleUpdates
256 {
257 get { return false; }
258 set { return; }
259 }
260
261 public override bool Flying
262 {
263 get { return flying; }
264 set { flying = value; }
265 }
266
267 /// <summary>
268 /// Returns if the avatar is colliding in general.
269 /// This includes the ground and objects and avatar.
270 /// </summary>
271 public override bool IsColliding
272 {
273//#@ get { return m_iscolliding; }
274 get { //##
275//Console.WriteLine(">>>>>>>>>>>> IC get = {0}", m_iscolliding); //##
276 return m_iscolliding; } //##
277 set
278 {
279 int i;
280 int truecount = 0;
281 int falsecount = 0;
282
283 if (m_colliderarr.Length >= 10)
284 {
285 for (i = 0; i < 10; i++)
286 {
287 m_colliderarr[i] = m_colliderarr[i + 1];
288 }
289 }
290 m_colliderarr[10] = value;
291
292 for (i = 0; i < 11; i++)
293 {
294 if (m_colliderarr[i])
295 {
296 truecount++;
297 }
298 else
299 {
300 falsecount++;
301 }
302 }
303
304 // Equal truecounts and false counts means we're colliding with something.
305
306 if (falsecount > 1.2*truecount)
307 {
308 m_iscolliding = false;
309 }
310 else
311 {
312 m_iscolliding = true;
313 }
314// ## Console.WriteLine("IC SET = {0} t{1} f{2} i {3}", value, truecount, falsecount, m_iscolliding);
315 if (m_wascolliding != m_iscolliding)
316 {
317 //base.SendCollisionUpdate(new CollisionEventUpdate());
318 }
319 m_wascolliding = m_iscolliding;
320 }
321 }
322
323 /// <summary>
324 /// Returns if an avatar is colliding with the ground
325 /// </summary>
326 public override bool CollidingGround
327 {
328 get { return m_iscollidingGround; }
329 set
330 {
331 // Collisions against the ground are not really reliable
332 // So, to get a consistant value we have to average the current result over time
333 // Currently we use 1 second = 10 calls to this.
334 int i;
335 int truecount = 0;
336 int falsecount = 0;
337
338 if (m_colliderGroundarr.Length >= 10)
339 {
340 for (i = 0; i < 10; i++)
341 {
342 m_colliderGroundarr[i] = m_colliderGroundarr[i + 1];
343 }
344 }
345 m_colliderGroundarr[10] = value;
346
347 for (i = 0; i < 11; i++)
348 {
349 if (m_colliderGroundarr[i])
350 {
351 truecount++;
352 }
353 else
354 {
355 falsecount++;
356 }
357 }
358
359 // Equal truecounts and false counts means we're colliding with something.
360
361 if (falsecount > 1.2*truecount)
362 {
363 m_iscollidingGround = false;
364 }
365 else
366 {
367 m_iscollidingGround = true;
368 }
369 if (m_wascollidingGround != m_iscollidingGround)
370 {
371 //base.SendCollisionUpdate(new CollisionEventUpdate());
372 }
373 m_wascollidingGround = m_iscollidingGround;
374 }
375 }
376
377 /// <summary>
378 /// Returns if the avatar is colliding with an object
379 /// </summary>
380 public override bool CollidingObj
381 {
382 get { return m_iscollidingObj; }
383 set
384 {
385 m_iscollidingObj = value;
386 if (value)
387 m_pidControllerActive = false;
388 else
389 m_pidControllerActive = true;
390 }
391 }
392
393 /// <summary>
394 /// turn the PID controller on or off.
395 /// The PID Controller will turn on all by itself in many situations
396 /// </summary>
397 /// <param name="status"></param>
398 public void SetPidStatus(bool status)
399 {
400 m_pidControllerActive = status;
401 }
402
403 public override bool Stopped
404 {
405 get { return _zeroFlag; }
406 }
407
408 /// <summary>
409 /// This 'puts' an avatar somewhere in the physics space.
410 /// Not really a good choice unless you 'know' it's a good
411 /// spot otherwise you're likely to orbit the avatar.
412 /// </summary>
413 public override Vector3 Position
414 {
415 get { return _position; }
416 set
417 {
418 if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
419 {
420 if (value.IsFinite())
421 {
422 if (value.Z > 9999999f)
423 {
424 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
425 }
426 if (value.Z < -90000f)
427 {
428 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
429 }
430
431 _position.X = value.X;
432 _position.Y = value.Y;
433 _position.Z = value.Z;
434
435 m_taintPosition.X = value.X;
436 m_taintPosition.Y = value.Y;
437 m_taintPosition.Z = value.Z;
438 _parent_scene.AddPhysicsActorTaint(this);
439 }
440 else
441 {
442 m_log.Warn("[PHYSICS]: Got a NaN Position from Scene on a Character");
443 }
444 }
445 }
446 }
447
448 public override Vector3 RotationalVelocity
449 {
450 get { return m_rotationalVelocity; }
451 set { m_rotationalVelocity = value; }
452 }
453
454 /// <summary>
455 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
456 /// and use it to offset landings properly
457 /// </summary>
458 public override Vector3 Size
459 {
460 get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); }
461 set
462 {
463 if (value.IsFinite())
464 {
465 m_pidControllerActive = true;
466
467 Vector3 SetSize = value;
468 m_tainted_CAPSULE_LENGTH = (SetSize.Z*1.15f) - CAPSULE_RADIUS*2.0f;
469 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
470
471 Velocity = Vector3.Zero;
472
473 _parent_scene.AddPhysicsActorTaint(this);
474 }
475 else
476 {
477 m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character");
478 }
479 }
480 }
481
482 private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector)
483 {
484 movementVector.Z = 0f;
485 float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y));
486 if (magnitude < 0.1f) return;
487
488 // normalize the velocity vector
489 float invMagnitude = 1.0f / magnitude;
490 movementVector.X *= invMagnitude;
491 movementVector.Y *= invMagnitude;
492
493 // if we change the capsule heading too often, the capsule can fall down
494 // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
495 // meaning only 4 possible capsule tilt orientations
496 if (movementVector.X > 0)
497 {
498 // east
499 if (movementVector.Y > 0)
500 {
501 // northeast
502 movementVector.X = (float)Math.Sqrt(2.0);
503 movementVector.Y = (float)Math.Sqrt(2.0);
504 }
505 else
506 {
507 // southeast
508 movementVector.X = (float)Math.Sqrt(2.0);
509 movementVector.Y = -(float)Math.Sqrt(2.0);
510 }
511 }
512 else
513 {
514 // west
515 if (movementVector.Y > 0)
516 {
517 // northwest
518 movementVector.X = -(float)Math.Sqrt(2.0);
519 movementVector.Y = (float)Math.Sqrt(2.0);
520 }
521 else
522 {
523 // southwest
524 movementVector.X = -(float)Math.Sqrt(2.0);
525 movementVector.Y = -(float)Math.Sqrt(2.0);
526 }
527 }
528
529
530 // movementVector.Z is zero
531
532 // calculate tilt components based on desired amount of tilt and current (snapped) heading.
533 // the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
534 float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane;
535 float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane;
536
537 //m_log.Debug("[PHYSICS] changing avatar tilt");
538 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent);
539 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced
540 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent);
541 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop
542 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
543 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
544 }
545
546 /// <summary>
547 /// This creates the Avatar's physical Surrogate at the position supplied
548 /// </summary>
549 /// <param name="npositionX"></param>
550 /// <param name="npositionY"></param>
551 /// <param name="npositionZ"></param>
552
553 // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
554 // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
555 // place that is safe to call this routine AvatarGeomAndBodyCreation.
556 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ, float tensor)
557 {
558 //CAPSULE_LENGTH = -5;
559 //CAPSULE_RADIUS = -5;
560 int dAMotorEuler = 1;
561 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
562 if (CAPSULE_LENGTH <= 0)
563 {
564 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
565 CAPSULE_LENGTH = 0.01f;
566
567 }
568
569 if (CAPSULE_RADIUS <= 0)
570 {
571 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
572 CAPSULE_RADIUS = 0.01f;
573
574 }
575
576 if(Shell != IntPtr.Zero)
577 {
578 try
579 {
580 d.GeomDestroy(Shell);
581 }
582 catch (System.AccessViolationException)
583 {
584 m_log.Error("[PHYSICS]: PrimGeom dead");
585 }
586 // Remove any old entries
587//string tShell;
588//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
589//Console.WriteLine("**** Remove {0}", tShell);
590 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
591 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
592 }
593
594 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
595 _parent_scene.geom_name_map[Shell] = m_name;
596 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this;
597Console.WriteLine("**** Create {2} Dicts: actor={0} name={1} height={3} rad={4}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, m_name, CAPSULE_LENGTH, CAPSULE_RADIUS);
598
599 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
600 d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
601
602 d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
603 Body = d.BodyCreate(_parent_scene.world);
604 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
605
606 _position.X = npositionX;
607 _position.Y = npositionY;
608 _position.Z = npositionZ;
609
610
611 m_taintPosition.X = npositionX;
612 m_taintPosition.Y = npositionY;
613 m_taintPosition.Z = npositionZ;
614
615 d.BodySetMass(Body, ref ShellMass);
616 d.Matrix3 m_caprot;
617 // 90 Stand up on the cap of the capped cyllinder
618 if (_parent_scene.IsAvCapsuleTilted)
619 {
620 d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2));
621 }
622 else
623 {
624 d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2));
625 }
626
627
628 d.GeomSetRotation(Shell, ref m_caprot);
629 d.BodySetRotation(Body, ref m_caprot);
630
631 d.GeomSetBody(Shell, Body);
632
633
634 // The purpose of the AMotor here is to keep the avatar's physical
635 // surrogate from rotating while moving
636 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
637 d.JointAttach(Amotor, Body, IntPtr.Zero);
638 d.JointSetAMotorMode(Amotor, dAMotorEuler);
639 d.JointSetAMotorNumAxes(Amotor, 3);
640 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
641 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
642 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
643 d.JointSetAMotorAngle(Amotor, 0, 0);
644 d.JointSetAMotorAngle(Amotor, 1, 0);
645 d.JointSetAMotorAngle(Amotor, 2, 0);
646
647 // These lowstops and high stops are effectively (no wiggle room)
648 if (_parent_scene.IsAvCapsuleTilted)
649 {
650 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
651 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
652 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
653 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
654 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
655 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
656 }
657 else
658 {
659 #region Documentation of capsule motor LowStop and HighStop parameters
660 // Intentionally introduce some tilt into the capsule by setting
661 // the motor stops to small epsilon values. This small tilt prevents
662 // the capsule from falling into the terrain; a straight-up capsule
663 // (with -0..0 motor stops) falls into the terrain for reasons yet
664 // to be comprehended in their entirety.
665 #endregion
666 AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero);
667 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f);
668 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
669 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f);
670 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced
671 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
672 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop
673 }
674
675 // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
676 // capped cyllinder will fall over
677 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
678 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor);
679
680 //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
681 //d.QfromR(
682 //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
683 //
684 //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
685 //standupStraight();
686 }
687
688 //
689 /// <summary>
690 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
691 /// This may be used in calculations in the scene/scenepresence
692 /// </summary>
693 public override float Mass
694 {
695 get
696 {
697 float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH);
698 return m_density*AVvolume;
699 }
700 }
701 public override void link(PhysicsActor obj)
702 {
703
704 }
705
706 public override void delink()
707 {
708
709 }
710
711 public override void LockAngularMotion(Vector3 axis)
712 {
713
714 }
715
716// This code is very useful. Written by DanX0r. We're just not using it right now.
717// Commented out to prevent a warning.
718//
719// private void standupStraight()
720// {
721// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
722// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
723// // change appearance and when you enter the simulator
724// // After this routine is done, the amotor stabilizes much quicker
725// d.Vector3 feet;
726// d.Vector3 head;
727// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
728// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
729// float posture = head.Z - feet.Z;
730
731// // restoring force proportional to lack of posture:
732// float servo = (2.5f - posture) * POSTURE_SERVO;
733// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
734// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
735// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
736// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
737// }
738
739 public override Vector3 Force
740 {
741 get { return _target_velocity; }
742 set { return; }
743 }
744
745 public override int VehicleType
746 {
747 get { return 0; }
748 set { return; }
749 }
750
751 public override void VehicleFloatParam(int param, float value)
752 {
753
754 }
755
756 public override void VehicleVectorParam(int param, Vector3 value)
757 {
758
759 }
760
761 public override void VehicleRotationParam(int param, Quaternion rotation)
762 {
763
764 }
765
766 public override void VehicleFlags(int flags, bool remove)
767 {
768 }
769
770 public override void SetVolumeDetect(int param)
771 {
772
773 }
774
775 public override Vector3 CenterOfMass
776 {
777 get { return Vector3.Zero; }
778 }
779
780 public override Vector3 GeometricCenter
781 {
782 get { return Vector3.Zero; }
783 }
784
785 public override PrimitiveBaseShape Shape
786 {
787 set { return; }
788 }
789
790 public override Vector3 Velocity
791 {
792 get {
793 // There's a problem with Vector3.Zero! Don't Use it Here!
794 if (_zeroFlag)
795 return Vector3.Zero;
796 m_lastUpdateSent = false;
797 return _velocity;
798 }
799 set
800 {
801 if (value.IsFinite())
802 {
803 m_pidControllerActive = true;
804 _target_velocity = value;
805 }
806 else
807 {
808 m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character");
809 }
810 }
811 }
812
813 public override Vector3 Torque
814 {
815 get { return Vector3.Zero; }
816 set { return; }
817 }
818
819 public override float CollisionScore
820 {
821 get { return 0f; }
822 set { }
823 }
824
825 public override bool Kinematic
826 {
827 get { return false; }
828 set { }
829 }
830
831 public override Quaternion Orientation
832 {
833 get { return Quaternion.Identity; }
834 set {
835 //Matrix3 or = Orientation.ToRotationMatrix();
836 //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
837 //d.BodySetRotation(Body, ref ord);
838 }
839 }
840
841 public override Vector3 Acceleration
842 {
843 get { return _acceleration; }
844 }
845
846 public void SetAcceleration(Vector3 accel)
847 {
848 m_pidControllerActive = true;
849 _acceleration = accel;
850 }
851
852 /// <summary>
853 /// Adds the force supplied to the Target Velocity
854 /// The PID controller takes this target velocity and tries to make it a reality
855 /// </summary>
856 /// <param name="force"></param>
857 public override void AddForce(Vector3 force, bool pushforce)
858 {
859 if (force.IsFinite())
860 {
861 if (pushforce)
862 {
863 m_pidControllerActive = false;
864 force *= 100f;
865//Console.WriteLine("DF 1"); // ##
866 if (!force.ApproxEquals(Vector3.Zero, 0.01f))
867 doForce(force);
868 // If uncommented, things get pushed off world
869 //
870 // m_log.Debug("Push!");
871 // _target_velocity.X += force.X;
872 // _target_velocity.Y += force.Y;
873 // _target_velocity.Z += force.Z;
874 }
875 else
876 {
877 m_pidControllerActive = true;
878 _target_velocity.X += force.X;
879 _target_velocity.Y += force.Y;
880 _target_velocity.Z += force.Z;
881 }
882 }
883 else
884 {
885 m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character");
886 }
887 //m_lastUpdateSent = false;
888 }
889
890 public override void AddAngularForce(Vector3 force, bool pushforce)
891 {
892
893 }
894
895 /// <summary>
896 /// After all of the forces add up with 'add force' we apply them with doForce
897 /// </summary>
898 /// <param name="force"></param>
899 public void doForce(Vector3 force)
900 {
901 if (!collidelock)
902 {
903 d.BodyAddForce(Body, force.X, force.Y, force.Z);
904 //d.BodySetRotation(Body, ref m_StandUpRotation);
905 //standupStraight();
906 d.Vector3 vel = d.BodyGetLinearVel(Body); //##
907//Console.WriteLine("AvVel <{0},{1},{2}>", vel.X, vel.Y, vel.Z); //##
908 }
909 }
910
911 public override void SetMomentum(Vector3 momentum)
912 {
913 }
914
915
916 /// <summary>
917 /// Called from Simulate
918 /// This is the avatar's movement control + PID Controller
919 /// </summary>
920 /// <param name="timeStep"></param>
921 public void Move(float timeStep, List<OdeCharacter> defects)
922 {
923 // no lock; for now it's only called from within Simulate()
924
925 // If the PID Controller isn't active then we set our force
926 // calculating base velocity to the current position
927
928 if (Body == IntPtr.Zero)
929 return;
930
931 if (m_pidControllerActive == false)
932 {
933 _zeroPosition = d.BodyGetPosition(Body);
934 }
935 //PidStatus = true;
936
937 d.Vector3 localpos = d.BodyGetPosition(Body);
938 Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
939
940 if (!localPos.IsFinite())
941 {
942
943 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
944 defects.Add(this);
945 // _parent_scene.RemoveCharacter(this);
946
947 // destroy avatar capsule and related ODE data
948 if (Amotor != IntPtr.Zero)
949 {
950 // Kill the Amotor
951 d.JointDestroy(Amotor);
952 Amotor = IntPtr.Zero;
953 }
954
955 //kill the Geometry
956 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
957
958 if (Body != IntPtr.Zero)
959 {
960 //kill the body
961 d.BodyDestroy(Body);
962
963 Body = IntPtr.Zero;
964 }
965
966 if(Shell != IntPtr.Zero)
967 {
968 try
969 {
970 d.GeomDestroy(Shell);
971 }
972 catch (System.AccessViolationException)
973 {
974 m_log.Error("[PHYSICS]: PrimGeom dead");
975 }
976 // Remove any old entries
977//string tShell;
978//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
979//Console.WriteLine("**** Remove {0}", tShell);
980
981 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
982 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
983 Shell = IntPtr.Zero;
984 }
985
986 return;
987 }
988
989 Vector3 vec = Vector3.Zero;
990 d.Vector3 vel = d.BodyGetLinearVel(Body);
991
992 float movementdivisor = 1f;
993
994 if (!m_alwaysRun)
995 {
996 movementdivisor = walkDivisor;
997 }
998 else
999 {
1000 movementdivisor = runDivisor;
1001 }
1002
1003 // if velocity is zero, use position control; otherwise, velocity control
1004 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
1005 {
1006 // keep track of where we stopped. No more slippin' & slidin'
1007 if (!_zeroFlag)
1008 {
1009 _zeroFlag = true;
1010 _zeroPosition = d.BodyGetPosition(Body);
1011 }
1012 if (m_pidControllerActive)
1013 {
1014 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1015 // react to the physics scene by moving it's position.
1016 // Avatar to Avatar collisions
1017 // Prim to avatar collisions
1018
1019 d.Vector3 pos = d.BodyGetPosition(Body);
1020 float errX = _zeroPosition.X - pos.X;
1021 float errY = _zeroPosition.Y - pos.Y;
1022 if( (Math.Abs(errX) > 0.1f) || (Math.Abs(errY) > 0.1f) )
1023 {
1024 vec.X = (_target_velocity.X - vel.X) * (PID_D) + (errX) * (PID_P * 2);
1025 vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (errY) * (PID_P * 2);
1026 }
1027 else
1028 { // close, jump to lateral destination
1029 d.BodySetPosition(Body, _zeroPosition.X, _zeroPosition.Y, pos.Z);
1030 }
1031// if (flying)
1032 if (flying || jumping) // add for jumping
1033 {
1034 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1035 }
1036 }
1037 //PidStatus = true;
1038 }
1039 else
1040 {
1041 m_pidControllerActive = true;
1042 _zeroFlag = false;
1043 if (m_iscolliding && !flying)
1044 {
1045 // We're standing on something
1046 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
1047 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
1048 }
1049 else if (m_iscolliding && flying)
1050 {
1051 // We're flying and colliding with something
1052 vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*(PID_D / 16);
1053 vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*(PID_D / 16);
1054 }
1055 else if (!m_iscolliding && flying)
1056 {
1057 // we're in mid air suspended
1058 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D/6);
1059 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D/6);
1060 }
1061
1062 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f)
1063 {
1064 // We're colliding with something and we're not flying but we're moving
1065 // This means we're walking or running.
1066 d.Vector3 pos = d.BodyGetPosition(Body);
1067 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P;
1068 if (_target_velocity.X > 0)
1069 {
1070 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1071 }
1072 if (_target_velocity.Y > 0)
1073 {
1074 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1075 }
1076 }
1077 else if (!m_iscolliding && !flying)
1078 {
1079 // we're not colliding and we're not flying so that means we're falling!
1080 // m_iscolliding includes collisions with the ground.
1081
1082 // d.Vector3 pos = d.BodyGetPosition(Body);
1083 if (Math.Abs(_target_velocity.X) > 0)
1084 {
1085 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1086 }
1087 if (Math.Abs(_target_velocity.Y) > 0)
1088 {
1089 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1090 }
1091 }
1092
1093 if (flying)
1094 {
1095 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
1096 }
1097 }
1098 if (flying)
1099 {
1100 vec.Z += ((-1 * _parent_scene.gravityz)*m_mass);
1101
1102 //Added for auto fly height. Kitto Flora
1103 //d.Vector3 pos = d.BodyGetPosition(Body);
1104 float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
1105
1106 if (_position.Z < target_altitude)
1107 {
1108 vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
1109 }
1110 // end add Kitto Flora
1111 }
1112 if (vec.IsFinite())
1113 {
1114 if (!vec.ApproxEquals(Vector3.Zero, 0.02f)) // 0.01 allows 0.002 !!
1115 {
1116//Console.WriteLine("DF 2"); // ##
1117
1118 doForce(vec);
1119 if (!_zeroFlag)
1120 {
1121// AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
1122 }
1123 }
1124 }
1125 else
1126 {
1127 m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()");
1128 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
1129 defects.Add(this);
1130 // _parent_scene.RemoveCharacter(this);
1131 // destroy avatar capsule and related ODE data
1132 if (Amotor != IntPtr.Zero)
1133 {
1134 // Kill the Amotor
1135 d.JointDestroy(Amotor);
1136 Amotor = IntPtr.Zero;
1137 }
1138 //kill the Geometry
1139 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1140
1141 if (Body != IntPtr.Zero)
1142 {
1143 //kill the body
1144 d.BodyDestroy(Body);
1145
1146 Body = IntPtr.Zero;
1147 }
1148
1149 if(Shell != IntPtr.Zero)
1150 {
1151 try
1152 {
1153 d.GeomDestroy(Shell);
1154 }
1155 catch (System.AccessViolationException)
1156 {
1157 m_log.Error("[PHYSICS]: PrimGeom dead");
1158 }
1159 // Remove any old entries
1160//string tShell;
1161//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1162//Console.WriteLine("**** Remove {0}", tShell);
1163
1164 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1165 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1166 Shell = IntPtr.Zero;
1167 }
1168 }
1169 }
1170
1171 /// <summary>
1172 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
1173 /// </summary>
1174 public void UpdatePositionAndVelocity()
1175 {
1176 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
1177 d.Vector3 vec;
1178 try
1179 {
1180 vec = d.BodyGetPosition(Body);
1181 }
1182 catch (NullReferenceException)
1183 {
1184 bad = true;
1185 _parent_scene.BadCharacter(this);
1186 vec = new d.Vector3(_position.X, _position.Y, _position.Z);
1187 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1188 m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid);
1189 }
1190
1191
1192 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1193 if (vec.X < 0.0f) vec.X = 0.0f;
1194 if (vec.Y < 0.0f) vec.Y = 0.0f;
1195 if (vec.X > (int)_parent_scene.WorldExtents.X - 0.05f) vec.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1196 if (vec.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) vec.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1197
1198 _position.X = vec.X;
1199 _position.Y = vec.Y;
1200 _position.Z = vec.Z;
1201
1202 // Did we move last? = zeroflag
1203 // This helps keep us from sliding all over
1204
1205 if (_zeroFlag)
1206 {
1207 _velocity.X = 0.0f;
1208 _velocity.Y = 0.0f;
1209 _velocity.Z = 0.0f;
1210
1211 // Did we send out the 'stopped' message?
1212 if (!m_lastUpdateSent)
1213 {
1214 m_lastUpdateSent = true;
1215 //base.RequestPhysicsterseUpdate();
1216
1217 }
1218 }
1219 else
1220 {
1221 m_lastUpdateSent = false;
1222 try
1223 {
1224 vec = d.BodyGetLinearVel(Body);
1225 }
1226 catch (NullReferenceException)
1227 {
1228 vec.X = _velocity.X;
1229 vec.Y = _velocity.Y;
1230 vec.Z = _velocity.Z;
1231 }
1232 _velocity.X = (vec.X);
1233 _velocity.Y = (vec.Y);
1234
1235 _velocity.Z = (vec.Z);
1236
1237 if (_velocity.Z < -6 && !m_hackSentFall)
1238 {
1239 m_hackSentFall = true;
1240 m_pidControllerActive = false;
1241 }
1242 else if (flying && !m_hackSentFly)
1243 {
1244 //m_hackSentFly = true;
1245 //base.SendCollisionUpdate(new CollisionEventUpdate());
1246 }
1247 else
1248 {
1249 m_hackSentFly = false;
1250 m_hackSentFall = false;
1251 }
1252 }
1253 }
1254
1255 /// <summary>
1256 /// Cleanup the things we use in the scene.
1257 /// </summary>
1258 public void Destroy()
1259 {
1260 m_tainted_isPhysical = false;
1261 _parent_scene.AddPhysicsActorTaint(this);
1262 }
1263
1264 public override void CrossingFailure()
1265 {
1266 }
1267
1268 public override Vector3 PIDTarget { set { return; } }
1269 public override bool PIDActive { set { return; } }
1270 public override float PIDTau { set { return; } }
1271
1272 public override float PIDHoverHeight { set { return; } }
1273 public override bool PIDHoverActive { set { return; } }
1274 public override PIDHoverType PIDHoverType { set { return; } }
1275 public override float PIDHoverTau { set { return; } }
1276
1277 public override Quaternion APIDTarget{ set { return; } }
1278
1279 public override bool APIDActive{ set { return; } }
1280
1281 public override float APIDStrength{ set { return; } }
1282
1283 public override float APIDDamping{ set { return; } }
1284
1285
1286 public override void SubscribeEvents(int ms)
1287 {
1288 m_requestedUpdateFrequency = ms;
1289 m_eventsubscription = ms;
1290 _parent_scene.addCollisionEventReporting(this);
1291 }
1292 public override void UnSubscribeEvents()
1293 {
1294 _parent_scene.remCollisionEventReporting(this);
1295 m_requestedUpdateFrequency = 0;
1296 m_eventsubscription = 0;
1297 }
1298 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1299 {
1300 if (m_eventsubscription > 0)
1301 {
1302 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
1303 }
1304 }
1305
1306 public void SendCollisions()
1307 {
1308 if (m_eventsubscription > m_requestedUpdateFrequency)
1309 {
1310 if (CollisionEventsThisFrame != null)
1311 {
1312 base.SendCollisionUpdate(CollisionEventsThisFrame);
1313 }
1314 CollisionEventsThisFrame = new CollisionEventUpdate();
1315 m_eventsubscription = 0;
1316 }
1317 }
1318 public override bool SubscribedEvents()
1319 {
1320 if (m_eventsubscription > 0)
1321 return true;
1322 return false;
1323 }
1324
1325 public void ProcessTaints(float timestep)
1326 {
1327 lock (m_syncRoot)
1328 {
1329
1330 if (m_tainted_isPhysical != m_isPhysical)
1331 {
1332 if (m_tainted_isPhysical)
1333 {
1334 // Create avatar capsule and related ODE data
1335 if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1336 {
1337 m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
1338 + (Shell!=IntPtr.Zero ? "Shell ":"")
1339 + (Body!=IntPtr.Zero ? "Body ":"")
1340 + (Amotor!=IntPtr.Zero ? "Amotor ":""));
1341 }
1342 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor);
1343 _parent_scene.AddCharacter(this);
1344 }
1345 else
1346 {
1347 _parent_scene.RemoveCharacter(this);
1348 // destroy avatar capsule and related ODE data
1349 if (Amotor != IntPtr.Zero)
1350 {
1351 // Kill the Amotor
1352 d.JointDestroy(Amotor);
1353 Amotor = IntPtr.Zero;
1354 }
1355 //kill the Geometry
1356 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1357
1358 if (Body != IntPtr.Zero)
1359 {
1360 //kill the body
1361 d.BodyDestroy(Body);
1362 Body = IntPtr.Zero;
1363 }
1364
1365 if(Shell != IntPtr.Zero)
1366 {
1367 try
1368 {
1369 d.GeomDestroy(Shell);
1370 }
1371 catch (System.AccessViolationException)
1372 {
1373 m_log.Error("[PHYSICS]: PrimGeom dead");
1374 }
1375 // Remove any old entries
1376 //string tShell;
1377 //_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1378 //Console.WriteLine("**** Remove {0}", tShell);
1379
1380 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1381 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1382 Shell = IntPtr.Zero;
1383 }
1384 }
1385
1386 m_isPhysical = m_tainted_isPhysical;
1387 }
1388
1389 if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1390 {
1391 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1392 {
1393
1394 m_pidControllerActive = true;
1395 // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1396 d.JointDestroy(Amotor);
1397 float prevCapsule = CAPSULE_LENGTH;
1398 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1399 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
1400 d.BodyDestroy(Body);
1401 AvatarGeomAndBodyCreation(_position.X, _position.Y,
1402 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1403 Velocity = Vector3.Zero;
1404 }
1405 else
1406 {
1407 m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - "
1408 + (Shell==IntPtr.Zero ? "Shell ":"")
1409 + (Body==IntPtr.Zero ? "Body ":"")
1410 + (Amotor==IntPtr.Zero ? "Amotor ":""));
1411 }
1412 }
1413
1414 if (!m_taintPosition.ApproxEquals(_position, 0.05f))
1415 {
1416 if (Body != IntPtr.Zero)
1417 {
1418 d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1419
1420 _position.X = m_taintPosition.X;
1421 _position.Y = m_taintPosition.Y;
1422 _position.Z = m_taintPosition.Z;
1423 }
1424 }
1425
1426 }
1427 }
1428
1429 internal void AddCollisionFrameTime(int p)
1430 {
1431 // protect it from overflow crashing
1432 if (m_eventsubscription + p >= int.MaxValue)
1433 m_eventsubscription = 0;
1434 m_eventsubscription += p;
1435 }
1436 }
1437}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..793774a
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -0,0 +1,3917 @@
1/* Copyright (c) Contributors, http://opensimulator.org/
2 * See CONTRIBUTORS.TXT for a full list of copyright holders.
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 * * Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * * Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
10 * * Neither the name of the OpenSimulator Project nor the
11 * names of its contributors may be used to endorse or promote products
12 * derived from this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * Revised March 5th 2010 by Kitto Flora. ODEDynamics.cs
26 * rolled into ODEPrim.cs
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using System.Runtime.InteropServices;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
36using Ode.NET;
37using OpenSim.Framework;
38using OpenSim.Region.Physics.Manager;
39
40
41namespace OpenSim.Region.Physics.OdePlugin
42{
43 /// <summary>
44 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
45 /// </summary>
46
47 public class OdePrim : PhysicsActor
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 private Vector3 _position;
52 private Vector3 _velocity;
53 private Vector3 _torque;
54 private Vector3 m_lastVelocity;
55 private Vector3 m_lastposition;
56 private Quaternion m_lastorientation = new Quaternion();
57 private Vector3 m_rotationalVelocity;
58 private Vector3 _size;
59 private Vector3 _acceleration;
60 // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f);
61 private Quaternion _orientation;
62 private Vector3 m_taintposition;
63 private Vector3 m_taintsize;
64 private Vector3 m_taintVelocity;
65 private Vector3 m_taintTorque;
66 private Quaternion m_taintrot;
67 private Vector3 m_rotateEnable = Vector3.One; // Current setting
68 private Vector3 m_rotateEnableRequest = Vector3.One; // Request from LSL
69 private bool m_rotateEnableUpdate = false;
70 private Vector3 m_lockX;
71 private Vector3 m_lockY;
72 private Vector3 m_lockZ;
73 private IntPtr Amotor = IntPtr.Zero;
74 private IntPtr AmotorX = IntPtr.Zero;
75 private IntPtr AmotorY = IntPtr.Zero;
76 private IntPtr AmotorZ = IntPtr.Zero;
77
78 private Vector3 m_PIDTarget;
79 private float m_PIDTau;
80 private float PID_D = 35f;
81 private float PID_G = 25f;
82 private bool m_usePID = false;
83
84 private Quaternion m_APIDTarget = new Quaternion();
85 private float m_APIDStrength = 0.5f;
86 private float m_APIDDamping = 0.5f;
87 private bool m_useAPID = false;
88
89 // These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
90 // do not confuse with VEHICLE HOVER
91
92 private float m_PIDHoverHeight;
93 private float m_PIDHoverTau;
94 private bool m_useHoverPID;
95 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
96 private float m_targetHoverHeight;
97 private float m_groundHeight;
98 private float m_waterHeight;
99 private float m_buoyancy; //m_buoyancy set by llSetBuoyancy()
100
101 // private float m_tensor = 5f;
102 private int body_autodisable_frames = 20;
103
104
105 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
106 | CollisionCategories.Space
107 | CollisionCategories.Body
108 | CollisionCategories.Character
109 );
110 private bool m_taintshape;
111 private bool m_taintPhysics;
112 private bool m_collidesLand = true;
113 private bool m_collidesWater;
114 public bool m_returnCollisions;
115
116 // Default we're a Geometry
117 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
118
119 // Default, Collide with Other Geometries, spaces and Bodies
120 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
121
122 public bool m_taintremove;
123 public bool m_taintdisable;
124 public bool m_disabled;
125 public bool m_taintadd;
126 public bool m_taintselected;
127 public bool m_taintCollidesWater;
128
129 public uint m_localID;
130
131 //public GCHandle gc;
132 private CollisionLocker ode;
133
134 private bool m_meshfailed = false;
135 private bool m_taintforce = false;
136 private bool m_taintaddangularforce = false;
137 private Vector3 m_force;
138 private List<Vector3> m_forcelist = new List<Vector3>();
139 private List<Vector3> m_angularforcelist = new List<Vector3>();
140
141 private IMesh _mesh;
142 private PrimitiveBaseShape _pbs;
143 private OdeScene _parent_scene;
144 public IntPtr m_targetSpace = IntPtr.Zero;
145 public IntPtr prim_geom;
146// public IntPtr prev_geom;
147 public IntPtr _triMeshData;
148
149 private IntPtr _linkJointGroup = IntPtr.Zero;
150 private PhysicsActor _parent;
151 private PhysicsActor m_taintparent;
152
153 private List<OdePrim> childrenPrim = new List<OdePrim>();
154
155 private bool iscolliding;
156 private bool m_isphysical;
157 private bool m_isSelected;
158
159 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
160
161 private bool m_throttleUpdates;
162 private int throttleCounter;
163 public int m_interpenetrationcount;
164 public float m_collisionscore;
165 public int m_roundsUnderMotionThreshold;
166 private int m_crossingfailures;
167
168 public bool outofBounds;
169 private float m_density = 10.000006836f; // Aluminum g/cm3;
170
171 public bool _zeroFlag; // if body has been stopped
172 private bool m_lastUpdateSent;
173
174 public IntPtr Body = IntPtr.Zero;
175 public String m_primName;
176 private Vector3 _target_velocity;
177 public d.Mass pMass;
178
179 public int m_eventsubscription;
180 private CollisionEventUpdate CollisionEventsThisFrame;
181
182 private IntPtr m_linkJoint = IntPtr.Zero;
183
184 public volatile bool childPrim;
185
186 internal int m_material = (int)Material.Wood;
187
188 private int frcount = 0; // Used to limit dynamics debug output to
189 private int revcount = 0; // Reverse motion while > 0
190
191 private IntPtr m_body = IntPtr.Zero;
192
193 // Vehicle properties ============================================================================================
194 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
195 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
196 private VehicleFlag m_flags = (VehicleFlag) 0; // Bit settings:
197 // HOVER_TERRAIN_ONLY
198 // HOVER_GLOBAL_HEIGHT
199 // NO_DEFLECTION_UP
200 // HOVER_WATER_ONLY
201 // HOVER_UP_ONLY
202 // LIMIT_MOTOR_UP
203 // LIMIT_ROLL_ONLY
204
205 // Linear properties
206 private Vector3 m_linearMotorDirection = Vector3.Zero; // (was m_linearMotorDirectionLASTSET) the (local) Velocity
207 //requested by LSL
208 private float m_linearMotorTimescale = 0; // Motor Attack rate set by LSL
209 private float m_linearMotorDecayTimescale = 0; // Motor Decay rate set by LSL
210 private Vector3 m_linearFrictionTimescale = Vector3.Zero; // General Friction set by LSL
211
212 private Vector3 m_lLinMotorDVel = Vector3.Zero; // decayed motor
213 private Vector3 m_lLinObjectVel = Vector3.Zero; // local frame object velocity
214 private Vector3 m_wLinObjectVel = Vector3.Zero; // world frame object velocity
215
216 //Angular properties
217 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
218
219 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
220 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
221 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
222
223 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
224// private Vector3 m_angObjectVel = Vector3.Zero; // current body angular velocity
225 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
226
227 //Deflection properties
228 // private float m_angularDeflectionEfficiency = 0;
229 // private float m_angularDeflectionTimescale = 0;
230 // private float m_linearDeflectionEfficiency = 0;
231 // private float m_linearDeflectionTimescale = 0;
232
233 //Banking properties
234 // private float m_bankingEfficiency = 0;
235 // private float m_bankingMix = 0;
236 // private float m_bankingTimescale = 0;
237
238 //Hover and Buoyancy properties
239 private float m_VhoverHeight = 0f;
240// private float m_VhoverEfficiency = 0f;
241 private float m_VhoverTimescale = 0f;
242 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
243 private float m_VehicleBuoyancy = 0f; // Set by VEHICLE_BUOYANCY, for a vehicle.
244 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
245 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
246 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
247
248 //Attractor properties
249 private float m_verticalAttractionEfficiency = 1.0f; // damped
250 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
251
252
253
254
255
256
257 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
258 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode)
259 {
260 ode = dode;
261 if (!pos.IsFinite())
262 {
263 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
264 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
265 m_log.Warn("[PHYSICS]: Got nonFinite Object create Position");
266 }
267
268 _position = pos;
269 m_taintposition = pos;
270 PID_D = parent_scene.bodyPIDD;
271 PID_G = parent_scene.bodyPIDG;
272 m_density = parent_scene.geomDefaultDensity;
273 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
274 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
275
276
277 prim_geom = IntPtr.Zero;
278// prev_geom = IntPtr.Zero;
279
280 if (!pos.IsFinite())
281 {
282 size = new Vector3(0.5f, 0.5f, 0.5f);
283 m_log.Warn("[PHYSICS]: Got nonFinite Object create Size");
284 }
285
286 if (size.X <= 0) size.X = 0.01f;
287 if (size.Y <= 0) size.Y = 0.01f;
288 if (size.Z <= 0) size.Z = 0.01f;
289
290 _size = size;
291 m_taintsize = _size;
292
293 if (!QuaternionIsFinite(rotation))
294 {
295 rotation = Quaternion.Identity;
296 m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation");
297 }
298
299 _orientation = rotation;
300 m_taintrot = _orientation;
301 _mesh = mesh;
302 _pbs = pbs;
303
304 _parent_scene = parent_scene;
305 m_targetSpace = (IntPtr)0;
306
307// if (pos.Z < 0)
308 if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y))
309 m_isphysical = false;
310 else
311 {
312 m_isphysical = pisPhysical;
313 // If we're physical, we need to be in the master space for now.
314 // linksets *should* be in a space together.. but are not currently
315 if (m_isphysical)
316 m_targetSpace = _parent_scene.space;
317 }
318 m_primName = primName;
319 m_taintadd = true;
320 _parent_scene.AddPhysicsActorTaint(this);
321 // don't do .add() here; old geoms get recycled with the same hash
322 }
323
324 public override int PhysicsActorType
325 {
326 get { return (int) ActorTypes.Prim; }
327 set { return; }
328 }
329
330 public override bool SetAlwaysRun
331 {
332 get { return false; }
333 set { return; }
334 }
335
336 public override uint LocalID
337 {
338 set {
339 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
340 m_localID = value; }
341 }
342
343 public override bool Grabbed
344 {
345 set { return; }
346 }
347
348 public override bool Selected
349 {
350 set {
351
352//Console.WriteLine("Sel {0} {1} {2}", m_primName, value, m_isphysical);
353 // This only makes the object not collidable if the object
354 // is physical or the object is modified somehow *IN THE FUTURE*
355 // without this, if an avatar selects prim, they can walk right
356 // through it while it's selected
357 m_collisionscore = 0;
358 if ((m_isphysical && !_zeroFlag) || !value)
359 {
360 m_taintselected = value;
361 _parent_scene.AddPhysicsActorTaint(this);
362 }
363 else
364 {
365 m_taintselected = value;
366 m_isSelected = value;
367 }
368 if(m_isSelected) disableBodySoft();
369 }
370 }
371
372 public override bool IsPhysical
373 {
374 get { return m_isphysical; }
375 set
376 {
377 m_isphysical = value;
378 if (!m_isphysical)
379 { // Zero the remembered last velocity
380 m_lastVelocity = Vector3.Zero;
381 if (m_type != Vehicle.TYPE_NONE) Halt();
382 }
383 }
384 }
385
386 public void setPrimForRemoval()
387 {
388 m_taintremove = true;
389 }
390
391 public override bool Flying
392 {
393 // no flying prims for you
394 get { return false; }
395 set { }
396 }
397
398 public override bool IsColliding
399 {
400 get { return iscolliding; }
401 set { iscolliding = value; }
402 }
403
404 public override bool CollidingGround
405 {
406 get { return false; }
407 set { return; }
408 }
409
410 public override bool CollidingObj
411 {
412 get { return false; }
413 set { return; }
414 }
415
416 public override bool ThrottleUpdates
417 {
418 get { return m_throttleUpdates; }
419 set { m_throttleUpdates = value; }
420 }
421
422 public override bool Stopped
423 {
424 get { return _zeroFlag; }
425 }
426
427 public override Vector3 Position
428 {
429 get { return _position; }
430
431 set { _position = value;
432 //m_log.Info("[PHYSICS]: " + _position.ToString());
433 }
434 }
435
436 public override Vector3 Size
437 {
438 get { return _size; }
439 set
440 {
441 if (value.IsFinite())
442 {
443 _size = value;
444 }
445 else
446 {
447 m_log.Warn("[PHYSICS]: Got NaN Size on object");
448 }
449 }
450 }
451
452 public override float Mass
453 {
454 get { return CalculateMass(); }
455 }
456
457 public override Vector3 Force
458 {
459 //get { return Vector3.Zero; }
460 get { return m_force; }
461 set
462 {
463 if (value.IsFinite())
464 {
465 m_force = value;
466 }
467 else
468 {
469 m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object");
470 }
471 }
472 }
473
474 public override int VehicleType
475 {
476 get { return (int)m_type; }
477 set { ProcessTypeChange((Vehicle)value); }
478 }
479
480 public override void VehicleFloatParam(int param, float value)
481 {
482 ProcessFloatVehicleParam((Vehicle) param, value);
483 }
484
485 public override void VehicleVectorParam(int param, Vector3 value)
486 {
487 ProcessVectorVehicleParam((Vehicle) param, value);
488 }
489
490 public override void VehicleRotationParam(int param, Quaternion rotation)
491 {
492 ProcessRotationVehicleParam((Vehicle) param, rotation);
493 }
494
495 public override void VehicleFlags(int param, bool remove)
496 {
497 ProcessVehicleFlags(param, remove);
498 }
499
500 public override void SetVolumeDetect(int param)
501 {
502 lock (_parent_scene.OdeLock)
503 {
504 m_isVolumeDetect = (param!=0);
505 }
506 }
507
508 public override Vector3 CenterOfMass
509 {
510 get { return Vector3.Zero; }
511 }
512
513 public override Vector3 GeometricCenter
514 {
515 get { return Vector3.Zero; }
516 }
517
518 public override PrimitiveBaseShape Shape
519 {
520 set
521 {
522 _pbs = value;
523 m_taintshape = true;
524 }
525 }
526
527 public override Vector3 Velocity
528 {
529 get
530 {
531 // Averate previous velocity with the new one so
532 // client object interpolation works a 'little' better
533 if (_zeroFlag)
534 return Vector3.Zero;
535
536 Vector3 returnVelocity = Vector3.Zero;
537 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2;
538 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2;
539 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2;
540 return returnVelocity;
541 }
542 set
543 {
544 if (value.IsFinite())
545 {
546 _velocity = value;
547
548 m_taintVelocity = value;
549 _parent_scene.AddPhysicsActorTaint(this);
550 }
551 else
552 {
553 m_log.Warn("[PHYSICS]: Got NaN Velocity in Object");
554 }
555
556 }
557 }
558
559 public override Vector3 Torque
560 {
561 get
562 {
563 if (!m_isphysical || Body == IntPtr.Zero)
564 return Vector3.Zero;
565
566 return _torque;
567 }
568
569 set
570 {
571 if (value.IsFinite())
572 {
573 m_taintTorque = value;
574 _parent_scene.AddPhysicsActorTaint(this);
575 }
576 else
577 {
578 m_log.Warn("[PHYSICS]: Got NaN Torque in Object");
579 }
580 }
581 }
582
583 public override float CollisionScore
584 {
585 get { return m_collisionscore; }
586 set { m_collisionscore = value; }
587 }
588
589 public override bool Kinematic
590 {
591 get { return false; }
592 set { }
593 }
594
595 public override Quaternion Orientation
596 {
597 get { return _orientation; }
598 set
599 {
600 if (QuaternionIsFinite(value))
601 {
602 _orientation = value;
603 }
604 else
605 m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object");
606
607 }
608 }
609
610
611 public override bool FloatOnWater
612 {
613 set {
614 m_taintCollidesWater = value;
615 _parent_scene.AddPhysicsActorTaint(this);
616 }
617 }
618
619 public override void SetMomentum(Vector3 momentum)
620 {
621 }
622
623 public override Vector3 PIDTarget
624 {
625 set
626 {
627 if (value.IsFinite())
628 {
629 m_PIDTarget = value;
630 }
631 else
632 m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object");
633 }
634 }
635 public override bool PIDActive { set { m_usePID = value; } }
636 public override float PIDTau { set { m_PIDTau = value; } }
637
638 // For RotLookAt
639 public override Quaternion APIDTarget { set { m_APIDTarget = value; } }
640 public override bool APIDActive { set { m_useAPID = value; } }
641 public override float APIDStrength { set { m_APIDStrength = value; } }
642 public override float APIDDamping { set { m_APIDDamping = value; } }
643
644 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
645 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
646 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
647 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
648
649 internal static bool QuaternionIsFinite(Quaternion q)
650 {
651 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
652 return false;
653 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
654 return false;
655 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
656 return false;
657 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
658 return false;
659 return true;
660 }
661
662 public override Vector3 Acceleration // client updates read data via here
663 {
664 get { return _acceleration; }
665 }
666
667
668 public void SetAcceleration(Vector3 accel) // No one calls this, and it would not do anything.
669 {
670 _acceleration = accel;
671 }
672
673 public override void AddForce(Vector3 force, bool pushforce)
674 {
675 if (force.IsFinite())
676 {
677 lock (m_forcelist)
678 m_forcelist.Add(force);
679
680 m_taintforce = true;
681 }
682 else
683 {
684 m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object");
685 }
686 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
687 }
688
689 public override void AddAngularForce(Vector3 force, bool pushforce)
690 {
691 if (force.IsFinite())
692 {
693 m_angularforcelist.Add(force);
694 m_taintaddangularforce = true;
695 }
696 else
697 {
698 m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object");
699 }
700 }
701
702 public override Vector3 RotationalVelocity
703 {
704 get
705 {
706 return m_rotationalVelocity;
707 }
708 set
709 {
710 if (value.IsFinite())
711 {
712 m_rotationalVelocity = value;
713 }
714 else
715 {
716 m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object");
717 }
718 }
719 }
720
721 public override void CrossingFailure()
722 {
723 m_crossingfailures++;
724 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
725 {
726 base.RaiseOutOfBounds(_position);
727 return;
728 }
729 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
730 {
731 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName);
732 }
733 }
734
735 public override float Buoyancy
736 {
737 get { return m_buoyancy; }
738// set { m_buoyancy = value; }
739 set {
740 m_buoyancy = value;
741
742 Console.WriteLine("m_buoyancy={0}", m_buoyancy);
743 }
744 }
745
746 public override void link(PhysicsActor obj)
747 {
748 m_taintparent = obj;
749 }
750
751 public override void delink()
752 {
753 m_taintparent = null;
754 }
755
756 public override void LockAngularMotion(Vector3 axis)
757 {
758 // This is actually ROTATION ENABLE, not a lock.
759 // default is <1,1,1> which is all enabled.
760 // The lock value is updated inside Move(), no point in using the taint system.
761 // OS 'm_taintAngularLock' etc change to m_rotateEnable.
762 if (axis.IsFinite())
763 {
764 axis.X = (axis.X > 0) ? 1f : 0f;
765 axis.Y = (axis.Y > 0) ? 1f : 0f;
766 axis.Z = (axis.Z > 0) ? 1f : 0f;
767 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
768 m_rotateEnableRequest = axis;
769 m_rotateEnableUpdate = true;
770 }
771 else
772 {
773 m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object");
774 }
775 }
776
777
778 public void SetGeom(IntPtr geom)
779 {
780 if(prim_geom != IntPtr.Zero)
781 {
782 // Remove any old entries
783//string tPA;
784//_parent_scene.geom_name_map.TryGetValue(prim_geom, out tPA);
785//Console.WriteLine("**** Remove {0}", tPA);
786 if(_parent_scene.geom_name_map.ContainsKey(prim_geom)) _parent_scene.geom_name_map.Remove(prim_geom);
787 if(_parent_scene.actor_name_map.ContainsKey(prim_geom)) _parent_scene.actor_name_map.Remove(prim_geom);
788 d.GeomDestroy(prim_geom);
789 }
790
791 prim_geom = geom;
792//Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName);
793 if (prim_geom != IntPtr.Zero)
794 {
795 _parent_scene.geom_name_map[prim_geom] = this.m_primName;
796 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
797 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
798 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
799//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, this.m_primName);
800 }
801
802 if (childPrim)
803 {
804 if (_parent != null && _parent is OdePrim)
805 {
806 OdePrim parent = (OdePrim)_parent;
807//Console.WriteLine("SetGeom calls ChildSetGeom");
808 parent.ChildSetGeom(this);
809 }
810 }
811 //m_log.Warn("Setting Geom to: " + prim_geom);
812 }
813
814 public void enableBodySoft()
815 {
816 if (!childPrim)
817 {
818 if (m_isphysical && Body != IntPtr.Zero)
819 {
820 d.BodyEnable(Body);
821 if (m_type != Vehicle.TYPE_NONE)
822 Enable(Body, _parent_scene);
823 }
824
825 m_disabled = false;
826 }
827 }
828
829 public void disableBodySoft()
830 {
831 m_disabled = true;
832
833 if (m_isphysical && Body != IntPtr.Zero)
834 {
835 d.BodyDisable(Body);
836 Halt();
837 }
838 }
839
840 public void enableBody()
841 {
842 // Don't enable this body if we're a child prim
843 // this should be taken care of in the parent function not here
844 if (!childPrim)
845 {
846 // Sets the geom to a body
847 Body = d.BodyCreate(_parent_scene.world);
848
849 setMass();
850 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
851 d.Quaternion myrot = new d.Quaternion();
852 myrot.X = _orientation.X;
853 myrot.Y = _orientation.Y;
854 myrot.Z = _orientation.Z;
855 myrot.W = _orientation.W;
856 d.BodySetQuaternion(Body, ref myrot);
857 d.GeomSetBody(prim_geom, Body);
858 m_collisionCategories |= CollisionCategories.Body;
859 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
860
861 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
862 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
863
864 d.BodySetAutoDisableFlag(Body, true);
865 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
866
867 // disconnect from world gravity so we can apply buoyancy
868 d.BodySetGravityMode (Body, false);
869
870 m_interpenetrationcount = 0;
871 m_collisionscore = 0;
872 m_disabled = false;
873
874 if (m_type != Vehicle.TYPE_NONE)
875 {
876 Enable(Body, _parent_scene);
877 }
878
879 _parent_scene.addActivePrim(this);
880 }
881 }
882
883 #region Mass Calculation
884
885 private float CalculateMass()
886 {
887 float volume = _size.X * _size.Y * _size.Z; // default
888 float tmp;
889
890 float returnMass = 0;
891 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
892 float hollowVolume = hollowAmount * hollowAmount;
893
894 switch (_pbs.ProfileShape)
895 {
896 case ProfileShape.Square:
897 // default box
898
899 if (_pbs.PathCurve == (byte)Extrusion.Straight)
900 {
901 if (hollowAmount > 0.0)
902 {
903 switch (_pbs.HollowShape)
904 {
905 case HollowShape.Square:
906 case HollowShape.Same:
907 break;
908
909 case HollowShape.Circle:
910
911 hollowVolume *= 0.78539816339f;
912 break;
913
914 case HollowShape.Triangle:
915
916 hollowVolume *= (0.5f * .5f);
917 break;
918
919 default:
920 hollowVolume = 0;
921 break;
922 }
923 volume *= (1.0f - hollowVolume);
924 }
925 }
926
927 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
928 {
929 //a tube
930
931 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
932 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
933 volume -= volume*tmp*tmp;
934
935 if (hollowAmount > 0.0)
936 {
937 hollowVolume *= hollowAmount;
938
939 switch (_pbs.HollowShape)
940 {
941 case HollowShape.Square:
942 case HollowShape.Same:
943 break;
944
945 case HollowShape.Circle:
946 hollowVolume *= 0.78539816339f;;
947 break;
948
949 case HollowShape.Triangle:
950 hollowVolume *= 0.5f * 0.5f;
951 break;
952 default:
953 hollowVolume = 0;
954 break;
955 }
956 volume *= (1.0f - hollowVolume);
957 }
958 }
959
960 break;
961
962 case ProfileShape.Circle:
963
964 if (_pbs.PathCurve == (byte)Extrusion.Straight)
965 {
966 volume *= 0.78539816339f; // elipse base
967
968 if (hollowAmount > 0.0)
969 {
970 switch (_pbs.HollowShape)
971 {
972 case HollowShape.Same:
973 case HollowShape.Circle:
974 break;
975
976 case HollowShape.Square:
977 hollowVolume *= 0.5f * 2.5984480504799f;
978 break;
979
980 case HollowShape.Triangle:
981 hollowVolume *= .5f * 1.27323954473516f;
982 break;
983
984 default:
985 hollowVolume = 0;
986 break;
987 }
988 volume *= (1.0f - hollowVolume);
989 }
990 }
991
992 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
993 {
994 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
995 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
996 volume *= (1.0f - tmp * tmp);
997
998 if (hollowAmount > 0.0)
999 {
1000
1001 // calculate the hollow volume by it's shape compared to the prim shape
1002 hollowVolume *= hollowAmount;
1003
1004 switch (_pbs.HollowShape)
1005 {
1006 case HollowShape.Same:
1007 case HollowShape.Circle:
1008 break;
1009
1010 case HollowShape.Square:
1011 hollowVolume *= 0.5f * 2.5984480504799f;
1012 break;
1013
1014 case HollowShape.Triangle:
1015 hollowVolume *= .5f * 1.27323954473516f;
1016 break;
1017
1018 default:
1019 hollowVolume = 0;
1020 break;
1021 }
1022 volume *= (1.0f - hollowVolume);
1023 }
1024 }
1025 break;
1026
1027 case ProfileShape.HalfCircle:
1028 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1029 {
1030 volume *= 0.52359877559829887307710723054658f;
1031 }
1032 break;
1033
1034 case ProfileShape.EquilateralTriangle:
1035
1036 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1037 {
1038 volume *= 0.32475953f;
1039
1040 if (hollowAmount > 0.0)
1041 {
1042
1043 // calculate the hollow volume by it's shape compared to the prim shape
1044 switch (_pbs.HollowShape)
1045 {
1046 case HollowShape.Same:
1047 case HollowShape.Triangle:
1048 hollowVolume *= .25f;
1049 break;
1050
1051 case HollowShape.Square:
1052 hollowVolume *= 0.499849f * 3.07920140172638f;
1053 break;
1054
1055 case HollowShape.Circle:
1056 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1057 // Cyllinder hollow volume calculation
1058
1059 hollowVolume *= 0.1963495f * 3.07920140172638f;
1060 break;
1061
1062 default:
1063 hollowVolume = 0;
1064 break;
1065 }
1066 volume *= (1.0f - hollowVolume);
1067 }
1068 }
1069 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1070 {
1071 volume *= 0.32475953f;
1072 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
1073 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1074 volume *= (1.0f - tmp * tmp);
1075
1076 if (hollowAmount > 0.0)
1077 {
1078
1079 hollowVolume *= hollowAmount;
1080
1081 switch (_pbs.HollowShape)
1082 {
1083 case HollowShape.Same:
1084 case HollowShape.Triangle:
1085 hollowVolume *= .25f;
1086 break;
1087
1088 case HollowShape.Square:
1089 hollowVolume *= 0.499849f * 3.07920140172638f;
1090 break;
1091
1092 case HollowShape.Circle:
1093
1094 hollowVolume *= 0.1963495f * 3.07920140172638f;
1095 break;
1096
1097 default:
1098 hollowVolume = 0;
1099 break;
1100 }
1101 volume *= (1.0f - hollowVolume);
1102 }
1103 }
1104 break;
1105
1106 default:
1107 break;
1108 }
1109
1110
1111
1112 float taperX1;
1113 float taperY1;
1114 float taperX;
1115 float taperY;
1116 float pathBegin;
1117 float pathEnd;
1118 float profileBegin;
1119 float profileEnd;
1120
1121 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
1122 {
1123 taperX1 = _pbs.PathScaleX * 0.01f;
1124 if (taperX1 > 1.0f)
1125 taperX1 = 2.0f - taperX1;
1126 taperX = 1.0f - taperX1;
1127
1128 taperY1 = _pbs.PathScaleY * 0.01f;
1129 if (taperY1 > 1.0f)
1130 taperY1 = 2.0f - taperY1;
1131 taperY = 1.0f - taperY1;
1132 }
1133 else
1134 {
1135 taperX = _pbs.PathTaperX * 0.01f;
1136 if (taperX < 0.0f)
1137 taperX = -taperX;
1138 taperX1 = 1.0f - taperX;
1139
1140 taperY = _pbs.PathTaperY * 0.01f;
1141 if (taperY < 0.0f)
1142 taperY = -taperY;
1143 taperY1 = 1.0f - taperY;
1144
1145 }
1146
1147
1148 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1149
1150 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
1151 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
1152 volume *= (pathEnd - pathBegin);
1153
1154// this is crude aproximation
1155 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
1156 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
1157 volume *= (profileEnd - profileBegin);
1158
1159 returnMass = m_density * volume;
1160
1161 if (returnMass <= 0)
1162 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1163// else if (returnMass > _parent_scene.maximumMassObject)
1164// returnMass = _parent_scene.maximumMassObject;
1165
1166
1167
1168
1169 // Recursively calculate mass
1170 bool HasChildPrim = false;
1171 lock (childrenPrim)
1172 {
1173 if (childrenPrim.Count > 0)
1174 {
1175 HasChildPrim = true;
1176 }
1177
1178 }
1179 if (HasChildPrim)
1180 {
1181 OdePrim[] childPrimArr = new OdePrim[0];
1182
1183 lock (childrenPrim)
1184 childPrimArr = childrenPrim.ToArray();
1185
1186 for (int i = 0; i < childPrimArr.Length; i++)
1187 {
1188 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
1189 returnMass += childPrimArr[i].CalculateMass();
1190 // failsafe, this shouldn't happen but with OpenSim, you never know :)
1191 if (i > 256)
1192 break;
1193 }
1194 }
1195 if (returnMass > _parent_scene.maximumMassObject)
1196 returnMass = _parent_scene.maximumMassObject;
1197 return returnMass;
1198 }// end CalculateMass
1199
1200 #endregion
1201
1202 public void setMass()
1203 {
1204 if (Body != (IntPtr) 0)
1205 {
1206 float newmass = CalculateMass();
1207
1208 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
1209
1210 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
1211 d.BodySetMass(Body, ref pMass);
1212 }
1213 }
1214
1215 public void disableBody()
1216 {
1217 //this kills the body so things like 'mesh' can re-create it.
1218 lock (this)
1219 {
1220 if (!childPrim)
1221 {
1222 if (Body != IntPtr.Zero)
1223 {
1224 _parent_scene.remActivePrim(this);
1225 m_collisionCategories &= ~CollisionCategories.Body;
1226 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1227
1228 if (prim_geom != IntPtr.Zero)
1229 {
1230 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1231 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1232 }
1233
1234
1235 d.BodyDestroy(Body);
1236 lock (childrenPrim)
1237 {
1238 if (childrenPrim.Count > 0)
1239 {
1240 foreach (OdePrim prm in childrenPrim)
1241 {
1242 _parent_scene.remActivePrim(prm);
1243 prm.Body = IntPtr.Zero;
1244 }
1245 }
1246 }
1247 Body = IntPtr.Zero;
1248 }
1249 }
1250 else
1251 {
1252 _parent_scene.remActivePrim(this);
1253
1254 m_collisionCategories &= ~CollisionCategories.Body;
1255 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1256
1257 if (prim_geom != IntPtr.Zero)
1258 {
1259 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1260 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1261 }
1262
1263
1264 Body = IntPtr.Zero;
1265 }
1266 }
1267 m_disabled = true;
1268 m_collisionscore = 0;
1269 }
1270
1271 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
1272
1273 public void setMesh(OdeScene parent_scene, IMesh mesh)
1274 {
1275 // This sleeper is there to moderate how long it takes between
1276 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
1277
1278 //Thread.Sleep(10);
1279
1280 //Kill Body so that mesh can re-make the geom
1281 if (IsPhysical && Body != IntPtr.Zero)
1282 {
1283 if (childPrim)
1284 {
1285 if (_parent != null)
1286 {
1287 OdePrim parent = (OdePrim)_parent;
1288 parent.ChildDelink(this);
1289 }
1290 }
1291 else
1292 {
1293 disableBody();
1294 }
1295 }
1296
1297 IntPtr vertices, indices;
1298 int vertexCount, indexCount;
1299 int vertexStride, triStride;
1300 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1301 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1302
1303 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
1304 if (m_MeshToTriMeshMap.ContainsKey(mesh))
1305 {
1306 _triMeshData = m_MeshToTriMeshMap[mesh];
1307 }
1308 else
1309 {
1310 _triMeshData = d.GeomTriMeshDataCreate();
1311
1312 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1313 d.GeomTriMeshDataPreprocess(_triMeshData);
1314 m_MeshToTriMeshMap[mesh] = _triMeshData;
1315 }
1316
1317 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1318 try
1319 {
1320 // if (prim_geom == IntPtr.Zero) // setGeom takes care of phys engine recreate and prim_geom pointer
1321 // {
1322 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
1323 // }
1324 }
1325 catch (AccessViolationException)
1326 {
1327 m_log.Error("[PHYSICS]: MESH LOCKED");
1328 return;
1329 }
1330
1331
1332 // if (IsPhysical && Body == (IntPtr) 0)
1333 // {
1334 // Recreate the body
1335 // m_interpenetrationcount = 0;
1336 // m_collisionscore = 0;
1337
1338 // enableBody();
1339 // }
1340 }
1341
1342 public void ProcessTaints(float timestep) //=============================================================================
1343 {
1344 if (m_taintadd)
1345 {
1346 changeadd(timestep);
1347 }
1348
1349 if (prim_geom != IntPtr.Zero)
1350 {
1351 if (!_position.ApproxEquals(m_taintposition, 0f))
1352 changemove(timestep);
1353
1354 if (m_taintrot != _orientation)
1355 {
1356 if(childPrim && IsPhysical) // For physical child prim...
1357 {
1358 rotate(timestep);
1359 // KF: ODE will also rotate the parent prim!
1360 // so rotate the root back to where it was
1361 OdePrim parent = (OdePrim)_parent;
1362 parent.rotate(timestep);
1363 }
1364 else
1365 {
1366 //Just rotate the prim
1367 rotate(timestep);
1368 }
1369 }
1370 //
1371
1372 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
1373 changePhysicsStatus(timestep);
1374 //
1375
1376 if (!_size.ApproxEquals(m_taintsize,0f))
1377 changesize(timestep);
1378 //
1379
1380 if (m_taintshape)
1381 changeshape(timestep);
1382 //
1383
1384 if (m_taintforce)
1385 changeAddForce(timestep);
1386
1387 if (m_taintaddangularforce)
1388 changeAddAngularForce(timestep);
1389
1390 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
1391 changeSetTorque(timestep);
1392
1393 if (m_taintdisable)
1394 changedisable(timestep);
1395
1396 if (m_taintselected != m_isSelected)
1397 changeSelectedStatus(timestep);
1398
1399 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
1400 changevelocity(timestep);
1401
1402 if (m_taintparent != _parent)
1403 changelink(timestep);
1404
1405 if (m_taintCollidesWater != m_collidesWater)
1406 changefloatonwater(timestep);
1407/* obsolete
1408 if (!m_angularLock.ApproxEquals(m_taintAngularLock,0f))
1409 changeAngularLock(timestep);
1410 */
1411 }
1412 else
1413 {
1414 m_log.Error("[PHYSICS]: The scene reused a disposed PhysActor! *waves finger*, Don't be evil. A couple of things can cause this. An improper prim breakdown(be sure to set prim_geom to zero after d.GeomDestroy! An improper buildup (creating the geom failed). Or, the Scene Reused a physics actor after disposing it.)");
1415 }
1416 }
1417
1418/* obsolete
1419 private void changeAngularLock(float timestep)
1420 {
1421 if (_parent == null)
1422 {
1423 m_angularLock = m_taintAngularLock;
1424 m_angularLockSet = true;
1425 }
1426 }
1427 */
1428 private void changelink(float timestep)
1429 {
1430 // If the newly set parent is not null
1431 // create link
1432 if (_parent == null && m_taintparent != null)
1433 {
1434 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1435 {
1436 OdePrim obj = (OdePrim)m_taintparent;
1437 //obj.disableBody();
1438 obj.ParentPrim(this);
1439
1440 /*
1441 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1442 {
1443 _linkJointGroup = d.JointGroupCreate(0);
1444 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1445 d.JointAttach(m_linkJoint, obj.Body, Body);
1446 d.JointSetFixed(m_linkJoint);
1447 }
1448 */
1449 }
1450 }
1451 // If the newly set parent is null
1452 // destroy link
1453 else if (_parent != null && m_taintparent == null)
1454 {
1455 if (_parent is OdePrim)
1456 {
1457 OdePrim obj = (OdePrim)_parent;
1458 obj.ChildDelink(this);
1459 childPrim = false;
1460 //_parent = null;
1461 }
1462
1463 /*
1464 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1465 d.JointGroupDestroy(_linkJointGroup);
1466
1467 _linkJointGroup = (IntPtr)0;
1468 m_linkJoint = (IntPtr)0;
1469 */
1470 }
1471
1472 _parent = m_taintparent;
1473 m_taintPhysics = m_isphysical;
1474 }
1475
1476 // I'm the parent
1477 // prim is the child
1478 public void ParentPrim(OdePrim prim)
1479 {
1480 if (this.m_localID != prim.m_localID)
1481 {
1482 if (Body == IntPtr.Zero)
1483 {
1484 Body = d.BodyCreate(_parent_scene.world);
1485 setMass();
1486 }
1487 if (Body != IntPtr.Zero)
1488 {
1489 lock (childrenPrim)
1490 {
1491 if (!childrenPrim.Contains(prim))
1492 {
1493 childrenPrim.Add(prim);
1494
1495 foreach (OdePrim prm in childrenPrim)
1496 {
1497 d.Mass m2;
1498 d.MassSetZero(out m2);
1499 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1500
1501
1502 d.Quaternion quat = new d.Quaternion();
1503 quat.W = prm._orientation.W;
1504 quat.X = prm._orientation.X;
1505 quat.Y = prm._orientation.Y;
1506 quat.Z = prm._orientation.Z;
1507
1508 d.Matrix3 mat = new d.Matrix3();
1509 d.RfromQ(out mat, ref quat);
1510 d.MassRotate(ref m2, ref mat);
1511 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1512 d.MassAdd(ref pMass, ref m2);
1513 }
1514 foreach (OdePrim prm in childrenPrim)
1515 {
1516
1517 prm.m_collisionCategories |= CollisionCategories.Body;
1518 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1519
1520 if (prm.prim_geom == IntPtr.Zero)
1521 {
1522 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet");
1523 continue;
1524 }
1525//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + m_primName);
1526 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1527 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1528
1529
1530 d.Quaternion quat = new d.Quaternion();
1531 quat.W = prm._orientation.W;
1532 quat.X = prm._orientation.X;
1533 quat.Y = prm._orientation.Y;
1534 quat.Z = prm._orientation.Z;
1535
1536 d.Matrix3 mat = new d.Matrix3();
1537 d.RfromQ(out mat, ref quat);
1538 if (Body != IntPtr.Zero)
1539 {
1540 d.GeomSetBody(prm.prim_geom, Body);
1541 prm.childPrim = true;
1542 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1543 //d.GeomSetOffsetPosition(prim.prim_geom,
1544 // (Position.X - prm.Position.X) - pMass.c.X,
1545 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1546 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1547 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1548 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1549 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1550 d.BodySetMass(Body, ref pMass);
1551 }
1552 else
1553 {
1554 m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body");
1555 }
1556
1557
1558 prm.m_interpenetrationcount = 0;
1559 prm.m_collisionscore = 0;
1560 prm.m_disabled = false;
1561
1562 prm.Body = Body;
1563 _parent_scene.addActivePrim(prm);
1564 }
1565 m_collisionCategories |= CollisionCategories.Body;
1566 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1567
1568//Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + m_primName);
1569 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1570//Console.WriteLine(" Post GeomSetCategoryBits 2");
1571 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1572
1573
1574 d.Quaternion quat2 = new d.Quaternion();
1575 quat2.W = _orientation.W;
1576 quat2.X = _orientation.X;
1577 quat2.Y = _orientation.Y;
1578 quat2.Z = _orientation.Z;
1579
1580 d.Matrix3 mat2 = new d.Matrix3();
1581 d.RfromQ(out mat2, ref quat2);
1582 d.GeomSetBody(prim_geom, Body);
1583 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1584 //d.GeomSetOffsetPosition(prim.prim_geom,
1585 // (Position.X - prm.Position.X) - pMass.c.X,
1586 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1587 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1588 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1589 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1590 d.BodySetMass(Body, ref pMass);
1591
1592 d.BodySetAutoDisableFlag(Body, true);
1593 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1594
1595
1596 m_interpenetrationcount = 0;
1597 m_collisionscore = 0;
1598 m_disabled = false;
1599
1600 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1601 if (m_type != Vehicle.TYPE_NONE) Enable(Body, _parent_scene);
1602 _parent_scene.addActivePrim(this);
1603 }
1604 }
1605 }
1606 }
1607
1608 }
1609
1610 private void ChildSetGeom(OdePrim odePrim)
1611 {
1612 //if (m_isphysical && Body != IntPtr.Zero)
1613 lock (childrenPrim)
1614 {
1615 foreach (OdePrim prm in childrenPrim)
1616 {
1617 //prm.childPrim = true;
1618 prm.disableBody();
1619 //prm.m_taintparent = null;
1620 //prm._parent = null;
1621 //prm.m_taintPhysics = false;
1622 //prm.m_disabled = true;
1623 //prm.childPrim = false;
1624 }
1625 }
1626 disableBody();
1627
1628
1629 if (Body != IntPtr.Zero)
1630 {
1631 _parent_scene.remActivePrim(this);
1632 }
1633
1634 lock (childrenPrim)
1635 {
1636 foreach (OdePrim prm in childrenPrim)
1637 {
1638 ParentPrim(prm);
1639 }
1640 }
1641
1642 }
1643
1644 private void ChildDelink(OdePrim odePrim)
1645 {
1646 // Okay, we have a delinked child.. need to rebuild the body.
1647 lock (childrenPrim)
1648 {
1649 foreach (OdePrim prm in childrenPrim)
1650 {
1651 prm.childPrim = true;
1652 prm.disableBody();
1653 //prm.m_taintparent = null;
1654 //prm._parent = null;
1655 //prm.m_taintPhysics = false;
1656 //prm.m_disabled = true;
1657 //prm.childPrim = false;
1658 }
1659 }
1660 disableBody();
1661
1662 lock (childrenPrim)
1663 {
1664 childrenPrim.Remove(odePrim);
1665 }
1666
1667 if (Body != IntPtr.Zero)
1668 {
1669 _parent_scene.remActivePrim(this);
1670 }
1671
1672 lock (childrenPrim)
1673 {
1674 foreach (OdePrim prm in childrenPrim)
1675 {
1676 ParentPrim(prm);
1677 }
1678 }
1679 }
1680
1681 private void changeSelectedStatus(float timestep)
1682 {
1683 if (m_taintselected)
1684 {
1685 m_collisionCategories = CollisionCategories.Selected;
1686 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1687
1688 // We do the body disable soft twice because 'in theory' a collision could have happened
1689 // in between the disabling and the collision properties setting
1690 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1691 // through the ground.
1692
1693 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1694 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1695 // so that causes the selected part to wake up and continue moving.
1696
1697 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1698 // assembly will stop simulating during the selection, because of the lack of atomicity
1699 // of select operations (their processing could be interrupted by a thread switch, causing
1700 // simulation to continue before all of the selected object notifications trickle down to
1701 // the physics engine).
1702
1703 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1704 // selected and disabled. then, due to a thread switch, the selection processing is
1705 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1706 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1707 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1708 // up, start simulating again, which in turn wakes up the last 50.
1709
1710 if (m_isphysical)
1711 {
1712 disableBodySoft();
1713 }
1714
1715 if (prim_geom != IntPtr.Zero)
1716 {
1717 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1718 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1719 }
1720
1721 if (m_isphysical)
1722 {
1723 disableBodySoft();
1724
1725 if (Body != IntPtr.Zero)
1726 {
1727 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1728 d.BodySetForce(Body, 0, 0, 0);
1729 enableBodySoft();
1730 }
1731 }
1732 }
1733 else
1734 {
1735 m_collisionCategories = CollisionCategories.Geom;
1736
1737 if (m_isphysical)
1738 m_collisionCategories |= CollisionCategories.Body;
1739
1740 m_collisionFlags = m_default_collisionFlags;
1741
1742 if (m_collidesLand)
1743 m_collisionFlags |= CollisionCategories.Land;
1744 if (m_collidesWater)
1745 m_collisionFlags |= CollisionCategories.Water;
1746
1747 if (prim_geom != IntPtr.Zero)
1748 {
1749 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1750 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1751 }
1752/* Uhhh - stop the motion if the object is _selected_!!
1753 if (m_isphysical)
1754 {
1755 if (Body != IntPtr.Zero)
1756 {
1757 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1758 d.BodySetForce(Body, 0, 0, 0);
1759 enableBodySoft();
1760 }
1761 }
1762*/
1763 }
1764
1765 resetCollisionAccounting();
1766 m_isSelected = m_taintselected;
1767 }//end changeSelectedStatus
1768
1769 public void ResetTaints()
1770 {
1771 m_taintposition = _position;
1772 m_taintrot = _orientation;
1773 m_taintPhysics = m_isphysical;
1774 m_taintselected = m_isSelected;
1775 m_taintsize = _size;
1776 m_taintshape = false;
1777 m_taintforce = false;
1778 m_taintdisable = false;
1779 m_taintVelocity = Vector3.Zero;
1780 }
1781
1782 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh)
1783 {
1784//Console.WriteLine("CreateGeom:");
1785 if (_mesh != null) // Special - make mesh
1786 {
1787 setMesh(_parent_scene, _mesh);
1788 }
1789 else // not a mesh
1790 {
1791 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) // special profile??
1792 {
1793 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // Equi-size
1794 {
1795 if (((_size.X / 2f) > 0f)) // Has size
1796 {
1797 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1798 try
1799 {
1800//Console.WriteLine(" CreateGeom 1");
1801 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1802 }
1803 catch (AccessViolationException)
1804 {
1805 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1806 ode.dunlock(_parent_scene.world);
1807 return;
1808 }
1809 }
1810 else
1811 {
1812 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1813 try
1814 {
1815//Console.WriteLine(" CreateGeom 2");
1816 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1817 }
1818 catch (AccessViolationException)
1819 {
1820 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1821 ode.dunlock(_parent_scene.world);
1822 return;
1823 }
1824 }
1825 }
1826 else // not equi-size
1827 {
1828 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1829 try
1830 {
1831//Console.WriteLine(" CreateGeom 3");
1832 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1833 }
1834 catch (AccessViolationException)
1835 {
1836 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1837 ode.dunlock(_parent_scene.world);
1838 return;
1839 }
1840 }
1841 }
1842
1843 else // not special profile
1844 {
1845 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1846 try
1847 {
1848//Console.WriteLine(" CreateGeom 4");
1849 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1850 }
1851 catch (AccessViolationException)
1852 {
1853 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1854 ode.dunlock(_parent_scene.world);
1855 return;
1856 }
1857 }
1858 }
1859 }
1860
1861 public void changeadd(float timestep)
1862 {
1863 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1864 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1865
1866 if (targetspace == IntPtr.Zero)
1867 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1868
1869 m_targetSpace = targetspace;
1870
1871 if (_mesh == null && m_meshfailed == false)
1872 {
1873 if (_parent_scene.needsMeshing(_pbs))
1874 {
1875 // Don't need to re-enable body.. it's done in SetMesh
1876 try
1877 {
1878 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1879 }
1880 catch
1881 {
1882 //Don't continuously try to mesh prims when meshing has failed
1883 m_meshfailed = true;
1884 }
1885 // createmesh returns null when it's a shape that isn't a cube.
1886 // m_log.Debug(m_localID);
1887 }
1888 }
1889
1890
1891 lock (_parent_scene.OdeLock)
1892 {
1893//Console.WriteLine("changeadd 1");
1894 CreateGeom(m_targetSpace, _mesh);
1895
1896 if (prim_geom != IntPtr.Zero)
1897 {
1898 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1899 d.Quaternion myrot = new d.Quaternion();
1900 myrot.X = _orientation.X;
1901 myrot.Y = _orientation.Y;
1902 myrot.Z = _orientation.Z;
1903 myrot.W = _orientation.W;
1904 d.GeomSetQuaternion(prim_geom, ref myrot);
1905 }
1906
1907 if (m_isphysical && Body == IntPtr.Zero)
1908 {
1909 enableBody();
1910 }
1911 }
1912
1913 changeSelectedStatus(timestep);
1914
1915 m_taintadd = false;
1916 }
1917
1918 public void changemove(float timestep)
1919 {
1920//Console.WriteLine("changemove sing/root {0} to {1}", m_primName, _position );
1921 if (m_isphysical)
1922 {
1923//Console.WriteLine("phys {0} {1} {2}", m_disabled, m_taintremove, childPrim);
1924// if (!m_disabled && !m_taintremove && !childPrim) After one edit m_disabled is sometimes set, disabling further edits!
1925 if (!m_taintremove && !childPrim)
1926 {
1927 if (Body == IntPtr.Zero)
1928 enableBody();
1929 //Prim auto disable after 20 frames,
1930 //if you move it, re-enable the prim manually.
1931 if (_parent != null)
1932 {
1933 if (m_linkJoint != IntPtr.Zero)
1934 {
1935 d.JointDestroy(m_linkJoint);
1936 m_linkJoint = IntPtr.Zero;
1937 }
1938 }
1939 if (Body != IntPtr.Zero)
1940 {
1941 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1942
1943 if (_parent != null)
1944 {
1945 OdePrim odParent = (OdePrim)_parent;
1946 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1947 {
1948// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1949Console.WriteLine(" JointCreateFixed");
1950 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1951 d.JointAttach(m_linkJoint, Body, odParent.Body);
1952 d.JointSetFixed(m_linkJoint);
1953 }
1954 }
1955 d.BodyEnable(Body);
1956 if (m_type != Vehicle.TYPE_NONE)
1957 {
1958 Enable(Body, _parent_scene);
1959 }
1960 }
1961 else
1962 {
1963 m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario.");
1964 }
1965 }
1966 //else
1967 // {
1968 //m_log.Debug("[BUG]: race!");
1969 //}
1970 }
1971 else
1972 {
1973 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1974 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1975 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1976
1977 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1978 m_targetSpace = tempspace;
1979
1980 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1981 if (prim_geom != IntPtr.Zero)
1982 {
1983 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1984
1985 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1986 d.SpaceAdd(m_targetSpace, prim_geom);
1987 }
1988 }
1989
1990 changeSelectedStatus(timestep);
1991
1992 resetCollisionAccounting();
1993 m_taintposition = _position;
1994 }
1995
1996
1997
1998 public void rotate(float timestep)
1999 {
2000 d.Quaternion myrot = new d.Quaternion();
2001 myrot.X = _orientation.X;
2002 myrot.Y = _orientation.Y;
2003 myrot.Z = _orientation.Z;
2004 myrot.W = _orientation.W;
2005 if (Body != IntPtr.Zero)
2006 {
2007 // KF: If this is a root prim do BodySet
2008 d.BodySetQuaternion(Body, ref myrot);
2009 }
2010 else
2011 {
2012 // daughter prim, do Geom set
2013 d.GeomSetQuaternion(prim_geom, ref myrot);
2014 }
2015
2016 resetCollisionAccounting();
2017 m_taintrot = _orientation;
2018 }
2019
2020 private void resetCollisionAccounting()
2021 {
2022 m_collisionscore = 0;
2023 m_interpenetrationcount = 0;
2024 m_disabled = false;
2025 }
2026
2027 public void changedisable(float timestep)
2028 {
2029 m_disabled = true;
2030 if (Body != IntPtr.Zero)
2031 {
2032 d.BodyDisable(Body);
2033 Body = IntPtr.Zero;
2034 }
2035
2036 m_taintdisable = false;
2037 }
2038
2039 public void changePhysicsStatus(float timestep)
2040 {
2041 if (m_isphysical == true)
2042 {
2043 if (Body == IntPtr.Zero)
2044 {
2045 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2046 {
2047 changeshape(2f);
2048 }
2049 else
2050 {
2051 enableBody();
2052 }
2053 }
2054 }
2055 else
2056 {
2057 if (Body != IntPtr.Zero)
2058 {
2059 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2060 {
2061 _mesh = null;
2062//Console.WriteLine("changePhysicsStatus for " + m_primName );
2063 changeadd(2f);
2064 }
2065 if (childPrim)
2066 {
2067 if (_parent != null)
2068 {
2069 OdePrim parent = (OdePrim)_parent;
2070 parent.ChildDelink(this);
2071 }
2072 }
2073 else
2074 {
2075 disableBody();
2076 }
2077 }
2078 }
2079
2080 changeSelectedStatus(timestep);
2081
2082 resetCollisionAccounting();
2083 m_taintPhysics = m_isphysical;
2084 }
2085
2086 public void changesize(float timestamp)
2087 {
2088
2089 string oldname = _parent_scene.geom_name_map[prim_geom];
2090
2091 if (_size.X <= 0) _size.X = 0.01f;
2092 if (_size.Y <= 0) _size.Y = 0.01f;
2093 if (_size.Z <= 0) _size.Z = 0.01f;
2094
2095 // Cleanup of old prim geometry
2096 if (_mesh != null)
2097 {
2098 // Cleanup meshing here
2099 }
2100 //kill body to rebuild
2101 if (IsPhysical && Body != IntPtr.Zero)
2102 {
2103 if (childPrim)
2104 {
2105 if (_parent != null)
2106 {
2107 OdePrim parent = (OdePrim)_parent;
2108 parent.ChildDelink(this);
2109 }
2110 }
2111 else
2112 {
2113 disableBody();
2114 }
2115 }
2116 if (d.SpaceQuery(m_targetSpace, prim_geom))
2117 {
2118 _parent_scene.waitForSpaceUnlock(m_targetSpace);
2119 d.SpaceRemove(m_targetSpace, prim_geom);
2120 }
2121 // we don't need to do space calculation because the client sends a position update also.
2122
2123 // Construction of new prim
2124 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2125 {
2126 float meshlod = _parent_scene.meshSculptLOD;
2127
2128 if (IsPhysical)
2129 meshlod = _parent_scene.MeshSculptphysicalLOD;
2130 // Don't need to re-enable body.. it's done in SetMesh
2131
2132 IMesh mesh = null;
2133
2134 try
2135 {
2136 if (_parent_scene.needsMeshing(_pbs))
2137 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2138 }
2139 catch
2140 {
2141 m_meshfailed = true;
2142 }
2143
2144 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2145//Console.WriteLine("changesize 1");
2146 CreateGeom(m_targetSpace, mesh);
2147
2148
2149 }
2150 else
2151 {
2152 _mesh = null;
2153//Console.WriteLine("changesize 2");
2154 CreateGeom(m_targetSpace, _mesh);
2155 }
2156
2157 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2158 d.Quaternion myrot = new d.Quaternion();
2159 myrot.X = _orientation.X;
2160 myrot.Y = _orientation.Y;
2161 myrot.Z = _orientation.Z;
2162 myrot.W = _orientation.W;
2163 d.GeomSetQuaternion(prim_geom, ref myrot);
2164
2165 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2166 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2167 {
2168 // Re creates body on size.
2169 // EnableBody also does setMass()
2170 enableBody();
2171 d.BodyEnable(Body);
2172 }
2173
2174 _parent_scene.geom_name_map[prim_geom] = oldname;
2175
2176 changeSelectedStatus(timestamp);
2177 if (childPrim)
2178 {
2179 if (_parent is OdePrim)
2180 {
2181 OdePrim parent = (OdePrim)_parent;
2182 parent.ChildSetGeom(this);
2183 }
2184 }
2185 resetCollisionAccounting();
2186 m_taintsize = _size;
2187 }
2188
2189
2190
2191 public void changefloatonwater(float timestep)
2192 {
2193 m_collidesWater = m_taintCollidesWater;
2194
2195 if (prim_geom != IntPtr.Zero)
2196 {
2197 if (m_collidesWater)
2198 {
2199 m_collisionFlags |= CollisionCategories.Water;
2200 }
2201 else
2202 {
2203 m_collisionFlags &= ~CollisionCategories.Water;
2204 }
2205 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2206 }
2207 }
2208
2209 public void changeshape(float timestamp)
2210 {
2211 string oldname = _parent_scene.geom_name_map[prim_geom];
2212
2213 // Cleanup of old prim geometry and Bodies
2214 if (IsPhysical && Body != IntPtr.Zero)
2215 {
2216 if (childPrim)
2217 {
2218 if (_parent != null)
2219 {
2220 OdePrim parent = (OdePrim)_parent;
2221 parent.ChildDelink(this);
2222 }
2223 }
2224 else
2225 {
2226 disableBody();
2227 }
2228 }
2229
2230
2231 // we don't need to do space calculation because the client sends a position update also.
2232 if (_size.X <= 0) _size.X = 0.01f;
2233 if (_size.Y <= 0) _size.Y = 0.01f;
2234 if (_size.Z <= 0) _size.Z = 0.01f;
2235 // Construction of new prim
2236
2237 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2238 {
2239 // Don't need to re-enable body.. it's done in SetMesh
2240 float meshlod = _parent_scene.meshSculptLOD;
2241
2242 if (IsPhysical)
2243 meshlod = _parent_scene.MeshSculptphysicalLOD;
2244 try
2245 {
2246 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2247 CreateGeom(m_targetSpace, mesh);
2248 }
2249 catch
2250 {
2251 m_meshfailed = true;
2252 }
2253 // createmesh returns null when it doesn't mesh.
2254 }
2255 else
2256 {
2257 _mesh = null;
2258//Console.WriteLine("changeshape");
2259 CreateGeom(m_targetSpace, null);
2260 }
2261
2262 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2263 d.Quaternion myrot = new d.Quaternion();
2264 //myrot.W = _orientation.w;
2265 myrot.W = _orientation.W;
2266 myrot.X = _orientation.X;
2267 myrot.Y = _orientation.Y;
2268 myrot.Z = _orientation.Z;
2269 d.GeomSetQuaternion(prim_geom, ref myrot);
2270
2271 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2272 if (IsPhysical && Body == IntPtr.Zero)
2273 {
2274 // Re creates body on size.
2275 // EnableBody also does setMass()
2276 enableBody();
2277 if (Body != IntPtr.Zero)
2278 {
2279 d.BodyEnable(Body);
2280 }
2281 }
2282 _parent_scene.geom_name_map[prim_geom] = oldname;
2283
2284 changeSelectedStatus(timestamp);
2285 if (childPrim)
2286 {
2287 if (_parent is OdePrim)
2288 {
2289 OdePrim parent = (OdePrim)_parent;
2290 parent.ChildSetGeom(this);
2291 }
2292 }
2293 resetCollisionAccounting();
2294 m_taintshape = false;
2295 }
2296
2297 public void changeAddForce(float timestamp)
2298 {
2299 if (!m_isSelected)
2300 {
2301 lock (m_forcelist)
2302 {
2303 //m_log.Info("[PHYSICS]: dequeing forcelist");
2304 if (IsPhysical)
2305 {
2306 Vector3 iforce = Vector3.Zero;
2307 int i = 0;
2308 try
2309 {
2310 for (i = 0; i < m_forcelist.Count; i++)
2311 {
2312
2313 iforce = iforce + (m_forcelist[i] * 100);
2314 }
2315 }
2316 catch (IndexOutOfRangeException)
2317 {
2318 m_forcelist = new List<Vector3>();
2319 m_collisionscore = 0;
2320 m_interpenetrationcount = 0;
2321 m_taintforce = false;
2322 return;
2323 }
2324 catch (ArgumentOutOfRangeException)
2325 {
2326 m_forcelist = new List<Vector3>();
2327 m_collisionscore = 0;
2328 m_interpenetrationcount = 0;
2329 m_taintforce = false;
2330 return;
2331 }
2332 d.BodyEnable(Body);
2333 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2334 }
2335 m_forcelist.Clear();
2336 }
2337
2338 m_collisionscore = 0;
2339 m_interpenetrationcount = 0;
2340 }
2341
2342 m_taintforce = false;
2343
2344 }
2345
2346
2347
2348 public void changeSetTorque(float timestamp)
2349 {
2350 if (!m_isSelected)
2351 {
2352 if (IsPhysical && Body != IntPtr.Zero)
2353 {
2354 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2355 }
2356 }
2357
2358 m_taintTorque = Vector3.Zero;
2359 }
2360
2361 public void changeAddAngularForce(float timestamp)
2362 {
2363 if (!m_isSelected)
2364 {
2365 lock (m_angularforcelist)
2366 {
2367 //m_log.Info("[PHYSICS]: dequeing forcelist");
2368 if (IsPhysical)
2369 {
2370 Vector3 iforce = Vector3.Zero;
2371 for (int i = 0; i < m_angularforcelist.Count; i++)
2372 {
2373 iforce = iforce + (m_angularforcelist[i] * 100);
2374 }
2375 d.BodyEnable(Body);
2376 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2377
2378 }
2379 m_angularforcelist.Clear();
2380 }
2381
2382 m_collisionscore = 0;
2383 m_interpenetrationcount = 0;
2384 }
2385
2386 m_taintaddangularforce = false;
2387 }
2388
2389 private void changevelocity(float timestep)
2390 {
2391 if (!m_isSelected)
2392 {
2393 Thread.Sleep(20);
2394 if (IsPhysical)
2395 {
2396 if (Body != IntPtr.Zero)
2397 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2398 }
2399
2400 //resetCollisionAccounting();
2401 }
2402 m_taintVelocity = Vector3.Zero;
2403 }
2404
2405 public void UpdatePositionAndVelocity()
2406 {
2407 return; // moved to the Move () method
2408 }
2409
2410 public d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
2411 {
2412 obj.I.M00 = pMat[0, 0];
2413 obj.I.M01 = pMat[0, 1];
2414 obj.I.M02 = pMat[0, 2];
2415 obj.I.M10 = pMat[1, 0];
2416 obj.I.M11 = pMat[1, 1];
2417 obj.I.M12 = pMat[1, 2];
2418 obj.I.M20 = pMat[2, 0];
2419 obj.I.M21 = pMat[2, 1];
2420 obj.I.M22 = pMat[2, 2];
2421 return obj;
2422 }
2423
2424 public override void SubscribeEvents(int ms)
2425 {
2426 m_eventsubscription = ms;
2427 _parent_scene.addCollisionEventReporting(this);
2428 }
2429
2430 public override void UnSubscribeEvents()
2431 {
2432 _parent_scene.remCollisionEventReporting(this);
2433 m_eventsubscription = 0;
2434 }
2435
2436 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
2437 {
2438 if (CollisionEventsThisFrame == null)
2439 CollisionEventsThisFrame = new CollisionEventUpdate();
2440 CollisionEventsThisFrame.addCollider(CollidedWith, contact);
2441 }
2442
2443 public void SendCollisions()
2444 {
2445 if (CollisionEventsThisFrame == null)
2446 return;
2447
2448 base.SendCollisionUpdate(CollisionEventsThisFrame);
2449
2450 if (CollisionEventsThisFrame.m_objCollisionList.Count == 0)
2451 CollisionEventsThisFrame = null;
2452 else
2453 CollisionEventsThisFrame = new CollisionEventUpdate();
2454 }
2455
2456 public override bool SubscribedEvents()
2457 {
2458 if (m_eventsubscription > 0)
2459 return true;
2460 return false;
2461 }
2462
2463 public static Matrix4 Inverse(Matrix4 pMat)
2464 {
2465 if (determinant3x3(pMat) == 0)
2466 {
2467 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
2468 }
2469
2470
2471
2472 return (Adjoint(pMat) / determinant3x3(pMat));
2473 }
2474
2475 public static Matrix4 Adjoint(Matrix4 pMat)
2476 {
2477 Matrix4 adjointMatrix = new Matrix4();
2478 for (int i=0; i<4; i++)
2479 {
2480 for (int j=0; j<4; j++)
2481 {
2482 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
2483 }
2484 }
2485
2486 adjointMatrix = Transpose(adjointMatrix);
2487 return adjointMatrix;
2488 }
2489
2490 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
2491 {
2492 Matrix4 minor = new Matrix4();
2493 int m = 0, n = 0;
2494 for (int i = 0; i < 4; i++)
2495 {
2496 if (i == iRow)
2497 continue;
2498 n = 0;
2499 for (int j = 0; j < 4; j++)
2500 {
2501 if (j == iCol)
2502 continue;
2503 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
2504 n++;
2505 }
2506 m++;
2507 }
2508 return minor;
2509 }
2510
2511 public static Matrix4 Transpose(Matrix4 pMat)
2512 {
2513 Matrix4 transposeMatrix = new Matrix4();
2514 for (int i = 0; i < 4; i++)
2515 for (int j = 0; j < 4; j++)
2516 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
2517 return transposeMatrix;
2518 }
2519
2520 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
2521 {
2522 switch (r)
2523 {
2524 case 0:
2525 switch (c)
2526 {
2527 case 0:
2528 pMat.M11 = val;
2529 break;
2530 case 1:
2531 pMat.M12 = val;
2532 break;
2533 case 2:
2534 pMat.M13 = val;
2535 break;
2536 case 3:
2537 pMat.M14 = val;
2538 break;
2539 }
2540
2541 break;
2542 case 1:
2543 switch (c)
2544 {
2545 case 0:
2546 pMat.M21 = val;
2547 break;
2548 case 1:
2549 pMat.M22 = val;
2550 break;
2551 case 2:
2552 pMat.M23 = val;
2553 break;
2554 case 3:
2555 pMat.M24 = val;
2556 break;
2557 }
2558
2559 break;
2560 case 2:
2561 switch (c)
2562 {
2563 case 0:
2564 pMat.M31 = val;
2565 break;
2566 case 1:
2567 pMat.M32 = val;
2568 break;
2569 case 2:
2570 pMat.M33 = val;
2571 break;
2572 case 3:
2573 pMat.M34 = val;
2574 break;
2575 }
2576
2577 break;
2578 case 3:
2579 switch (c)
2580 {
2581 case 0:
2582 pMat.M41 = val;
2583 break;
2584 case 1:
2585 pMat.M42 = val;
2586 break;
2587 case 2:
2588 pMat.M43 = val;
2589 break;
2590 case 3:
2591 pMat.M44 = val;
2592 break;
2593 }
2594
2595 break;
2596 }
2597 }
2598 private static float determinant3x3(Matrix4 pMat)
2599 {
2600 float det = 0;
2601 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
2602 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
2603 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
2604 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
2605 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
2606 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
2607
2608 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
2609 return det;
2610
2611 }
2612
2613 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
2614 {
2615 dst.c.W = src.c.W;
2616 dst.c.X = src.c.X;
2617 dst.c.Y = src.c.Y;
2618 dst.c.Z = src.c.Z;
2619 dst.mass = src.mass;
2620 dst.I.M00 = src.I.M00;
2621 dst.I.M01 = src.I.M01;
2622 dst.I.M02 = src.I.M02;
2623 dst.I.M10 = src.I.M10;
2624 dst.I.M11 = src.I.M11;
2625 dst.I.M12 = src.I.M12;
2626 dst.I.M20 = src.I.M20;
2627 dst.I.M21 = src.I.M21;
2628 dst.I.M22 = src.I.M22;
2629 }
2630
2631 public override void SetMaterial(int pMaterial)
2632 {
2633 m_material = pMaterial;
2634 }
2635
2636 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
2637 {
2638 switch (pParam)
2639 {
2640 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
2641 if (pValue < 0.01f) pValue = 0.01f;
2642 // m_angularDeflectionEfficiency = pValue;
2643 break;
2644 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
2645 if (pValue < 0.1f) pValue = 0.1f;
2646 // m_angularDeflectionTimescale = pValue;
2647 break;
2648 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
2649 if (pValue < 0.3f) pValue = 0.3f;
2650 m_angularMotorDecayTimescale = pValue;
2651 break;
2652 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
2653 if (pValue < 0.3f) pValue = 0.3f;
2654 m_angularMotorTimescale = pValue;
2655 break;
2656 case Vehicle.BANKING_EFFICIENCY:
2657 if (pValue < 0.01f) pValue = 0.01f;
2658 // m_bankingEfficiency = pValue;
2659 break;
2660 case Vehicle.BANKING_MIX:
2661 if (pValue < 0.01f) pValue = 0.01f;
2662 // m_bankingMix = pValue;
2663 break;
2664 case Vehicle.BANKING_TIMESCALE:
2665 if (pValue < 0.01f) pValue = 0.01f;
2666 // m_bankingTimescale = pValue;
2667 break;
2668 case Vehicle.BUOYANCY:
2669 if (pValue < -1f) pValue = -1f;
2670 if (pValue > 1f) pValue = 1f;
2671 m_VehicleBuoyancy = pValue;
2672 break;
2673// case Vehicle.HOVER_EFFICIENCY:
2674// if (pValue < 0f) pValue = 0f;
2675// if (pValue > 1f) pValue = 1f;
2676// m_VhoverEfficiency = pValue;
2677// break;
2678 case Vehicle.HOVER_HEIGHT:
2679 m_VhoverHeight = pValue;
2680 break;
2681 case Vehicle.HOVER_TIMESCALE:
2682 if (pValue < 0.1f) pValue = 0.1f;
2683 m_VhoverTimescale = pValue;
2684 break;
2685 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
2686 if (pValue < 0.01f) pValue = 0.01f;
2687 // m_linearDeflectionEfficiency = pValue;
2688 break;
2689 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
2690 if (pValue < 0.01f) pValue = 0.01f;
2691 // m_linearDeflectionTimescale = pValue;
2692 break;
2693 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
2694 if (pValue < 0.3f) pValue = 0.3f;
2695 m_linearMotorDecayTimescale = pValue;
2696 break;
2697 case Vehicle.LINEAR_MOTOR_TIMESCALE:
2698 if (pValue < 0.1f) pValue = 0.1f;
2699 m_linearMotorTimescale = pValue;
2700 break;
2701 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
2702 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
2703 if (pValue > 1.0f) pValue = 1.0f;
2704 m_verticalAttractionEfficiency = pValue;
2705 break;
2706 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
2707 if (pValue < 0.1f) pValue = 0.1f;
2708 m_verticalAttractionTimescale = pValue;
2709 break;
2710
2711 // These are vector properties but the engine lets you use a single float value to
2712 // set all of the components to the same value
2713 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2714 if (pValue > 30f) pValue = 30f;
2715 if (pValue < 0.1f) pValue = 0.1f;
2716 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
2717 break;
2718 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2719 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
2720 UpdateAngDecay();
2721 break;
2722 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2723 if (pValue < 0.1f) pValue = 0.1f;
2724 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
2725 break;
2726 case Vehicle.LINEAR_MOTOR_DIRECTION:
2727 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
2728 UpdateLinDecay();
2729 break;
2730 case Vehicle.LINEAR_MOTOR_OFFSET:
2731 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
2732 break;
2733
2734 }
2735
2736 }//end ProcessFloatVehicleParam
2737
2738 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
2739 {
2740 switch (pParam)
2741 {
2742 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2743 if (pValue.X > 30f) pValue.X = 30f;
2744 if (pValue.X < 0.1f) pValue.X = 0.1f;
2745 if (pValue.Y > 30f) pValue.Y = 30f;
2746 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2747 if (pValue.Z > 30f) pValue.Z = 30f;
2748 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2749 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2750 break;
2751 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2752 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
2753 // Limit requested angular speed to 2 rps= 4 pi rads/sec
2754 if(m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
2755 if(m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
2756 if(m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
2757 if(m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
2758 if(m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
2759 if(m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
2760 UpdateAngDecay();
2761 break;
2762 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2763 if (pValue.X < 0.1f) pValue.X = 0.1f;
2764 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2765 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2766 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2767 break;
2768 case Vehicle.LINEAR_MOTOR_DIRECTION:
2769 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting
2770 UpdateLinDecay();
2771 break;
2772 case Vehicle.LINEAR_MOTOR_OFFSET:
2773 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
2774 break;
2775 }
2776
2777 }//end ProcessVectorVehicleParam
2778
2779 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
2780 {
2781 switch (pParam)
2782 {
2783 case Vehicle.REFERENCE_FRAME:
2784 // m_referenceFrame = pValue;
2785 break;
2786 }
2787
2788 }//end ProcessRotationVehicleParam
2789
2790 internal void ProcessVehicleFlags(int pParam, bool remove)
2791 {
2792 if (remove)
2793 {
2794 m_flags &= ~((VehicleFlag)pParam);
2795 }
2796 else
2797 {
2798 m_flags |= (VehicleFlag)pParam;
2799 }
2800 }
2801
2802 internal void ProcessTypeChange(Vehicle pType)
2803 {
2804 // Set Defaults For Type
2805 m_type = pType;
2806 switch (pType)
2807 {
2808 case Vehicle.TYPE_SLED:
2809 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
2810 m_angularFrictionTimescale = new Vector3(30, 30, 30);
2811// m_lLinMotorVel = Vector3.Zero;
2812 m_linearMotorTimescale = 1000;
2813 m_linearMotorDecayTimescale = 120;
2814 m_angularMotorDirection = Vector3.Zero;
2815 m_angularMotorDVel = Vector3.Zero;
2816 m_angularMotorTimescale = 1000;
2817 m_angularMotorDecayTimescale = 120;
2818 m_VhoverHeight = 0;
2819// m_VhoverEfficiency = 1;
2820 m_VhoverTimescale = 10;
2821 m_VehicleBuoyancy = 0;
2822 // m_linearDeflectionEfficiency = 1;
2823 // m_linearDeflectionTimescale = 1;
2824 // m_angularDeflectionEfficiency = 1;
2825 // m_angularDeflectionTimescale = 1000;
2826 // m_bankingEfficiency = 0;
2827 // m_bankingMix = 1;
2828 // m_bankingTimescale = 10;
2829 // m_referenceFrame = Quaternion.Identity;
2830 m_flags &=
2831 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2832 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2833 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2834 break;
2835 case Vehicle.TYPE_CAR:
2836 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
2837 m_angularFrictionTimescale = new Vector3(30, 30, 30); // was 1000, but sl max frict time is 30.
2838// m_lLinMotorVel = Vector3.Zero;
2839 m_linearMotorTimescale = 1;
2840 m_linearMotorDecayTimescale = 60;
2841 m_angularMotorDirection = Vector3.Zero;
2842 m_angularMotorDVel = Vector3.Zero;
2843 m_angularMotorTimescale = 1;
2844 m_angularMotorDecayTimescale = 0.8f;
2845 m_VhoverHeight = 0;
2846// m_VhoverEfficiency = 0;
2847 m_VhoverTimescale = 1000;
2848 m_VehicleBuoyancy = 0;
2849 // // m_linearDeflectionEfficiency = 1;
2850 // // m_linearDeflectionTimescale = 2;
2851 // // m_angularDeflectionEfficiency = 0;
2852 // m_angularDeflectionTimescale = 10;
2853 m_verticalAttractionEfficiency = 1f;
2854 m_verticalAttractionTimescale = 10f;
2855 // m_bankingEfficiency = -0.2f;
2856 // m_bankingMix = 1;
2857 // m_bankingTimescale = 1;
2858 // m_referenceFrame = Quaternion.Identity;
2859 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2860 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY |
2861 VehicleFlag.LIMIT_MOTOR_UP);
2862 break;
2863 case Vehicle.TYPE_BOAT:
2864 m_linearFrictionTimescale = new Vector3(10, 3, 2);
2865 m_angularFrictionTimescale = new Vector3(10,10,10);
2866// m_lLinMotorVel = Vector3.Zero;
2867 m_linearMotorTimescale = 5;
2868 m_linearMotorDecayTimescale = 60;
2869 m_angularMotorDirection = Vector3.Zero;
2870 m_angularMotorDVel = Vector3.Zero;
2871 m_angularMotorTimescale = 4;
2872 m_angularMotorDecayTimescale = 4;
2873 m_VhoverHeight = 0;
2874// m_VhoverEfficiency = 0.5f;
2875 m_VhoverTimescale = 2;
2876 m_VehicleBuoyancy = 1;
2877 // m_linearDeflectionEfficiency = 0.5f;
2878 // m_linearDeflectionTimescale = 3;
2879 // m_angularDeflectionEfficiency = 0.5f;
2880 // m_angularDeflectionTimescale = 5;
2881 m_verticalAttractionEfficiency = 0.5f;
2882 m_verticalAttractionTimescale = 5f;
2883 // m_bankingEfficiency = -0.3f;
2884 // m_bankingMix = 0.8f;
2885 // m_bankingTimescale = 1;
2886 // m_referenceFrame = Quaternion.Identity;
2887 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY |
2888 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2889 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY |
2890 VehicleFlag.LIMIT_MOTOR_UP);
2891 break;
2892 case Vehicle.TYPE_AIRPLANE:
2893 m_linearFrictionTimescale = new Vector3(200, 10, 5);
2894 m_angularFrictionTimescale = new Vector3(20, 20, 20);
2895// m_lLinMotorVel = Vector3.Zero;
2896 m_linearMotorTimescale = 2;
2897 m_linearMotorDecayTimescale = 60;
2898 m_angularMotorDirection = Vector3.Zero;
2899 m_angularMotorDVel = Vector3.Zero;
2900 m_angularMotorTimescale = 4;
2901 m_angularMotorDecayTimescale = 4;
2902 m_VhoverHeight = 0;
2903// m_VhoverEfficiency = 0.5f;
2904 m_VhoverTimescale = 1000;
2905 m_VehicleBuoyancy = 0;
2906 // m_linearDeflectionEfficiency = 0.5f;
2907 // m_linearDeflectionTimescale = 3;
2908 // m_angularDeflectionEfficiency = 1;
2909 // m_angularDeflectionTimescale = 2;
2910 m_verticalAttractionEfficiency = 0.9f;
2911 m_verticalAttractionTimescale = 2f;
2912 // m_bankingEfficiency = 1;
2913 // m_bankingMix = 0.7f;
2914 // m_bankingTimescale = 2;
2915 // m_referenceFrame = Quaternion.Identity;
2916 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2917 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2918 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
2919 break;
2920 case Vehicle.TYPE_BALLOON:
2921 m_linearFrictionTimescale = new Vector3(5, 5, 5);
2922 m_angularFrictionTimescale = new Vector3(10, 10, 10);
2923 m_linearMotorTimescale = 5;
2924 m_linearMotorDecayTimescale = 60;
2925 m_angularMotorDirection = Vector3.Zero;
2926 m_angularMotorDVel = Vector3.Zero;
2927 m_angularMotorTimescale = 6;
2928 m_angularMotorDecayTimescale = 10;
2929 m_VhoverHeight = 5;
2930// m_VhoverEfficiency = 0.8f;
2931 m_VhoverTimescale = 10;
2932 m_VehicleBuoyancy = 1;
2933 // m_linearDeflectionEfficiency = 0;
2934 // m_linearDeflectionTimescale = 5;
2935 // m_angularDeflectionEfficiency = 0;
2936 // m_angularDeflectionTimescale = 5;
2937 m_verticalAttractionEfficiency = 1f;
2938 m_verticalAttractionTimescale = 100f;
2939 // m_bankingEfficiency = 0;
2940 // m_bankingMix = 0.7f;
2941 // m_bankingTimescale = 5;
2942 // m_referenceFrame = Quaternion.Identity;
2943 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2944 VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2945 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2946 break;
2947
2948 }
2949 }//end SetDefaultsForType
2950
2951 internal void Enable(IntPtr pBody, OdeScene pParentScene)
2952 {
2953 if (m_type == Vehicle.TYPE_NONE)
2954 return;
2955
2956 m_body = pBody;
2957 }
2958
2959
2960 internal void Halt()
2961 { // Kill all motions, when non-physical
2962 // m_linearMotorDirection = Vector3.Zero;
2963 m_lLinMotorDVel = Vector3.Zero;
2964 m_lLinObjectVel = Vector3.Zero;
2965 m_wLinObjectVel = Vector3.Zero;
2966 m_angularMotorDirection = Vector3.Zero;
2967 m_lastAngularVelocity = Vector3.Zero;
2968 m_angularMotorDVel = Vector3.Zero;
2969 _acceleration = Vector3.Zero;
2970 }
2971
2972 private void UpdateLinDecay()
2973 {
2974// if (Math.Abs(m_linearMotorDirection.X) > Math.Abs(m_lLinMotorDVel.X)) m_lLinMotorDVel.X = m_linearMotorDirection.X;
2975// if (Math.Abs(m_linearMotorDirection.Y) > Math.Abs(m_lLinMotorDVel.Y)) m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2976// if (Math.Abs(m_linearMotorDirection.Z) > Math.Abs(m_lLinMotorDVel.Z)) m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2977 m_lLinMotorDVel.X = m_linearMotorDirection.X;
2978 m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2979 m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2980 } // else let the motor decay on its own
2981
2982 private void UpdateAngDecay()
2983 {
2984// if (Math.Abs(m_angularMotorDirection.X) > Math.Abs(m_angularMotorDVel.X)) m_angularMotorDVel.X = m_angularMotorDirection.X;
2985// if (Math.Abs(m_angularMotorDirection.Y) > Math.Abs(m_angularMotorDVel.Y)) m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2986// if (Math.Abs(m_angularMotorDirection.Z) > Math.Abs(m_angularMotorDVel.Z)) m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2987 m_angularMotorDVel.X = m_angularMotorDirection.X;
2988 m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2989 m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2990 } // else let the motor decay on its own
2991
2992 public void Move(float timestep)
2993 {
2994 float fx = 0;
2995 float fy = 0;
2996 float fz = 0;
2997 Vector3 linvel; // velocity applied, including any reversal
2998 int outside = 0;
2999
3000 // If geomCrossingFailuresBeforeOutofbounds is set to 0 in OpenSim.ini then phys objects bounce off region borders.
3001 // This is a temp patch until proper region crossing is developed.
3002
3003 int failureLimit = _parent_scene.geomCrossingFailuresBeforeOutofbounds;
3004 int fence = _parent_scene.geomRegionFence;
3005
3006 float border_limit = 0.05f; // original limit
3007 if (fence == 1) border_limit = 0.5f; // bounce point
3008
3009 frcount++; // used to limit debug comment output
3010 if (frcount > 50)
3011 frcount = 0;
3012
3013 if(revcount > 0) revcount--;
3014
3015 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // Only move root prims.
3016 {
3017 // Old public void UpdatePositionAndVelocity(), more accuratley calculated here
3018 bool lastZeroFlag = _zeroFlag; // was it stopped
3019
3020 d.Vector3 vec = d.BodyGetPosition(Body);
3021 Vector3 l_position = Vector3.Zero;
3022 l_position.X = vec.X;
3023 l_position.Y = vec.Y;
3024 l_position.Z = vec.Z;
3025 m_lastposition = _position;
3026 _position = l_position;
3027
3028 d.Quaternion ori = d.BodyGetQuaternion(Body);
3029 // Quaternion l_orientation = Quaternion.Identity;
3030 _orientation.X = ori.X;
3031 _orientation.Y = ori.Y;
3032 _orientation.Z = ori.Z;
3033 _orientation.W = ori.W;
3034 m_lastorientation = _orientation;
3035
3036 d.Vector3 vel = d.BodyGetLinearVel(Body);
3037 m_lastVelocity = _velocity;
3038 _velocity.X = vel.X;
3039 _velocity.Y = vel.Y;
3040 _velocity.Z = vel.Z;
3041 _acceleration = ((_velocity - m_lastVelocity) / timestep);
3042
3043 d.Vector3 torque = d.BodyGetTorque(Body);
3044 _torque = new Vector3(torque.X, torque.Y, torque.Z);
3045
3046 base.RequestPhysicsterseUpdate();
3047
3048//Console.WriteLine("Move {0} at {1}", m_primName, l_position);
3049
3050 // Check if outside region
3051 // In Scene.cs/CrossPrimGroupIntoNewRegion the object is checked for 0.1M from border!
3052 if (l_position.X > ((float)_parent_scene.WorldExtents.X - border_limit))
3053 {
3054 l_position.X = ((float)_parent_scene.WorldExtents.X - border_limit);
3055 outside = 1;
3056 }
3057
3058 if (l_position.X < border_limit)
3059 {
3060 l_position.X = border_limit;
3061 outside = 2;
3062 }
3063 if (l_position.Y > ((float)_parent_scene.WorldExtents.Y - border_limit))
3064 {
3065 l_position.Y = ((float)_parent_scene.WorldExtents.Y - border_limit);
3066 outside = 3;
3067 }
3068
3069 if (l_position.Y < border_limit)
3070 {
3071 l_position.Y = border_limit;
3072 outside = 4;
3073 }
3074
3075 if (outside > 0)
3076 {
3077//Console.WriteLine(" fence = {0}",fence);
3078
3079//Console.WriteLine("Border {0}", l_position);
3080 if (fence == 1) // bounce object off boundary
3081 {
3082 if (revcount == 0)
3083 {
3084 if (outside < 3)
3085 {
3086 _velocity.X = -_velocity.X;
3087 }
3088 else
3089 {
3090 _velocity.Y = -_velocity.Y;
3091 }
3092 if (m_type != Vehicle.TYPE_NONE) Halt();
3093 _position = l_position;
3094 m_taintposition = _position;
3095 m_lastVelocity = _velocity;
3096 _acceleration = Vector3.Zero;
3097 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
3098 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
3099 base.RequestPhysicsterseUpdate();
3100
3101 revcount = 25; // wait for object to move away from border
3102 }
3103 } // else old crossing mode
3104 else if (m_crossingfailures < failureLimit)
3105 { // keep trying to cross?
3106 _position = l_position;
3107 //_parent_scene.remActivePrim(this);
3108 if (_parent == null) base.RequestPhysicsterseUpdate();
3109 return; // Dont process any other motion?
3110 }
3111 else
3112 { // Too many tries
3113 if (_parent == null) base.RaiseOutOfBounds(l_position);
3114//Console.WriteLine("ROOB 2");
3115
3116 return; // Dont process any other motion?
3117 } // end various methods
3118 } // end outside region horizontally
3119
3120
3121 if (l_position.Z < 0)
3122 {
3123 // This is so prim that get lost underground don't fall forever and suck up
3124 //
3125 // Sim resources and memory.
3126 // Disables the prim's movement physics....
3127 // It's a hack and will generate a console message if it fails.
3128
3129 //IsPhysical = false;
3130 if (_parent == null) base.RaiseOutOfBounds(_position);
3131//Console.WriteLine("ROOB 3");
3132
3133
3134 _acceleration.X = 0; // This stuff may stop client display but it has no
3135 _acceleration.Y = 0; // effect on the object in phys engine!
3136 _acceleration.Z = 0;
3137
3138 _velocity.X = 0;
3139 _velocity.Y = 0;
3140 _velocity.Z = 0;
3141 m_rotationalVelocity.X = 0;
3142 m_rotationalVelocity.Y = 0;
3143 m_rotationalVelocity.Z = 0;
3144
3145 if (_parent == null) base.RequestPhysicsterseUpdate();
3146
3147 m_throttleUpdates = false;
3148 throttleCounter = 0;
3149 _zeroFlag = true;
3150 //outofBounds = true;
3151 } // end neg Z check
3152
3153 // Is it moving?
3154 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
3155 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
3156 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02)
3157 && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, _orientation)) < 0.0001)) // KF 0.01 is far to large
3158 {
3159 _zeroFlag = true;
3160 m_throttleUpdates = false;
3161 }
3162 else
3163 {
3164 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3165 _zeroFlag = false;
3166 m_lastUpdateSent = false;
3167 //m_throttleUpdates = false;
3168 }
3169
3170 if (_zeroFlag)
3171 { // Its stopped
3172 _velocity.X = 0.0f;
3173 _velocity.Y = 0.0f;
3174 _velocity.Z = 0.0f;
3175
3176 _acceleration.X = 0;
3177 _acceleration.Y = 0;
3178 _acceleration.Z = 0;
3179
3180 m_rotationalVelocity.X = 0;
3181 m_rotationalVelocity.Y = 0;
3182 m_rotationalVelocity.Z = 0;
3183 if (!m_lastUpdateSent)
3184 {
3185 m_throttleUpdates = false;
3186 throttleCounter = 0;
3187 if (_parent == null)
3188 {
3189 base.RequestPhysicsterseUpdate();
3190 }
3191
3192 m_lastUpdateSent = true;
3193 }
3194 }
3195 else
3196 { // Its moving
3197 if (lastZeroFlag != _zeroFlag)
3198 {
3199 if (_parent == null)
3200 {
3201 base.RequestPhysicsterseUpdate();
3202 }
3203 }
3204 m_lastUpdateSent = false;
3205 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3206 {
3207 if (_parent == null)
3208 {
3209 base.RequestPhysicsterseUpdate();
3210 }
3211 }
3212 else
3213 {
3214 throttleCounter++;
3215 }
3216 }
3217 m_lastposition = l_position;
3218
3219 /// End UpdatePositionAndVelocity insert
3220
3221
3222 // Rotation lock =====================================
3223 if(m_rotateEnableUpdate)
3224 {
3225 // Snapshot current angles, set up Amotor(s)
3226 m_rotateEnableUpdate = false;
3227 m_rotateEnable = m_rotateEnableRequest;
3228Console.WriteLine("RotEnable {0} = {1}",m_primName, m_rotateEnable);
3229
3230 if (Amotor != IntPtr.Zero)
3231 {
3232 d.JointDestroy(Amotor);
3233 Amotor = IntPtr.Zero;
3234Console.WriteLine("Old Amotor Destroyed");
3235 }
3236
3237 if (!m_rotateEnable.ApproxEquals(Vector3.One, 0.003f))
3238 { // not all are enabled
3239 d.Quaternion r = d.BodyGetQuaternion(Body);
3240 Quaternion locrot = new Quaternion(r.X, r.Y, r.Z, r.W);
3241 // extract the axes vectors
3242 Vector3 vX = new Vector3(1f,0f,0f);
3243 Vector3 vY = new Vector3(0f,1f,0f);
3244 Vector3 vZ = new Vector3(0f,0f,1f);
3245 vX = vX * locrot;
3246 vY = vY * locrot;
3247 vZ = vZ * locrot;
3248 // snapshot the current angle vectors
3249 m_lockX = vX;
3250 m_lockY = vY;
3251 m_lockZ = vZ;
3252 // m_lockRot = locrot;
3253 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3254 d.JointAttach(Amotor, Body, IntPtr.Zero);
3255 d.JointSetAMotorMode(Amotor, 0); // User mode??
3256Console.WriteLine("New Amotor Created for {0}", m_primName);
3257
3258 float axisnum = 3; // how many to lock
3259 axisnum = (axisnum - (m_rotateEnable.X + m_rotateEnable.Y + m_rotateEnable.Z));
3260 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3261Console.WriteLine("AxisNum={0}",(int)axisnum);
3262
3263 int i = 0;
3264
3265 if (m_rotateEnable.X == 0)
3266 {
3267 d.JointSetAMotorAxis(Amotor, i, 0, m_lockX.X, m_lockX.Y, m_lockX.Z);
3268Console.WriteLine("AxisX {0} set to {1}", i, m_lockX);
3269 i++;
3270 }
3271
3272 if (m_rotateEnable.Y == 0)
3273 {
3274 d.JointSetAMotorAxis(Amotor, i, 0, m_lockY.X, m_lockY.Y, m_lockY.Z);
3275Console.WriteLine("AxisY {0} set to {1}", i, m_lockY);
3276 i++;
3277 }
3278
3279 if (m_rotateEnable.Z == 0)
3280 {
3281 d.JointSetAMotorAxis(Amotor, i, 0, m_lockZ.X, m_lockZ.Y, m_lockZ.Z);
3282Console.WriteLine("AxisZ {0} set to {1}", i, m_lockZ);
3283 i++;
3284 }
3285
3286 // These lowstops and high stops are effectively (no wiggle room)
3287 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0f);
3288 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
3289 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0f);
3290 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3291 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3292 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3293 d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 0f);
3294 d.JointSetAMotorParam(Amotor, (int) dParam.Vel3, 0f);
3295 d.JointSetAMotorParam(Amotor, (int) dParam.Vel2, 0f);
3296 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f);
3297 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
3298 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
3299 } // else none are locked
3300 } // end Rotation Update
3301
3302
3303 // VEHICLE processing ==========================================
3304 if (m_type != Vehicle.TYPE_NONE)
3305 {
3306 // get body attitude
3307 d.Quaternion rot = d.BodyGetQuaternion(Body);
3308 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
3309 Quaternion irotq = Quaternion.Inverse(rotq);
3310
3311 // VEHICLE Linear Motion
3312 d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame
3313 Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z);
3314 m_lLinObjectVel = vel_now * irotq;
3315
3316 if (m_linearMotorDecayTimescale < 300.0f) //setting of 300 or more disables decay rate
3317 {
3318 if ( Vector3.Mag(m_lLinMotorDVel) < 1.0f)
3319 {
3320 float decayfactor = m_linearMotorDecayTimescale/timestep;
3321 Vector3 decayAmount = (m_lLinMotorDVel/decayfactor);
3322 m_lLinMotorDVel -= decayAmount;
3323 }
3324 else
3325 {
3326 float decayfactor = 3.0f - (0.57f * (float)Math.Log((double)(m_linearMotorDecayTimescale)));
3327 Vector3 decel = Vector3.Normalize(m_lLinMotorDVel) * decayfactor * timestep;
3328 m_lLinMotorDVel -= decel;
3329 }
3330 if (m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3331 {
3332 m_lLinMotorDVel = Vector3.Zero;
3333 }
3334
3335 /* else
3336 {
3337 if (Math.Abs(m_lLinMotorDVel.X) < Math.Abs(m_lLinObjectVel.X)) m_lLinObjectVel.X = m_lLinMotorDVel.X;
3338 if (Math.Abs(m_lLinMotorDVel.Y) < Math.Abs(m_lLinObjectVel.Y)) m_lLinObjectVel.Y = m_lLinMotorDVel.Y;
3339 if (Math.Abs(m_lLinMotorDVel.Z) < Math.Abs(m_lLinObjectVel.Z)) m_lLinObjectVel.Z = m_lLinMotorDVel.Z;
3340 } */
3341 } // end linear motor decay
3342
3343 if ( (! m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! m_lLinObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3344 {
3345 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3346 if (m_linearMotorTimescale < 300.0f)
3347 {
3348 Vector3 attack_error = m_lLinMotorDVel - m_lLinObjectVel;
3349 float linfactor = m_linearMotorTimescale/timestep;
3350 Vector3 attackAmount = (attack_error/linfactor) * 1.3f;
3351 m_lLinObjectVel += attackAmount;
3352 }
3353 if (m_linearFrictionTimescale.X < 300.0f)
3354 {
3355 float fricfactor = m_linearFrictionTimescale.X / timestep;
3356 float fricX = m_lLinObjectVel.X / fricfactor;
3357 m_lLinObjectVel.X -= fricX;
3358 }
3359 if (m_linearFrictionTimescale.Y < 300.0f)
3360 {
3361 float fricfactor = m_linearFrictionTimescale.Y / timestep;
3362 float fricY = m_lLinObjectVel.Y / fricfactor;
3363 m_lLinObjectVel.Y -= fricY;
3364 }
3365 if (m_linearFrictionTimescale.Z < 300.0f)
3366 {
3367 float fricfactor = m_linearFrictionTimescale.Z / timestep;
3368 float fricZ = m_lLinObjectVel.Z / fricfactor;
3369 m_lLinObjectVel.Z -= fricZ;
3370 }
3371 }
3372 m_wLinObjectVel = m_lLinObjectVel * rotq;
3373
3374 // Gravity and Buoyancy
3375 Vector3 grav = Vector3.Zero;
3376 if(m_VehicleBuoyancy < 1.0f)
3377 {
3378 // There is some gravity, make a gravity force vector
3379 // that is applied after object velocity.
3380 d.Mass objMass;
3381 d.BodyGetMass(Body, out objMass);
3382 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
3383 grav.Z = _parent_scene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Applied later as a force
3384 } // else its 1.0, no gravity.
3385
3386 // Hovering
3387 if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
3388 {
3389 // We should hover, get the target height
3390 d.Vector3 pos = d.BodyGetPosition(Body);
3391 if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY)
3392 {
3393 m_VhoverTargetHeight = _parent_scene.GetWaterLevel() + m_VhoverHeight;
3394 }
3395 else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY)
3396 {
3397 m_VhoverTargetHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
3398 }
3399 else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT)
3400 {
3401 m_VhoverTargetHeight = m_VhoverHeight;
3402 }
3403
3404 if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY)
3405 {
3406 // If body is aready heigher, use its height as target height
3407 if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
3408 }
3409
3410// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
3411// m_VhoverTimescale = 0f; // time to acheive height
3412// timestep is time since last frame,in secs
3413 float herr0 = pos.Z - m_VhoverTargetHeight;
3414 // Replace Vertical speed with correction figure if significant
3415 if(Math.Abs(herr0) > 0.01f )
3416 {
3417 //? d.Mass objMass;
3418 //? d.BodyGetMass(Body, out objMass);
3419 m_wLinObjectVel.Z = - ( (herr0 * timestep * 50.0f) / m_VhoverTimescale);
3420 //KF: m_VhoverEfficiency is not yet implemented
3421 }
3422 else
3423 {
3424 m_wLinObjectVel.Z = 0f;
3425 }
3426 }
3427 else
3428 { // not hovering
3429 if (m_wLinObjectVel.Z == 0f)
3430 { // Gravity rules
3431 m_wLinObjectVel.Z = vel_now.Z;
3432 } // else the motor has it
3433 }
3434 linvel = m_wLinObjectVel;
3435
3436 // Vehicle Linear Motion done =======================================
3437 // Apply velocity
3438 d.BodySetLinearVel(Body, linvel.X, linvel.Y, linvel.Z);
3439 // apply gravity force
3440 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
3441//if(frcount == 0) Console.WriteLine("Grav {0}", grav);
3442 // end MoveLinear()
3443
3444
3445 // MoveAngular
3446 /*
3447 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
3448
3449 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
3450 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
3451 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
3452
3453 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
3454 private Vector3 m_angObjectVel = Vector3.Zero; // what was last applied to body
3455 */
3456//if(frcount == 0) Console.WriteLine("MoveAngular ");
3457
3458 d.Vector3 angularObjectVel = d.BodyGetAngularVel(Body);
3459 Vector3 angObjectVel = new Vector3(angularObjectVel.X, angularObjectVel.Y, angularObjectVel.Z);
3460 angObjectVel = angObjectVel * irotq; // ============ Converts to LOCAL rotation
3461
3462//if(frcount == 0) Console.WriteLine("V0 = {0}", angObjectVel);
3463
3464 // Decay Angular Motor 1. In SL this also depends on attack rate! decay ~= 23/Attack.
3465 float atk_decayfactor = 23.0f / (m_angularMotorTimescale * timestep);
3466 m_angularMotorDVel -= m_angularMotorDVel / atk_decayfactor;
3467 // Decay Angular Motor 2.
3468 if (m_angularMotorDecayTimescale < 300.0f)
3469 {
3470 if ( Vector3.Mag(m_angularMotorDVel) < 1.0f)
3471 {
3472 float decayfactor = (m_angularMotorDecayTimescale)/timestep;
3473 Vector3 decayAmount = (m_angularMotorDVel/decayfactor);
3474 m_angularMotorDVel -= decayAmount;
3475 }
3476 else
3477 {
3478 Vector3 decel = Vector3.Normalize(m_angularMotorDVel) * timestep / m_angularMotorDecayTimescale;
3479 m_angularMotorDVel -= decel;
3480 }
3481
3482 if (m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3483 {
3484 m_angularMotorDVel = Vector3.Zero;
3485 }
3486 else
3487 {
3488 if (Math.Abs(m_angularMotorDVel.X) < Math.Abs(angObjectVel.X)) angObjectVel.X = m_angularMotorDVel.X;
3489 if (Math.Abs(m_angularMotorDVel.Y) < Math.Abs(angObjectVel.Y)) angObjectVel.Y = m_angularMotorDVel.Y;
3490 if (Math.Abs(m_angularMotorDVel.Z) < Math.Abs(angObjectVel.Z)) angObjectVel.Z = m_angularMotorDVel.Z;
3491 }
3492 } // end decay angular motor
3493//if(frcount == 0) Console.WriteLine("MotorDvel {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3494
3495//if(frcount == 0) Console.WriteLine("VA = {0}", angObjectVel);
3496
3497 if ( (! m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! angObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3498 { // if motor or object have motion
3499 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3500
3501 if (m_angularMotorTimescale < 300.0f)
3502 {
3503 Vector3 attack_error = m_angularMotorDVel - angObjectVel;
3504 float angfactor = m_angularMotorTimescale/timestep;
3505 Vector3 attackAmount = (attack_error/angfactor);
3506 angObjectVel += attackAmount;
3507//if(frcount == 0) Console.WriteLine("Accel {0} Attk {1}",FrAaccel, attackAmount);
3508//if(frcount == 0) Console.WriteLine("V2+= {0}", angObjectVel);
3509 }
3510
3511 angObjectVel.X -= angObjectVel.X / (m_angularFrictionTimescale.X * 0.7f / timestep);
3512 angObjectVel.Y -= angObjectVel.Y / (m_angularFrictionTimescale.Y * 0.7f / timestep);
3513 angObjectVel.Z -= angObjectVel.Z / (m_angularFrictionTimescale.Z * 0.7f / timestep);
3514 } // else no signif. motion
3515
3516//if(frcount == 0) Console.WriteLine("Dmotor {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3517 // Bank section tba
3518 // Deflection section tba
3519//if(frcount == 0) Console.WriteLine("V3 = {0}", angObjectVel);
3520
3521
3522 /* // Rotation Axis Disables:
3523 if (!m_angularEnable.ApproxEquals(Vector3.One, 0.003f))
3524 {
3525 if (m_angularEnable.X == 0)
3526 angObjectVel.X = 0f;
3527 if (m_angularEnable.Y == 0)
3528 angObjectVel.Y = 0f;
3529 if (m_angularEnable.Z == 0)
3530 angObjectVel.Z = 0f;
3531 }
3532 */
3533 angObjectVel = angObjectVel * rotq; // ================ Converts to WORLD rotation
3534
3535 // Vertical attractor section
3536 Vector3 vertattr = Vector3.Zero;
3537
3538 if(m_verticalAttractionTimescale < 300)
3539 {
3540 float VAservo = 1.0f / (m_verticalAttractionTimescale * timestep);
3541 // make a vector pointing up
3542 Vector3 verterr = Vector3.Zero;
3543 verterr.Z = 1.0f;
3544 // rotate it to Body Angle
3545 verterr = verterr * rotq;
3546 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
3547 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
3548 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
3549
3550 if (verterr.Z < 0.0f)
3551 { // Deflection from vertical exceeds 90-degrees. This method will ensure stable return to
3552 // vertical, BUT for some reason a z-rotation is imparted to the object. TBI.
3553//Console.WriteLine("InvertFlip");
3554 verterr.X = 2.0f - verterr.X;
3555 verterr.Y = 2.0f - verterr.Y;
3556 }
3557 verterr *= 0.5f;
3558 // verterror is 0 (no error) to +/- 1 (max error at 180-deg tilt)
3559 Vector3 xyav = angObjectVel;
3560 xyav.Z = 0.0f;
3561 if ((!xyav.ApproxEquals(Vector3.Zero, 0.001f)) || (verterr.Z < 0.49f))
3562 {
3563 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
3564 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
3565 vertattr.X = verterr.Y;
3566 vertattr.Y = - verterr.X;
3567 vertattr.Z = 0f;
3568//if(frcount == 0) Console.WriteLine("VAerr=" + verterr);
3569
3570 // scaling appears better usingsquare-law
3571 float damped = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
3572 float bounce = 1.0f - damped;
3573 // 0 = crit damp, 1 = bouncy
3574 float oavz = angObjectVel.Z; // retain z velocity
3575 // time-scaled correction, which sums, therefore is bouncy:
3576 angObjectVel = (angObjectVel + (vertattr * VAservo * 0.0333f)) * bounce;
3577 // damped, good @ < 90:
3578 angObjectVel = angObjectVel + (vertattr * VAservo * 0.0667f * damped);
3579 angObjectVel.Z = oavz;
3580//if(frcount == 0) Console.WriteLine("VA+");
3581//Console.WriteLine("VAttr {0} OAvel {1}", vertattr, angObjectVel);
3582 }
3583 else
3584 {
3585 // else error is very small
3586 angObjectVel.X = 0f;
3587 angObjectVel.Y = 0f;
3588//if(frcount == 0) Console.WriteLine("VA0");
3589 }
3590 } // else vertical attractor is off
3591//if(frcount == 0) Console.WriteLine("V1 = {0}", angObjectVel);
3592
3593
3594 m_lastAngularVelocity = angObjectVel;
3595 // apply Angular Velocity to body
3596 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
3597//if(frcount == 0) Console.WriteLine("V4 = {0}", m_lastAngularVelocity);
3598
3599 } // end VEHICLES
3600 else
3601 {
3602 // Dyamics (NON-'VEHICLES') are dealt with here ================================================================
3603
3604 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
3605
3606 /// Dynamics Buoyancy
3607 //KF: m_buoyancy is set by llSetBuoyancy() and is for non-vehicle.
3608 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
3609 // NB Prims in ODE are no subject to global gravity
3610 // This should only affect gravity operations
3611
3612 float m_mass = CalculateMass();
3613 // calculate z-force due togravity on object.
3614 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; // force = acceleration * mass
3615
3616 if ((m_usePID) && (m_PIDTau > 0.0f)) // Dynamics llMoveToTarget.
3617 {
3618 fz = 0; // llMoveToTarget ignores gravity.
3619 // it also ignores mass of object, and any physical resting on it.
3620 // Vector3 m_PIDTarget is where we are going
3621 // float m_PIDTau is time to get there
3622 fx = 0;
3623 fy = 0;
3624 d.Vector3 pos = d.BodyGetPosition(Body);
3625 Vector3 error = new Vector3(
3626 (m_PIDTarget.X - pos.X),
3627 (m_PIDTarget.Y - pos.Y),
3628 (m_PIDTarget.Z - pos.Z));
3629 if (error.ApproxEquals(Vector3.Zero,0.01f))
3630 { // Very close, Jump there and quit move
3631 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3632 _target_velocity = Vector3.Zero;
3633 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3634 }
3635 else
3636 {
3637 float scale = 50.0f * timestep / m_PIDTau;
3638 if ((error.ApproxEquals(Vector3.Zero,0.5f)) && (_target_velocity != Vector3.Zero))
3639 {
3640 // Nearby, quit update of velocity
3641 }
3642 else
3643 { // Far, calc damped velocity
3644 _target_velocity = error * scale;
3645 }
3646 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3647 }
3648 } // end PID MoveToTarget
3649
3650 /* Original OS implementation: Does not work correctly as another phys object resting on THIS object purturbs its position.
3651 This is incorrect behavior. llMoveToTarget must move the Body no matter what phys object is resting on it.
3652
3653 //if (!d.BodyIsEnabled(Body))
3654 //d.BodySetForce(Body, 0f, 0f, 0f);
3655
3656 // no lock; for now it's only called from within Simulate()
3657
3658 // If the PID Controller isn't active then we set our force
3659 // calculating base velocity to the current position
3660
3661 if ((m_PIDTau < 1) && (m_PIDTau != 0))
3662 {
3663 //PID_G = PID_G / m_PIDTau;
3664 m_PIDTau = 1;
3665 }
3666
3667 if ((PID_G - m_PIDTau) <= 0)
3668 {
3669 PID_G = m_PIDTau + 1;
3670 }
3671 //PidStatus = true;
3672
3673 // PhysicsVector vec = new PhysicsVector();
3674// d.Vector3 vel = d.BodyGetLinearVel(Body);
3675
3676 d.Vector3 pos = d.BodyGetPosition(Body);
3677 _target_velocity =
3678 new Vector3(
3679 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
3680 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
3681 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
3682 );
3683
3684if(frcount == 0) Console.WriteLine("PID {0} b={1} fz={2} vel={3}", m_primName, m_buoyancy, fz, _target_velocity);
3685 // if velocity is zero, use position control; otherwise, velocity control
3686
3687 if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f))
3688 {
3689 // keep track of where we stopped. No more slippin' & slidin'
3690
3691 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3692 // react to the physics scene by moving it's position.
3693 // Avatar to Avatar collisions
3694 // Prim to avatar collisions
3695
3696 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
3697 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
3698 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
3699 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3700 d.BodySetLinearVel(Body, 0, 0, 0);
3701 d.BodyAddForce(Body, 0, 0, fz);
3702 // return;
3703 }
3704 else
3705 {
3706 _zeroFlag = false;
3707
3708 // We're flying and colliding with something
3709 fx = ((_target_velocity.X) - vel.X) * (PID_D);
3710 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
3711
3712 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
3713
3714 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3715 }
3716 } // end if (m_usePID)
3717 End of old PID system */
3718
3719
3720 /// Dynamics Hover ===================================================================================
3721 // Hover PID Controller can only run if the PIDcontroller is not in use.
3722 if (m_useHoverPID && !m_usePID)
3723 {
3724//Console.WriteLine("Hover " + m_primName);
3725
3726 // If we're using the PID controller, then we have no gravity
3727 fz = (-1 * _parent_scene.gravityz) * m_mass;
3728
3729 // no lock; for now it's only called from within Simulate()
3730
3731 // If the PID Controller isn't active then we set our force
3732 // calculating base velocity to the current position
3733
3734 if ((m_PIDTau < 1))
3735 {
3736 PID_G = PID_G / m_PIDTau;
3737 }
3738
3739 if ((PID_G - m_PIDTau) <= 0)
3740 {
3741 PID_G = m_PIDTau + 1;
3742 }
3743
3744
3745 // Where are we, and where are we headed?
3746 d.Vector3 pos = d.BodyGetPosition(Body);
3747// d.Vector3 vel = d.BodyGetLinearVel(Body);
3748
3749
3750 // Non-Vehicles have a limited set of Hover options.
3751 // determine what our target height really is based on HoverType
3752 switch (m_PIDHoverType)
3753 {
3754 case PIDHoverType.Ground:
3755 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3756 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3757 break;
3758 case PIDHoverType.GroundAndWater:
3759 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3760 m_waterHeight = _parent_scene.GetWaterLevel();
3761 if (m_groundHeight > m_waterHeight)
3762 {
3763 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3764 }
3765 else
3766 {
3767 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3768 }
3769 break;
3770
3771 } // end switch (m_PIDHoverType)
3772
3773
3774 _target_velocity =
3775 new Vector3(0.0f, 0.0f,
3776 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3777 );
3778
3779 // if velocity is zero, use position control; otherwise, velocity control
3780
3781 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3782 {
3783 // keep track of where we stopped. No more slippin' & slidin'
3784
3785 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3786 // react to the physics scene by moving it's position.
3787 // Avatar to Avatar collisions
3788 // Prim to avatar collisions
3789 d.Vector3 dlinvel = vel;
3790
3791 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3792 d.BodySetLinearVel(Body, dlinvel.X, dlinvel.Y, dlinvel.Z);
3793 d.BodyAddForce(Body, 0, 0, fz);
3794 //KF this prevents furthur motions return;
3795 }
3796 else
3797 {
3798 _zeroFlag = false;
3799
3800 // We're flying and colliding with something
3801 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3802 }
3803 } // end m_useHoverPID && !m_usePID
3804
3805 /// Dynamics RotLookAt =================================================================================
3806 if (m_useAPID)
3807 {
3808 // RotLookAt, apparently overrides all other rotation sources. Inputs:
3809 // Quaternion m_APIDTarget
3810 // float m_APIDStrength // From SL experiments, this is the time to get there
3811 // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly
3812 // Also in SL the mass of the object has no effect on time to get there.
3813 // Factors:
3814 // get present body rotation
3815 float limit = 1.0f;
3816 float scaler = 50f; // adjusts damping time
3817 float RLAservo = 0f;
3818
3819 d.Quaternion rot = d.BodyGetQuaternion(Body);
3820 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
3821 Quaternion rot_diff = Quaternion.Inverse(rotq) * m_APIDTarget;
3822 float diff_angle;
3823 Vector3 diff_axis;
3824 rot_diff.GetAxisAngle(out diff_axis, out diff_angle);
3825 diff_axis.Normalize();
3826 if(diff_angle > 0.01f) // diff_angle is always +ve
3827 {
3828// PhysicsVector rotforce = new PhysicsVector(diff_axis.X, diff_axis.Y, diff_axis.Z);
3829 Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z);
3830 rotforce = rotforce * rotq;
3831 if(diff_angle > limit) diff_angle = limit; // cap the rotate rate
3832// RLAservo = timestep / m_APIDStrength * m_mass * scaler;
3833 // rotforce = rotforce * RLAservo * diff_angle ;
3834 // d.BodyAddRelTorque(Body, rotforce.X, rotforce.Y, rotforce.Z);
3835 RLAservo = timestep / m_APIDStrength * scaler;
3836 rotforce = rotforce * RLAservo * diff_angle ;
3837 /*
3838 if (m_angularEnable.X == 0)
3839 rotforce.X = 0;
3840 if (m_angularEnable.Y == 0)
3841 rotforce.Y = 0;
3842 if (m_angularEnable.Z == 0)
3843 rotforce.Z = 0;
3844 */
3845 d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z);
3846//Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo);
3847 }
3848//if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle);
3849 } // end m_useAPID
3850
3851 /// Dynamics Apply Forces ===================================================================================
3852 fx *= m_mass;
3853 fy *= m_mass;
3854 //fz *= m_mass;
3855
3856 fx += m_force.X;
3857 fy += m_force.Y;
3858 fz += m_force.Z;
3859
3860 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3861 if (fx != 0 || fy != 0 || fz != 0)
3862 {
3863 //m_taintdisable = true;
3864 //base.RaiseOutOfBounds(Position);
3865 //d.BodySetLinearVel(Body, fx, fy, 0f);
3866 if (!d.BodyIsEnabled(Body))
3867 {
3868 // A physical body at rest on a surface will auto-disable after a while,
3869 // this appears to re-enable it incase the surface it is upon vanishes,
3870 // and the body should fall again.
3871 d.BodySetLinearVel(Body, 0f, 0f, 0f);
3872 d.BodySetForce(Body, 0, 0, 0);
3873 enableBodySoft();
3874 }
3875
3876 // 35x10 = 350n times the mass per second applied maximum.
3877 float nmax = 35f * m_mass;
3878 float nmin = -35f * m_mass;
3879
3880
3881 if (fx > nmax)
3882 fx = nmax;
3883 if (fx < nmin)
3884 fx = nmin;
3885 if (fy > nmax)
3886 fy = nmax;
3887 if (fy < nmin)
3888 fy = nmin;
3889 d.BodyAddForce(Body, fx, fy, fz);
3890//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
3891 } // end apply forces
3892 } // end Dynamics
3893
3894/* obsolete?
3895 else
3896 { // is not physical, or is not a body or is selected
3897 // from old UpdatePositionAndVelocity, ... Not a body.. so Make sure the client isn't interpolating
3898 _velocity.X = 0;
3899 _velocity.Y = 0;
3900 _velocity.Z = 0;
3901
3902 _acceleration.X = 0;
3903 _acceleration.Y = 0;
3904 _acceleration.Z = 0;
3905
3906 m_rotationalVelocity.X = 0;
3907 m_rotationalVelocity.Y = 0;
3908 m_rotationalVelocity.Z = 0;
3909 _zeroFlag = true;
3910 return;
3911 }
3912 */
3913 } // end root prims
3914
3915 } // end Move()
3916 } // end class
3917}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..7314107
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
@@ -0,0 +1,375 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using OpenMetaverse;
34using OpenSim.Region.Physics.Manager;
35using Ode.NET;
36using log4net;
37
38namespace OpenSim.Region.Physics.OdePlugin
39{
40 /// <summary>
41 /// Processes raycast requests as ODE is in a state to be able to do them.
42 /// This ensures that it's thread safe and there will be no conflicts.
43 /// Requests get returned by a different thread then they were requested by.
44 /// </summary>
45 public class ODERayCastRequestManager
46 {
47 /// <summary>
48 /// Pending Raycast Requests
49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51
52 /// <summary>
53 /// Scene that created this object.
54 /// </summary>
55 private OdeScene m_scene;
56
57 /// <summary>
58 /// ODE contact array to be filled by the collision testing
59 /// </summary>
60 d.ContactGeom[] contacts = new d.ContactGeom[5];
61
62 /// <summary>
63 /// ODE near callback delegate
64 /// </summary>
65 private d.NearCallback nearCallback;
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private List<ContactResult> m_contactResults = new List<ContactResult>();
68
69
70 public ODERayCastRequestManager(OdeScene pScene)
71 {
72 m_scene = pScene;
73 nearCallback = near;
74
75 }
76
77 /// <summary>
78 /// Queues a raycast
79 /// </summary>
80 /// <param name="position">Origin of Ray</param>
81 /// <param name="direction">Ray normal</param>
82 /// <param name="length">Ray length</param>
83 /// <param name="retMethod">Return method to send the results</param>
84 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
85 {
86 lock (m_PendingRequests)
87 {
88 ODERayCastRequest req = new ODERayCastRequest();
89 req.callbackMethod = retMethod;
90 req.length = length;
91 req.Normal = direction;
92 req.Origin = position;
93
94 m_PendingRequests.Add(req);
95 }
96 }
97
98 /// <summary>
99 /// Process all queued raycast requests
100 /// </summary>
101 /// <returns>Time in MS the raycasts took to process.</returns>
102 public int ProcessQueuedRequests()
103 {
104 int time = System.Environment.TickCount;
105 lock (m_PendingRequests)
106 {
107 if (m_PendingRequests.Count > 0)
108 {
109 ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
110 for (int i = 0; i < reqs.Length; i++)
111 {
112 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
113 RayCast(reqs[i]); // if there isn't anyone to send results
114 }
115 /*
116 foreach (ODERayCastRequest req in m_PendingRequests)
117 {
118 if (req.callbackMethod != null) // quick optimization here, don't raycast
119 RayCast(req); // if there isn't anyone to send results to
120
121 }
122 */
123 m_PendingRequests.Clear();
124 }
125 }
126
127 lock (m_contactResults)
128 m_contactResults.Clear();
129
130 return System.Environment.TickCount - time;
131 }
132
133 /// <summary>
134 /// Method that actually initiates the raycast
135 /// </summary>
136 /// <param name="req"></param>
137 private void RayCast(ODERayCastRequest req)
138 {
139 // Create the ray
140 IntPtr ray = d.CreateRay(m_scene.space, req.length);
141 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
142
143 // Collide test
144 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
145
146 // Remove Ray
147 d.GeomDestroy(ray);
148
149
150 // Define default results
151 bool hitYN = false;
152 uint hitConsumerID = 0;
153 float distance = 999999999999f;
154 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
155 Vector3 snormal = Vector3.Zero;
156
157 // Find closest contact and object.
158 lock (m_contactResults)
159 {
160 foreach (ContactResult cResult in m_contactResults)
161 {
162 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
163 {
164 closestcontact = cResult.Pos;
165 hitConsumerID = cResult.ConsumerID;
166 distance = cResult.Depth;
167 hitYN = true;
168 snormal = cResult.Normal;
169 }
170 }
171
172 m_contactResults.Clear();
173 }
174
175 // Return results
176 if (req.callbackMethod != null)
177 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
178 }
179
180 // This is the standard Near. Uses space AABBs to speed up detection.
181 private void near(IntPtr space, IntPtr g1, IntPtr g2)
182 {
183
184 //Don't test against heightfield Geom, or you'll be sorry!
185
186 /*
187 terminate called after throwing an instance of 'std::bad_alloc'
188 what(): std::bad_alloc
189 Stacktrace:
190
191 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
192 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
193 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
194 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
195 fffff>
196 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
197 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
198 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
199 0x00114>
200 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
201 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
202 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
203 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
204 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
205 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
206
207 Native stacktrace:
208
209 mono [0x80d2a42]
210 [0xb7f5840c]
211 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
212 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
213 /usr/lib/libstdc++.so.6 [0xb45fa865]
214 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
215 /usr/lib/libstdc++.so.6 [0xb45fa9da]
216 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
217 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
218 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
219 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
220 libode.so(dCollide+0x102) [0xb46571b2]
221 [0x95cfdec9]
222 [0x8ea07fe1]
223 [0xab260146]
224 libode.so [0xb465a5c4]
225 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
226 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
227 [0x95cf978e]
228 [0x8ea07945]
229 [0x95cf2bbc]
230 [0xab2787e7]
231 [0xab419fb3]
232 [0xab416657]
233 [0xab415bda]
234 [0xb609b08e]
235 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
236 mono [0x81a2f0f]
237 mono [0x81d28b6]
238 mono [0x81ea2c6]
239 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
240 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
241 */
242
243 // Exclude heightfield geom
244
245 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
246 return;
247 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
248 return;
249
250 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
251 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
252 {
253 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
254 return;
255
256 // Separating static prim geometry spaces.
257 // We'll be calling near recursivly if one
258 // of them is a space to find all of the
259 // contact points in the space
260 try
261 {
262 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
263 }
264 catch (AccessViolationException)
265 {
266 m_log.Warn("[PHYSICS]: Unable to collide test a space");
267 return;
268 }
269 //Colliding a space or a geom with a space or a geom. so drill down
270
271 //Collide all geoms in each space..
272 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
273 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
274 return;
275 }
276
277 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
278 return;
279
280 int count = 0;
281 try
282 {
283
284 if (g1 == g2)
285 return; // Can't collide with yourself
286
287 lock (contacts)
288 {
289 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
290 }
291 }
292 catch (SEHException)
293 {
294 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
295 }
296 catch (Exception e)
297 {
298 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
299 return;
300 }
301
302 PhysicsActor p1 = null;
303 PhysicsActor p2 = null;
304
305 if (g1 != IntPtr.Zero)
306 m_scene.actor_name_map.TryGetValue(g1, out p1);
307
308 if (g2 != IntPtr.Zero)
309 m_scene.actor_name_map.TryGetValue(g1, out p2);
310
311 // Loop over contacts, build results.
312 for (int i = 0; i < count; i++)
313 {
314 if (p1 != null) {
315 if (p1 is OdePrim)
316 {
317 ContactResult collisionresult = new ContactResult();
318
319 collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
320 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
321 collisionresult.Depth = contacts[i].depth;
322 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
323 contacts[i].normal.Z);
324 lock (m_contactResults)
325 m_contactResults.Add(collisionresult);
326 }
327 }
328
329 if (p2 != null)
330 {
331 if (p2 is OdePrim)
332 {
333 ContactResult collisionresult = new ContactResult();
334
335 collisionresult.ConsumerID = ((OdePrim)p2).m_localID;
336 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
337 collisionresult.Depth = contacts[i].depth;
338 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
339 contacts[i].normal.Z);
340
341 lock (m_contactResults)
342 m_contactResults.Add(collisionresult);
343 }
344 }
345
346
347 }
348
349 }
350
351 /// <summary>
352 /// Dereference the creator scene so that it can be garbage collected if needed.
353 /// </summary>
354 internal void Dispose()
355 {
356 m_scene = null;
357 }
358 }
359
360 public struct ODERayCastRequest
361 {
362 public Vector3 Origin;
363 public Vector3 Normal;
364 public float length;
365 public RaycastCallback callbackMethod;
366 }
367
368 public struct ContactResult
369 {
370 public Vector3 Pos;
371 public float Depth;
372 public uint ConsumerID;
373 public Vector3 Normal;
374 }
375}
diff --git a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs
index ca7a4f8..b4a3c48 100644
--- a/OpenSim/Region/Physics/PhysXPlugin/PhysXPlugin.cs
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePhysicsJoint.cs
@@ -26,51 +26,23 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using OpenMetaverse;
30using Nini.Config; 30using Ode.NET;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager; 32using OpenSim.Region.Physics.Manager;
33using PhysXWrapper; 33using OpenSim.Region.Physics.OdePlugin;
34using Quaternion=OpenMetaverse.Quaternion;
35using System.Reflection;
36using log4net;
37using OpenMetaverse;
38 34
39namespace OpenSim.Region.Physics.PhysXPlugin 35namespace OpenSim.Region.Physics.OdePlugin
40{ 36{
41 /// <summary> 37 class OdePhysicsJoint : PhysicsJoint
42 /// Will be the PhysX plugin but for now will be a very basic physics engine
43 /// </summary>
44 public class PhysXPlugin : IPhysicsPlugin
45 { 38 {
46 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 public override bool IsInPhysicsEngine
47 private PhysXScene _mScene;
48
49 public PhysXPlugin()
50 {
51 }
52
53 public bool Init()
54 { 40 {
55 return true; 41 get
56 }
57
58 public PhysicsScene GetScene(string sceneIdentifier)
59 {
60 if (_mScene == null)
61 { 42 {
62 _mScene = new PhysXScene(sceneIdentifier); 43 return (jointID != IntPtr.Zero);
63 } 44 }
64 return (_mScene);
65 }
66
67 public string GetName()
68 {
69 return ("RealPhysX");
70 }
71
72 public void Dispose()
73 {
74 } 45 }
46 public IntPtr jointID;
75 } 47 }
76} 48}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
new file mode 100644
index 0000000..86f9893
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
@@ -0,0 +1,3869 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28//#define USE_DRAWSTUFF
29
30using System;
31using System.Collections.Generic;
32using System.Reflection;
33using System.Runtime.InteropServices;
34using System.Threading;
35using System.IO;
36using System.Diagnostics;
37using log4net;
38using Nini.Config;
39using Ode.NET;
40#if USE_DRAWSTUFF
41using Drawstuff.NET;
42#endif
43using OpenSim.Framework;
44using OpenSim.Region.Physics.Manager;
45using OpenMetaverse;
46
47//using OpenSim.Region.Physics.OdePlugin.Meshing;
48
49namespace OpenSim.Region.Physics.OdePlugin
50{
51 /// <summary>
52 /// ODE plugin
53 /// </summary>
54 public class OdePlugin : IPhysicsPlugin
55 {
56 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
57
58 private CollisionLocker ode;
59 private OdeScene _mScene;
60
61 public OdePlugin()
62 {
63 ode = new CollisionLocker();
64 }
65
66 public bool Init()
67 {
68 return true;
69 }
70
71 public PhysicsScene GetScene(String sceneIdentifier)
72 {
73 if (_mScene == null)
74 {
75 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
76 // http://opensimulator.org/mantis/view.php?id=2750).
77 d.InitODE();
78
79 _mScene = new OdeScene(ode, sceneIdentifier);
80 }
81 return (_mScene);
82 }
83
84 public string GetName()
85 {
86 return ("ChODE");
87 }
88
89 public void Dispose()
90 {
91 }
92 }
93
94 public enum StatusIndicators : int
95 {
96 Generic = 0,
97 Start = 1,
98 End = 2
99 }
100
101 public struct sCollisionData
102 {
103 public uint ColliderLocalId;
104 public uint CollidedWithLocalId;
105 public int NumberOfCollisions;
106 public int CollisionType;
107 public int StatusIndicator;
108 public int lastframe;
109 }
110
111 [Flags]
112 public enum CollisionCategories : int
113 {
114 Disabled = 0,
115 Geom = 0x00000001,
116 Body = 0x00000002,
117 Space = 0x00000004,
118 Character = 0x00000008,
119 Land = 0x00000010,
120 Water = 0x00000020,
121 Wind = 0x00000040,
122 Sensor = 0x00000080,
123 Selected = 0x00000100
124 }
125
126 /// <summary>
127 /// Material type for a primitive
128 /// </summary>
129 public enum Material : int
130 {
131 /// <summary></summary>
132 Stone = 0,
133 /// <summary></summary>
134 Metal = 1,
135 /// <summary></summary>
136 Glass = 2,
137 /// <summary></summary>
138 Wood = 3,
139 /// <summary></summary>
140 Flesh = 4,
141 /// <summary></summary>
142 Plastic = 5,
143 /// <summary></summary>
144 Rubber = 6
145
146 }
147
148 public sealed class OdeScene : PhysicsScene
149 {
150 private readonly ILog m_log;
151 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
152
153 CollisionLocker ode;
154
155 private Random fluidRandomizer = new Random(Environment.TickCount);
156
157 private const uint m_regionWidth = Constants.RegionSize;
158 private const uint m_regionHeight = Constants.RegionSize;
159
160 private float ODE_STEPSIZE = 0.020f;
161 private float metersInSpace = 29.9f;
162 private float m_timeDilation = 1.0f;
163
164 public float gravityx = 0f;
165 public float gravityy = 0f;
166 public float gravityz = -9.8f;
167
168 private float contactsurfacelayer = 0.001f;
169
170 private int worldHashspaceLow = -4;
171 private int worldHashspaceHigh = 128;
172
173 private int smallHashspaceLow = -4;
174 private int smallHashspaceHigh = 66;
175
176 private float waterlevel = 0f;
177 private int framecount = 0;
178 //private int m_returncollisions = 10;
179
180 private readonly IntPtr contactgroup;
181
182 internal IntPtr LandGeom;
183 internal IntPtr WaterGeom;
184
185 private float nmTerrainContactFriction = 255.0f;
186 private float nmTerrainContactBounce = 0.1f;
187 private float nmTerrainContactERP = 0.1025f;
188
189 private float mTerrainContactFriction = 75f;
190 private float mTerrainContactBounce = 0.1f;
191 private float mTerrainContactERP = 0.05025f;
192
193 private float nmAvatarObjectContactFriction = 250f;
194 private float nmAvatarObjectContactBounce = 0.1f;
195
196 private float mAvatarObjectContactFriction = 75f;
197 private float mAvatarObjectContactBounce = 0.1f;
198
199 private float avPIDD = 3200f;
200 private float avPIDP = 1400f;
201 private float avCapRadius = 0.37f;
202 private float avStandupTensor = 2000000f;
203 private bool avCapsuleTilted = true; // true = old compatibility mode with leaning capsule; false = new corrected mode
204 public bool IsAvCapsuleTilted { get { return avCapsuleTilted; } set { avCapsuleTilted = value; } }
205 private float avDensity = 80f;
206 private float avHeightFudgeFactor = 0.52f;
207 private float avMovementDivisorWalk = 1.3f;
208 private float avMovementDivisorRun = 0.8f;
209 private float minimumGroundFlightOffset = 3f;
210 public float maximumMassObject = 10000.01f;
211
212 public bool meshSculptedPrim = true;
213 public bool forceSimplePrimMeshing = false;
214
215 public float meshSculptLOD = 32;
216 public float MeshSculptphysicalLOD = 16;
217
218 public float geomDefaultDensity = 10.000006836f;
219
220 public int geomContactPointsStartthrottle = 3;
221 public int geomUpdatesPerThrottledUpdate = 15;
222
223 public float bodyPIDD = 35f;
224 public float bodyPIDG = 25;
225
226 public int geomCrossingFailuresBeforeOutofbounds = 5;
227 public int geomRegionFence = 0;
228
229 public float bodyMotorJointMaxforceTensor = 2;
230
231 public int bodyFramesAutoDisable = 20;
232
233 private DateTime m_lastframe = DateTime.UtcNow;
234
235 private float[] _watermap;
236 private bool m_filterCollisions = true;
237
238 private d.NearCallback nearCallback;
239 public d.TriCallback triCallback;
240 public d.TriArrayCallback triArrayCallback;
241 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
242 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
243 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
244 private readonly HashSet<OdePrim> _taintedPrimH = new HashSet<OdePrim>();
245 private readonly Object _taintedPrimLock = new Object();
246 private readonly List<OdePrim> _taintedPrimL = new List<OdePrim>();
247 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
248 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
249 private readonly List<PhysicsActor> _collisionEventPrim = new List<PhysicsActor>();
250 private readonly HashSet<OdeCharacter> _badCharacter = new HashSet<OdeCharacter>();
251 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
252 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
253 private bool m_NINJA_physics_joints_enabled = false;
254 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
255 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
256 private d.ContactGeom[] contacts;
257 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>(); // lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
258 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
259 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>(); // can lock for longer. accessed only by OdeScene.
260 private readonly List<string> requestedJointsToBeDeleted = new List<string>(); // lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
261 private Object externalJointRequestsLock = new Object();
262 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
263 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
264 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
265 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
266
267 private d.Contact contact;
268 private d.Contact TerrainContact;
269 private d.Contact AvatarMovementprimContact;
270 private d.Contact AvatarMovementTerrainContact;
271 private d.Contact WaterContact;
272 private d.Contact[,] m_materialContacts;
273
274//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
275//Ckrinke private int m_randomizeWater = 200;
276 private int m_physicsiterations = 10;
277 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
278 private readonly PhysicsActor PANull = new NullPhysicsActor();
279 private float step_time = 0.0f;
280//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
281//Ckrinke private int ms = 0;
282 public IntPtr world;
283 //private bool returncollisions = false;
284 // private uint obj1LocalID = 0;
285 private uint obj2LocalID = 0;
286 //private int ctype = 0;
287 private OdeCharacter cc1;
288 private OdePrim cp1;
289 private OdeCharacter cc2;
290 private OdePrim cp2;
291 //private int cStartStop = 0;
292 //private string cDictKey = "";
293
294 public IntPtr space;
295
296 //private IntPtr tmpSpace;
297 // split static geometry collision handling into spaces of 30 meters
298 public IntPtr[,] staticPrimspace;
299
300 public Object OdeLock;
301
302 public IMesher mesher;
303
304 private IConfigSource m_config;
305
306 public bool physics_logging = false;
307 public int physics_logging_interval = 0;
308 public bool physics_logging_append_existing_logfile = false;
309
310 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
311 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
312
313 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
314 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
315 // TODO: unused: private uint heightmapWidthSamples;
316 // TODO: unused: private uint heightmapHeightSamples;
317
318 private volatile int m_global_contactcount = 0;
319
320 private Vector3 m_worldOffset = Vector3.Zero;
321 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
322 private PhysicsScene m_parentScene = null;
323
324 private ODERayCastRequestManager m_rayCastManager;
325
326 /// <summary>
327 /// Initiailizes the scene
328 /// Sets many properties that ODE requires to be stable
329 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
330 /// </summary>
331 public OdeScene(CollisionLocker dode, string sceneIdentifier)
332 {
333 m_log
334 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
335
336 OdeLock = new Object();
337 ode = dode;
338 nearCallback = near;
339 triCallback = TriCallback;
340 triArrayCallback = TriArrayCallback;
341 m_rayCastManager = new ODERayCastRequestManager(this);
342 lock (OdeLock)
343 {
344 // Create the world and the first space
345 world = d.WorldCreate();
346 space = d.HashSpaceCreate(IntPtr.Zero);
347
348
349 contactgroup = d.JointGroupCreate(0);
350 //contactgroup
351
352 d.WorldSetAutoDisableFlag(world, false);
353 #if USE_DRAWSTUFF
354
355 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
356 viewthread.Start();
357 #endif
358 }
359
360
361 _watermap = new float[258 * 258];
362
363 // Zero out the prim spaces array (we split our space into smaller spaces so
364 // we can hit test less.
365 }
366
367#if USE_DRAWSTUFF
368 public void startvisualization(object o)
369 {
370 ds.Functions fn;
371 fn.version = ds.VERSION;
372 fn.start = new ds.CallbackFunction(start);
373 fn.step = new ds.CallbackFunction(step);
374 fn.command = new ds.CallbackFunction(command);
375 fn.stop = null;
376 fn.path_to_textures = "./textures";
377 string[] args = new string[0];
378 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
379 }
380#endif
381
382 // Initialize the mesh plugin
383 public override void Initialise(IMesher meshmerizer, IConfigSource config)
384 {
385 mesher = meshmerizer;
386 m_config = config;
387 // Defaults
388
389 if (Environment.OSVersion.Platform == PlatformID.Unix)
390 {
391 avPIDD = 3200.0f;
392 avPIDP = 1400.0f;
393 avStandupTensor = 2000000f;
394 }
395 else
396 {
397 avPIDD = 2200.0f;
398 avPIDP = 900.0f;
399 avStandupTensor = 550000f;
400 }
401
402 int contactsPerCollision = 80;
403
404 if (m_config != null)
405 {
406 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
407 if (physicsconfig != null)
408 {
409 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
410 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
411 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
412
413 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
414 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
415
416 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
417 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
418 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
419
420 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
421
422 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
423 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
424 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
425
426 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
427 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
428 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
429
430 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
431 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
432
433 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
434 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
435
436 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
437 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
438
439 avDensity = physicsconfig.GetFloat("av_density", 80f);
440 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
441 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
442 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
443 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
444 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
445
446 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
447
448 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
449 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
450 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
451 geomRegionFence = physicsconfig.GetInt("region_border_fence", 0);
452
453 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
454 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
455
456 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
457 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
458
459 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
460 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
461 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
462 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
463 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
464
465 if (Environment.OSVersion.Platform == PlatformID.Unix)
466 {
467 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
468 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
469 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
470 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
471 }
472 else
473 {
474 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
475 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
476 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
477 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
478 }
479
480 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
481 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
482 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
483
484 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
485 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
486 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
487 }
488 }
489
490 contacts = new d.ContactGeom[contactsPerCollision];
491
492 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
493
494 // Centeral contact friction and bounce
495 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
496 // an avatar falls through in Z but not in X or Y when walking on a prim.
497 contact.surface.mode |= d.ContactFlags.SoftERP;
498 contact.surface.mu = nmAvatarObjectContactFriction;
499 contact.surface.bounce = nmAvatarObjectContactBounce;
500 contact.surface.soft_cfm = 0.010f;
501 contact.surface.soft_erp = 0.010f;
502
503 // Terrain contact friction and Bounce
504 // This is the *non* moving version. Use this when an avatar
505 // isn't moving to keep it in place better
506 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
507 TerrainContact.surface.mu = nmTerrainContactFriction;
508 TerrainContact.surface.bounce = nmTerrainContactBounce;
509 TerrainContact.surface.soft_erp = nmTerrainContactERP;
510
511 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
512 WaterContact.surface.mu = 0f; // No friction
513 WaterContact.surface.bounce = 0.0f; // No bounce
514 WaterContact.surface.soft_cfm = 0.010f;
515 WaterContact.surface.soft_erp = 0.010f;
516
517 // Prim contact friction and bounce
518 // THis is the *non* moving version of friction and bounce
519 // Use this when an avatar comes in contact with a prim
520 // and is moving
521 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
522 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
523
524 // Terrain contact friction bounce and various error correcting calculations
525 // Use this when an avatar is in contact with the terrain and moving.
526 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
527 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
528 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
529 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
530
531
532 /*
533 <summary></summary>
534 Stone = 0,
535 /// <summary></summary>
536 Metal = 1,
537 /// <summary></summary>
538 Glass = 2,
539 /// <summary></summary>
540 Wood = 3,
541 /// <summary></summary>
542 Flesh = 4,
543 /// <summary></summary>
544 Plastic = 5,
545 /// <summary></summary>
546 Rubber = 6
547 */
548
549 m_materialContacts = new d.Contact[7,2];
550
551 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
552 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
553 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
554 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
555 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
556 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
557
558 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
559 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
560 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
561 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
562 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
563 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
564
565 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
566 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
567 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
568 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
569 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
570 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
571
572 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
573 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
574 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
575 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
576 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
577 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
578
579 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
580 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
581 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
582 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
583 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
584 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
585
586 /*
587 private float nmAvatarObjectContactFriction = 250f;
588 private float nmAvatarObjectContactBounce = 0.1f;
589
590 private float mAvatarObjectContactFriction = 75f;
591 private float mAvatarObjectContactBounce = 0.1f;
592 */
593 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
594 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
595 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
596 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
597 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
598 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
599
600 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
601 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
602 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
603 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
604 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
605 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
606
607 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
608 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
609 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
610 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
611 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
612 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
613
614 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
615 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
616 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
617 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
618 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
619 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
620
621 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
622 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
623 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
624 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
625 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
626 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
627
628 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
629 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
630 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
631 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
632 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
633 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
634
635 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
636 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
637 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
638 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
639 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
640 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
641
642 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
643 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
644 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
645 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
646 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
647 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
648
649 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
650 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
651 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
652 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
653 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
654 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
655
656 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
657
658 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
659
660 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
661 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
662
663 d.WorldSetLinearDamping(world, 256f);
664 d.WorldSetAngularDamping(world, 256f);
665 d.WorldSetAngularDampingThreshold(world, 256f);
666 d.WorldSetLinearDampingThreshold(world, 256f);
667 d.WorldSetMaxAngularSpeed(world, 256f);
668
669 // Set how many steps we go without running collision testing
670 // This is in addition to the step size.
671 // Essentially Steps * m_physicsiterations
672 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
673 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
674
675
676
677 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
678 {
679 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
680 {
681 staticPrimspace[i, j] = IntPtr.Zero;
682 }
683 }
684 }
685
686 internal void waitForSpaceUnlock(IntPtr space)
687 {
688 //if (space != IntPtr.Zero)
689 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
690 }
691
692 /// <summary>
693 /// Debug space message for printing the space that a prim/avatar is in.
694 /// </summary>
695 /// <param name="pos"></param>
696 /// <returns>Returns which split up space the given position is in.</returns>
697 public string whichspaceamIin(Vector3 pos)
698 {
699 return calculateSpaceForGeom(pos).ToString();
700 }
701
702 #region Collision Detection
703
704 /// <summary>
705 /// This is our near callback. A geometry is near a body
706 /// </summary>
707 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
708 /// <param name="g1">a geometry or space</param>
709 /// <param name="g2">another geometry or space</param>
710 private void near(IntPtr space, IntPtr g1, IntPtr g2)
711 {
712 // no lock here! It's invoked from within Simulate(), which is thread-locked
713
714 // Test if we're colliding a geom with a space.
715 // If so we have to drill down into the space recursively
716//Console.WriteLine("near -----------"); //##
717 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
718 {
719 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
720 return;
721
722 // Separating static prim geometry spaces.
723 // We'll be calling near recursivly if one
724 // of them is a space to find all of the
725 // contact points in the space
726 try
727 {
728 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
729 }
730 catch (AccessViolationException)
731 {
732 m_log.Warn("[PHYSICS]: Unable to collide test a space");
733 return;
734 }
735 //Colliding a space or a geom with a space or a geom. so drill down
736
737 //Collide all geoms in each space..
738 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
739 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
740 return;
741 }
742
743 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
744 return;
745
746 IntPtr b1 = d.GeomGetBody(g1);
747 IntPtr b2 = d.GeomGetBody(g2);
748
749 // d.GeomClassID id = d.GeomGetClass(g1);
750
751 String name1 = null;
752 String name2 = null;
753
754 if (!geom_name_map.TryGetValue(g1, out name1))
755 {
756 name1 = "null";
757 }
758 if (!geom_name_map.TryGetValue(g2, out name2))
759 {
760 name2 = "null";
761 }
762
763 //if (id == d.GeomClassId.TriMeshClass)
764 //{
765 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
766 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
767 //}
768
769 // Figure out how many contact points we have
770 int count = 0;
771 try
772 {
773 // Colliding Geom To Geom
774 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
775
776 if (g1 == g2)
777 return; // Can't collide with yourself
778
779 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
780 return;
781
782 lock (contacts)
783 {
784 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
785 if (count > contacts.Length)
786 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
787 }
788 }
789 catch (SEHException)
790 {
791 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
792 ode.drelease(world);
793 base.TriggerPhysicsBasedRestart();
794 }
795 catch (Exception e)
796 {
797 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
798 return;
799 }
800
801 PhysicsActor p1;
802 PhysicsActor p2;
803
804 if (!actor_name_map.TryGetValue(g1, out p1))
805 {
806 p1 = PANull;
807 }
808
809 if (!actor_name_map.TryGetValue(g2, out p2))
810 {
811 p2 = PANull;
812 }
813
814 ContactPoint maxDepthContact = new ContactPoint();
815 if (p1.CollisionScore + count >= float.MaxValue)
816 p1.CollisionScore = 0;
817 p1.CollisionScore += count;
818
819 if (p2.CollisionScore + count >= float.MaxValue)
820 p2.CollisionScore = 0;
821 p2.CollisionScore += count;
822
823 for (int i = 0; i < count; i++)
824 {
825 d.ContactGeom curContact = contacts[i];
826
827 if (curContact.depth > maxDepthContact.PenetrationDepth)
828 {
829 maxDepthContact = new ContactPoint(
830 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
831 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
832 curContact.depth
833 );
834 }
835
836 //m_log.Warn("[CCOUNT]: " + count);
837 IntPtr joint;
838 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
839 // allows us to have different settings
840
841 // We only need to test p2 for 'jump crouch purposes'
842 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
843 {
844 // Testing if the collision is at the feet of the avatar
845
846 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
847//#@ if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
848//#@ p2.IsColliding = true;
849 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)){ //##
850//Console.WriteLine("AvColl 1 {0} - {1} - {2} - {3}", //##
851// curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); //##
852 p2.IsColliding = true; //##
853 }else{
854//Console.WriteLine("AvColl 2 {0} - {1} - {2} - {3}", //##
855// curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f)); //##
856
857 } //##
858 }
859 else
860 {
861//Console.WriteLine("AvColl 3 {0}", p2.PhysicsActorType); //##
862 p2.IsColliding = true;
863 }
864
865 //if ((framecount % m_returncollisions) == 0)
866
867 switch (p1.PhysicsActorType)
868 {
869 case (int)ActorTypes.Agent:
870 p2.CollidingObj = true;
871 break;
872 case (int)ActorTypes.Prim:
873 if (p2.Velocity.LengthSquared() > 0.0f)
874 p2.CollidingObj = true;
875 break;
876 case (int)ActorTypes.Unknown:
877 p2.CollidingGround = true;
878 break;
879 default:
880 p2.CollidingGround = true;
881 break;
882 }
883
884 // we don't want prim or avatar to explode
885
886 #region InterPenetration Handling - Unintended physics explosions
887# region disabled code1
888
889 if (curContact.depth >= 0.08f)
890 {
891 //This is disabled at the moment only because it needs more tweaking
892 //It will eventually be uncommented
893 /*
894 if (contact.depth >= 1.00f)
895 {
896 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
897 }
898
899 //If you interpenetrate a prim with an agent
900 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
901 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
902 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
903 p2.PhysicsActorType == (int) ActorTypes.Prim))
904 {
905
906 //contact.depth = contact.depth * 4.15f;
907 /*
908 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
909 {
910 p2.CollidingObj = true;
911 contact.depth = 0.003f;
912 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
913 OdeCharacter character = (OdeCharacter) p2;
914 character.SetPidStatus(true);
915 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
916
917 }
918 else
919 {
920
921 //contact.depth = 0.0000000f;
922 }
923 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
924 {
925
926 p1.CollidingObj = true;
927 contact.depth = 0.003f;
928 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
929 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
930 OdeCharacter character = (OdeCharacter)p1;
931 character.SetPidStatus(true);
932 }
933 else
934 {
935
936 //contact.depth = 0.0000000f;
937 }
938
939
940
941 }
942*/
943 // If you interpenetrate a prim with another prim
944 /*
945 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
946 {
947 #region disabledcode2
948 //OdePrim op1 = (OdePrim)p1;
949 //OdePrim op2 = (OdePrim)p2;
950 //op1.m_collisionscore++;
951 //op2.m_collisionscore++;
952
953 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
954 //{
955 //op1.m_taintdisable = true;
956 //AddPhysicsActorTaint(p1);
957 //op2.m_taintdisable = true;
958 //AddPhysicsActorTaint(p2);
959 //}
960
961 //if (contact.depth >= 0.25f)
962 //{
963 // Don't collide, one or both prim will expld.
964
965 //op1.m_interpenetrationcount++;
966 //op2.m_interpenetrationcount++;
967 //interpenetrations_before_disable = 200;
968 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
969 //{
970 //op1.m_taintdisable = true;
971 //AddPhysicsActorTaint(p1);
972 //}
973 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
974 //{
975 // op2.m_taintdisable = true;
976 //AddPhysicsActorTaint(p2);
977 //}
978
979 //contact.depth = contact.depth / 8f;
980 //contact.normal = new d.Vector3(0, 0, 1);
981 //}
982 //if (op1.m_disabled || op2.m_disabled)
983 //{
984 //Manually disabled objects stay disabled
985 //contact.depth = 0f;
986 //}
987 #endregion
988 }
989 */
990#endregion
991 if (curContact.depth >= 1.00f)
992 {
993 //m_log.Info("[P]: " + contact.depth.ToString());
994 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
995 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
996 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
997 p2.PhysicsActorType == (int) ActorTypes.Unknown))
998 {
999 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1000 {
1001 if (p2 is OdeCharacter)
1002 {
1003 OdeCharacter character = (OdeCharacter) p2;
1004
1005 //p2.CollidingObj = true;
1006 curContact.depth = 0.00000003f;
1007 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
1008 curContact.pos =
1009 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1010 curContact.pos.Y + (p1.Size.Y/2),
1011 curContact.pos.Z + (p1.Size.Z/2));
1012 character.SetPidStatus(true);
1013 }
1014 }
1015
1016
1017 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1018 {
1019 if (p1 is OdeCharacter)
1020 {
1021 OdeCharacter character = (OdeCharacter) p1;
1022
1023 //p2.CollidingObj = true;
1024 curContact.depth = 0.00000003f;
1025 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1026 curContact.pos =
1027 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1028 curContact.pos.Y + (p1.Size.Y/2),
1029 curContact.pos.Z + (p1.Size.Z/2));
1030 character.SetPidStatus(true);
1031 }
1032 }
1033 }
1034 }
1035 }
1036
1037 #endregion
1038
1039 // Logic for collision handling
1040 // Note, that if *all* contacts are skipped (VolumeDetect)
1041 // The prim still detects (and forwards) collision events but
1042 // appears to be phantom for the world
1043 Boolean skipThisContact = false;
1044
1045 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1046 skipThisContact = true; // No collision on volume detect prims
1047
1048 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1049 skipThisContact = true; // No collision on volume detect prims
1050
1051 if (!skipThisContact && curContact.depth < 0f)
1052 skipThisContact = true;
1053
1054 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1055 skipThisContact = true;
1056
1057 const int maxContactsbeforedeath = 4000;
1058 joint = IntPtr.Zero;
1059
1060 if (!skipThisContact)
1061 {
1062 // If we're colliding against terrain
1063 if (name1 == "Terrain" || name2 == "Terrain")
1064 {
1065 // If we're moving
1066 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1067 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1068 {
1069 // Use the movement terrain contact
1070 AvatarMovementTerrainContact.geom = curContact;
1071 _perloopContact.Add(curContact);
1072 if (m_global_contactcount < maxContactsbeforedeath)
1073 {
1074 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1075 m_global_contactcount++;
1076 }
1077 }
1078 else
1079 {
1080 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1081 {
1082 // Use the non moving terrain contact
1083 TerrainContact.geom = curContact;
1084 _perloopContact.Add(curContact);
1085 if (m_global_contactcount < maxContactsbeforedeath)
1086 {
1087 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1088 m_global_contactcount++;
1089 }
1090 }
1091 else
1092 {
1093 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1094 {
1095 // prim prim contact
1096 // int pj294950 = 0;
1097 int movintYN = 0;
1098 int material = (int) Material.Wood;
1099 // prim terrain contact
1100 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1101 {
1102 movintYN = 1;
1103 }
1104
1105 if (p2 is OdePrim)
1106 material = ((OdePrim)p2).m_material;
1107
1108 //m_log.DebugFormat("Material: {0}", material);
1109 m_materialContacts[material, movintYN].geom = curContact;
1110 _perloopContact.Add(curContact);
1111
1112 if (m_global_contactcount < maxContactsbeforedeath)
1113 {
1114 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1115 m_global_contactcount++;
1116
1117 }
1118
1119 }
1120 else
1121 {
1122
1123 int movintYN = 0;
1124 // prim terrain contact
1125 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1126 {
1127 movintYN = 1;
1128 }
1129
1130 int material = (int)Material.Wood;
1131
1132 if (p2 is OdePrim)
1133 material = ((OdePrim)p2).m_material;
1134 //m_log.DebugFormat("Material: {0}", material);
1135 m_materialContacts[material, movintYN].geom = curContact;
1136 _perloopContact.Add(curContact);
1137
1138 if (m_global_contactcount < maxContactsbeforedeath)
1139 {
1140 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1141 m_global_contactcount++;
1142
1143 }
1144 }
1145 }
1146 }
1147 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1148 //{
1149 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1150 //}
1151 }
1152 else if (name1 == "Water" || name2 == "Water")
1153 {
1154 /*
1155 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1156 {
1157 }
1158 else
1159 {
1160 }
1161 */
1162 //WaterContact.surface.soft_cfm = 0.0000f;
1163 //WaterContact.surface.soft_erp = 0.00000f;
1164 if (curContact.depth > 0.1f)
1165 {
1166 curContact.depth *= 52;
1167 //contact.normal = new d.Vector3(0, 0, 1);
1168 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1169 }
1170 WaterContact.geom = curContact;
1171 _perloopContact.Add(curContact);
1172 if (m_global_contactcount < maxContactsbeforedeath)
1173 {
1174 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1175 m_global_contactcount++;
1176 }
1177 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1178 }
1179 else
1180 {
1181 // we're colliding with prim or avatar
1182 // check if we're moving
1183 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1184 {
1185 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1186 {
1187 // Use the Movement prim contact
1188 AvatarMovementprimContact.geom = curContact;
1189 _perloopContact.Add(curContact);
1190 if (m_global_contactcount < maxContactsbeforedeath)
1191 {
1192 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1193 m_global_contactcount++;
1194 }
1195 }
1196 else
1197 {
1198 // Use the non movement contact
1199 contact.geom = curContact;
1200 _perloopContact.Add(curContact);
1201
1202 if (m_global_contactcount < maxContactsbeforedeath)
1203 {
1204 joint = d.JointCreateContact(world, contactgroup, ref contact);
1205 m_global_contactcount++;
1206 }
1207 }
1208 }
1209 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1210 {
1211 //p1.PhysicsActorType
1212 int material = (int)Material.Wood;
1213
1214 if (p2 is OdePrim)
1215 material = ((OdePrim)p2).m_material;
1216
1217 //m_log.DebugFormat("Material: {0}", material);
1218 m_materialContacts[material, 0].geom = curContact;
1219 _perloopContact.Add(curContact);
1220
1221 if (m_global_contactcount < maxContactsbeforedeath)
1222 {
1223 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1224 m_global_contactcount++;
1225
1226 }
1227 }
1228 }
1229
1230 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1231 {
1232 d.JointAttach(joint, b1, b2);
1233 m_global_contactcount++;
1234 }
1235
1236 }
1237 collision_accounting_events(p1, p2, maxDepthContact);
1238 if (count > geomContactPointsStartthrottle)
1239 {
1240 // If there are more then 3 contact points, it's likely
1241 // that we've got a pile of objects, so ...
1242 // We don't want to send out hundreds of terse updates over and over again
1243 // so lets throttle them and send them again after it's somewhat sorted out.
1244 p2.ThrottleUpdates = true;
1245 }
1246 //m_log.Debug(count.ToString());
1247 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1248 }
1249 }
1250
1251 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1252 {
1253 bool result = false;
1254 //return result;
1255 if (!m_filterCollisions)
1256 return false;
1257
1258 ActorTypes at = (ActorTypes)atype;
1259 lock (_perloopContact)
1260 {
1261 foreach (d.ContactGeom contact in _perloopContact)
1262 {
1263 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1264 //{
1265 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1266 if (at == ActorTypes.Agent)
1267 {
1268 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1269 {
1270
1271 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1272 {
1273 //contactGeom.depth *= .00005f;
1274 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1275 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1276 result = true;
1277 break;
1278 }
1279 else
1280 {
1281 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1282 }
1283 }
1284 else
1285 {
1286 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1287 //int i = 0;
1288 }
1289 }
1290 else if (at == ActorTypes.Prim)
1291 {
1292 //d.AABB aabb1 = new d.AABB();
1293 //d.AABB aabb2 = new d.AABB();
1294
1295 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1296 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1297 //aabb1.
1298 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)) && contactGeom.g1 != LandGeom && contactGeom.g2 != LandGeom)
1299 {
1300 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1301 {
1302 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1303 {
1304 result = true;
1305 break;
1306 }
1307 }
1308 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1309 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1310 }
1311
1312 }
1313
1314 //}
1315
1316 }
1317 }
1318 return result;
1319 }
1320
1321 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1322 {
1323 // obj1LocalID = 0;
1324 //returncollisions = false;
1325 obj2LocalID = 0;
1326 //ctype = 0;
1327 //cStartStop = 0;
1328 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1329 return;
1330
1331 switch ((ActorTypes)p2.PhysicsActorType)
1332 {
1333 case ActorTypes.Agent:
1334 cc2 = (OdeCharacter)p2;
1335
1336 // obj1LocalID = cc2.m_localID;
1337 switch ((ActorTypes)p1.PhysicsActorType)
1338 {
1339 case ActorTypes.Agent:
1340 cc1 = (OdeCharacter)p1;
1341 obj2LocalID = cc1.m_localID;
1342 cc1.AddCollisionEvent(cc2.m_localID, contact);
1343 //ctype = (int)CollisionCategories.Character;
1344
1345 //if (cc1.CollidingObj)
1346 //cStartStop = (int)StatusIndicators.Generic;
1347 //else
1348 //cStartStop = (int)StatusIndicators.Start;
1349
1350 //returncollisions = true;
1351 break;
1352 case ActorTypes.Prim:
1353 if (p1 is OdePrim)
1354 {
1355 cp1 = (OdePrim) p1;
1356 obj2LocalID = cp1.m_localID;
1357 cp1.AddCollisionEvent(cc2.m_localID, contact);
1358 }
1359 //ctype = (int)CollisionCategories.Geom;
1360
1361 //if (cp1.CollidingObj)
1362 //cStartStop = (int)StatusIndicators.Generic;
1363 //else
1364 //cStartStop = (int)StatusIndicators.Start;
1365
1366 //returncollisions = true;
1367 break;
1368
1369 case ActorTypes.Ground:
1370 case ActorTypes.Unknown:
1371 obj2LocalID = 0;
1372 //ctype = (int)CollisionCategories.Land;
1373 //returncollisions = true;
1374 break;
1375 }
1376
1377 cc2.AddCollisionEvent(obj2LocalID, contact);
1378 break;
1379 case ActorTypes.Prim:
1380
1381 if (p2 is OdePrim)
1382 {
1383 cp2 = (OdePrim) p2;
1384
1385 // obj1LocalID = cp2.m_localID;
1386 switch ((ActorTypes) p1.PhysicsActorType)
1387 {
1388 case ActorTypes.Agent:
1389 if (p1 is OdeCharacter)
1390 {
1391 cc1 = (OdeCharacter) p1;
1392 obj2LocalID = cc1.m_localID;
1393 cc1.AddCollisionEvent(cp2.m_localID, contact);
1394 //ctype = (int)CollisionCategories.Character;
1395
1396 //if (cc1.CollidingObj)
1397 //cStartStop = (int)StatusIndicators.Generic;
1398 //else
1399 //cStartStop = (int)StatusIndicators.Start;
1400 //returncollisions = true;
1401 }
1402 break;
1403 case ActorTypes.Prim:
1404
1405 if (p1 is OdePrim)
1406 {
1407 cp1 = (OdePrim) p1;
1408 obj2LocalID = cp1.m_localID;
1409 cp1.AddCollisionEvent(cp2.m_localID, contact);
1410 //ctype = (int)CollisionCategories.Geom;
1411
1412 //if (cp1.CollidingObj)
1413 //cStartStop = (int)StatusIndicators.Generic;
1414 //else
1415 //cStartStop = (int)StatusIndicators.Start;
1416
1417 //returncollisions = true;
1418 }
1419 break;
1420
1421 case ActorTypes.Ground:
1422 case ActorTypes.Unknown:
1423 obj2LocalID = 0;
1424 //ctype = (int)CollisionCategories.Land;
1425
1426 //returncollisions = true;
1427 break;
1428 }
1429
1430 cp2.AddCollisionEvent(obj2LocalID, contact);
1431 }
1432 break;
1433 }
1434 //if (returncollisions)
1435 //{
1436
1437 //lock (m_storedCollisions)
1438 //{
1439 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1440 //if (m_storedCollisions.ContainsKey(cDictKey))
1441 //{
1442 //sCollisionData objd = m_storedCollisions[cDictKey];
1443 //objd.NumberOfCollisions += 1;
1444 //objd.lastframe = framecount;
1445 //m_storedCollisions[cDictKey] = objd;
1446 //}
1447 //else
1448 //{
1449 //sCollisionData objd = new sCollisionData();
1450 //objd.ColliderLocalId = obj1LocalID;
1451 //objd.CollidedWithLocalId = obj2LocalID;
1452 //objd.CollisionType = ctype;
1453 //objd.NumberOfCollisions = 1;
1454 //objd.lastframe = framecount;
1455 //objd.StatusIndicator = cStartStop;
1456 //m_storedCollisions.Add(cDictKey, objd);
1457 //}
1458 //}
1459 // }
1460 }
1461
1462 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1463 {
1464 /* String name1 = null;
1465 String name2 = null;
1466
1467 if (!geom_name_map.TryGetValue(trimesh, out name1))
1468 {
1469 name1 = "null";
1470 }
1471 if (!geom_name_map.TryGetValue(refObject, out name2))
1472 {
1473 name2 = "null";
1474 }
1475
1476 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1477 */
1478 return 1;
1479 }
1480
1481 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1482 {
1483 String name1 = null;
1484 String name2 = null;
1485
1486 if (!geom_name_map.TryGetValue(trimesh, out name1))
1487 {
1488 name1 = "null";
1489 }
1490
1491 if (!geom_name_map.TryGetValue(refObject, out name2))
1492 {
1493 name2 = "null";
1494 }
1495
1496 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1497
1498 d.Vector3 v0 = new d.Vector3();
1499 d.Vector3 v1 = new d.Vector3();
1500 d.Vector3 v2 = new d.Vector3();
1501
1502 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1503 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1504
1505 return 1;
1506 }
1507
1508 /// <summary>
1509 /// This is our collision testing routine in ODE
1510 /// </summary>
1511 /// <param name="timeStep"></param>
1512 private void collision_optimized(float timeStep)
1513 {
1514 _perloopContact.Clear();
1515
1516 lock (_characters)
1517 {
1518 foreach (OdeCharacter chr in _characters)
1519 {
1520 // Reset the collision values to false
1521 // since we don't know if we're colliding yet
1522
1523 // For some reason this can happen. Don't ask...
1524 //
1525 if (chr == null)
1526 continue;
1527
1528 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1529 continue;
1530
1531 chr.IsColliding = false;
1532 chr.CollidingGround = false;
1533 chr.CollidingObj = false;
1534
1535 // test the avatar's geometry for collision with the space
1536 // This will return near and the space that they are the closest to
1537 // And we'll run this again against the avatar and the space segment
1538 // This will return with a bunch of possible objects in the space segment
1539 // and we'll run it again on all of them.
1540 try
1541 {
1542 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1543 }
1544 catch (AccessViolationException)
1545 {
1546 m_log.Warn("[PHYSICS]: Unable to space collide");
1547 }
1548 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1549 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1550 //{
1551 //chr.Position.Z = terrainheight + 10.0f;
1552 //forcedZ = true;
1553 //}
1554 }
1555 }
1556
1557 lock (_activeprims)
1558 {
1559 List<OdePrim> removeprims = null;
1560 foreach (OdePrim chr in _activeprims)
1561 {
1562 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1563 {
1564 try
1565 {
1566 lock (chr)
1567 {
1568 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1569 {
1570 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1571 }
1572 else
1573 {
1574 if (removeprims == null)
1575 {
1576 removeprims = new List<OdePrim>();
1577 }
1578 removeprims.Add(chr);
1579 m_log.Debug("[PHYSICS]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1580 }
1581 }
1582 }
1583 catch (AccessViolationException)
1584 {
1585 m_log.Warn("[PHYSICS]: Unable to space collide");
1586 }
1587 }
1588 }
1589 if (removeprims != null)
1590 {
1591 foreach (OdePrim chr in removeprims)
1592 {
1593 _activeprims.Remove(chr);
1594 }
1595 }
1596 }
1597
1598 _perloopContact.Clear();
1599 }
1600
1601 #endregion
1602
1603 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1604 {
1605 m_worldOffset = offset;
1606 WorldExtents = new Vector2(extents.X, extents.Y);
1607 m_parentScene = pScene;
1608
1609 }
1610
1611 // Recovered for use by fly height. Kitto Flora
1612 public float GetTerrainHeightAtXY(float x, float y)
1613 {
1614
1615 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1616 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1617
1618 IntPtr heightFieldGeom = IntPtr.Zero;
1619
1620 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1621 {
1622 if (heightFieldGeom != IntPtr.Zero)
1623 {
1624 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1625 {
1626
1627 int index;
1628
1629
1630 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1631 (int)x < 0.001f || (int)y < 0.001f)
1632 return 0;
1633
1634 x = x - offsetX;
1635 y = y - offsetY;
1636
1637 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1638
1639 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1640 {
1641 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1642 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1643 }
1644
1645 else
1646 return 0f;
1647 }
1648 else
1649 {
1650 return 0f;
1651 }
1652
1653 }
1654 else
1655 {
1656 return 0f;
1657 }
1658
1659 }
1660 else
1661 {
1662 return 0f;
1663 }
1664
1665
1666 }
1667// End recovered. Kitto Flora
1668
1669 public void addCollisionEventReporting(PhysicsActor obj)
1670 {
1671 lock (_collisionEventPrim)
1672 {
1673 if (!_collisionEventPrim.Contains(obj))
1674 _collisionEventPrim.Add(obj);
1675 }
1676 }
1677
1678 public void remCollisionEventReporting(PhysicsActor obj)
1679 {
1680 lock (_collisionEventPrim)
1681 {
1682 if (!_collisionEventPrim.Contains(obj))
1683 _collisionEventPrim.Remove(obj);
1684 }
1685 }
1686
1687 #region Add/Remove Entities
1688
1689 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1690 {
1691 Vector3 pos;
1692 pos.X = position.X;
1693 pos.Y = position.Y;
1694 pos.Z = position.Z;
1695 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1696 newAv.Flying = isFlying;
1697 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1698
1699 return newAv;
1700 }
1701
1702 public void AddCharacter(OdeCharacter chr)
1703 {
1704 lock (_characters)
1705 {
1706 if (!_characters.Contains(chr))
1707 {
1708 _characters.Add(chr);
1709 if (chr.bad)
1710 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1711 }
1712 }
1713 }
1714
1715 public void RemoveCharacter(OdeCharacter chr)
1716 {
1717 lock (_characters)
1718 {
1719 if (_characters.Contains(chr))
1720 {
1721 _characters.Remove(chr);
1722 }
1723 }
1724 }
1725 public void BadCharacter(OdeCharacter chr)
1726 {
1727 lock (_badCharacter)
1728 {
1729 if (!_badCharacter.Contains(chr))
1730 _badCharacter.Add(chr);
1731 }
1732 }
1733
1734 public override void RemoveAvatar(PhysicsActor actor)
1735 {
1736 //m_log.Debug("[PHYSICS]:ODELOCK");
1737 ((OdeCharacter) actor).Destroy();
1738
1739 }
1740
1741 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1742 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1743 {
1744
1745 Vector3 pos = position;
1746 Vector3 siz = size;
1747 Quaternion rot = rotation;
1748
1749 OdePrim newPrim;
1750 lock (OdeLock)
1751 {
1752 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1753
1754 lock (_prims)
1755 _prims.Add(newPrim);
1756 }
1757
1758 return newPrim;
1759 }
1760
1761 public void addActivePrim(OdePrim activatePrim)
1762 {
1763 // adds active prim.. (ones that should be iterated over in collisions_optimized
1764 lock (_activeprims)
1765 {
1766 if (!_activeprims.Contains(activatePrim))
1767 _activeprims.Add(activatePrim);
1768 //else
1769 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1770 }
1771 }
1772
1773 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1774 Vector3 size, Quaternion rotation) //To be removed
1775 {
1776 return AddPrimShape(primName, pbs, position, size, rotation, false);
1777 }
1778
1779 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1780 Vector3 size, Quaternion rotation, bool isPhysical)
1781 {
1782 PhysicsActor result;
1783 IMesh mesh = null;
1784
1785 if (needsMeshing(pbs))
1786 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1787
1788 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1789
1790 return result;
1791 }
1792
1793 public override float TimeDilation
1794 {
1795 get { return m_timeDilation; }
1796 }
1797
1798 public override bool SupportsNINJAJoints
1799 {
1800 get { return m_NINJA_physics_joints_enabled; }
1801 }
1802
1803 // internal utility function: must be called within a lock (OdeLock)
1804 private void InternalAddActiveJoint(PhysicsJoint joint)
1805 {
1806 activeJoints.Add(joint);
1807 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1808 }
1809
1810 // internal utility function: must be called within a lock (OdeLock)
1811 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1812 {
1813 pendingJoints.Add(joint);
1814 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1815 }
1816
1817 // internal utility function: must be called within a lock (OdeLock)
1818 private void InternalRemovePendingJoint(PhysicsJoint joint)
1819 {
1820 pendingJoints.Remove(joint);
1821 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1822 }
1823
1824 // internal utility function: must be called within a lock (OdeLock)
1825 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1826 {
1827 activeJoints.Remove(joint);
1828 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1829 }
1830
1831 public override void DumpJointInfo()
1832 {
1833 string hdr = "[NINJA] JOINTINFO: ";
1834 foreach (PhysicsJoint j in pendingJoints)
1835 {
1836 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1837 }
1838 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1839 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1840 {
1841 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1842 }
1843 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1844 foreach (PhysicsJoint j in activeJoints)
1845 {
1846 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1847 }
1848 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1849 foreach (string jointName in SOPName_to_activeJoint.Keys)
1850 {
1851 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1852 }
1853 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1854
1855 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1856 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1857 foreach (string actorName in joints_connecting_actor.Keys)
1858 {
1859 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1860 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1861 {
1862 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1863 }
1864 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1865 }
1866 }
1867
1868 public override void RequestJointDeletion(string ObjectNameInScene)
1869 {
1870 lock (externalJointRequestsLock)
1871 {
1872 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1873 {
1874 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1875 }
1876 }
1877 }
1878
1879 private void DeleteRequestedJoints()
1880 {
1881 List<string> myRequestedJointsToBeDeleted;
1882 lock (externalJointRequestsLock)
1883 {
1884 // make a local copy of the shared list for processing (threading issues)
1885 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1886 }
1887
1888 foreach (string jointName in myRequestedJointsToBeDeleted)
1889 {
1890 lock (OdeLock)
1891 {
1892 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1893 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1894 {
1895 OdePhysicsJoint joint = null;
1896 if (SOPName_to_activeJoint.ContainsKey(jointName))
1897 {
1898 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1899 InternalRemoveActiveJoint(joint);
1900 }
1901 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1902 {
1903 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1904 InternalRemovePendingJoint(joint);
1905 }
1906
1907 if (joint != null)
1908 {
1909 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1910 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1911 {
1912 string bodyName = joint.BodyNames[iBodyName];
1913 if (bodyName != "NULL")
1914 {
1915 joints_connecting_actor[bodyName].Remove(joint);
1916 if (joints_connecting_actor[bodyName].Count == 0)
1917 {
1918 joints_connecting_actor.Remove(bodyName);
1919 }
1920 }
1921 }
1922
1923 DoJointDeactivated(joint);
1924 if (joint.jointID != IntPtr.Zero)
1925 {
1926 d.JointDestroy(joint.jointID);
1927 joint.jointID = IntPtr.Zero;
1928 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1929 }
1930 else
1931 {
1932 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1933 }
1934 }
1935 else
1936 {
1937 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1938 }
1939 }
1940 else
1941 {
1942 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1943 }
1944 }
1945 }
1946
1947 // remove processed joints from the shared list
1948 lock (externalJointRequestsLock)
1949 {
1950 foreach (string jointName in myRequestedJointsToBeDeleted)
1951 {
1952 requestedJointsToBeDeleted.Remove(jointName);
1953 }
1954 }
1955 }
1956
1957 // for pending joints we don't know if their associated bodies exist yet or not.
1958 // the joint is actually created during processing of the taints
1959 private void CreateRequestedJoints()
1960 {
1961 List<PhysicsJoint> myRequestedJointsToBeCreated;
1962 lock (externalJointRequestsLock)
1963 {
1964 // make a local copy of the shared list for processing (threading issues)
1965 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1966 }
1967
1968 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1969 {
1970 lock (OdeLock)
1971 {
1972 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1973 {
1974 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1975 continue;
1976 }
1977 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1978 {
1979 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
1980 continue;
1981 }
1982
1983 InternalAddPendingJoint(joint as OdePhysicsJoint);
1984
1985 if (joint.BodyNames.Count >= 2)
1986 {
1987 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1988 {
1989 string bodyName = joint.BodyNames[iBodyName];
1990 if (bodyName != "NULL")
1991 {
1992 if (!joints_connecting_actor.ContainsKey(bodyName))
1993 {
1994 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1995 }
1996 joints_connecting_actor[bodyName].Add(joint);
1997 }
1998 }
1999 }
2000 }
2001 }
2002
2003 // remove processed joints from shared list
2004 lock (externalJointRequestsLock)
2005 {
2006 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2007 {
2008 requestedJointsToBeCreated.Remove(joint);
2009 }
2010 }
2011
2012 }
2013
2014 // public function to add an request for joint creation
2015 // this joint will just be added to a waiting list that is NOT processed during the main
2016 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2017
2018 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2019 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2020
2021 {
2022
2023 OdePhysicsJoint joint = new OdePhysicsJoint();
2024 joint.ObjectNameInScene = objectNameInScene;
2025 joint.Type = jointType;
2026 joint.Position = position;
2027 joint.Rotation = rotation;
2028 joint.RawParams = parms;
2029 joint.BodyNames = new List<string>(bodyNames);
2030 joint.TrackedBodyName = trackedBodyName;
2031 joint.LocalRotation = localRotation;
2032 joint.jointID = IntPtr.Zero;
2033 joint.ErrorMessageCount = 0;
2034
2035 lock (externalJointRequestsLock)
2036 {
2037 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2038 {
2039 requestedJointsToBeCreated.Add(joint);
2040 }
2041 }
2042 return joint;
2043 }
2044
2045 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2046 {
2047 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2048 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2049 {
2050
2051 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2052 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2053 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2054 {
2055 jointsToRemove.Add(j);
2056 }
2057 foreach (PhysicsJoint j in jointsToRemove)
2058 {
2059 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2060 RequestJointDeletion(j.ObjectNameInScene);
2061 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2062 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2063 }
2064 }
2065 }
2066
2067 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2068 {
2069 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2070 lock (OdeLock)
2071 {
2072 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2073 RemoveAllJointsConnectedToActor(actor);
2074 }
2075 }
2076
2077 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2078 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2079 {
2080 Debug.Assert(joint.IsInPhysicsEngine);
2081 d.Vector3 pos = new d.Vector3();
2082
2083 if (!(joint is OdePhysicsJoint))
2084 {
2085 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2086 }
2087 else
2088 {
2089 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2090 switch (odeJoint.Type)
2091 {
2092 case PhysicsJointType.Ball:
2093 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2094 break;
2095 case PhysicsJointType.Hinge:
2096 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2097 break;
2098 }
2099 }
2100 return new Vector3(pos.X, pos.Y, pos.Z);
2101 }
2102
2103 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2104 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2105 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2106 // keeping track of the joint's original orientation relative to one of the involved bodies.
2107 public override Vector3 GetJointAxis(PhysicsJoint joint)
2108 {
2109 Debug.Assert(joint.IsInPhysicsEngine);
2110 d.Vector3 axis = new d.Vector3();
2111
2112 if (!(joint is OdePhysicsJoint))
2113 {
2114 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2115 }
2116 else
2117 {
2118 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2119 switch (odeJoint.Type)
2120 {
2121 case PhysicsJointType.Ball:
2122 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2123 break;
2124 case PhysicsJointType.Hinge:
2125 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2126 break;
2127 }
2128 }
2129 return new Vector3(axis.X, axis.Y, axis.Z);
2130 }
2131
2132
2133 public void remActivePrim(OdePrim deactivatePrim)
2134 {
2135 lock (_activeprims)
2136 {
2137 _activeprims.Remove(deactivatePrim);
2138 }
2139 }
2140
2141 public override void RemovePrim(PhysicsActor prim)
2142 {
2143 if (prim is OdePrim)
2144 {
2145 lock (OdeLock)
2146 {
2147 OdePrim p = (OdePrim) prim;
2148
2149 p.setPrimForRemoval();
2150 AddPhysicsActorTaint(prim);
2151 //RemovePrimThreadLocked(p);
2152 }
2153 }
2154 }
2155
2156 /// <summary>
2157 /// This is called from within simulate but outside the locked portion
2158 /// We need to do our own locking here
2159 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2160 ///
2161 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2162 /// that the space was using.
2163 /// </summary>
2164 /// <param name="prim"></param>
2165 public void RemovePrimThreadLocked(OdePrim prim)
2166 {
2167//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2168 lock (prim)
2169 {
2170 remCollisionEventReporting(prim);
2171 lock (ode)
2172 {
2173 if (prim.prim_geom != IntPtr.Zero)
2174 {
2175 prim.ResetTaints();
2176
2177 if (prim.IsPhysical)
2178 {
2179 prim.disableBody();
2180 if (prim.childPrim)
2181 {
2182 prim.childPrim = false;
2183 prim.Body = IntPtr.Zero;
2184 prim.m_disabled = true;
2185 prim.IsPhysical = false;
2186 }
2187
2188
2189 }
2190 // we don't want to remove the main space
2191
2192 // If the geometry is in the targetspace, remove it from the target space
2193 //m_log.Warn(prim.m_targetSpace);
2194
2195 //if (prim.m_targetSpace != IntPtr.Zero)
2196 //{
2197 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2198 //{
2199
2200 //if (d.GeomIsSpace(prim.m_targetSpace))
2201 //{
2202 //waitForSpaceUnlock(prim.m_targetSpace);
2203 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2204 prim.m_targetSpace = IntPtr.Zero;
2205 //}
2206 //else
2207 //{
2208 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2209 //((OdePrim)prim).m_targetSpace.ToString());
2210 //}
2211
2212 //}
2213 //}
2214 //m_log.Warn(prim.prim_geom);
2215 try
2216 {
2217 if (prim.prim_geom != IntPtr.Zero)
2218 {
2219
2220//string tPA;
2221//geom_name_map.TryGetValue(prim.prim_geom, out tPA);
2222//Console.WriteLine("**** Remove {0}", tPA);
2223 if(geom_name_map.ContainsKey(prim.prim_geom)) geom_name_map.Remove(prim.prim_geom);
2224 if(actor_name_map.ContainsKey(prim.prim_geom)) actor_name_map.Remove(prim.prim_geom);
2225 d.GeomDestroy(prim.prim_geom);
2226 prim.prim_geom = IntPtr.Zero;
2227 }
2228 else
2229 {
2230 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2231 }
2232 }
2233 catch (AccessViolationException)
2234 {
2235 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2236 }
2237 lock (_prims)
2238 _prims.Remove(prim);
2239
2240 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2241 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2242 //{
2243 //if (prim.m_targetSpace != null)
2244 //{
2245 //if (d.GeomIsSpace(prim.m_targetSpace))
2246 //{
2247 //waitForSpaceUnlock(prim.m_targetSpace);
2248 //d.SpaceRemove(space, prim.m_targetSpace);
2249 // free up memory used by the space.
2250 //d.SpaceDestroy(prim.m_targetSpace);
2251 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2252 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2253 //}
2254 //else
2255 //{
2256 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2257 //((OdePrim) prim).m_targetSpace.ToString());
2258 //}
2259 //}
2260 //}
2261
2262 if (SupportsNINJAJoints)
2263 {
2264 RemoveAllJointsConnectedToActorThreadLocked(prim);
2265 }
2266 }
2267 }
2268 }
2269 }
2270
2271 #endregion
2272
2273 #region Space Separation Calculation
2274
2275 /// <summary>
2276 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2277 /// </summary>
2278 /// <param name="pSpace"></param>
2279 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2280 {
2281 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2282 {
2283 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2284 {
2285 if (staticPrimspace[x, y] == pSpace)
2286 staticPrimspace[x, y] = IntPtr.Zero;
2287 }
2288 }
2289 }
2290
2291 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2292 {
2293 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2294 }
2295
2296 /// <summary>
2297 /// Called when a static prim moves. Allocates a space for the prim based on its position
2298 /// </summary>
2299 /// <param name="geom">the pointer to the geom that moved</param>
2300 /// <param name="pos">the position that the geom moved to</param>
2301 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2302 /// <returns>a pointer to the new space it's in</returns>
2303 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2304 {
2305 // Called from setting the Position and Size of an ODEPrim so
2306 // it's already in locked space.
2307
2308 // we don't want to remove the main space
2309 // we don't need to test physical here because this function should
2310 // never be called if the prim is physical(active)
2311
2312 // All physical prim end up in the root space
2313 //Thread.Sleep(20);
2314 if (currentspace != space)
2315 {
2316 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2317 //if (currentspace == IntPtr.Zero)
2318 //{
2319 //int adfadf = 0;
2320 //}
2321 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2322 {
2323 if (d.GeomIsSpace(currentspace))
2324 {
2325 waitForSpaceUnlock(currentspace);
2326 d.SpaceRemove(currentspace, geom);
2327 }
2328 else
2329 {
2330 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2331 " Geom:" + geom);
2332 }
2333 }
2334 else
2335 {
2336 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2337 if (sGeomIsIn != IntPtr.Zero)
2338 {
2339 if (d.GeomIsSpace(currentspace))
2340 {
2341 waitForSpaceUnlock(sGeomIsIn);
2342 d.SpaceRemove(sGeomIsIn, geom);
2343 }
2344 else
2345 {
2346 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2347 sGeomIsIn + " Geom:" + geom);
2348 }
2349 }
2350 }
2351
2352 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2353 if (d.SpaceGetNumGeoms(currentspace) == 0)
2354 {
2355 if (currentspace != IntPtr.Zero)
2356 {
2357 if (d.GeomIsSpace(currentspace))
2358 {
2359 waitForSpaceUnlock(currentspace);
2360 waitForSpaceUnlock(space);
2361 d.SpaceRemove(space, currentspace);
2362 // free up memory used by the space.
2363
2364 //d.SpaceDestroy(currentspace);
2365 resetSpaceArrayItemToZero(currentspace);
2366 }
2367 else
2368 {
2369 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2370 currentspace + " Geom:" + geom);
2371 }
2372 }
2373 }
2374 }
2375 else
2376 {
2377 // this is a physical object that got disabled. ;.;
2378 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2379 {
2380 if (d.SpaceQuery(currentspace, geom))
2381 {
2382 if (d.GeomIsSpace(currentspace))
2383 {
2384 waitForSpaceUnlock(currentspace);
2385 d.SpaceRemove(currentspace, geom);
2386 }
2387 else
2388 {
2389 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2390 currentspace + " Geom:" + geom);
2391 }
2392 }
2393 else
2394 {
2395 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2396 if (sGeomIsIn != IntPtr.Zero)
2397 {
2398 if (d.GeomIsSpace(sGeomIsIn))
2399 {
2400 waitForSpaceUnlock(sGeomIsIn);
2401 d.SpaceRemove(sGeomIsIn, geom);
2402 }
2403 else
2404 {
2405 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2406 sGeomIsIn + " Geom:" + geom);
2407 }
2408 }
2409 }
2410 }
2411 }
2412
2413 // The routines in the Position and Size sections do the 'inserting' into the space,
2414 // so all we have to do is make sure that the space that we're putting the prim into
2415 // is in the 'main' space.
2416 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2417 IntPtr newspace = calculateSpaceForGeom(pos);
2418
2419 if (newspace == IntPtr.Zero)
2420 {
2421 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2422 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2423 }
2424
2425 return newspace;
2426 }
2427
2428 /// <summary>
2429 /// Creates a new space at X Y
2430 /// </summary>
2431 /// <param name="iprimspaceArrItemX"></param>
2432 /// <param name="iprimspaceArrItemY"></param>
2433 /// <returns>A pointer to the created space</returns>
2434 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2435 {
2436 // creating a new space for prim and inserting it into main space.
2437 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2438 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2439 waitForSpaceUnlock(space);
2440 d.SpaceSetSublevel(space, 1);
2441 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2442 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2443 }
2444
2445 /// <summary>
2446 /// Calculates the space the prim should be in by its position
2447 /// </summary>
2448 /// <param name="pos"></param>
2449 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2450 public IntPtr calculateSpaceForGeom(Vector3 pos)
2451 {
2452 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2453 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2454 return staticPrimspace[xyspace[0], xyspace[1]];
2455 }
2456
2457 /// <summary>
2458 /// Holds the space allocation logic
2459 /// </summary>
2460 /// <param name="pos"></param>
2461 /// <returns>an array item based on the position</returns>
2462 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2463 {
2464 int[] returnint = new int[2];
2465
2466 returnint[0] = (int) (pos.X/metersInSpace);
2467
2468 if (returnint[0] > ((int) (259f/metersInSpace)))
2469 returnint[0] = ((int) (259f/metersInSpace));
2470 if (returnint[0] < 0)
2471 returnint[0] = 0;
2472
2473 returnint[1] = (int) (pos.Y/metersInSpace);
2474 if (returnint[1] > ((int) (259f/metersInSpace)))
2475 returnint[1] = ((int) (259f/metersInSpace));
2476 if (returnint[1] < 0)
2477 returnint[1] = 0;
2478
2479 return returnint;
2480 }
2481
2482 #endregion
2483
2484 /// <summary>
2485 /// Routine to figure out if we need to mesh this prim with our mesher
2486 /// </summary>
2487 /// <param name="pbs"></param>
2488 /// <returns></returns>
2489 public bool needsMeshing(PrimitiveBaseShape pbs)
2490 {
2491 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2492 // but we still need to check for sculptie meshing being enabled so this is the most
2493 // convenient place to do it for now...
2494
2495 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2496 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2497 int iPropertiesNotSupportedDefault = 0;
2498
2499 if (pbs.SculptEntry && !meshSculptedPrim)
2500 {
2501#if SPAM
2502 m_log.Warn("NonMesh");
2503#endif
2504 return false;
2505 }
2506
2507 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2508 if (!forceSimplePrimMeshing)
2509 {
2510 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2511 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2512 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2513 {
2514
2515 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2516 && pbs.ProfileHollow == 0
2517 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2518 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2519 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2520 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2521 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2522 {
2523#if SPAM
2524 m_log.Warn("NonMesh");
2525#endif
2526 return false;
2527 }
2528 }
2529 }
2530
2531 if (pbs.ProfileHollow != 0)
2532 iPropertiesNotSupportedDefault++;
2533
2534 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2535 iPropertiesNotSupportedDefault++;
2536
2537 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2538 iPropertiesNotSupportedDefault++;
2539
2540 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2541 iPropertiesNotSupportedDefault++;
2542
2543 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2544 iPropertiesNotSupportedDefault++;
2545
2546 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2547 iPropertiesNotSupportedDefault++;
2548
2549 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
2550 iPropertiesNotSupportedDefault++;
2551
2552 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2553 iPropertiesNotSupportedDefault++;
2554
2555 // test for torus
2556 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2557 {
2558 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2559 {
2560 iPropertiesNotSupportedDefault++;
2561 }
2562 }
2563 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2564 {
2565 if (pbs.PathCurve == (byte)Extrusion.Straight)
2566 {
2567 iPropertiesNotSupportedDefault++;
2568 }
2569
2570 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2571 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2572 {
2573 iPropertiesNotSupportedDefault++;
2574 }
2575 }
2576 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2577 {
2578 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2579 {
2580 iPropertiesNotSupportedDefault++;
2581 }
2582 }
2583 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2584 {
2585 if (pbs.PathCurve == (byte)Extrusion.Straight)
2586 {
2587 iPropertiesNotSupportedDefault++;
2588 }
2589 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2590 {
2591 iPropertiesNotSupportedDefault++;
2592 }
2593 }
2594
2595
2596 if (iPropertiesNotSupportedDefault == 0)
2597 {
2598#if SPAM
2599 m_log.Warn("NonMesh");
2600#endif
2601 return false;
2602 }
2603#if SPAM
2604 m_log.Debug("Mesh");
2605#endif
2606 return true;
2607 }
2608
2609 /// <summary>
2610 /// Called after our prim properties are set Scale, position etc.
2611 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2612 /// This assures us that we have no race conditions
2613 /// </summary>
2614 /// <param name="prim"></param>
2615 public override void AddPhysicsActorTaint(PhysicsActor prim)
2616 {
2617
2618 if (prim is OdePrim)
2619 {
2620 OdePrim taintedprim = ((OdePrim) prim);
2621 lock (_taintedPrimLock)
2622 {
2623 if (!(_taintedPrimH.Contains(taintedprim)))
2624 {
2625//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2626 _taintedPrimH.Add(taintedprim); // HashSet for searching
2627 _taintedPrimL.Add(taintedprim); // List for ordered readout
2628 }
2629 }
2630 return;
2631 }
2632 else if (prim is OdeCharacter)
2633 {
2634 OdeCharacter taintedchar = ((OdeCharacter)prim);
2635 lock (_taintedActors)
2636 {
2637 if (!(_taintedActors.Contains(taintedchar)))
2638 {
2639 _taintedActors.Add(taintedchar);
2640 if (taintedchar.bad)
2641 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2642 }
2643 }
2644 }
2645 }
2646
2647 /// <summary>
2648 /// This is our main simulate loop
2649 /// It's thread locked by a Mutex in the scene.
2650 /// It holds Collisions, it instructs ODE to step through the physical reactions
2651 /// It moves the objects around in memory
2652 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2653 /// </summary>
2654 /// <param name="timeStep"></param>
2655 /// <returns></returns>
2656 public override float Simulate(float timeStep)
2657 {
2658 if (framecount >= int.MaxValue)
2659 framecount = 0;
2660 //if (m_worldOffset != Vector3.Zero)
2661 // return 0;
2662
2663 framecount++;
2664
2665 DateTime now = DateTime.UtcNow;
2666 TimeSpan SinceLastFrame = now - m_lastframe;
2667 m_lastframe = now;
2668 float realtime = (float)SinceLastFrame.TotalSeconds;
2669// Console.WriteLine("ts={0} rt={1}", timeStep, realtime);
2670 timeStep = realtime;
2671
2672 // float fps = 1.0f / realtime;
2673 float fps = 0.0f; // number of ODE steps in this Simulate step
2674 //m_log.Info(timeStep.ToString());
2675 step_time += timeStep;
2676
2677 // If We're loaded down by something else,
2678 // or debugging with the Visual Studio project on pause
2679 // skip a few frames to catch up gracefully.
2680 // without shooting the physicsactors all over the place
2681
2682 if (step_time >= m_SkipFramesAtms)
2683 {
2684 // Instead of trying to catch up, it'll do 5 physics frames only
2685 step_time = ODE_STEPSIZE;
2686 m_physicsiterations = 5;
2687 }
2688 else
2689 {
2690 m_physicsiterations = 10;
2691 }
2692
2693 if (SupportsNINJAJoints)
2694 {
2695 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2696 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2697 }
2698
2699 lock (OdeLock)
2700 {
2701 // Process 10 frames if the sim is running normal..
2702 // process 5 frames if the sim is running slow
2703 //try
2704 //{
2705 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2706 //}
2707 //catch (StackOverflowException)
2708 //{
2709 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2710 // ode.drelease(world);
2711 //base.TriggerPhysicsBasedRestart();
2712 //}
2713
2714 int i = 0;
2715
2716 // Figure out the Frames Per Second we're going at.
2717 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2718
2719 // fps = (step_time / ODE_STEPSIZE) * 1000;
2720 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2721 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2722
2723 // step_time = 0.09375f;
2724
2725 while (step_time > 0.0f)
2726 {
2727 //lock (ode)
2728 //{
2729 //if (!ode.lockquery())
2730 //{
2731 // ode.dlock(world);
2732 try
2733 {
2734 // Insert, remove Characters
2735 bool processedtaints = false;
2736
2737 lock (_taintedActors)
2738 {
2739 if (_taintedActors.Count > 0)
2740 {
2741 foreach (OdeCharacter character in _taintedActors)
2742 {
2743
2744 character.ProcessTaints(ODE_STEPSIZE);
2745
2746 processedtaints = true;
2747 //character.m_collisionscore = 0;
2748 }
2749
2750 if (processedtaints)
2751 _taintedActors.Clear();
2752 }
2753 } // end lock _taintedActors
2754
2755 // Modify other objects in the scene.
2756 processedtaints = false;
2757
2758 lock (_taintedPrimLock)
2759 {
2760 foreach (OdePrim prim in _taintedPrimL)
2761 {
2762 if (prim.m_taintremove)
2763 {
2764 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2765 RemovePrimThreadLocked(prim);
2766 }
2767 else
2768 {
2769 //Console.WriteLine("Simulate calls ProcessTaints");
2770 prim.ProcessTaints(ODE_STEPSIZE);
2771 }
2772 processedtaints = true;
2773 prim.m_collisionscore = 0;
2774
2775 // This loop can block up the Heartbeat for a very long time on large regions.
2776 // We need to let the Watchdog know that the Heartbeat is not dead
2777 // NOTE: This is currently commented out, but if things like OAR loading are
2778 // timing the heartbeat out we will need to uncomment it
2779 //Watchdog.UpdateThread();
2780 }
2781
2782 if (SupportsNINJAJoints)
2783 {
2784 // Create pending joints, if possible
2785
2786 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2787 // a joint requires specifying the body id of both involved bodies
2788 if (pendingJoints.Count > 0)
2789 {
2790 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2791 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2792 foreach (PhysicsJoint joint in pendingJoints)
2793 {
2794 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2795 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(),
2796 System.StringSplitOptions.RemoveEmptyEntries);
2797 List<IntPtr> jointBodies = new List<IntPtr>();
2798 bool allJointBodiesAreReady = true;
2799 foreach (string jointParam in jointParams)
2800 {
2801 if (jointParam == "NULL")
2802 {
2803 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2804 jointBodies.Add(IntPtr.Zero);
2805 }
2806 else
2807 {
2808 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2809 bool foundPrim = false;
2810 lock (_prims)
2811 {
2812 foreach (OdePrim prim in _prims) // FIXME: inefficient
2813 {
2814 if (prim.SOPName == jointParam)
2815 {
2816 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2817 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2818 {
2819 jointBodies.Add(prim.Body);
2820 foundPrim = true;
2821 break;
2822 }
2823 else
2824 {
2825 DoJointErrorMessage(joint, "prim name " + jointParam +
2826 " exists but is not (yet) physical; deferring joint creation. " +
2827 "IsPhysical property is " + prim.IsPhysical +
2828 " and body is " + prim.Body);
2829 foundPrim = false;
2830 break;
2831 }
2832 }
2833 }
2834 }
2835 if (foundPrim)
2836 {
2837 // all is fine
2838 }
2839 else
2840 {
2841 allJointBodiesAreReady = false;
2842 break;
2843 }
2844 }
2845 }
2846 if (allJointBodiesAreReady)
2847 {
2848 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2849 if (jointBodies[0] == jointBodies[1])
2850 {
2851 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2852 }
2853 else
2854 {
2855 switch (joint.Type)
2856 {
2857 case PhysicsJointType.Ball:
2858 {
2859 IntPtr odeJoint;
2860 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2861 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2862 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2863 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2864 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2865 d.JointSetBallAnchor(odeJoint,
2866 joint.Position.X,
2867 joint.Position.Y,
2868 joint.Position.Z);
2869 //DoJointErrorMessage(joint, "ODE joint setting OK");
2870 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2871 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2872 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2873 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2874
2875 if (joint is OdePhysicsJoint)
2876 {
2877 ((OdePhysicsJoint)joint).jointID = odeJoint;
2878 }
2879 else
2880 {
2881 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2882 }
2883 }
2884 break;
2885 case PhysicsJointType.Hinge:
2886 {
2887 IntPtr odeJoint;
2888 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2889 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2890 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2891 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2892 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2893 d.JointSetHingeAnchor(odeJoint,
2894 joint.Position.X,
2895 joint.Position.Y,
2896 joint.Position.Z);
2897 // We use the orientation of the x-axis of the joint's coordinate frame
2898 // as the axis for the hinge.
2899
2900 // Therefore, we must get the joint's coordinate frame based on the
2901 // joint.Rotation field, which originates from the orientation of the
2902 // joint's proxy object in the scene.
2903
2904 // The joint's coordinate frame is defined as the transformation matrix
2905 // that converts a vector from joint-local coordinates into world coordinates.
2906 // World coordinates are defined as the XYZ coordinate system of the sim,
2907 // as shown in the top status-bar of the viewer.
2908
2909 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2910 // and use that as the hinge axis.
2911
2912 //joint.Rotation.Normalize();
2913 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2914
2915 // Now extract the X axis of the joint's coordinate frame.
2916
2917 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2918 // tar pit of transposed, inverted, and generally messed-up orientations.
2919 // (In other words, Matrix4.AtAxis() is borked.)
2920 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2921
2922 // Instead, compute the X axis of the coordinate frame by transforming
2923 // the (1,0,0) vector. At least that works.
2924
2925 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2926 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2927 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2928 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2929 d.JointSetHingeAxis(odeJoint,
2930 jointAxis.X,
2931 jointAxis.Y,
2932 jointAxis.Z);
2933 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2934 if (joint is OdePhysicsJoint)
2935 {
2936 ((OdePhysicsJoint)joint).jointID = odeJoint;
2937 }
2938 else
2939 {
2940 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2941 }
2942 }
2943 break;
2944 }
2945 successfullyProcessedPendingJoints.Add(joint);
2946 }
2947 }
2948 else
2949 {
2950 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2951 }
2952 }
2953 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2954 {
2955 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2956 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2957 InternalRemovePendingJoint(successfullyProcessedJoint);
2958 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2959 InternalAddActiveJoint(successfullyProcessedJoint);
2960 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2961 }
2962 }
2963 } // end SupportsNINJAJoints
2964
2965 if (processedtaints)
2966//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2967 _taintedPrimH.Clear(); // ??? if this only ???
2968 _taintedPrimL.Clear();
2969 } // end lock _taintedPrimLock
2970
2971 // Move characters
2972 lock (_characters)
2973 {
2974 List<OdeCharacter> defects = new List<OdeCharacter>();
2975 foreach (OdeCharacter actor in _characters)
2976 {
2977 if (actor != null)
2978 actor.Move(ODE_STEPSIZE, defects);
2979 }
2980 if (0 != defects.Count)
2981 {
2982 foreach (OdeCharacter defect in defects)
2983 {
2984 RemoveCharacter(defect);
2985 }
2986 }
2987 } // end lock _characters
2988
2989 // Move other active objects
2990 lock (_activeprims)
2991 {
2992 foreach (OdePrim prim in _activeprims)
2993 {
2994 prim.m_collisionscore = 0;
2995 prim.Move(ODE_STEPSIZE);
2996 }
2997 } // end lock _activeprims
2998
2999 //if ((framecount % m_randomizeWater) == 0)
3000 // randomizeWater(waterlevel);
3001
3002 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
3003 m_rayCastManager.ProcessQueuedRequests();
3004
3005 collision_optimized(ODE_STEPSIZE);
3006
3007 lock (_collisionEventPrim)
3008 {
3009 foreach (PhysicsActor obj in _collisionEventPrim)
3010 {
3011 if (obj == null)
3012 continue;
3013
3014 switch ((ActorTypes)obj.PhysicsActorType)
3015 {
3016 case ActorTypes.Agent:
3017 OdeCharacter cobj = (OdeCharacter)obj;
3018 cobj.AddCollisionFrameTime(100);
3019 cobj.SendCollisions();
3020 break;
3021 case ActorTypes.Prim:
3022 OdePrim pobj = (OdePrim)obj;
3023 pobj.SendCollisions();
3024 break;
3025 }
3026 }
3027 } // end lock _collisionEventPrim
3028
3029 //if (m_global_contactcount > 5)
3030 //{
3031 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3032 //}
3033
3034 m_global_contactcount = 0;
3035
3036 d.WorldQuickStep(world, ODE_STEPSIZE);
3037 d.JointGroupEmpty(contactgroup);
3038 fps++;
3039 //ode.dunlock(world);
3040 } // end try
3041 catch (Exception e)
3042 {
3043 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3044 ode.dunlock(world);
3045 }
3046
3047 step_time -= ODE_STEPSIZE;
3048 i++;
3049 //}
3050 //else
3051 //{
3052 //fps = 0;
3053 //}
3054 //}
3055 } // end while (step_time > 0.0f)
3056
3057 lock (_characters)
3058 {
3059 foreach (OdeCharacter actor in _characters)
3060 {
3061 if (actor != null)
3062 {
3063 if (actor.bad)
3064 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3065 actor.UpdatePositionAndVelocity();
3066 }
3067 }
3068 }
3069
3070 lock (_badCharacter)
3071 {
3072 if (_badCharacter.Count > 0)
3073 {
3074 foreach (OdeCharacter chr in _badCharacter)
3075 {
3076 RemoveCharacter(chr);
3077 }
3078 _badCharacter.Clear();
3079 }
3080 }
3081
3082 lock (_activeprims)
3083 {
3084 //if (timeStep < 0.2f)
3085 {
3086 foreach (OdePrim actor in _activeprims)
3087 {
3088 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3089 {
3090 actor.UpdatePositionAndVelocity();
3091
3092 if (SupportsNINJAJoints)
3093 {
3094 // If an actor moved, move its joint proxy objects as well.
3095 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3096 // for this purpose but it is never called! So we just do the joint
3097 // movement code here.
3098
3099 if (actor.SOPName != null &&
3100 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3101 joints_connecting_actor[actor.SOPName] != null &&
3102 joints_connecting_actor[actor.SOPName].Count > 0)
3103 {
3104 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3105 {
3106 if (affectedJoint.IsInPhysicsEngine)
3107 {
3108 DoJointMoved(affectedJoint);
3109 }
3110 else
3111 {
3112 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3113 }
3114 }
3115 }
3116 }
3117 }
3118 }
3119 }
3120 } // end lock _activeprims
3121
3122 //DumpJointInfo();
3123
3124 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3125 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3126 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3127 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3128 {
3129 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3130 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3131
3132 if (physics_logging_append_existing_logfile)
3133 {
3134 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3135 TextWriter fwriter = File.AppendText(fname);
3136 fwriter.WriteLine(header);
3137 fwriter.Close();
3138 }
3139 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3140 }
3141 } // end lock OdeLock
3142
3143 return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter!
3144 } // end Simulate
3145
3146 public override void GetResults()
3147 {
3148 }
3149
3150 public override bool IsThreaded
3151 {
3152 // for now we won't be multithreaded
3153 get { return (false); }
3154 }
3155
3156 #region ODE Specific Terrain Fixes
3157 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3158 {
3159 float[] returnarr = new float[262144];
3160 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3161
3162 // Filling out the array into its multi-dimensional components
3163 for (int y = 0; y < WorldExtents.Y; y++)
3164 {
3165 for (int x = 0; x < WorldExtents.X; x++)
3166 {
3167 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3168 }
3169 }
3170
3171 // Resize using Nearest Neighbour
3172
3173 // This particular way is quick but it only works on a multiple of the original
3174
3175 // The idea behind this method can be described with the following diagrams
3176 // second pass and third pass happen in the same loop really.. just separated
3177 // them to show what this does.
3178
3179 // First Pass
3180 // ResultArr:
3181 // 1,1,1,1,1,1
3182 // 1,1,1,1,1,1
3183 // 1,1,1,1,1,1
3184 // 1,1,1,1,1,1
3185 // 1,1,1,1,1,1
3186 // 1,1,1,1,1,1
3187
3188 // Second Pass
3189 // ResultArr2:
3190 // 1,,1,,1,,1,,1,,1,
3191 // ,,,,,,,,,,
3192 // 1,,1,,1,,1,,1,,1,
3193 // ,,,,,,,,,,
3194 // 1,,1,,1,,1,,1,,1,
3195 // ,,,,,,,,,,
3196 // 1,,1,,1,,1,,1,,1,
3197 // ,,,,,,,,,,
3198 // 1,,1,,1,,1,,1,,1,
3199 // ,,,,,,,,,,
3200 // 1,,1,,1,,1,,1,,1,
3201
3202 // Third pass fills in the blanks
3203 // ResultArr2:
3204 // 1,1,1,1,1,1,1,1,1,1,1,1
3205 // 1,1,1,1,1,1,1,1,1,1,1,1
3206 // 1,1,1,1,1,1,1,1,1,1,1,1
3207 // 1,1,1,1,1,1,1,1,1,1,1,1
3208 // 1,1,1,1,1,1,1,1,1,1,1,1
3209 // 1,1,1,1,1,1,1,1,1,1,1,1
3210 // 1,1,1,1,1,1,1,1,1,1,1,1
3211 // 1,1,1,1,1,1,1,1,1,1,1,1
3212 // 1,1,1,1,1,1,1,1,1,1,1,1
3213 // 1,1,1,1,1,1,1,1,1,1,1,1
3214 // 1,1,1,1,1,1,1,1,1,1,1,1
3215
3216 // X,Y = .
3217 // X+1,y = ^
3218 // X,Y+1 = *
3219 // X+1,Y+1 = #
3220
3221 // Filling in like this;
3222 // .*
3223 // ^#
3224 // 1st .
3225 // 2nd *
3226 // 3rd ^
3227 // 4th #
3228 // on single loop.
3229
3230 float[,] resultarr2 = new float[512, 512];
3231 for (int y = 0; y < WorldExtents.Y; y++)
3232 {
3233 for (int x = 0; x < WorldExtents.X; x++)
3234 {
3235 resultarr2[y * 2, x * 2] = resultarr[y, x];
3236
3237 if (y < WorldExtents.Y)
3238 {
3239 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3240 }
3241 if (x < WorldExtents.X)
3242 {
3243 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3244 }
3245 if (x < WorldExtents.X && y < WorldExtents.Y)
3246 {
3247 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3248 }
3249 }
3250 }
3251
3252 //Flatten out the array
3253 int i = 0;
3254 for (int y = 0; y < 512; y++)
3255 {
3256 for (int x = 0; x < 512; x++)
3257 {
3258 if (resultarr2[y, x] <= 0)
3259 returnarr[i] = 0.0000001f;
3260 else
3261 returnarr[i] = resultarr2[y, x];
3262
3263 i++;
3264 }
3265 }
3266
3267 return returnarr;
3268 }
3269
3270 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3271 {
3272 float[] returnarr = new float[262144];
3273 float[,] resultarr = new float[512,512];
3274
3275 // Filling out the array into its multi-dimensional components
3276 for (int y = 0; y < 256; y++)
3277 {
3278 for (int x = 0; x < 256; x++)
3279 {
3280 resultarr[y, x] = heightMap[y * 256 + x];
3281 }
3282 }
3283
3284 // Resize using interpolation
3285
3286 // This particular way is quick but it only works on a multiple of the original
3287
3288 // The idea behind this method can be described with the following diagrams
3289 // second pass and third pass happen in the same loop really.. just separated
3290 // them to show what this does.
3291
3292 // First Pass
3293 // ResultArr:
3294 // 1,1,1,1,1,1
3295 // 1,1,1,1,1,1
3296 // 1,1,1,1,1,1
3297 // 1,1,1,1,1,1
3298 // 1,1,1,1,1,1
3299 // 1,1,1,1,1,1
3300
3301 // Second Pass
3302 // ResultArr2:
3303 // 1,,1,,1,,1,,1,,1,
3304 // ,,,,,,,,,,
3305 // 1,,1,,1,,1,,1,,1,
3306 // ,,,,,,,,,,
3307 // 1,,1,,1,,1,,1,,1,
3308 // ,,,,,,,,,,
3309 // 1,,1,,1,,1,,1,,1,
3310 // ,,,,,,,,,,
3311 // 1,,1,,1,,1,,1,,1,
3312 // ,,,,,,,,,,
3313 // 1,,1,,1,,1,,1,,1,
3314
3315 // Third pass fills in the blanks
3316 // ResultArr2:
3317 // 1,1,1,1,1,1,1,1,1,1,1,1
3318 // 1,1,1,1,1,1,1,1,1,1,1,1
3319 // 1,1,1,1,1,1,1,1,1,1,1,1
3320 // 1,1,1,1,1,1,1,1,1,1,1,1
3321 // 1,1,1,1,1,1,1,1,1,1,1,1
3322 // 1,1,1,1,1,1,1,1,1,1,1,1
3323 // 1,1,1,1,1,1,1,1,1,1,1,1
3324 // 1,1,1,1,1,1,1,1,1,1,1,1
3325 // 1,1,1,1,1,1,1,1,1,1,1,1
3326 // 1,1,1,1,1,1,1,1,1,1,1,1
3327 // 1,1,1,1,1,1,1,1,1,1,1,1
3328
3329 // X,Y = .
3330 // X+1,y = ^
3331 // X,Y+1 = *
3332 // X+1,Y+1 = #
3333
3334 // Filling in like this;
3335 // .*
3336 // ^#
3337 // 1st .
3338 // 2nd *
3339 // 3rd ^
3340 // 4th #
3341 // on single loop.
3342
3343 float[,] resultarr2 = new float[512,512];
3344 for (int y = 0; y < (int)Constants.RegionSize; y++)
3345 {
3346 for (int x = 0; x < (int)Constants.RegionSize; x++)
3347 {
3348 resultarr2[y*2, x*2] = resultarr[y, x];
3349
3350 if (y < (int)Constants.RegionSize)
3351 {
3352 if (y + 1 < (int)Constants.RegionSize)
3353 {
3354 if (x + 1 < (int)Constants.RegionSize)
3355 {
3356 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3357 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3358 }
3359 else
3360 {
3361 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3362 }
3363 }
3364 else
3365 {
3366 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3367 }
3368 }
3369 if (x < (int)Constants.RegionSize)
3370 {
3371 if (x + 1 < (int)Constants.RegionSize)
3372 {
3373 if (y + 1 < (int)Constants.RegionSize)
3374 {
3375 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3376 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3377 }
3378 else
3379 {
3380 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3381 }
3382 }
3383 else
3384 {
3385 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3386 }
3387 }
3388 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3389 {
3390 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3391 {
3392 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3393 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3394 }
3395 else
3396 {
3397 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3398 }
3399 }
3400 }
3401 }
3402 //Flatten out the array
3403 int i = 0;
3404 for (int y = 0; y < 512; y++)
3405 {
3406 for (int x = 0; x < 512; x++)
3407 {
3408 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3409 {
3410 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3411 resultarr2[y, x] = 0;
3412 }
3413 returnarr[i] = resultarr2[y, x];
3414 i++;
3415 }
3416 }
3417
3418 return returnarr;
3419 }
3420
3421 #endregion
3422
3423 public override void SetTerrain(float[] heightMap)
3424 {
3425 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3426 {
3427 if (m_parentScene is OdeScene)
3428 {
3429 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3430 }
3431 }
3432 else
3433 {
3434 SetTerrain(heightMap, m_worldOffset);
3435 }
3436 }
3437
3438 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3439 {
3440
3441 uint regionsize = (uint) Constants.RegionSize; // visible region size eg. 256(M)
3442
3443 uint heightmapWidth = regionsize + 1; // ODE map size 257 x 257 (Meters) (1 extra
3444 uint heightmapHeight = regionsize + 1;
3445
3446 uint heightmapWidthSamples = (uint)regionsize + 2; // Sample file size, 258 x 258 samples
3447 uint heightmapHeightSamples = (uint)regionsize + 2;
3448
3449 // Array of height samples for ODE
3450 float[] _heightmap;
3451 _heightmap = new float[(heightmapWidthSamples * heightmapHeightSamples)]; // loaded samples 258 x 258
3452
3453 // Other ODE parameters
3454 const float scale = 1.0f;
3455 const float offset = 0.0f;
3456 const float thickness = 2.0f; // Was 0.2f, Larger appears to prevent Av fall-through
3457 const int wrap = 0;
3458
3459 float hfmin = 2000f;
3460 float hfmax = -2000f;
3461 float minele = 0.0f; // Dont allow -ve heights
3462
3463 uint x = 0;
3464 uint y = 0;
3465 uint xx = 0;
3466 uint yy = 0;
3467
3468 // load the height samples array from the heightMap
3469 for ( x = 0; x < heightmapWidthSamples; x++) // 0 to 257
3470 {
3471 for ( y = 0; y < heightmapHeightSamples; y++) // 0 to 257
3472 {
3473 xx = x - 1;
3474 if (xx < 0) xx = 0;
3475 if (xx > (regionsize - 1)) xx = regionsize - 1;
3476
3477 yy = y - 1;
3478 if (yy < 0) yy = 0;
3479 if (yy > (regionsize - 1)) yy = regionsize - 1;
3480 // Input xx = 0 0 1 2 ..... 254 255 255 256 total in
3481 // Output x = 0 1 2 3 ..... 255 256 257 258 total out
3482 float val= heightMap[(yy * regionsize) + xx]; // input from heightMap, <0-255 * 256> <0-255>
3483 if (val < minele) val = minele;
3484 _heightmap[x * (regionsize + 2) + y] = val; // samples output to _heightmap, <0-257 * 258> <0-257>
3485 hfmin = (val < hfmin) ? val : hfmin;
3486 hfmax = (val > hfmax) ? val : hfmax;
3487 }
3488 }
3489
3490 lock (OdeLock)
3491 {
3492 IntPtr GroundGeom = IntPtr.Zero;
3493 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3494 {
3495 RegionTerrain.Remove(pOffset);
3496 if (GroundGeom != IntPtr.Zero)
3497 {
3498 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3499 {
3500 TerrainHeightFieldHeights.Remove(GroundGeom);
3501 }
3502 d.SpaceRemove(space, GroundGeom);
3503 d.GeomDestroy(GroundGeom);
3504 }
3505 }
3506 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3507 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3508 heightmapWidth, heightmapHeight, (int)heightmapWidthSamples,
3509 (int)heightmapHeightSamples, scale, offset, thickness, wrap);
3510 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3511 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3512 if (GroundGeom != IntPtr.Zero)
3513 {
3514 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3515 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3516 }
3517 geom_name_map[GroundGeom] = "Terrain";
3518
3519 d.Matrix3 R = new d.Matrix3();
3520
3521 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3522 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3523 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3524
3525 q1 = q1 * q2;
3526 //q1 = q1 * q3;
3527 Vector3 v3;
3528 float angle;
3529 q1.GetAxisAngle(out v3, out angle);
3530
3531 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3532 d.GeomSetRotation(GroundGeom, ref R);
3533 d.GeomSetPosition(GroundGeom, (pOffset.X + (regionsize * 0.5f)) - 0.5f, (pOffset.Y + (regionsize * 0.5f)) - 0.5f, 0);
3534 IntPtr testGround = IntPtr.Zero;
3535 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3536 {
3537 RegionTerrain.Remove(pOffset);
3538 }
3539 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3540 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3541 }
3542 }
3543
3544 public override void DeleteTerrain()
3545 {
3546 }
3547
3548 public float GetWaterLevel()
3549 {
3550 return waterlevel;
3551 }
3552
3553 public override bool SupportsCombining()
3554 {
3555 return true;
3556 }
3557
3558 public override void UnCombine(PhysicsScene pScene)
3559 {
3560 IntPtr localGround = IntPtr.Zero;
3561// float[] localHeightfield;
3562 bool proceed = false;
3563 List<IntPtr> geomDestroyList = new List<IntPtr>();
3564
3565 lock (OdeLock)
3566 {
3567 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3568 {
3569 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3570 {
3571 if (geom == localGround)
3572 {
3573// localHeightfield = TerrainHeightFieldHeights[geom];
3574 proceed = true;
3575 }
3576 else
3577 {
3578 geomDestroyList.Add(geom);
3579 }
3580 }
3581
3582 if (proceed)
3583 {
3584 m_worldOffset = Vector3.Zero;
3585 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3586 m_parentScene = null;
3587
3588 foreach (IntPtr g in geomDestroyList)
3589 {
3590 // removingHeightField needs to be done or the garbage collector will
3591 // collect the terrain data before we tell ODE to destroy it causing
3592 // memory corruption
3593 if (TerrainHeightFieldHeights.ContainsKey(g))
3594 {
3595// float[] removingHeightField = TerrainHeightFieldHeights[g];
3596 TerrainHeightFieldHeights.Remove(g);
3597
3598 if (RegionTerrain.ContainsKey(g))
3599 {
3600 RegionTerrain.Remove(g);
3601 }
3602
3603 d.GeomDestroy(g);
3604 //removingHeightField = new float[0];
3605 }
3606 }
3607
3608 }
3609 else
3610 {
3611 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3612
3613 }
3614 }
3615 }
3616 }
3617
3618 public override void SetWaterLevel(float baseheight)
3619 {
3620 waterlevel = baseheight;
3621 randomizeWater(waterlevel);
3622 }
3623
3624 public void randomizeWater(float baseheight)
3625 {
3626 const uint heightmapWidth = m_regionWidth + 2;
3627 const uint heightmapHeight = m_regionHeight + 2;
3628 const uint heightmapWidthSamples = m_regionWidth + 2;
3629 const uint heightmapHeightSamples = m_regionHeight + 2;
3630 const float scale = 1.0f;
3631 const float offset = 0.0f;
3632 const float thickness = 2.9f;
3633 const int wrap = 0;
3634
3635 for (int i = 0; i < (258 * 258); i++)
3636 {
3637 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3638 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3639 }
3640
3641 lock (OdeLock)
3642 {
3643 if (WaterGeom != IntPtr.Zero)
3644 {
3645 d.SpaceRemove(space, WaterGeom);
3646 }
3647 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3648 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3649 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3650 offset, thickness, wrap);
3651 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3652 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3653 if (WaterGeom != IntPtr.Zero)
3654 {
3655 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3656 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3657
3658 }
3659 geom_name_map[WaterGeom] = "Water";
3660
3661 d.Matrix3 R = new d.Matrix3();
3662
3663 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3664 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3665 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3666
3667 q1 = q1 * q2;
3668 //q1 = q1 * q3;
3669 Vector3 v3;
3670 float angle;
3671 q1.GetAxisAngle(out v3, out angle);
3672
3673 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3674 d.GeomSetRotation(WaterGeom, ref R);
3675 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3676
3677 }
3678
3679 }
3680
3681 public override void Dispose()
3682 {
3683 m_rayCastManager.Dispose();
3684 m_rayCastManager = null;
3685
3686 lock (OdeLock)
3687 {
3688 lock (_prims)
3689 {
3690 foreach (OdePrim prm in _prims)
3691 {
3692 RemovePrim(prm);
3693 }
3694 }
3695
3696 //foreach (OdeCharacter act in _characters)
3697 //{
3698 //RemoveAvatar(act);
3699 //}
3700 d.WorldDestroy(world);
3701 //d.CloseODE();
3702 }
3703 }
3704 public override Dictionary<uint, float> GetTopColliders()
3705 {
3706 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3707 int cnt = 0;
3708 lock (_prims)
3709 {
3710 foreach (OdePrim prm in _prims)
3711 {
3712 if (prm.CollisionScore > 0)
3713 {
3714 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3715 cnt++;
3716 prm.CollisionScore = 0f;
3717 if (cnt > 25)
3718 {
3719 break;
3720 }
3721 }
3722 }
3723 }
3724 return returncolliders;
3725 }
3726
3727 public override bool SupportsRayCast()
3728 {
3729 return true;
3730 }
3731
3732 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3733 {
3734 if (retMethod != null)
3735 {
3736 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3737 }
3738 }
3739
3740#if USE_DRAWSTUFF
3741 // Keyboard callback
3742 public void command(int cmd)
3743 {
3744 IntPtr geom;
3745 d.Mass mass;
3746 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3747
3748
3749
3750 Char ch = Char.ToLower((Char)cmd);
3751 switch ((Char)ch)
3752 {
3753 case 'w':
3754 try
3755 {
3756 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3757
3758 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3759 ds.SetViewpoint(ref xyz, ref hpr);
3760 }
3761 catch (ArgumentException)
3762 { hpr.X = 0; }
3763 break;
3764
3765 case 'a':
3766 hpr.X++;
3767 ds.SetViewpoint(ref xyz, ref hpr);
3768 break;
3769
3770 case 's':
3771 try
3772 {
3773 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
3774
3775 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3776 ds.SetViewpoint(ref xyz, ref hpr);
3777 }
3778 catch (ArgumentException)
3779 { hpr.X = 0; }
3780 break;
3781 case 'd':
3782 hpr.X--;
3783 ds.SetViewpoint(ref xyz, ref hpr);
3784 break;
3785 case 'r':
3786 xyz.Z++;
3787 ds.SetViewpoint(ref xyz, ref hpr);
3788 break;
3789 case 'f':
3790 xyz.Z--;
3791 ds.SetViewpoint(ref xyz, ref hpr);
3792 break;
3793 case 'e':
3794 xyz.Y++;
3795 ds.SetViewpoint(ref xyz, ref hpr);
3796 break;
3797 case 'q':
3798 xyz.Y--;
3799 ds.SetViewpoint(ref xyz, ref hpr);
3800 break;
3801 }
3802 }
3803
3804 public void step(int pause)
3805 {
3806
3807 ds.SetColor(1.0f, 1.0f, 0.0f);
3808 ds.SetTexture(ds.Texture.Wood);
3809 lock (_prims)
3810 {
3811 foreach (OdePrim prm in _prims)
3812 {
3813 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3814 if (prm.prim_geom != IntPtr.Zero)
3815 {
3816 d.Vector3 pos;
3817 d.GeomCopyPosition(prm.prim_geom, out pos);
3818 //d.BodyCopyPosition(body, out pos);
3819
3820 d.Matrix3 R;
3821 d.GeomCopyRotation(prm.prim_geom, out R);
3822 //d.BodyCopyRotation(body, out R);
3823
3824
3825 d.Vector3 sides = new d.Vector3();
3826 sides.X = prm.Size.X;
3827 sides.Y = prm.Size.Y;
3828 sides.Z = prm.Size.Z;
3829
3830 ds.DrawBox(ref pos, ref R, ref sides);
3831 }
3832 }
3833 }
3834 ds.SetColor(1.0f, 0.0f, 0.0f);
3835 lock (_characters)
3836 {
3837 foreach (OdeCharacter chr in _characters)
3838 {
3839 if (chr.Shell != IntPtr.Zero)
3840 {
3841 IntPtr body = d.GeomGetBody(chr.Shell);
3842
3843 d.Vector3 pos;
3844 d.GeomCopyPosition(chr.Shell, out pos);
3845 //d.BodyCopyPosition(body, out pos);
3846
3847 d.Matrix3 R;
3848 d.GeomCopyRotation(chr.Shell, out R);
3849 //d.BodyCopyRotation(body, out R);
3850
3851 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3852 d.Vector3 sides = new d.Vector3();
3853 sides.X = 0.5f;
3854 sides.Y = 0.5f;
3855 sides.Z = 0.5f;
3856
3857 ds.DrawBox(ref pos, ref R, ref sides);
3858 }
3859 }
3860 }
3861 }
3862
3863 public void start(int unused)
3864 {
3865 ds.SetViewpoint(ref xyz, ref hpr);
3866 }
3867#endif
3868 }
3869}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs
new file mode 100644
index 0000000..69e2d03
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/Tests/ODETestClass.cs
@@ -0,0 +1,122 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using log4net;
35using System.Reflection;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 [TestFixture]
40 public class ODETestClass
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private OdePlugin cbt;
45 private PhysicsScene ps;
46 private IMeshingPlugin imp;
47
48 [SetUp]
49 public void Initialize()
50 {
51 // Loading ODEPlugin
52 cbt = new OdePlugin();
53 // Loading Zero Mesher
54 imp = new ZeroMesherPlugin();
55 // Getting Physics Scene
56 ps = cbt.GetScene("test");
57 // Initializing Physics Scene.
58 ps.Initialise(imp.GetMesher(),null);
59 float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize];
60 for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++)
61 {
62 _heightmap[i] = 21f;
63 }
64 ps.SetTerrain(_heightmap);
65 }
66
67 [TearDown]
68 public void Terminate()
69 {
70 ps.DeleteTerrain();
71 ps.Dispose();
72
73 }
74
75 [Test]
76 public void CreateAndDropPhysicalCube()
77 {
78 PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox();
79 Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f);
80 Vector3 size = new Vector3(0.5f, 0.5f, 0.5f);
81 Quaternion rot = Quaternion.Identity;
82 PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true);
83 OdePrim oprim = (OdePrim)prim;
84 OdeScene pscene = (OdeScene) ps;
85
86 Assert.That(oprim.m_taintadd);
87
88 prim.LocalID = 5;
89
90 for (int i = 0; i < 58; i++)
91 {
92 ps.Simulate(0.133f);
93
94 Assert.That(oprim.prim_geom != (IntPtr)0);
95
96 Assert.That(oprim.m_targetSpace != (IntPtr)0);
97
98 //Assert.That(oprim.m_targetSpace == pscene.space);
99 m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space);
100
101 Assert.That(!oprim.m_taintadd);
102 m_log.Info("Prim Position (" + oprim.m_localID + "): " + prim.Position.ToString());
103
104 // Make sure we're above the ground
105 //Assert.That(prim.Position.Z > 20f);
106 //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore);
107
108 // Make sure we've got a Body
109 Assert.That(oprim.Body != (IntPtr)0);
110 //m_log.Info(
111 }
112
113 // Make sure we're not somewhere above the ground
114 Assert.That(prim.Position.Z < 21.5f);
115
116 ps.RemovePrim(prim);
117 Assert.That(oprim.m_taintremove);
118 ps.Simulate(0.133f);
119 Assert.That(oprim.Body == (IntPtr)0);
120 }
121 }
122}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs
new file mode 100644
index 0000000..87ca446
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/drawstuff.cs
@@ -0,0 +1,98 @@
1/*
2 * Copyright ODE
3 * Ode.NET - .NET bindings for ODE
4 * Jason Perkins (starkos@industriousone.com)
5 * Licensed under the New BSD
6 * Part of the OpenDynamicsEngine
7Open Dynamics Engine
8Copyright (c) 2001-2007, Russell L. Smith.
9All rights reserved.
10
11Redistribution and use in source and binary forms, with or without
12modification, are permitted provided that the following conditions
13are met:
14
15Redistributions of source code must retain the above copyright notice,
16this list of conditions and the following disclaimer.
17
18Redistributions in binary form must reproduce the above copyright notice,
19this list of conditions and the following disclaimer in the documentation
20and/or other materials provided with the distribution.
21
22Neither the names of ODE's copyright owner nor the names of its
23contributors may be used to endorse or promote products derived from
24this software without specific prior written permission.
25
26THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 *
39 */
40
41using System;
42using System.Runtime.InteropServices;
43using Ode.NET;
44
45namespace Drawstuff.NET
46{
47#if dDOUBLE
48 using dReal = System.Double;
49#else
50 using dReal = System.Single;
51#endif
52
53 public static class ds
54 {
55 public const int VERSION = 2;
56
57 public enum Texture
58 {
59 None,
60 Wood
61 }
62
63 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
64 public delegate void CallbackFunction(int arg);
65
66 [StructLayout(LayoutKind.Sequential)]
67 public struct Functions
68 {
69 public int version;
70 public CallbackFunction start;
71 public CallbackFunction step;
72 public CallbackFunction command;
73 public CallbackFunction stop;
74 public string path_to_textures;
75 }
76
77 [DllImport("drawstuff", EntryPoint = "dsDrawBox")]
78 public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides);
79
80 [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")]
81 public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius);
82
83 [DllImport("drawstuff", EntryPoint = "dsDrawConvex")]
84 public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons);
85
86 [DllImport("drawstuff", EntryPoint = "dsSetColor")]
87 public static extern void SetColor(float red, float green, float blue);
88
89 [DllImport("drawstuff", EntryPoint = "dsSetTexture")]
90 public static extern void SetTexture(Texture texture);
91
92 [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")]
93 public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr);
94
95 [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")]
96 public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn);
97 }
98}
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
index a2229e8..2a66060 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -1210,7 +1210,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1210 1210
1211 public override float APIDDamping{ set { return; } } 1211 public override float APIDDamping{ set { return; } }
1212 1212
1213
1214 public override void SubscribeEvents(int ms) 1213 public override void SubscribeEvents(int ms)
1215 { 1214 {
1216 m_requestedUpdateFrequency = ms; 1215 m_requestedUpdateFrequency = ms;
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index c91658e..243e2d7 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -572,8 +572,8 @@ namespace OpenSim.Region.Physics.OdePlugin
572 break; 572 break;
573 573
574 case HollowShape.Circle: 574 case HollowShape.Circle:
575 // Hollow shape is a perfect cyllinder in respect to the cube's scale 575 // Hollow shape is a perfect cylinder in respect to the cube's scale
576 // Cyllinder hollow volume calculation 576 // Cylinder hollow volume calculation
577 577
578 hollowVolume *= 0.1963495f * 3.07920140172638f; 578 hollowVolume *= 0.1963495f * 3.07920140172638f;
579 break; 579 break;
@@ -2819,7 +2819,7 @@ Console.WriteLine(" JointCreateFixed");
2819 } 2819 }
2820 public override bool PIDActive { set { m_usePID = value; } } 2820 public override bool PIDActive { set { m_usePID = value; } }
2821 public override float PIDTau { set { m_PIDTau = value; } } 2821 public override float PIDTau { set { m_PIDTau = value; } }
2822 2822
2823 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } 2823 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
2824 public override bool PIDHoverActive { set { m_useHoverPID = value; } } 2824 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
2825 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } 2825 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
index 91ec3df..9ba5ebb 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
@@ -301,7 +301,7 @@ namespace OpenSim.Region.Physics.POSPlugin
301 { 301 {
302 set { return; } 302 set { return; }
303 } 303 }
304 304
305 public override Quaternion APIDTarget 305 public override Quaternion APIDTarget
306 { 306 {
307 set { return; } 307 set { return; }
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index ff0e743..d854176 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -88,89 +88,7 @@ namespace OpenSim.Region.RegionCombinerModule
88 public void RegionLoaded(Scene scene) 88 public void RegionLoaded(Scene scene)
89 { 89 {
90 if (enabledYN) 90 if (enabledYN)
91 {
92 RegionLoadedDoWork(scene); 91 RegionLoadedDoWork(scene);
93
94 scene.EventManager.OnNewPresence += NewPresence;
95 }
96 }
97
98 private void NewPresence(ScenePresence presence)
99 {
100 if (presence.IsChildAgent)
101 {
102 byte[] throttleData;
103
104 try
105 {
106 throttleData = presence.ControllingClient.GetThrottlesPacked(1);
107 }
108 catch (NotImplementedException)
109 {
110 return;
111 }
112
113 if (throttleData == null)
114 return;
115
116 if (throttleData.Length == 0)
117 return;
118
119 if (throttleData.Length != 28)
120 return;
121
122 byte[] adjData;
123 int pos = 0;
124
125 if (!BitConverter.IsLittleEndian)
126 {
127 byte[] newData = new byte[7 * 4];
128 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
129
130 for (int i = 0; i < 7; i++)
131 Array.Reverse(newData, i * 4, 4);
132
133 adjData = newData;
134 }
135 else
136 {
137 adjData = throttleData;
138 }
139
140 // 0.125f converts from bits to bytes
141 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
142 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
143 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
144 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
145 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
146 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
147 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
148 // State is a subcategory of task that we allocate a percentage to
149
150
151 //int total = resend + land + wind + cloud + task + texture + asset;
152
153 byte[] data = new byte[7 * 4];
154 int ii = 0;
155
156 Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4;
157 Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4;
158 Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4;
159 Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4;
160 Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4;
161 Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4;
162 Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4);
163
164 try
165 {
166 presence.ControllingClient.SetChildAgentThrottle(data);
167 }
168 catch (NotImplementedException)
169 {
170 return;
171 }
172
173 }
174 } 92 }
175 93
176 private void RegionLoadedDoWork(Scene scene) 94 private void RegionLoadedDoWork(Scene scene)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index ee32755..61e4934 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -248,6 +248,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
248 248
249 } 249 }
250 250
251 public static void StateChange(IScriptEngine engine, uint localID, UUID itemID)
252 {
253 // Remove a specific script
254
255 // Remove dataserver events
256 m_Dataserver[engine].RemoveEvents(localID, itemID);
257
258 IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
259 if (comms != null)
260 comms.DeleteListener(itemID);
261
262 IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>();
263 xmlrpc.DeleteChannels(itemID);
264 xmlrpc.CancelSRDRequests(itemID);
265
266 // Remove Sensors
267 m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID);
268
269 }
270
251 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID) 271 public static Object[] GetSerializationData(IScriptEngine engine, UUID itemID)
252 { 272 {
253 List<Object> data = new List<Object>(); 273 List<Object> data = new List<Object>();
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 8bf9482..e94790f 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Diagnostics; //for [DebuggerNonUserCode]
31using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
32using System.Text; 33using System.Text;
33using System.Threading; 34using System.Threading;
@@ -81,7 +82,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
81 /// </summary> 82 /// </summary>
82 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi 83 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
83 { 84 {
84 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 85// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
85 protected IScriptEngine m_ScriptEngine; 86 protected IScriptEngine m_ScriptEngine;
86 protected SceneObjectPart m_host; 87 protected SceneObjectPart m_host;
87 protected uint m_localID; 88 protected uint m_localID;
@@ -99,6 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
99 protected int m_notecardLineReadCharsMax = 255; 100 protected int m_notecardLineReadCharsMax = 255;
100 protected int m_scriptConsoleChannel = 0; 101 protected int m_scriptConsoleChannel = 0;
101 protected bool m_scriptConsoleChannelEnabled = false; 102 protected bool m_scriptConsoleChannelEnabled = false;
103 protected bool m_debuggerSafe = false;
102 protected IUrlModule m_UrlModule = null; 104 protected IUrlModule m_UrlModule = null;
103 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache = 105 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache =
104 new Dictionary<UUID, UserInfoCacheEntry>(); 106 new Dictionary<UUID, UserInfoCacheEntry>();
@@ -109,6 +111,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
109 m_host = host; 111 m_host = host;
110 m_localID = localID; 112 m_localID = localID;
111 m_itemID = itemID; 113 m_itemID = itemID;
114 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
112 115
113 m_ScriptDelayFactor = 116 m_ScriptDelayFactor =
114 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); 117 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
@@ -161,6 +164,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
161 get { return m_ScriptEngine.World; } 164 get { return m_ScriptEngine.World; }
162 } 165 }
163 166
167 [DebuggerNonUserCode]
164 public void state(string newState) 168 public void state(string newState)
165 { 169 {
166 m_ScriptEngine.SetState(m_itemID, newState); 170 m_ScriptEngine.SetState(m_itemID, newState);
@@ -170,6 +174,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
170 /// Reset the named script. The script must be present 174 /// Reset the named script. The script must be present
171 /// in the same prim. 175 /// in the same prim.
172 /// </summary> 176 /// </summary>
177 [DebuggerNonUserCode]
173 public void llResetScript() 178 public void llResetScript()
174 { 179 {
175 m_host.AddScriptLPS(1); 180 m_host.AddScriptLPS(1);
@@ -226,9 +231,62 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
226 } 231 }
227 } 232 }
228 233
234 public List<ScenePresence> GetLinkAvatars(int linkType)
235 {
236 List<ScenePresence> ret = new List<ScenePresence>();
237 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
238 return ret;
239
240 List<ScenePresence> avs = m_host.ParentGroup.GetLinkedAvatars();
241
242 switch (linkType)
243 {
244 case ScriptBaseClass.LINK_SET:
245 return avs;
246
247 case ScriptBaseClass.LINK_ROOT:
248 return ret;
249
250 case ScriptBaseClass.LINK_ALL_OTHERS:
251 return avs;
252
253 case ScriptBaseClass.LINK_ALL_CHILDREN:
254 return avs;
255
256 case ScriptBaseClass.LINK_THIS:
257 return ret;
258
259 default:
260 if (linkType < 0)
261 return ret;
262
263 int partCount = m_host.ParentGroup.GetPartCount();
264
265 if (linkType <= partCount)
266 {
267 return ret;
268 }
269 else
270 {
271 linkType = linkType - partCount;
272 if (linkType > avs.Count)
273 {
274 return ret;
275 }
276 else
277 {
278 ret.Add(avs[linkType-1]);
279 return ret;
280 }
281 }
282 }
283 }
284
229 public List<SceneObjectPart> GetLinkParts(int linkType) 285 public List<SceneObjectPart> GetLinkParts(int linkType)
230 { 286 {
231 List<SceneObjectPart> ret = new List<SceneObjectPart>(); 287 List<SceneObjectPart> ret = new List<SceneObjectPart>();
288 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
289 return ret;
232 ret.Add(m_host); 290 ret.Add(m_host);
233 291
234 switch (linkType) 292 switch (linkType)
@@ -288,40 +346,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
288 protected UUID InventorySelf() 346 protected UUID InventorySelf()
289 { 347 {
290 UUID invItemID = new UUID(); 348 UUID invItemID = new UUID();
291 349 bool unlock = false;
292 lock (m_host.TaskInventory) 350 if (!m_host.TaskInventory.IsReadLockedByMe())
351 {
352 m_host.TaskInventory.LockItemsForRead(true);
353 unlock = true;
354 }
355 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
293 { 356 {
294 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 357 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
295 { 358 {
296 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID) 359 invItemID = inv.Key;
297 { 360 break;
298 invItemID = inv.Key;
299 break;
300 }
301 } 361 }
302 } 362 }
303 363 if (unlock)
364 {
365 m_host.TaskInventory.LockItemsForRead(false);
366 }
304 return invItemID; 367 return invItemID;
305 } 368 }
306 369
307 protected UUID InventoryKey(string name, int type) 370 protected UUID InventoryKey(string name, int type)
308 { 371 {
309 m_host.AddScriptLPS(1); 372 m_host.AddScriptLPS(1);
310 373 m_host.TaskInventory.LockItemsForRead(true);
311 lock (m_host.TaskInventory) 374
375 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
312 { 376 {
313 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 377 if (inv.Value.Name == name)
314 { 378 {
315 if (inv.Value.Name == name) 379 m_host.TaskInventory.LockItemsForRead(false);
380
381 if (inv.Value.Type != type)
316 { 382 {
317 if (inv.Value.Type != type) 383 return UUID.Zero;
318 return UUID.Zero;
319
320 return inv.Value.AssetID;
321 } 384 }
385
386 return inv.Value.AssetID;
322 } 387 }
323 } 388 }
324 389
390 m_host.TaskInventory.LockItemsForRead(false);
325 return UUID.Zero; 391 return UUID.Zero;
326 } 392 }
327 393
@@ -329,17 +395,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
329 { 395 {
330 m_host.AddScriptLPS(1); 396 m_host.AddScriptLPS(1);
331 397
332 lock (m_host.TaskInventory) 398
399 m_host.TaskInventory.LockItemsForRead(true);
400
401 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
333 { 402 {
334 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 403 if (inv.Value.Name == name)
335 { 404 {
336 if (inv.Value.Name == name) 405 m_host.TaskInventory.LockItemsForRead(false);
337 { 406 return inv.Value.AssetID;
338 return inv.Value.AssetID;
339 }
340 } 407 }
341 } 408 }
342 409
410 m_host.TaskInventory.LockItemsForRead(false);
411
412
343 return UUID.Zero; 413 return UUID.Zero;
344 } 414 }
345 415
@@ -481,26 +551,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
481 551
482 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke 552 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
483 553
484 // Old implementation of llRot2Euler. Normalization not required as Atan2 function will 554 // Utility function for llRot2Euler
485 // only return values >= -PI (-180 degrees) and <= PI (180 degrees).
486 555
487 public LSL_Vector llRot2Euler(LSL_Rotation r) 556 // normalize an angle between -PI and PI (-180 to +180 degrees)
557 protected double NormalizeAngle(double angle)
558 {
559 if (angle > -Math.PI && angle < Math.PI)
560 return angle;
561
562 int numPis = (int)(Math.PI / angle);
563 double remainder = angle - Math.PI * numPis;
564 if (numPis % 2 == 1)
565 return Math.PI - angle;
566 return remainder;
567 }
568
569 public LSL_Vector llRot2Euler(LSL_Rotation q1)
488 { 570 {
489 m_host.AddScriptLPS(1); 571 m_host.AddScriptLPS(1);
490 //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke 572 LSL_Vector eul = new LSL_Vector();
491 LSL_Rotation t = new LSL_Rotation(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s); 573
492 double m = (t.x + t.y + t.z + t.s); 574 double sqw = q1.s*q1.s;
493 if (m == 0) return new LSL_Vector(); 575 double sqx = q1.x*q1.x;
494 double n = 2 * (r.y * r.s + r.x * r.z); 576 double sqy = q1.z*q1.z;
495 double p = m * m - n * n; 577 double sqz = q1.y*q1.y;
496 if (p > 0) 578 double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
497 return new LSL_Vector(Math.Atan2(2.0 * (r.x * r.s - r.y * r.z), (-t.x - t.y + t.z + t.s)), 579 double test = q1.x*q1.z + q1.y*q1.s;
498 Math.Atan2(n, Math.Sqrt(p)), 580 if (test > 0.4999*unit) { // singularity at north pole
499 Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))); 581 eul.z = 2 * Math.Atan2(q1.x,q1.s);
500 else if (n > 0) 582 eul.y = Math.PI/2;
501 return new LSL_Vector(0.0, Math.PI * 0.5, Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)); 583 eul.x = 0;
502 else 584 return eul;
503 return new LSL_Vector(0.0, -Math.PI * 0.5, Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)); 585 }
586 if (test < -0.4999*unit) { // singularity at south pole
587 eul.z = -2 * Math.Atan2(q1.x,q1.s);
588 eul.y = -Math.PI/2;
589 eul.x = 0;
590 return eul;
591 }
592 eul.z = Math.Atan2(2*q1.z*q1.s-2*q1.x*q1.y , sqx - sqy - sqz + sqw);
593 eul.y = Math.Asin(2*test/unit);
594 eul.x = Math.Atan2(2*q1.x*q1.s-2*q1.z*q1.y , -sqx + sqy - sqz + sqw);
595 return eul;
504 } 596 }
505 597
506 /* From wiki: 598 /* From wiki:
@@ -702,77 +794,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
702 { 794 {
703 //A and B should both be normalized 795 //A and B should both be normalized
704 m_host.AddScriptLPS(1); 796 m_host.AddScriptLPS(1);
705 LSL_Rotation rotBetween; 797 /* This method is more accurate than the SL one, and thus causes problems
706 // Check for zero vectors. If either is zero, return zero rotation. Otherwise, 798 for scripts that deal with the SL inaccuracy around 180-degrees -.- .._.
707 // continue calculation. 799
708 if (a == new LSL_Vector(0.0f, 0.0f, 0.0f) || b == new LSL_Vector(0.0f, 0.0f, 0.0f)) 800 double dotProduct = LSL_Vector.Dot(a, b);
709 { 801 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
710 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 802 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
711 } 803 double angle = Math.Acos(dotProduct / magProduct);
712 else 804 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
713 { 805 double s = Math.Sin(angle / 2);
714 a = LSL_Vector.Norm(a); 806
715 b = LSL_Vector.Norm(b); 807 double x = axis.x * s;
716 double dotProduct = LSL_Vector.Dot(a, b); 808 double y = axis.y * s;
717 // There are two degenerate cases possible. These are for vectors 180 or 809 double z = axis.z * s;
718 // 0 degrees apart. These have to be detected and handled individually. 810 double w = Math.Cos(angle / 2);
719 // 811
720 // Check for vectors 180 degrees apart. 812 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
721 // A dot product of -1 would mean the angle between vectors is 180 degrees. 813 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
722 if (dotProduct < -0.9999999f) 814
723 { 815 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
724 // First assume X axis is orthogonal to the vectors. 816 */
725 LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f); 817
726 orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a)); 818 // This method mimics the 180 errors found in SL
727 // Check for near zero vector. A very small non-zero number here will create 819 // See www.euclideanspace.com... angleBetween
728 // a rotation in an undesired direction. 820 LSL_Vector vec_a = a;
729 if (LSL_Vector.Mag(orthoVector) > 0.0001) 821 LSL_Vector vec_b = b;
730 { 822
731 rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f); 823 // Eliminate zero length
732 } 824 LSL_Float vec_a_mag = LSL_Vector.Mag(vec_a);
733 // If the magnitude of the vector was near zero, then assume the X axis is not 825 LSL_Float vec_b_mag = LSL_Vector.Mag(vec_b);
734 // orthogonal and use the Z axis instead. 826 if (vec_a_mag < 0.00001 ||
735 else 827 vec_b_mag < 0.00001)
736 { 828 {
737 // Set 180 z rotation. 829 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
738 rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f); 830 }
739 } 831
740 } 832 // Normalize
741 // Check for parallel vectors. 833 vec_a = llVecNorm(vec_a);
742 // A dot product of 1 would mean the angle between vectors is 0 degrees. 834 vec_b = llVecNorm(vec_b);
743 else if (dotProduct > 0.9999999f) 835
744 { 836 // Calculate axis and rotation angle
745 // Set zero rotation. 837 LSL_Vector axis = vec_a % vec_b;
746 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 838 LSL_Float cos_theta = vec_a * vec_b;
747 } 839
748 else 840 // Check if parallel
749 { 841 if (cos_theta > 0.99999)
750 // All special checks have been performed so get the axis of rotation. 842 {
751 LSL_Vector crossProduct = LSL_Vector.Cross(a, b); 843 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
752 // Quarternion s value is the length of the unit vector + dot product. 844 }
753 double qs = 1.0 + dotProduct; 845
754 rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs); 846 // Check if anti-parallel
755 // Normalize the rotation. 847 else if (cos_theta < -0.99999)
756 double mag = LSL_Rotation.Mag(rotBetween); 848 {
757 // We shouldn't have to worry about a divide by zero here. The qs value will be 849 LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (vec_a.x / (vec_a * vec_a) * vec_a);
758 // non-zero because we already know if we're here, then the dotProduct is not -1 so 850 if (LSL_Vector.Mag(orthog_axis) < 0.000001) orthog_axis = new LSL_Vector(0.0, 0.0, 1.0);
759 // qs will not be zero. Also, we've already handled the input vectors being zero so the 851 return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0);
760 // crossProduct vector should also not be zero. 852 }
761 rotBetween.x = rotBetween.x / mag; 853 else // other rotation
762 rotBetween.y = rotBetween.y / mag; 854 {
763 rotBetween.z = rotBetween.z / mag; 855 LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f;
764 rotBetween.s = rotBetween.s / mag; 856 axis = llVecNorm(axis);
765 // Check for undefined values and set zero rotation if any found. This code might not actually be required 857 double x, y, z, s, t;
766 // any longer since zero vectors are checked for at the top. 858 s = Math.Cos(theta);
767 if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s)) 859 t = Math.Sin(theta);
768 { 860 x = axis.x * t;
769 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 861 y = axis.y * t;
770 } 862 z = axis.z * t;
771 } 863 return new LSL_Rotation(x,y,z,s);
772 } 864 }
773 return rotBetween; 865 }
774 } 866
775
776 public void llWhisper(int channelID, string text) 867 public void llWhisper(int channelID, string text)
777 { 868 {
778 m_host.AddScriptLPS(1); 869 m_host.AddScriptLPS(1);
@@ -1096,10 +1187,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1096 return detectedParams.TouchUV; 1187 return detectedParams.TouchUV;
1097 } 1188 }
1098 1189
1190 [DebuggerNonUserCode]
1099 public virtual void llDie() 1191 public virtual void llDie()
1100 { 1192 {
1101 m_host.AddScriptLPS(1); 1193 m_host.AddScriptLPS(1);
1102 throw new SelfDeleteException(); 1194 if (!m_host.IsAttachment) throw new SelfDeleteException();
1103 } 1195 }
1104 1196
1105 public LSL_Float llGround(LSL_Vector offset) 1197 public LSL_Float llGround(LSL_Vector offset)
@@ -1172,6 +1264,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1172 1264
1173 public void llSetStatus(int status, int value) 1265 public void llSetStatus(int status, int value)
1174 { 1266 {
1267 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
1268 return;
1175 m_host.AddScriptLPS(1); 1269 m_host.AddScriptLPS(1);
1176 1270
1177 int statusrotationaxis = 0; 1271 int statusrotationaxis = 0;
@@ -1402,6 +1496,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1402 { 1496 {
1403 m_host.AddScriptLPS(1); 1497 m_host.AddScriptLPS(1);
1404 1498
1499 SetColor(m_host, color, face);
1500 }
1501
1502 protected void SetColor(SceneObjectPart part, LSL_Vector color, int face)
1503 {
1504 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1505 return;
1506
1507 Primitive.TextureEntry tex = part.Shape.Textures;
1508 Color4 texcolor;
1509 if (face >= 0 && face < GetNumberOfSides(part))
1510 {
1511 texcolor = tex.CreateFace((uint)face).RGBA;
1512 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1513 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1514 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1515 tex.FaceTextures[face].RGBA = texcolor;
1516 part.UpdateTexture(tex);
1517 return;
1518 }
1519 else if (face == ScriptBaseClass.ALL_SIDES)
1520 {
1521 for (uint i = 0; i < GetNumberOfSides(part); i++)
1522 {
1523 if (tex.FaceTextures[i] != null)
1524 {
1525 texcolor = tex.FaceTextures[i].RGBA;
1526 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1527 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1528 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1529 tex.FaceTextures[i].RGBA = texcolor;
1530 }
1531 texcolor = tex.DefaultTexture.RGBA;
1532 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1533 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1534 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1535 tex.DefaultTexture.RGBA = texcolor;
1536 }
1537 part.UpdateTexture(tex);
1538 return;
1539 }
1540
1405 if (face == ScriptBaseClass.ALL_SIDES) 1541 if (face == ScriptBaseClass.ALL_SIDES)
1406 face = SceneObjectPart.ALL_SIDES; 1542 face = SceneObjectPart.ALL_SIDES;
1407 1543
@@ -1410,6 +1546,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1410 1546
1411 public void SetTexGen(SceneObjectPart part, int face,int style) 1547 public void SetTexGen(SceneObjectPart part, int face,int style)
1412 { 1548 {
1549 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1550 return;
1551
1413 Primitive.TextureEntry tex = part.Shape.Textures; 1552 Primitive.TextureEntry tex = part.Shape.Textures;
1414 MappingType textype; 1553 MappingType textype;
1415 textype = MappingType.Default; 1554 textype = MappingType.Default;
@@ -1440,6 +1579,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1440 1579
1441 public void SetGlow(SceneObjectPart part, int face, float glow) 1580 public void SetGlow(SceneObjectPart part, int face, float glow)
1442 { 1581 {
1582 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1583 return;
1584
1443 Primitive.TextureEntry tex = part.Shape.Textures; 1585 Primitive.TextureEntry tex = part.Shape.Textures;
1444 if (face >= 0 && face < GetNumberOfSides(part)) 1586 if (face >= 0 && face < GetNumberOfSides(part))
1445 { 1587 {
@@ -1465,6 +1607,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1465 1607
1466 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump) 1608 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1467 { 1609 {
1610 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1611 return;
1468 1612
1469 Shininess sval = new Shininess(); 1613 Shininess sval = new Shininess();
1470 1614
@@ -1515,6 +1659,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1515 1659
1516 public void SetFullBright(SceneObjectPart part, int face, bool bright) 1660 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1517 { 1661 {
1662 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1663 return;
1664
1518 Primitive.TextureEntry tex = part.Shape.Textures; 1665 Primitive.TextureEntry tex = part.Shape.Textures;
1519 if (face >= 0 && face < GetNumberOfSides(part)) 1666 if (face >= 0 && face < GetNumberOfSides(part))
1520 { 1667 {
@@ -1575,13 +1722,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1575 m_host.AddScriptLPS(1); 1722 m_host.AddScriptLPS(1);
1576 1723
1577 List<SceneObjectPart> parts = GetLinkParts(linknumber); 1724 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1578 1725 if (parts.Count > 0)
1579 foreach (SceneObjectPart part in parts) 1726 {
1580 SetAlpha(part, alpha, face); 1727 try
1728 {
1729 parts[0].ParentGroup.areUpdatesSuspended = true;
1730 foreach (SceneObjectPart part in parts)
1731 SetAlpha(part, alpha, face);
1732 }
1733 finally
1734 {
1735 parts[0].ParentGroup.areUpdatesSuspended = false;
1736 }
1737 }
1581 } 1738 }
1582 1739
1583 protected void SetAlpha(SceneObjectPart part, double alpha, int face) 1740 protected void SetAlpha(SceneObjectPart part, double alpha, int face)
1584 { 1741 {
1742 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1743 return;
1744
1585 Primitive.TextureEntry tex = part.Shape.Textures; 1745 Primitive.TextureEntry tex = part.Shape.Textures;
1586 Color4 texcolor; 1746 Color4 texcolor;
1587 if (face >= 0 && face < GetNumberOfSides(part)) 1747 if (face >= 0 && face < GetNumberOfSides(part))
@@ -1627,7 +1787,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1627 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction, 1787 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1628 float wind, float tension, LSL_Vector Force) 1788 float wind, float tension, LSL_Vector Force)
1629 { 1789 {
1630 if (part == null) 1790 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1631 return; 1791 return;
1632 1792
1633 if (flexi) 1793 if (flexi)
@@ -1662,7 +1822,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1662 /// <param name="falloff"></param> 1822 /// <param name="falloff"></param>
1663 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff) 1823 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1664 { 1824 {
1665 if (part == null) 1825 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1666 return; 1826 return;
1667 1827
1668 if (light) 1828 if (light)
@@ -1739,15 +1899,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1739 m_host.AddScriptLPS(1); 1899 m_host.AddScriptLPS(1);
1740 1900
1741 List<SceneObjectPart> parts = GetLinkParts(linknumber); 1901 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1742 1902 if (parts.Count > 0)
1743 foreach (SceneObjectPart part in parts) 1903 {
1744 SetTexture(part, texture, face); 1904 try
1745 1905 {
1906 parts[0].ParentGroup.areUpdatesSuspended = true;
1907 foreach (SceneObjectPart part in parts)
1908 SetTexture(part, texture, face);
1909 }
1910 finally
1911 {
1912 parts[0].ParentGroup.areUpdatesSuspended = false;
1913 }
1914 }
1746 ScriptSleep(200); 1915 ScriptSleep(200);
1747 } 1916 }
1748 1917
1749 protected void SetTexture(SceneObjectPart part, string texture, int face) 1918 protected void SetTexture(SceneObjectPart part, string texture, int face)
1750 { 1919 {
1920 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1921 return;
1922
1751 UUID textureID=new UUID(); 1923 UUID textureID=new UUID();
1752 1924
1753 if (!UUID.TryParse(texture, out textureID)) 1925 if (!UUID.TryParse(texture, out textureID))
@@ -1793,6 +1965,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1793 1965
1794 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) 1966 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1795 { 1967 {
1968 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1969 return;
1970
1796 Primitive.TextureEntry tex = part.Shape.Textures; 1971 Primitive.TextureEntry tex = part.Shape.Textures;
1797 if (face >= 0 && face < GetNumberOfSides(part)) 1972 if (face >= 0 && face < GetNumberOfSides(part))
1798 { 1973 {
@@ -1829,6 +2004,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1829 2004
1830 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) 2005 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1831 { 2006 {
2007 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2008 return;
2009
1832 Primitive.TextureEntry tex = part.Shape.Textures; 2010 Primitive.TextureEntry tex = part.Shape.Textures;
1833 if (face >= 0 && face < GetNumberOfSides(part)) 2011 if (face >= 0 && face < GetNumberOfSides(part))
1834 { 2012 {
@@ -1865,6 +2043,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1865 2043
1866 protected void RotateTexture(SceneObjectPart part, double rotation, int face) 2044 protected void RotateTexture(SceneObjectPart part, double rotation, int face)
1867 { 2045 {
2046 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2047 return;
2048
1868 Primitive.TextureEntry tex = part.Shape.Textures; 2049 Primitive.TextureEntry tex = part.Shape.Textures;
1869 if (face >= 0 && face < GetNumberOfSides(part)) 2050 if (face >= 0 && face < GetNumberOfSides(part))
1870 { 2051 {
@@ -1935,6 +2116,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1935 2116
1936 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) 2117 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos)
1937 { 2118 {
2119 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2120 return;
2121
1938 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) 2122 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
1939 LSL_Vector currentPos = GetPartLocalPos(part); 2123 LSL_Vector currentPos = GetPartLocalPos(part);
1940 2124
@@ -1951,7 +2135,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1951 } 2135 }
1952 else 2136 else
1953 { 2137 {
1954 LSL_Vector rel_vec = SetPosAdjust(currentPos, targetPos); 2138 LSL_Vector rel_vec = SetPosAdjust(new LSL_Vector(part.OffsetPosition.X, part.OffsetPosition.Y, part.OffsetPosition.Z), targetPos);
1955 part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z); 2139 part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z);
1956 SceneObjectGroup parent = part.ParentGroup; 2140 SceneObjectGroup parent = part.ParentGroup;
1957 parent.HasGroupChanged = true; 2141 parent.HasGroupChanged = true;
@@ -2034,6 +2218,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2034 2218
2035 protected void SetRot(SceneObjectPart part, Quaternion rot) 2219 protected void SetRot(SceneObjectPart part, Quaternion rot)
2036 { 2220 {
2221 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2222 return;
2223
2037 part.UpdateRotation(rot); 2224 part.UpdateRotation(rot);
2038 // Update rotation does not move the object in the physics scene if it's a linkset. 2225 // Update rotation does not move the object in the physics scene if it's a linkset.
2039 2226
@@ -2653,12 +2840,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2653 2840
2654 m_host.AddScriptLPS(1); 2841 m_host.AddScriptLPS(1);
2655 2842
2843 m_host.TaskInventory.LockItemsForRead(true);
2656 TaskInventoryItem item = m_host.TaskInventory[invItemID]; 2844 TaskInventoryItem item = m_host.TaskInventory[invItemID];
2657 2845 m_host.TaskInventory.LockItemsForRead(false);
2658 lock (m_host.TaskInventory)
2659 {
2660 item = m_host.TaskInventory[invItemID];
2661 }
2662 2846
2663 if (item.PermsGranter == UUID.Zero) 2847 if (item.PermsGranter == UUID.Zero)
2664 return 0; 2848 return 0;
@@ -2733,6 +2917,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2733 if (dist > m_ScriptDistanceFactor * 10.0f) 2917 if (dist > m_ScriptDistanceFactor * 10.0f)
2734 return; 2918 return;
2735 2919
2920 //Clone is thread-safe
2736 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 2921 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
2737 2922
2738 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory) 2923 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory)
@@ -2795,6 +2980,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2795 2980
2796 public void llLookAt(LSL_Vector target, double strength, double damping) 2981 public void llLookAt(LSL_Vector target, double strength, double damping)
2797 { 2982 {
2983 /*
2798 m_host.AddScriptLPS(1); 2984 m_host.AddScriptLPS(1);
2799 // Determine where we are looking from 2985 // Determine where we are looking from
2800 LSL_Vector from = llGetPos(); 2986 LSL_Vector from = llGetPos();
@@ -2814,10 +3000,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2814 // the angles of rotation in radians into rotation value 3000 // the angles of rotation in radians into rotation value
2815 3001
2816 LSL_Types.Quaternion rot = llEuler2Rot(angle); 3002 LSL_Types.Quaternion rot = llEuler2Rot(angle);
2817 Quaternion rotation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s); 3003
2818 m_host.startLookAt(rotation, (float)damping, (float)strength); 3004 // This would only work if your physics system contains an APID controller:
3005 // Quaternion rotation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
3006 // m_host.startLookAt(rotation, (float)damping, (float)strength);
3007
2819 // Orient the object to the angle calculated 3008 // Orient the object to the angle calculated
2820 //llSetRot(rot); 3009 llSetRot(rot);
3010 */
3011
3012 //The above code, while nice, doesn't replicate the behaviour of SL and tends to "roll" the object.
3013 //There's probably a smarter way of doing this, my rotation math-fu is weak.
3014 // http://bugs.meta7.com/view.php?id=28
3015 // - Tom
3016
3017 LSL_Rotation newrot = llGetRot() * llRotBetween(new LSL_Vector(1.0d, 0.0d, 0.0d) * llGetRot(), new LSL_Vector(0.0d, 0.0d, -1.0d));
3018 llSetRot(newrot * llRotBetween(new LSL_Vector(0.0d,0.0d,1.0d) * newrot, target - llGetPos()));
3019
3020 }
3021
3022 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3023 {
3024 m_host.AddScriptLPS(1);
3025// NotImplemented("llRotLookAt");
3026 m_host.RotLookAt(Rot2Quaternion(target), (float)strength, (float)damping);
3027
2821 } 3028 }
2822 3029
2823 public void llStopLookAt() 3030 public void llStopLookAt()
@@ -2866,13 +3073,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2866 { 3073 {
2867 TaskInventoryItem item; 3074 TaskInventoryItem item;
2868 3075
2869 lock (m_host.TaskInventory) 3076 m_host.TaskInventory.LockItemsForRead(true);
3077 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2870 { 3078 {
2871 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3079 m_host.TaskInventory.LockItemsForRead(false);
2872 return; 3080 return;
2873 else
2874 item = m_host.TaskInventory[InventorySelf()];
2875 } 3081 }
3082 else
3083 {
3084 item = m_host.TaskInventory[InventorySelf()];
3085 }
3086 m_host.TaskInventory.LockItemsForRead(false);
2876 3087
2877 if (item.PermsGranter != UUID.Zero) 3088 if (item.PermsGranter != UUID.Zero)
2878 { 3089 {
@@ -2894,13 +3105,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2894 { 3105 {
2895 TaskInventoryItem item; 3106 TaskInventoryItem item;
2896 3107
3108 m_host.TaskInventory.LockItemsForRead(true);
2897 lock (m_host.TaskInventory) 3109 lock (m_host.TaskInventory)
2898 { 3110 {
3111
2899 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3112 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3113 {
3114 m_host.TaskInventory.LockItemsForRead(false);
2900 return; 3115 return;
3116 }
2901 else 3117 else
3118 {
2902 item = m_host.TaskInventory[InventorySelf()]; 3119 item = m_host.TaskInventory[InventorySelf()];
3120 }
2903 } 3121 }
3122 m_host.TaskInventory.LockItemsForRead(false);
2904 3123
2905 m_host.AddScriptLPS(1); 3124 m_host.AddScriptLPS(1);
2906 3125
@@ -2932,18 +3151,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2932 { 3151 {
2933 m_host.AddScriptLPS(1); 3152 m_host.AddScriptLPS(1);
2934 3153
2935 if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
2936 return;
2937
2938 TaskInventoryItem item; 3154 TaskInventoryItem item;
2939 3155
2940 lock (m_host.TaskInventory) 3156 m_host.TaskInventory.LockItemsForRead(true);
3157
3158 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2941 { 3159 {
2942 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3160 m_host.TaskInventory.LockItemsForRead(false);
2943 return; 3161 return;
2944 else
2945 item = m_host.TaskInventory[InventorySelf()];
2946 } 3162 }
3163 else
3164 {
3165 item = m_host.TaskInventory[InventorySelf()];
3166 }
3167
3168 m_host.TaskInventory.LockItemsForRead(false);
2947 3169
2948 if (item.PermsGranter != m_host.OwnerID) 3170 if (item.PermsGranter != m_host.OwnerID)
2949 return; 3171 return;
@@ -2954,10 +3176,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2954 3176
2955 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 3177 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
2956 3178
2957 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; 3179 grp.AttachToAgent(m_host.OwnerID, (uint)attachment, Vector3.Zero, false);
2958 if (attachmentsModule != null)
2959 attachmentsModule.AttachObject(presence.ControllingClient,
2960 grp, (uint)attachment, false);
2961 } 3180 }
2962 } 3181 }
2963 3182
@@ -2970,13 +3189,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2970 3189
2971 TaskInventoryItem item; 3190 TaskInventoryItem item;
2972 3191
2973 lock (m_host.TaskInventory) 3192 m_host.TaskInventory.LockItemsForRead(true);
3193
3194 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2974 { 3195 {
2975 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3196 m_host.TaskInventory.LockItemsForRead(false);
2976 return; 3197 return;
2977 else
2978 item = m_host.TaskInventory[InventorySelf()];
2979 } 3198 }
3199 else
3200 {
3201 item = m_host.TaskInventory[InventorySelf()];
3202 }
3203 m_host.TaskInventory.LockItemsForRead(false);
3204
2980 3205
2981 if (item.PermsGranter != m_host.OwnerID) 3206 if (item.PermsGranter != m_host.OwnerID)
2982 return; 3207 return;
@@ -3015,6 +3240,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3015 3240
3016 public void llInstantMessage(string user, string message) 3241 public void llInstantMessage(string user, string message)
3017 { 3242 {
3243 UUID result;
3244 if (!UUID.TryParse(user, out result))
3245 {
3246 ShoutError("An invalid key was passed to llInstantMessage");
3247 ScriptSleep(2000);
3248 return;
3249 }
3250
3251
3018 m_host.AddScriptLPS(1); 3252 m_host.AddScriptLPS(1);
3019 3253
3020 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance. 3254 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
@@ -3029,14 +3263,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3029 UUID friendTransactionID = UUID.Random(); 3263 UUID friendTransactionID = UUID.Random();
3030 3264
3031 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); 3265 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
3032 3266
3033 GridInstantMessage msg = new GridInstantMessage(); 3267 GridInstantMessage msg = new GridInstantMessage();
3034 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; 3268 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
3035 msg.toAgentID = new Guid(user); // toAgentID.Guid; 3269 msg.toAgentID = new Guid(user); // toAgentID.Guid;
3036 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here 3270 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
3037// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message); 3271// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
3038// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString()); 3272// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
3039 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp; 3273 DateTime dt = DateTime.UtcNow;
3274
3275 // Ticks from UtcNow, but make it look like local. Evil, huh?
3276 dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
3277
3278 try
3279 {
3280 // Convert that to the PST timezone
3281 TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
3282 dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
3283 }
3284 catch
3285 {
3286 // No logging here, as it could be VERY spammy
3287 }
3288
3289 // And make it look local again to fool the unix time util
3290 dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
3291
3292 msg.timestamp = (uint)Util.ToUnixTime(dt);
3293
3040 //if (client != null) 3294 //if (client != null)
3041 //{ 3295 //{
3042 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName; 3296 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
@@ -3050,13 +3304,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3050 msg.message = message.Substring(0, 1024); 3304 msg.message = message.Substring(0, 1024);
3051 else 3305 else
3052 msg.message = message; 3306 msg.message = message;
3053 msg.dialog = (byte)19; // messgage from script ??? // dialog; 3307 msg.dialog = (byte)19; // MessageFromObject
3054 msg.fromGroup = false;// fromGroup; 3308 msg.fromGroup = false;// fromGroup;
3055 msg.offline = (byte)0; //offline; 3309 msg.offline = (byte)0; //offline;
3056 msg.ParentEstateID = 0; //ParentEstateID; 3310 msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID;
3057 msg.Position = Vector3.Zero;// new Vector3(m_host.AbsolutePosition); 3311 msg.Position = new Vector3(m_host.AbsolutePosition);
3058 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; 3312 msg.RegionID = World.RegionInfo.RegionID.Guid;
3059 msg.binaryBucket = new byte[0];// binaryBucket; 3313 msg.binaryBucket = Util.StringToBytes256(m_host.OwnerID.ToString());
3060 3314
3061 if (m_TransferModule != null) 3315 if (m_TransferModule != null)
3062 { 3316 {
@@ -3076,7 +3330,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3076 } 3330 }
3077 3331
3078 emailModule.SendEmail(m_host.UUID, address, subject, message); 3332 emailModule.SendEmail(m_host.UUID, address, subject, message);
3079 ScriptSleep(20000); 3333 ScriptSleep(15000);
3080 } 3334 }
3081 3335
3082 public void llGetNextEmail(string address, string subject) 3336 public void llGetNextEmail(string address, string subject)
@@ -3178,13 +3432,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3178 m_host.AddScriptLPS(1); 3432 m_host.AddScriptLPS(1);
3179 } 3433 }
3180 3434
3181 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3182 {
3183 m_host.AddScriptLPS(1);
3184 Quaternion rot = new Quaternion((float)target.x, (float)target.y, (float)target.z, (float)target.s);
3185 m_host.RotLookAt(rot, (float)strength, (float)damping);
3186 }
3187
3188 public LSL_Integer llStringLength(string str) 3435 public LSL_Integer llStringLength(string str)
3189 { 3436 {
3190 m_host.AddScriptLPS(1); 3437 m_host.AddScriptLPS(1);
@@ -3208,14 +3455,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3208 3455
3209 TaskInventoryItem item; 3456 TaskInventoryItem item;
3210 3457
3211 lock (m_host.TaskInventory) 3458 m_host.TaskInventory.LockItemsForRead(true);
3459 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3212 { 3460 {
3213 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3461 m_host.TaskInventory.LockItemsForRead(false);
3214 return; 3462 return;
3215 else
3216 item = m_host.TaskInventory[InventorySelf()];
3217 } 3463 }
3218 3464 else
3465 {
3466 item = m_host.TaskInventory[InventorySelf()];
3467 }
3468 m_host.TaskInventory.LockItemsForRead(false);
3219 if (item.PermsGranter == UUID.Zero) 3469 if (item.PermsGranter == UUID.Zero)
3220 return; 3470 return;
3221 3471
@@ -3245,13 +3495,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3245 3495
3246 TaskInventoryItem item; 3496 TaskInventoryItem item;
3247 3497
3248 lock (m_host.TaskInventory) 3498 m_host.TaskInventory.LockItemsForRead(true);
3499 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3249 { 3500 {
3250 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3501 m_host.TaskInventory.LockItemsForRead(false);
3251 return; 3502 return;
3252 else 3503 }
3253 item = m_host.TaskInventory[InventorySelf()]; 3504 else
3505 {
3506 item = m_host.TaskInventory[InventorySelf()];
3254 } 3507 }
3508 m_host.TaskInventory.LockItemsForRead(false);
3509
3255 3510
3256 if (item.PermsGranter == UUID.Zero) 3511 if (item.PermsGranter == UUID.Zero)
3257 return; 3512 return;
@@ -3322,10 +3577,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3322 3577
3323 TaskInventoryItem item; 3578 TaskInventoryItem item;
3324 3579
3325 lock (m_host.TaskInventory) 3580
3581 m_host.TaskInventory.LockItemsForRead(true);
3582 if (!m_host.TaskInventory.ContainsKey(invItemID))
3583 {
3584 m_host.TaskInventory.LockItemsForRead(false);
3585 return;
3586 }
3587 else
3326 { 3588 {
3327 item = m_host.TaskInventory[invItemID]; 3589 item = m_host.TaskInventory[invItemID];
3328 } 3590 }
3591 m_host.TaskInventory.LockItemsForRead(false);
3329 3592
3330 if (agentID == UUID.Zero || perm == 0) // Releasing permissions 3593 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
3331 { 3594 {
@@ -3357,11 +3620,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3357 3620
3358 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3621 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3359 { 3622 {
3360 lock (m_host.TaskInventory) 3623 m_host.TaskInventory.LockItemsForWrite(true);
3361 { 3624 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3362 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3625 m_host.TaskInventory[invItemID].PermsMask = perm;
3363 m_host.TaskInventory[invItemID].PermsMask = perm; 3626 m_host.TaskInventory.LockItemsForWrite(false);
3364 }
3365 3627
3366 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3628 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3367 "run_time_permissions", new Object[] { 3629 "run_time_permissions", new Object[] {
@@ -3381,11 +3643,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3381 3643
3382 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3644 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3383 { 3645 {
3384 lock (m_host.TaskInventory) 3646 m_host.TaskInventory.LockItemsForWrite(true);
3385 { 3647 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3386 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3648 m_host.TaskInventory[invItemID].PermsMask = perm;
3387 m_host.TaskInventory[invItemID].PermsMask = perm; 3649 m_host.TaskInventory.LockItemsForWrite(false);
3388 }
3389 3650
3390 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3651 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3391 "run_time_permissions", new Object[] { 3652 "run_time_permissions", new Object[] {
@@ -3406,11 +3667,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3406 3667
3407 if (!m_waitingForScriptAnswer) 3668 if (!m_waitingForScriptAnswer)
3408 { 3669 {
3409 lock (m_host.TaskInventory) 3670 m_host.TaskInventory.LockItemsForWrite(true);
3410 { 3671 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3411 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3672 m_host.TaskInventory[invItemID].PermsMask = 0;
3412 m_host.TaskInventory[invItemID].PermsMask = 0; 3673 m_host.TaskInventory.LockItemsForWrite(false);
3413 }
3414 3674
3415 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; 3675 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
3416 m_waitingForScriptAnswer=true; 3676 m_waitingForScriptAnswer=true;
@@ -3445,10 +3705,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3445 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) 3705 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3446 llReleaseControls(); 3706 llReleaseControls();
3447 3707
3448 lock (m_host.TaskInventory) 3708
3449 { 3709 m_host.TaskInventory.LockItemsForWrite(true);
3450 m_host.TaskInventory[invItemID].PermsMask = answer; 3710 m_host.TaskInventory[invItemID].PermsMask = answer;
3451 } 3711 m_host.TaskInventory.LockItemsForWrite(false);
3712
3452 3713
3453 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3714 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3454 "run_time_permissions", new Object[] { 3715 "run_time_permissions", new Object[] {
@@ -3460,16 +3721,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3460 { 3721 {
3461 m_host.AddScriptLPS(1); 3722 m_host.AddScriptLPS(1);
3462 3723
3463 lock (m_host.TaskInventory) 3724 m_host.TaskInventory.LockItemsForRead(true);
3725
3726 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3464 { 3727 {
3465 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3728 if (item.Type == 10 && item.ItemID == m_itemID)
3466 { 3729 {
3467 if (item.Type == 10 && item.ItemID == m_itemID) 3730 m_host.TaskInventory.LockItemsForRead(false);
3468 { 3731 return item.PermsGranter.ToString();
3469 return item.PermsGranter.ToString();
3470 }
3471 } 3732 }
3472 } 3733 }
3734 m_host.TaskInventory.LockItemsForRead(false);
3473 3735
3474 return UUID.Zero.ToString(); 3736 return UUID.Zero.ToString();
3475 } 3737 }
@@ -3478,19 +3740,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3478 { 3740 {
3479 m_host.AddScriptLPS(1); 3741 m_host.AddScriptLPS(1);
3480 3742
3481 lock (m_host.TaskInventory) 3743 m_host.TaskInventory.LockItemsForRead(true);
3744
3745 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3482 { 3746 {
3483 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3747 if (item.Type == 10 && item.ItemID == m_itemID)
3484 { 3748 {
3485 if (item.Type == 10 && item.ItemID == m_itemID) 3749 int perms = item.PermsMask;
3486 { 3750 if (m_automaticLinkPermission)
3487 int perms = item.PermsMask; 3751 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
3488 if (m_automaticLinkPermission) 3752 m_host.TaskInventory.LockItemsForRead(false);
3489 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; 3753 return perms;
3490 return perms;
3491 }
3492 } 3754 }
3493 } 3755 }
3756 m_host.TaskInventory.LockItemsForRead(false);
3494 3757
3495 return 0; 3758 return 0;
3496 } 3759 }
@@ -3512,9 +3775,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3512 public void llSetLinkColor(int linknumber, LSL_Vector color, int face) 3775 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
3513 { 3776 {
3514 List<SceneObjectPart> parts = GetLinkParts(linknumber); 3777 List<SceneObjectPart> parts = GetLinkParts(linknumber);
3515 3778 if (parts.Count > 0)
3516 foreach (SceneObjectPart part in parts) 3779 {
3517 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 3780 try
3781 {
3782 parts[0].ParentGroup.areUpdatesSuspended = true;
3783 foreach (SceneObjectPart part in parts)
3784 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face);
3785 }
3786 finally
3787 {
3788 parts[0].ParentGroup.areUpdatesSuspended = false;
3789 }
3790 }
3518 } 3791 }
3519 3792
3520 public void llCreateLink(string target, int parent) 3793 public void llCreateLink(string target, int parent)
@@ -3527,11 +3800,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3527 return; 3800 return;
3528 3801
3529 TaskInventoryItem item; 3802 TaskInventoryItem item;
3530 lock (m_host.TaskInventory) 3803 m_host.TaskInventory.LockItemsForRead(true);
3531 { 3804 item = m_host.TaskInventory[invItemID];
3532 item = m_host.TaskInventory[invItemID]; 3805 m_host.TaskInventory.LockItemsForRead(false);
3533 } 3806
3534
3535 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3807 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3536 && !m_automaticLinkPermission) 3808 && !m_automaticLinkPermission)
3537 { 3809 {
@@ -3584,16 +3856,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3584 m_host.AddScriptLPS(1); 3856 m_host.AddScriptLPS(1);
3585 UUID invItemID = InventorySelf(); 3857 UUID invItemID = InventorySelf();
3586 3858
3587 lock (m_host.TaskInventory) 3859 m_host.TaskInventory.LockItemsForRead(true);
3588 {
3589 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3860 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3590 && !m_automaticLinkPermission) 3861 && !m_automaticLinkPermission)
3591 { 3862 {
3592 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); 3863 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
3864 m_host.TaskInventory.LockItemsForRead(false);
3593 return; 3865 return;
3594 } 3866 }
3595 } 3867 m_host.TaskInventory.LockItemsForRead(false);
3596 3868
3597 if (linknum < ScriptBaseClass.LINK_THIS) 3869 if (linknum < ScriptBaseClass.LINK_THIS)
3598 return; 3870 return;
3599 3871
@@ -3632,10 +3904,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3632 // Restructuring Multiple Prims. 3904 // Restructuring Multiple Prims.
3633 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts); 3905 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3634 parts.Remove(parentPrim.RootPart); 3906 parts.Remove(parentPrim.RootPart);
3635 foreach (SceneObjectPart part in parts) 3907 if (parts.Count > 0)
3636 { 3908 {
3637 parentPrim.DelinkFromGroup(part.LocalId, true); 3909 try
3910 {
3911 parts[0].ParentGroup.areUpdatesSuspended = true;
3912 foreach (SceneObjectPart part in parts)
3913 {
3914 parentPrim.DelinkFromGroup(part.LocalId, true);
3915 }
3916 }
3917 finally
3918 {
3919 parts[0].ParentGroup.areUpdatesSuspended = false;
3920 }
3638 } 3921 }
3922
3639 parentPrim.HasGroupChanged = true; 3923 parentPrim.HasGroupChanged = true;
3640 parentPrim.ScheduleGroupForFullUpdate(); 3924 parentPrim.ScheduleGroupForFullUpdate();
3641 parentPrim.TriggerScriptChangedEvent(Changed.LINK); 3925 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
@@ -3644,11 +3928,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3644 { 3928 {
3645 SceneObjectPart newRoot = parts[0]; 3929 SceneObjectPart newRoot = parts[0];
3646 parts.Remove(newRoot); 3930 parts.Remove(newRoot);
3647 foreach (SceneObjectPart part in parts) 3931
3932 try
3648 { 3933 {
3649 part.UpdateFlag = 0; 3934 parts[0].ParentGroup.areUpdatesSuspended = true;
3650 newRoot.ParentGroup.LinkToGroup(part.ParentGroup); 3935 foreach (SceneObjectPart part in parts)
3936 {
3937 part.UpdateFlag = 0;
3938 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
3939 }
3651 } 3940 }
3941 finally
3942 {
3943 parts[0].ParentGroup.areUpdatesSuspended = false;
3944 }
3945
3946
3652 newRoot.ParentGroup.HasGroupChanged = true; 3947 newRoot.ParentGroup.HasGroupChanged = true;
3653 newRoot.ParentGroup.ScheduleGroupForFullUpdate(); 3948 newRoot.ParentGroup.ScheduleGroupForFullUpdate();
3654 } 3949 }
@@ -3694,6 +3989,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3694 } 3989 }
3695 else 3990 else
3696 { 3991 {
3992 if (linknum > m_host.ParentGroup.PrimCount || (linknum == 1 && m_host.ParentGroup.PrimCount == 1))
3993 {
3994 linknum -= (m_host.ParentGroup.PrimCount) + 1;
3995
3996 List<ScenePresence> avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET);
3997 if (avatars.Count > linknum)
3998 {
3999 return avatars[linknum].UUID.ToString();
4000 }
4001 }
3697 return UUID.Zero.ToString(); 4002 return UUID.Zero.ToString();
3698 } 4003 }
3699 } 4004 }
@@ -3770,17 +4075,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3770 m_host.AddScriptLPS(1); 4075 m_host.AddScriptLPS(1);
3771 int count = 0; 4076 int count = 0;
3772 4077
3773 lock (m_host.TaskInventory) 4078 m_host.TaskInventory.LockItemsForRead(true);
4079 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3774 { 4080 {
3775 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4081 if (inv.Value.Type == type || type == -1)
3776 { 4082 {
3777 if (inv.Value.Type == type || type == -1) 4083 count = count + 1;
3778 {
3779 count = count + 1;
3780 }
3781 } 4084 }
3782 } 4085 }
3783 4086
4087 m_host.TaskInventory.LockItemsForRead(false);
3784 return count; 4088 return count;
3785 } 4089 }
3786 4090
@@ -3789,16 +4093,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3789 m_host.AddScriptLPS(1); 4093 m_host.AddScriptLPS(1);
3790 ArrayList keys = new ArrayList(); 4094 ArrayList keys = new ArrayList();
3791 4095
3792 lock (m_host.TaskInventory) 4096 m_host.TaskInventory.LockItemsForRead(true);
4097 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3793 { 4098 {
3794 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4099 if (inv.Value.Type == type || type == -1)
3795 { 4100 {
3796 if (inv.Value.Type == type || type == -1) 4101 keys.Add(inv.Value.Name);
3797 {
3798 keys.Add(inv.Value.Name);
3799 }
3800 } 4102 }
3801 } 4103 }
4104 m_host.TaskInventory.LockItemsForRead(false);
3802 4105
3803 if (keys.Count == 0) 4106 if (keys.Count == 0)
3804 { 4107 {
@@ -3835,20 +4138,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3835 } 4138 }
3836 4139
3837 // move the first object found with this inventory name 4140 // move the first object found with this inventory name
3838 lock (m_host.TaskInventory) 4141 m_host.TaskInventory.LockItemsForRead(true);
4142 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3839 { 4143 {
3840 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4144 if (inv.Value.Name == inventory)
3841 { 4145 {
3842 if (inv.Value.Name == inventory) 4146 found = true;
3843 { 4147 objId = inv.Key;
3844 found = true; 4148 assetType = inv.Value.Type;
3845 objId = inv.Key; 4149 objName = inv.Value.Name;
3846 assetType = inv.Value.Type; 4150 break;
3847 objName = inv.Value.Name;
3848 break;
3849 }
3850 } 4151 }
3851 } 4152 }
4153 m_host.TaskInventory.LockItemsForRead(false);
3852 4154
3853 if (!found) 4155 if (!found)
3854 { 4156 {
@@ -3856,9 +4158,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3856 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); 4158 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3857 } 4159 }
3858 4160
3859 // check if destination is an avatar 4161 // check if destination is an object
3860 if (World.GetScenePresence(destId) != null) 4162 if (World.GetSceneObjectPart(destId) != null)
4163 {
4164 // destination is an object
4165 World.MoveTaskInventoryItem(destId, m_host, objId);
4166 }
4167 else
3861 { 4168 {
4169 ScenePresence presence = World.GetScenePresence(destId);
4170
4171 if (presence == null)
4172 {
4173 UserAccount account =
4174 World.UserAccountService.GetUserAccount(
4175 World.RegionInfo.ScopeID,
4176 destId);
4177
4178 if (account == null)
4179 {
4180 llSay(0, "Can't find destination "+destId.ToString());
4181 return;
4182 }
4183 }
4184
3862 // destination is an avatar 4185 // destination is an avatar
3863 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId); 4186 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
3864 4187
@@ -3882,31 +4205,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3882 4205
3883 if (m_TransferModule != null) 4206 if (m_TransferModule != null)
3884 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 4207 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
4208
4209 //This delay should only occur when giving inventory to avatars.
4210 ScriptSleep(3000);
3885 } 4211 }
3886 else
3887 {
3888 // destination is an object
3889 World.MoveTaskInventoryItem(destId, m_host, objId);
3890 }
3891 ScriptSleep(3000);
3892 } 4212 }
3893 4213
4214 [DebuggerNonUserCode]
3894 public void llRemoveInventory(string name) 4215 public void llRemoveInventory(string name)
3895 { 4216 {
3896 m_host.AddScriptLPS(1); 4217 m_host.AddScriptLPS(1);
3897 4218
3898 lock (m_host.TaskInventory) 4219 List<TaskInventoryItem> inv;
4220 try
3899 { 4221 {
3900 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4222 m_host.TaskInventory.LockItemsForRead(true);
4223 inv = new List<TaskInventoryItem>(m_host.TaskInventory.Values);
4224 }
4225 finally
4226 {
4227 m_host.TaskInventory.LockItemsForRead(false);
4228 }
4229 foreach (TaskInventoryItem item in inv)
4230 {
4231 if (item.Name == name)
3901 { 4232 {
3902 if (item.Name == name) 4233 if (item.ItemID == m_itemID)
3903 { 4234 throw new ScriptDeleteException();
3904 if (item.ItemID == m_itemID) 4235 else
3905 throw new ScriptDeleteException(); 4236 m_host.Inventory.RemoveInventoryItem(item.ItemID);
3906 else 4237 return;
3907 m_host.Inventory.RemoveInventoryItem(item.ItemID);
3908 return;
3909 }
3910 } 4238 }
3911 } 4239 }
3912 } 4240 }
@@ -3972,6 +4300,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3972 ce.time = Util.EnvironmentTickCount(); 4300 ce.time = Util.EnvironmentTickCount();
3973 ce.account = account; 4301 ce.account = account;
3974 ce.pinfo = pinfo; 4302 ce.pinfo = pinfo;
4303 m_userInfoCache[uuid] = ce;
3975 } 4304 }
3976 else 4305 else
3977 { 4306 {
@@ -4047,6 +4376,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4047 { 4376 {
4048 m_host.AddScriptLPS(1); 4377 m_host.AddScriptLPS(1);
4049 4378
4379 //Clone is thread safe
4050 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 4380 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
4051 4381
4052 foreach (TaskInventoryItem item in itemDictionary.Values) 4382 foreach (TaskInventoryItem item in itemDictionary.Values)
@@ -4100,6 +4430,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4100 ScenePresence presence = World.GetScenePresence(agentId); 4430 ScenePresence presence = World.GetScenePresence(agentId);
4101 if (presence != null) 4431 if (presence != null)
4102 { 4432 {
4433 // agent must not be a god
4434 if (presence.GodLevel >= 200) return;
4435
4103 // agent must be over the owners land 4436 // agent must be over the owners land
4104 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4437 if (m_host.OwnerID == World.LandChannel.GetLandObject(
4105 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) 4438 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
@@ -4159,17 +4492,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4159 UUID soundId = UUID.Zero; 4492 UUID soundId = UUID.Zero;
4160 if (!UUID.TryParse(impact_sound, out soundId)) 4493 if (!UUID.TryParse(impact_sound, out soundId))
4161 { 4494 {
4162 lock (m_host.TaskInventory) 4495 m_host.TaskInventory.LockItemsForRead(true);
4496 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4163 { 4497 {
4164 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4498 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound)
4165 { 4499 {
4166 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) 4500 soundId = item.AssetID;
4167 { 4501 break;
4168 soundId = item.AssetID;
4169 break;
4170 }
4171 } 4502 }
4172 } 4503 }
4504 m_host.TaskInventory.LockItemsForRead(false);
4173 } 4505 }
4174 m_host.CollisionSound = soundId; 4506 m_host.CollisionSound = soundId;
4175 m_host.CollisionSoundVolume = (float)impact_volume; 4507 m_host.CollisionSoundVolume = (float)impact_volume;
@@ -4215,6 +4547,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4215 UUID partItemID; 4547 UUID partItemID;
4216 foreach (SceneObjectPart part in parts) 4548 foreach (SceneObjectPart part in parts)
4217 { 4549 {
4550 //Clone is thread safe
4218 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); 4551 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
4219 4552
4220 foreach (TaskInventoryItem item in itemsDictionary.Values) 4553 foreach (TaskInventoryItem item in itemsDictionary.Values)
@@ -4429,17 +4762,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4429 4762
4430 m_host.AddScriptLPS(1); 4763 m_host.AddScriptLPS(1);
4431 4764
4432 lock (m_host.TaskInventory) 4765 m_host.TaskInventory.LockItemsForRead(true);
4766 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4433 { 4767 {
4434 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4768 if (item.Type == 10 && item.ItemID == m_itemID)
4435 { 4769 {
4436 if (item.Type == 10 && item.ItemID == m_itemID) 4770 result = item.Name!=null?item.Name:String.Empty;
4437 { 4771 break;
4438 result = item.Name != null ? item.Name : String.Empty;
4439 break;
4440 }
4441 } 4772 }
4442 } 4773 }
4774 m_host.TaskInventory.LockItemsForRead(false);
4443 4775
4444 return result; 4776 return result;
4445 } 4777 }
@@ -4592,23 +4924,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4592 { 4924 {
4593 m_host.AddScriptLPS(1); 4925 m_host.AddScriptLPS(1);
4594 4926
4595 lock (m_host.TaskInventory) 4927 m_host.TaskInventory.LockItemsForRead(true);
4928 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4596 { 4929 {
4597 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4930 if (inv.Value.Name == name)
4598 { 4931 {
4599 if (inv.Value.Name == name) 4932 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4600 { 4933 {
4601 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) 4934 m_host.TaskInventory.LockItemsForRead(false);
4602 { 4935 return inv.Value.AssetID.ToString();
4603 return inv.Value.AssetID.ToString(); 4936 }
4604 } 4937 else
4605 else 4938 {
4606 { 4939 m_host.TaskInventory.LockItemsForRead(false);
4607 return UUID.Zero.ToString(); 4940 return UUID.Zero.ToString();
4608 }
4609 } 4941 }
4610 } 4942 }
4611 } 4943 }
4944 m_host.TaskInventory.LockItemsForRead(false);
4612 4945
4613 return UUID.Zero.ToString(); 4946 return UUID.Zero.ToString();
4614 } 4947 }
@@ -4761,14 +5094,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4761 { 5094 {
4762 m_host.AddScriptLPS(1); 5095 m_host.AddScriptLPS(1);
4763 5096
4764 if (src == null) 5097 return src.Length;
4765 {
4766 return 0;
4767 }
4768 else
4769 {
4770 return src.Length;
4771 }
4772 } 5098 }
4773 5099
4774 public LSL_Integer llList2Integer(LSL_List src, int index) 5100 public LSL_Integer llList2Integer(LSL_List src, int index)
@@ -4814,7 +5140,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4814 else if (src.Data[index] is LSL_Float) 5140 else if (src.Data[index] is LSL_Float)
4815 return Convert.ToDouble(((LSL_Float) src.Data[index]).value); 5141 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
4816 else if (src.Data[index] is LSL_String) 5142 else if (src.Data[index] is LSL_String)
4817 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string); 5143 {
5144 string str = ((LSL_String) src.Data[index]).m_string;
5145 Match m = Regex.Match(str, "^\\s*(-?\\+?[,0-9]+\\.?[0-9]*)");
5146 if (m != Match.Empty)
5147 {
5148 str = m.Value;
5149 double d = 0.0;
5150 if (!Double.TryParse(str, out d))
5151 return 0.0;
5152
5153 return d;
5154 }
5155 return 0.0;
5156 }
4818 return Convert.ToDouble(src.Data[index]); 5157 return Convert.ToDouble(src.Data[index]);
4819 } 5158 }
4820 catch (FormatException) 5159 catch (FormatException)
@@ -5499,7 +5838,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5499 public void llSetSoundQueueing(int queue) 5838 public void llSetSoundQueueing(int queue)
5500 { 5839 {
5501 m_host.AddScriptLPS(1); 5840 m_host.AddScriptLPS(1);
5502 NotImplemented("llSetSoundQueueing");
5503 } 5841 }
5504 5842
5505 public void llSetSoundRadius(double radius) 5843 public void llSetSoundRadius(double radius)
@@ -5544,10 +5882,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5544 m_host.AddScriptLPS(1); 5882 m_host.AddScriptLPS(1);
5545 5883
5546 List<SceneObjectPart> parts = GetLinkParts(linknumber); 5884 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5547 5885 if (parts.Count > 0)
5548 foreach (var part in parts)
5549 { 5886 {
5550 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate); 5887 try
5888 {
5889 parts[0].ParentGroup.areUpdatesSuspended = true;
5890 foreach (var part in parts)
5891 {
5892 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
5893 }
5894 }
5895 finally
5896 {
5897 parts[0].ParentGroup.areUpdatesSuspended = false;
5898 }
5551 } 5899 }
5552 } 5900 }
5553 5901
@@ -5601,6 +5949,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5601 ScriptSleep(5000); 5949 ScriptSleep(5000);
5602 } 5950 }
5603 5951
5952 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers)
5953 {
5954 return ParseString2List(str, separators, in_spacers, false);
5955 }
5956
5604 public LSL_Integer llOverMyLand(string id) 5957 public LSL_Integer llOverMyLand(string id)
5605 { 5958 {
5606 m_host.AddScriptLPS(1); 5959 m_host.AddScriptLPS(1);
@@ -5801,7 +6154,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5801 return m_host.ParentGroup.RootPart.AttachmentPoint; 6154 return m_host.ParentGroup.RootPart.AttachmentPoint;
5802 } 6155 }
5803 6156
5804 public LSL_Integer llGetFreeMemory() 6157 public virtual LSL_Integer llGetFreeMemory()
5805 { 6158 {
5806 m_host.AddScriptLPS(1); 6159 m_host.AddScriptLPS(1);
5807 // Make scripts designed for LSO happy 6160 // Make scripts designed for LSO happy
@@ -6112,14 +6465,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6112 6465
6113 protected UUID GetTaskInventoryItem(string name) 6466 protected UUID GetTaskInventoryItem(string name)
6114 { 6467 {
6115 lock (m_host.TaskInventory) 6468 m_host.TaskInventory.LockItemsForRead(true);
6469 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6116 { 6470 {
6117 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6471 if (inv.Value.Name == name)
6118 { 6472 {
6119 if (inv.Value.Name == name) 6473 m_host.TaskInventory.LockItemsForRead(false);
6120 return inv.Key; 6474 return inv.Key;
6121 } 6475 }
6122 } 6476 }
6477 m_host.TaskInventory.LockItemsForRead(false);
6123 6478
6124 return UUID.Zero; 6479 return UUID.Zero;
6125 } 6480 }
@@ -6447,22 +6802,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6447 } 6802 }
6448 6803
6449 // copy the first script found with this inventory name 6804 // copy the first script found with this inventory name
6450 lock (m_host.TaskInventory) 6805 m_host.TaskInventory.LockItemsForRead(true);
6806 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6451 { 6807 {
6452 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6808 if (inv.Value.Name == name)
6453 { 6809 {
6454 if (inv.Value.Name == name) 6810 // make sure the object is a script
6811 if (10 == inv.Value.Type)
6455 { 6812 {
6456 // make sure the object is a script 6813 found = true;
6457 if (10 == inv.Value.Type) 6814 srcId = inv.Key;
6458 { 6815 break;
6459 found = true;
6460 srcId = inv.Key;
6461 break;
6462 }
6463 } 6816 }
6464 } 6817 }
6465 } 6818 }
6819 m_host.TaskInventory.LockItemsForRead(false);
6466 6820
6467 if (!found) 6821 if (!found)
6468 { 6822 {
@@ -6546,6 +6900,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6546 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) 6900 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist)
6547 { 6901 {
6548 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 6902 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6903 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
6904 return shapeBlock;
6549 6905
6550 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && 6906 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
6551 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && 6907 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
@@ -6621,6 +6977,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6621 6977
6622 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge) 6978 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge)
6623 { 6979 {
6980 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
6981 return;
6982
6624 ObjectShapePacket.ObjectDataBlock shapeBlock; 6983 ObjectShapePacket.ObjectDataBlock shapeBlock;
6625 6984
6626 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 6985 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6670,6 +7029,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6670 7029
6671 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge) 7030 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge)
6672 { 7031 {
7032 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7033 return;
7034
6673 ObjectShapePacket.ObjectDataBlock shapeBlock; 7035 ObjectShapePacket.ObjectDataBlock shapeBlock;
6674 7036
6675 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7037 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6712,6 +7074,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6712 7074
6713 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge) 7075 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge)
6714 { 7076 {
7077 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7078 return;
7079
6715 ObjectShapePacket.ObjectDataBlock shapeBlock; 7080 ObjectShapePacket.ObjectDataBlock shapeBlock;
6716 7081
6717 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7082 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6838,6 +7203,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6838 7203
6839 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type) 7204 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type)
6840 { 7205 {
7206 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7207 return;
7208
6841 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 7209 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6842 UUID sculptId; 7210 UUID sculptId;
6843 7211
@@ -6853,13 +7221,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6853 shapeBlock.PathScaleX = 100; 7221 shapeBlock.PathScaleX = 100;
6854 shapeBlock.PathScaleY = 150; 7222 shapeBlock.PathScaleY = 150;
6855 7223
6856 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER && 7224 if ((type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER) == 0 &&
6857 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE && 7225 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE) == 0 &&
6858 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE && 7226 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE) == 0 &&
6859 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) 7227 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) == 0)
6860 { 7228 {
6861 // default 7229 // default
6862 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; 7230 type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
6863 } 7231 }
6864 7232
6865 // retain pathcurve 7233 // retain pathcurve
@@ -6878,25 +7246,83 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6878 ScriptSleep(200); 7246 ScriptSleep(200);
6879 } 7247 }
6880 7248
6881 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) 7249 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
6882 { 7250 {
6883 m_host.AddScriptLPS(1); 7251 m_host.AddScriptLPS(1);
6884 7252
6885 List<SceneObjectPart> parts = GetLinkParts(linknumber); 7253 List<SceneObjectPart> parts = GetLinkParts(linknumber);
7254 List<ScenePresence> avatars = GetLinkAvatars(linknumber);
7255 if (parts.Count>0)
7256 {
7257 try
7258 {
7259 parts[0].ParentGroup.areUpdatesSuspended = true;
7260 foreach (SceneObjectPart part in parts)
7261 SetPrimParams(part, rules);
7262 }
7263 finally
7264 {
7265 parts[0].ParentGroup.areUpdatesSuspended = false;
7266 }
7267 }
7268 if (avatars.Count > 0)
7269 {
7270 foreach (ScenePresence avatar in avatars)
7271 SetPrimParams(avatar, rules);
7272 }
7273 }
6886 7274
6887 foreach (SceneObjectPart part in parts) 7275 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
6888 SetPrimParams(part, rules); 7276 {
6889 7277 llSetLinkPrimitiveParamsFast(linknumber, rules);
6890 ScriptSleep(200); 7278 ScriptSleep(200);
6891 } 7279 }
6892 7280
6893 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules) 7281 protected void SetPrimParams(ScenePresence av, LSL_List rules)
6894 { 7282 {
6895 llSetLinkPrimitiveParams(linknumber, rules); 7283 //This is a special version of SetPrimParams to deal with avatars which are sat on the linkset.
7284 //We only support PRIM_POSITION and PRIM_ROTATION
7285
7286 int idx = 0;
7287
7288 while (idx < rules.Length)
7289 {
7290 int code = rules.GetLSLIntegerItem(idx++);
7291
7292 int remain = rules.Length - idx;
7293
7294
7295
7296 switch (code)
7297 {
7298 case (int)ScriptBaseClass.PRIM_POSITION:
7299 if (remain < 1)
7300 return;
7301 LSL_Vector v;
7302 v = rules.GetVector3Item(idx++);
7303 av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
7304 av.SendFullUpdateToAllClients();
7305
7306 break;
7307
7308 case (int)ScriptBaseClass.PRIM_ROTATION:
7309 if (remain < 1)
7310 return;
7311 LSL_Rotation r;
7312 r = rules.GetQuaternionItem(idx++);
7313 av.OffsetRotation = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
7314 av.SendFullUpdateToAllClients();
7315 break;
7316 }
7317 }
7318
6896 } 7319 }
6897 7320
6898 protected void SetPrimParams(SceneObjectPart part, LSL_List rules) 7321 protected void SetPrimParams(SceneObjectPart part, LSL_List rules)
6899 { 7322 {
7323 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7324 return;
7325
6900 int idx = 0; 7326 int idx = 0;
6901 7327
6902 while (idx < rules.Length) 7328 while (idx < rules.Length)
@@ -7413,13 +7839,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7413 public LSL_Integer llGetNumberOfPrims() 7839 public LSL_Integer llGetNumberOfPrims()
7414 { 7840 {
7415 m_host.AddScriptLPS(1); 7841 m_host.AddScriptLPS(1);
7416 int avatarCount = 0; 7842 int avatarCount = m_host.ParentGroup.GetLinkedAvatars().Count;
7417 World.ForEachScenePresence(delegate(ScenePresence presence) 7843
7418 {
7419 if (!presence.IsChildAgent && presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID))
7420 avatarCount++;
7421 });
7422
7423 return m_host.ParentGroup.PrimCount + avatarCount; 7844 return m_host.ParentGroup.PrimCount + avatarCount;
7424 } 7845 }
7425 7846
@@ -7435,55 +7856,98 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7435 m_host.AddScriptLPS(1); 7856 m_host.AddScriptLPS(1);
7436 UUID objID = UUID.Zero; 7857 UUID objID = UUID.Zero;
7437 LSL_List result = new LSL_List(); 7858 LSL_List result = new LSL_List();
7859
7860 // If the ID is not valid, return null result
7438 if (!UUID.TryParse(obj, out objID)) 7861 if (!UUID.TryParse(obj, out objID))
7439 { 7862 {
7440 result.Add(new LSL_Vector()); 7863 result.Add(new LSL_Vector());
7441 result.Add(new LSL_Vector()); 7864 result.Add(new LSL_Vector());
7442 return result; 7865 return result;
7443 } 7866 }
7867
7868 // Check if this is an attached prim. If so, replace
7869 // the UUID with the avatar UUID and report it's bounding box
7870 SceneObjectPart part = World.GetSceneObjectPart(objID);
7871 if (part != null && part.ParentGroup.IsAttachment)
7872 objID = part.ParentGroup.RootPart.AttachedAvatar;
7873
7874 // Find out if this is an avatar ID. If so, return it's box
7444 ScenePresence presence = World.GetScenePresence(objID); 7875 ScenePresence presence = World.GetScenePresence(objID);
7445 if (presence != null) 7876 if (presence != null)
7446 { 7877 {
7447 if (presence.ParentID == 0) // not sat on an object 7878 // As per LSL Wiki, there is no difference between sitting
7879 // and standing avatar since server 1.36
7880 LSL_Vector lower;
7881 LSL_Vector upper;
7882 if (presence.Animator.Animations.DefaultAnimation.AnimID
7883 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
7448 { 7884 {
7449 LSL_Vector lower; 7885 // This is for ground sitting avatars
7450 LSL_Vector upper; 7886 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7451 if (presence.Animator.Animations.DefaultAnimation.AnimID 7887 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7452 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) 7888 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7453 {
7454 // This is for ground sitting avatars
7455 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7456 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7457 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7458 }
7459 else
7460 {
7461 // This is for standing/flying avatars
7462 float height = presence.Appearance.AvatarHeight / 2.0f;
7463 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7464 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7465 }
7466 result.Add(lower);
7467 result.Add(upper);
7468 return result;
7469 } 7889 }
7470 else 7890 else
7471 { 7891 {
7472 // sitting on an object so we need the bounding box of that 7892 // This is for standing/flying avatars
7473 // which should include the avatar so set the UUID to the 7893 float height = presence.Appearance.AvatarHeight / 2.0f;
7474 // UUID of the object the avatar is sat on and allow it to fall through 7894 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7475 // to processing an object 7895 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7476 SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
7477 objID = p.UUID;
7478 } 7896 }
7897
7898 // Adjust to the documented error offsets (see LSL Wiki)
7899 lower += new LSL_Vector(0.05f, 0.05f, 0.05f);
7900 upper -= new LSL_Vector(0.05f, 0.05f, 0.05f);
7901
7902 if (lower.x > upper.x)
7903 lower.x = upper.x;
7904 if (lower.y > upper.y)
7905 lower.y = upper.y;
7906 if (lower.z > upper.z)
7907 lower.z = upper.z;
7908
7909 result.Add(lower);
7910 result.Add(upper);
7911 return result;
7479 } 7912 }
7480 SceneObjectPart part = World.GetSceneObjectPart(objID); 7913
7914 part = World.GetSceneObjectPart(objID);
7481 // Currently only works for single prims without a sitting avatar 7915 // Currently only works for single prims without a sitting avatar
7482 if (part != null) 7916 if (part != null)
7483 { 7917 {
7484 Vector3 halfSize = part.Scale / 2.0f; 7918 float minX;
7485 LSL_Vector lower = new LSL_Vector(halfSize.X * -1.0f, halfSize.Y * -1.0f, halfSize.Z * -1.0f); 7919 float maxX;
7486 LSL_Vector upper = new LSL_Vector(halfSize.X, halfSize.Y, halfSize.Z); 7920 float minY;
7921 float maxY;
7922 float minZ;
7923 float maxZ;
7924
7925 // This BBox is in sim coordinates, with the offset being
7926 // a contained point.
7927 Vector3[] offsets = World.GetCombinedBoundingBox(new List<SceneObjectGroup> { part.ParentGroup },
7928 out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
7929
7930 minX -= offsets[0].X;
7931 maxX -= offsets[0].X;
7932 minY -= offsets[0].Y;
7933 maxY -= offsets[0].Y;
7934 minZ -= offsets[0].Z;
7935 maxZ -= offsets[0].Z;
7936
7937 LSL_Vector lower;
7938 LSL_Vector upper;
7939
7940 // Adjust to the documented error offsets (see LSL Wiki)
7941 lower = new LSL_Vector(minX + 0.05f, minY + 0.05f, minZ + 0.05f);
7942 upper = new LSL_Vector(maxX - 0.05f, maxY - 0.05f, maxZ - 0.05f);
7943
7944 if (lower.x > upper.x)
7945 lower.x = upper.x;
7946 if (lower.y > upper.y)
7947 lower.y = upper.y;
7948 if (lower.z > upper.z)
7949 lower.z = upper.z;
7950
7487 result.Add(lower); 7951 result.Add(lower);
7488 result.Add(upper); 7952 result.Add(upper);
7489 return result; 7953 return result;
@@ -7728,24 +8192,95 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7728 break; 8192 break;
7729 8193
7730 case (int)ScriptBaseClass.PRIM_BUMP_SHINY: 8194 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
7731 // TODO--------------
7732 if (remain < 1) 8195 if (remain < 1)
7733 return res; 8196 return res;
8197 face = (int)rules.GetLSLIntegerItem(idx++);
7734 8198
7735 face=(int)rules.GetLSLIntegerItem(idx++); 8199 tex = part.Shape.Textures;
7736 8200 int shiny;
7737 res.Add(new LSL_Integer(0)); 8201 if (face == ScriptBaseClass.ALL_SIDES)
7738 res.Add(new LSL_Integer(0)); 8202 {
8203 for (face = 0; face < GetNumberOfSides(part); face++)
8204 {
8205 Shininess shinyness = tex.GetFace((uint)face).Shiny;
8206 if (shinyness == Shininess.High)
8207 {
8208 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
8209 }
8210 else if (shinyness == Shininess.Medium)
8211 {
8212 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
8213 }
8214 else if (shinyness == Shininess.Low)
8215 {
8216 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8217 }
8218 else
8219 {
8220 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8221 }
8222 res.Add(new LSL_Integer(shiny));
8223 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
8224 }
8225 }
8226 else
8227 {
8228 Shininess shinyness = tex.GetFace((uint)face).Shiny;
8229 if (shinyness == Shininess.High)
8230 {
8231 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
8232 }
8233 else if (shinyness == Shininess.Medium)
8234 {
8235 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
8236 }
8237 else if (shinyness == Shininess.Low)
8238 {
8239 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8240 }
8241 else
8242 {
8243 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8244 }
8245 res.Add(new LSL_Integer(shiny));
8246 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
8247 }
7739 break; 8248 break;
7740 8249
7741 case (int)ScriptBaseClass.PRIM_FULLBRIGHT: 8250 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
7742 // TODO--------------
7743 if (remain < 1) 8251 if (remain < 1)
7744 return res; 8252 return res;
8253 face = (int)rules.GetLSLIntegerItem(idx++);
7745 8254
7746 face=(int)rules.GetLSLIntegerItem(idx++); 8255 tex = part.Shape.Textures;
7747 8256 int fullbright;
7748 res.Add(new LSL_Integer(0)); 8257 if (face == ScriptBaseClass.ALL_SIDES)
8258 {
8259 for (face = 0; face < GetNumberOfSides(part); face++)
8260 {
8261 if (tex.GetFace((uint)face).Fullbright == true)
8262 {
8263 fullbright = ScriptBaseClass.TRUE;
8264 }
8265 else
8266 {
8267 fullbright = ScriptBaseClass.FALSE;
8268 }
8269 res.Add(new LSL_Integer(fullbright));
8270 }
8271 }
8272 else
8273 {
8274 if (tex.GetFace((uint)face).Fullbright == true)
8275 {
8276 fullbright = ScriptBaseClass.TRUE;
8277 }
8278 else
8279 {
8280 fullbright = ScriptBaseClass.FALSE;
8281 }
8282 res.Add(new LSL_Integer(fullbright));
8283 }
7749 break; 8284 break;
7750 8285
7751 case (int)ScriptBaseClass.PRIM_FLEXIBLE: 8286 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
@@ -7766,14 +8301,37 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7766 break; 8301 break;
7767 8302
7768 case (int)ScriptBaseClass.PRIM_TEXGEN: 8303 case (int)ScriptBaseClass.PRIM_TEXGEN:
7769 // TODO--------------
7770 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR) 8304 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
7771 if (remain < 1) 8305 if (remain < 1)
7772 return res; 8306 return res;
8307 face = (int)rules.GetLSLIntegerItem(idx++);
7773 8308
7774 face=(int)rules.GetLSLIntegerItem(idx++); 8309 tex = part.Shape.Textures;
7775 8310 if (face == ScriptBaseClass.ALL_SIDES)
7776 res.Add(new LSL_Integer(0)); 8311 {
8312 for (face = 0; face < GetNumberOfSides(part); face++)
8313 {
8314 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
8315 {
8316 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
8317 }
8318 else
8319 {
8320 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
8321 }
8322 }
8323 }
8324 else
8325 {
8326 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
8327 {
8328 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
8329 }
8330 else
8331 {
8332 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
8333 }
8334 }
7777 break; 8335 break;
7778 8336
7779 case (int)ScriptBaseClass.PRIM_POINT_LIGHT: 8337 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
@@ -7792,13 +8350,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7792 break; 8350 break;
7793 8351
7794 case (int)ScriptBaseClass.PRIM_GLOW: 8352 case (int)ScriptBaseClass.PRIM_GLOW:
7795 // TODO--------------
7796 if (remain < 1) 8353 if (remain < 1)
7797 return res; 8354 return res;
8355 face = (int)rules.GetLSLIntegerItem(idx++);
7798 8356
7799 face=(int)rules.GetLSLIntegerItem(idx++); 8357 tex = part.Shape.Textures;
7800 8358 float primglow;
7801 res.Add(new LSL_Float(0)); 8359 if (face == ScriptBaseClass.ALL_SIDES)
8360 {
8361 for (face = 0; face < GetNumberOfSides(part); face++)
8362 {
8363 primglow = tex.GetFace((uint)face).Glow;
8364 res.Add(new LSL_Float(primglow));
8365 }
8366 }
8367 else
8368 {
8369 primglow = tex.GetFace((uint)face).Glow;
8370 res.Add(new LSL_Float(primglow));
8371 }
7802 break; 8372 break;
7803 case (int)ScriptBaseClass.PRIM_TEXT: 8373 case (int)ScriptBaseClass.PRIM_TEXT:
7804 Color4 textColor = part.GetTextColor(); 8374 Color4 textColor = part.GetTextColor();
@@ -8339,8 +8909,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8339 // The function returns an ordered list 8909 // The function returns an ordered list
8340 // representing the tokens found in the supplied 8910 // representing the tokens found in the supplied
8341 // sources string. If two successive tokenizers 8911 // sources string. If two successive tokenizers
8342 // are encountered, then a NULL entry is added 8912 // are encountered, then a null-string entry is
8343 // to the list. 8913 // added to the list.
8344 // 8914 //
8345 // It is a precondition that the source and 8915 // It is a precondition that the source and
8346 // toekizer lisst are non-null. If they are null, 8916 // toekizer lisst are non-null. If they are null,
@@ -8348,7 +8918,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8348 // while their lengths are being determined. 8918 // while their lengths are being determined.
8349 // 8919 //
8350 // A small amount of working memoryis required 8920 // A small amount of working memoryis required
8351 // of approximately 8*#tokenizers. 8921 // of approximately 8*#tokenizers + 8*srcstrlen.
8352 // 8922 //
8353 // There are many ways in which this function 8923 // There are many ways in which this function
8354 // can be implemented, this implementation is 8924 // can be implemented, this implementation is
@@ -8364,149 +8934,111 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8364 // and eliminates redundant tokenizers as soon 8934 // and eliminates redundant tokenizers as soon
8365 // as is possible. 8935 // as is possible.
8366 // 8936 //
8367 // The implementation tries to avoid any copying 8937 // The implementation tries to minimize temporary
8368 // of arrays or other objects. 8938 // garbage generation.
8369 // </remarks> 8939 // </remarks>
8370 8940
8371 private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls) 8941 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8372 { 8942 {
8373 int beginning = 0; 8943 return ParseString2List(src, separators, spacers, true);
8374 int srclen = src.Length; 8944 }
8375 int seplen = separators.Length;
8376 object[] separray = separators.Data;
8377 int spclen = spacers.Length;
8378 object[] spcarray = spacers.Data;
8379 int mlen = seplen+spclen;
8380
8381 int[] offset = new int[mlen+1];
8382 bool[] active = new bool[mlen];
8383
8384 int best;
8385 int j;
8386
8387 // Initial capacity reduces resize cost
8388
8389 LSL_List tokens = new LSL_List();
8390 8945
8391 // All entries are initially valid 8946 private LSL_List ParseString2List(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
8947 {
8948 int srclen = src.Length;
8949 int seplen = separators.Length;
8950 object[] separray = separators.Data;
8951 int spclen = spacers.Length;
8952 object[] spcarray = spacers.Data;
8953 int dellen = 0;
8954 string[] delarray = new string[seplen+spclen];
8392 8955
8393 for (int i = 0; i < mlen; i++) 8956 int outlen = 0;
8394 active[i] = true; 8957 string[] outarray = new string[srclen*2+1];
8395 8958
8396 offset[mlen] = srclen; 8959 int i, j;
8960 string d;
8397 8961
8398 while (beginning < srclen) 8962 m_host.AddScriptLPS(1);
8399 {
8400
8401 best = mlen; // as bad as it gets
8402 8963
8403 // Scan for separators 8964 /*
8965 * Convert separator and spacer lists to C# strings.
8966 * Also filter out null strings so we don't hang.
8967 */
8968 for (i = 0; i < seplen; i ++) {
8969 d = separray[i].ToString();
8970 if (d.Length > 0) {
8971 delarray[dellen++] = d;
8972 }
8973 }
8974 seplen = dellen;
8404 8975
8405 for (j = 0; j < seplen; j++) 8976 for (i = 0; i < spclen; i ++) {
8406 { 8977 d = spcarray[i].ToString();
8407 if (active[j]) 8978 if (d.Length > 0) {
8408 { 8979 delarray[dellen++] = d;
8409 // scan all of the markers
8410 if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1)
8411 {
8412 // not present at all
8413 active[j] = false;
8414 }
8415 else
8416 {
8417 // present and correct
8418 if (offset[j] < offset[best])
8419 {
8420 // closest so far
8421 best = j;
8422 if (offset[best] == beginning)
8423 break;
8424 }
8425 }
8426 }
8427 } 8980 }
8981 }
8428 8982
8429 // Scan for spacers 8983 /*
8984 * Scan through source string from beginning to end.
8985 */
8986 for (i = 0;;) {
8430 8987
8431 if (offset[best] != beginning) 8988 /*
8432 { 8989 * Find earliest delimeter in src starting at i (if any).
8433 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++) 8990 */
8434 { 8991 int earliestDel = -1;
8435 if (active[j]) 8992 int earliestSrc = srclen;
8436 { 8993 string earliestStr = null;
8437 // scan all of the markers 8994 for (j = 0; j < dellen; j ++) {
8438 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1) 8995 d = delarray[j];
8439 { 8996 if (d != null) {
8440 // not present at all 8997 int index = src.IndexOf(d, i);
8441 active[j] = false; 8998 if (index < 0) {
8442 } 8999 delarray[j] = null; // delim nowhere in src, don't check it anymore
8443 else 9000 } else if (index < earliestSrc) {
8444 { 9001 earliestSrc = index; // where delimeter starts in source string
8445 // present and correct 9002 earliestDel = j; // where delimeter is in delarray[]
8446 if (offset[j] < offset[best]) 9003 earliestStr = d; // the delimeter string from delarray[]
8447 { 9004 if (index == i) break; // can't do any better than found at beg of string
8448 // closest so far
8449 best = j;
8450 }
8451 }
8452 } 9005 }
8453 } 9006 }
8454 } 9007 }
8455 9008
8456 // This is the normal exit from the scanning loop 9009 /*
8457 9010 * Output source string starting at i through start of earliest delimeter.
8458 if (best == mlen) 9011 */
8459 { 9012 if (keepNulls || (earliestSrc > i)) {
8460 // no markers were found on this pass 9013 outarray[outlen++] = src.Substring(i, earliestSrc - i);
8461 // so we're pretty much done
8462 if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
8463 tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
8464 break;
8465 } 9014 }
8466 9015
8467 // Otherwise we just add the newly delimited token 9016 /*
8468 // and recalculate where the search should continue. 9017 * If no delimeter found at or after i, we're done scanning.
8469 if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0)) 9018 */
8470 tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning))); 9019 if (earliestDel < 0) break;
8471 9020
8472 if (best < seplen) 9021 /*
8473 { 9022 * If delimeter was a spacer, output the spacer.
8474 beginning = offset[best] + (separray[best].ToString()).Length; 9023 */
8475 } 9024 if (earliestDel >= seplen) {
8476 else 9025 outarray[outlen++] = earliestStr;
8477 {
8478 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
8479 string str = spcarray[best - seplen].ToString();
8480 if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
8481 tokens.Add(new LSL_String(str));
8482 } 9026 }
8483 }
8484
8485 // This an awkward an not very intuitive boundary case. If the
8486 // last substring is a tokenizer, then there is an implied trailing
8487 // null list entry. Hopefully the single comparison will not be too
8488 // arduous. Alternatively the 'break' could be replced with a return
8489 // but that's shabby programming.
8490 9027
8491 if ((beginning == srclen) && (keepNulls)) 9028 /*
8492 { 9029 * Look at rest of src string following delimeter.
8493 if (srclen != 0) 9030 */
8494 tokens.Add(new LSL_String("")); 9031 i = earliestSrc + earliestStr.Length;
8495 } 9032 }
8496 9033
8497 return tokens; 9034 /*
8498 } 9035 * Make up an exact-sized output array suitable for an LSL_List object.
8499 9036 */
8500 public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers) 9037 object[] outlist = new object[outlen];
8501 { 9038 for (i = 0; i < outlen; i ++) {
8502 m_host.AddScriptLPS(1); 9039 outlist[i] = new LSL_String(outarray[i]);
8503 return this.ParseString(src, separators, spacers, false); 9040 }
8504 } 9041 return new LSL_List(outlist);
8505
8506 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8507 {
8508 m_host.AddScriptLPS(1);
8509 return this.ParseString(src, separators, spacers, true);
8510 } 9042 }
8511 9043
8512 public LSL_Integer llGetObjectPermMask(int mask) 9044 public LSL_Integer llGetObjectPermMask(int mask)
@@ -8583,28 +9115,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8583 { 9115 {
8584 m_host.AddScriptLPS(1); 9116 m_host.AddScriptLPS(1);
8585 9117
8586 lock (m_host.TaskInventory) 9118 m_host.TaskInventory.LockItemsForRead(true);
9119 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8587 { 9120 {
8588 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9121 if (inv.Value.Name == item)
8589 { 9122 {
8590 if (inv.Value.Name == item) 9123 m_host.TaskInventory.LockItemsForRead(false);
9124 switch (mask)
8591 { 9125 {
8592 switch (mask) 9126 case 0:
8593 { 9127 return (int)inv.Value.BasePermissions;
8594 case 0: 9128 case 1:
8595 return (int)inv.Value.BasePermissions; 9129 return (int)inv.Value.CurrentPermissions;
8596 case 1: 9130 case 2:
8597 return (int)inv.Value.CurrentPermissions; 9131 return (int)inv.Value.GroupPermissions;
8598 case 2: 9132 case 3:
8599 return (int)inv.Value.GroupPermissions; 9133 return (int)inv.Value.EveryonePermissions;
8600 case 3: 9134 case 4:
8601 return (int)inv.Value.EveryonePermissions; 9135 return (int)inv.Value.NextPermissions;
8602 case 4:
8603 return (int)inv.Value.NextPermissions;
8604 }
8605 } 9136 }
8606 } 9137 }
8607 } 9138 }
9139 m_host.TaskInventory.LockItemsForRead(false);
8608 9140
8609 return -1; 9141 return -1;
8610 } 9142 }
@@ -8651,16 +9183,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8651 { 9183 {
8652 m_host.AddScriptLPS(1); 9184 m_host.AddScriptLPS(1);
8653 9185
8654 lock (m_host.TaskInventory) 9186 m_host.TaskInventory.LockItemsForRead(true);
9187 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8655 { 9188 {
8656 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9189 if (inv.Value.Name == item)
8657 { 9190 {
8658 if (inv.Value.Name == item) 9191 m_host.TaskInventory.LockItemsForRead(false);
8659 { 9192 return inv.Value.CreatorID.ToString();
8660 return inv.Value.CreatorID.ToString();
8661 }
8662 } 9193 }
8663 } 9194 }
9195 m_host.TaskInventory.LockItemsForRead(false);
8664 9196
8665 llSay(0, "No item name '" + item + "'"); 9197 llSay(0, "No item name '" + item + "'");
8666 9198
@@ -8711,8 +9243,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8711 return UUID.Zero.ToString(); 9243 return UUID.Zero.ToString();
8712 } 9244 }
8713 reply = new LSL_Vector( 9245 reply = new LSL_Vector(
8714 info.RegionLocX * Constants.RegionSize, 9246 info.RegionLocX,
8715 info.RegionLocY * Constants.RegionSize, 9247 info.RegionLocY,
8716 0).ToString(); 9248 0).ToString();
8717 break; 9249 break;
8718 case 6: // DATA_SIM_STATUS 9250 case 6: // DATA_SIM_STATUS
@@ -8925,17 +9457,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8925 int width = 0; 9457 int width = 0;
8926 int height = 0; 9458 int height = 0;
8927 9459
8928 ParcelMediaCommandEnum? commandToSend = null; 9460 uint commandToSend = 0;
8929 float time = 0.0f; // default is from start 9461 float time = 0.0f; // default is from start
8930 9462
8931 ScenePresence presence = null; 9463 ScenePresence presence = null;
8932 9464
8933 for (int i = 0; i < commandList.Data.Length; i++) 9465 for (int i = 0; i < commandList.Data.Length; i++)
8934 { 9466 {
8935 ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i]; 9467 uint command = (uint)(commandList.GetLSLIntegerItem(i));
8936 switch (command) 9468 switch (command)
8937 { 9469 {
8938 case ParcelMediaCommandEnum.Agent: 9470 case (uint)ParcelMediaCommandEnum.Agent:
8939 // we send only to one agent 9471 // we send only to one agent
8940 if ((i + 1) < commandList.Length) 9472 if ((i + 1) < commandList.Length)
8941 { 9473 {
@@ -8952,25 +9484,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8952 } 9484 }
8953 break; 9485 break;
8954 9486
8955 case ParcelMediaCommandEnum.Loop: 9487 case (uint)ParcelMediaCommandEnum.Loop:
8956 loop = 1; 9488 loop = 1;
8957 commandToSend = command; 9489 commandToSend = command;
8958 update = true; //need to send the media update packet to set looping 9490 update = true; //need to send the media update packet to set looping
8959 break; 9491 break;
8960 9492
8961 case ParcelMediaCommandEnum.Play: 9493 case (uint)ParcelMediaCommandEnum.Play:
8962 loop = 0; 9494 loop = 0;
8963 commandToSend = command; 9495 commandToSend = command;
8964 update = true; //need to send the media update packet to make sure it doesn't loop 9496 update = true; //need to send the media update packet to make sure it doesn't loop
8965 break; 9497 break;
8966 9498
8967 case ParcelMediaCommandEnum.Pause: 9499 case (uint)ParcelMediaCommandEnum.Pause:
8968 case ParcelMediaCommandEnum.Stop: 9500 case (uint)ParcelMediaCommandEnum.Stop:
8969 case ParcelMediaCommandEnum.Unload: 9501 case (uint)ParcelMediaCommandEnum.Unload:
8970 commandToSend = command; 9502 commandToSend = command;
8971 break; 9503 break;
8972 9504
8973 case ParcelMediaCommandEnum.Url: 9505 case (uint)ParcelMediaCommandEnum.Url:
8974 if ((i + 1) < commandList.Length) 9506 if ((i + 1) < commandList.Length)
8975 { 9507 {
8976 if (commandList.Data[i + 1] is LSL_String) 9508 if (commandList.Data[i + 1] is LSL_String)
@@ -8983,7 +9515,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8983 } 9515 }
8984 break; 9516 break;
8985 9517
8986 case ParcelMediaCommandEnum.Texture: 9518 case (uint)ParcelMediaCommandEnum.Texture:
8987 if ((i + 1) < commandList.Length) 9519 if ((i + 1) < commandList.Length)
8988 { 9520 {
8989 if (commandList.Data[i + 1] is LSL_String) 9521 if (commandList.Data[i + 1] is LSL_String)
@@ -8996,7 +9528,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8996 } 9528 }
8997 break; 9529 break;
8998 9530
8999 case ParcelMediaCommandEnum.Time: 9531 case (uint)ParcelMediaCommandEnum.Time:
9000 if ((i + 1) < commandList.Length) 9532 if ((i + 1) < commandList.Length)
9001 { 9533 {
9002 if (commandList.Data[i + 1] is LSL_Float) 9534 if (commandList.Data[i + 1] is LSL_Float)
@@ -9008,7 +9540,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9008 } 9540 }
9009 break; 9541 break;
9010 9542
9011 case ParcelMediaCommandEnum.AutoAlign: 9543 case (uint)ParcelMediaCommandEnum.AutoAlign:
9012 if ((i + 1) < commandList.Length) 9544 if ((i + 1) < commandList.Length)
9013 { 9545 {
9014 if (commandList.Data[i + 1] is LSL_Integer) 9546 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9022,7 +9554,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9022 } 9554 }
9023 break; 9555 break;
9024 9556
9025 case ParcelMediaCommandEnum.Type: 9557 case (uint)ParcelMediaCommandEnum.Type:
9026 if ((i + 1) < commandList.Length) 9558 if ((i + 1) < commandList.Length)
9027 { 9559 {
9028 if (commandList.Data[i + 1] is LSL_String) 9560 if (commandList.Data[i + 1] is LSL_String)
@@ -9035,7 +9567,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9035 } 9567 }
9036 break; 9568 break;
9037 9569
9038 case ParcelMediaCommandEnum.Desc: 9570 case (uint)ParcelMediaCommandEnum.Desc:
9039 if ((i + 1) < commandList.Length) 9571 if ((i + 1) < commandList.Length)
9040 { 9572 {
9041 if (commandList.Data[i + 1] is LSL_String) 9573 if (commandList.Data[i + 1] is LSL_String)
@@ -9048,7 +9580,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9048 } 9580 }
9049 break; 9581 break;
9050 9582
9051 case ParcelMediaCommandEnum.Size: 9583 case (uint)ParcelMediaCommandEnum.Size:
9052 if ((i + 2) < commandList.Length) 9584 if ((i + 2) < commandList.Length)
9053 { 9585 {
9054 if (commandList.Data[i + 1] is LSL_Integer) 9586 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9118,7 +9650,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9118 } 9650 }
9119 } 9651 }
9120 9652
9121 if (commandToSend != null) 9653 if (commandToSend != 0)
9122 { 9654 {
9123 // the commandList contained a start/stop/... command, too 9655 // the commandList contained a start/stop/... command, too
9124 if (presence == null) 9656 if (presence == null)
@@ -9155,7 +9687,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9155 9687
9156 if (aList.Data[i] != null) 9688 if (aList.Data[i] != null)
9157 { 9689 {
9158 switch ((ParcelMediaCommandEnum) aList.Data[i]) 9690 switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString()))
9159 { 9691 {
9160 case ParcelMediaCommandEnum.Url: 9692 case ParcelMediaCommandEnum.Url:
9161 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL)); 9693 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
@@ -9198,16 +9730,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9198 { 9730 {
9199 m_host.AddScriptLPS(1); 9731 m_host.AddScriptLPS(1);
9200 9732
9201 lock (m_host.TaskInventory) 9733 m_host.TaskInventory.LockItemsForRead(true);
9734 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
9202 { 9735 {
9203 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9736 if (inv.Value.Name == name)
9204 { 9737 {
9205 if (inv.Value.Name == name) 9738 m_host.TaskInventory.LockItemsForRead(false);
9206 { 9739 return inv.Value.Type;
9207 return inv.Value.Type;
9208 }
9209 } 9740 }
9210 } 9741 }
9742 m_host.TaskInventory.LockItemsForRead(false);
9211 9743
9212 return -1; 9744 return -1;
9213 } 9745 }
@@ -9218,15 +9750,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9218 9750
9219 if (quick_pay_buttons.Data.Length < 4) 9751 if (quick_pay_buttons.Data.Length < 4)
9220 { 9752 {
9221 LSLError("List must have at least 4 elements"); 9753 int x;
9222 return; 9754 for (x=quick_pay_buttons.Data.Length; x<= 4; x++)
9755 {
9756 quick_pay_buttons.Add(ScriptBaseClass.PAY_HIDE);
9757 }
9223 } 9758 }
9224 m_host.ParentGroup.RootPart.PayPrice[0]=price; 9759 int[] nPrice = new int[5];
9225 9760 nPrice[0]=price;
9226 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0]; 9761 nPrice[1] = (LSL_Integer)quick_pay_buttons.Data[0];
9227 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1]; 9762 nPrice[2] = (LSL_Integer)quick_pay_buttons.Data[1];
9228 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2]; 9763 nPrice[3] = (LSL_Integer)quick_pay_buttons.Data[2];
9229 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3]; 9764 nPrice[4] = (LSL_Integer)quick_pay_buttons.Data[3];
9765 m_host.ParentGroup.RootPart.PayPrice = nPrice;
9230 m_host.ParentGroup.HasGroupChanged = true; 9766 m_host.ParentGroup.HasGroupChanged = true;
9231 } 9767 }
9232 9768
@@ -9238,17 +9774,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9238 if (invItemID == UUID.Zero) 9774 if (invItemID == UUID.Zero)
9239 return new LSL_Vector(); 9775 return new LSL_Vector();
9240 9776
9241 lock (m_host.TaskInventory) 9777 m_host.TaskInventory.LockItemsForRead(true);
9778 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9242 { 9779 {
9243 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 9780 m_host.TaskInventory.LockItemsForRead(false);
9244 return new LSL_Vector(); 9781 return new LSL_Vector();
9782 }
9245 9783
9246 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 9784 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9247 { 9785 {
9248 ShoutError("No permissions to track the camera"); 9786 ShoutError("No permissions to track the camera");
9249 return new LSL_Vector(); 9787 m_host.TaskInventory.LockItemsForRead(false);
9250 } 9788 return new LSL_Vector();
9251 } 9789 }
9790 m_host.TaskInventory.LockItemsForRead(false);
9252 9791
9253 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 9792 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9254 if (presence != null) 9793 if (presence != null)
@@ -9266,17 +9805,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9266 if (invItemID == UUID.Zero) 9805 if (invItemID == UUID.Zero)
9267 return new LSL_Rotation(); 9806 return new LSL_Rotation();
9268 9807
9269 lock (m_host.TaskInventory) 9808 m_host.TaskInventory.LockItemsForRead(true);
9809 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9270 { 9810 {
9271 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 9811 m_host.TaskInventory.LockItemsForRead(false);
9272 return new LSL_Rotation(); 9812 return new LSL_Rotation();
9273 9813 }
9274 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 9814 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9275 { 9815 {
9276 ShoutError("No permissions to track the camera"); 9816 ShoutError("No permissions to track the camera");
9277 return new LSL_Rotation(); 9817 m_host.TaskInventory.LockItemsForRead(false);
9278 } 9818 return new LSL_Rotation();
9279 } 9819 }
9820 m_host.TaskInventory.LockItemsForRead(false);
9280 9821
9281 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 9822 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9282 if (presence != null) 9823 if (presence != null)
@@ -9338,8 +9879,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9338 { 9879 {
9339 m_host.AddScriptLPS(1); 9880 m_host.AddScriptLPS(1);
9340 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0); 9881 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0);
9341 if (detectedParams == null) return; // only works on the first detected avatar 9882 if (detectedParams == null)
9342 9883 {
9884 if (m_host.IsAttachment == true)
9885 {
9886 detectedParams = new DetectParams();
9887 detectedParams.Key = m_host.OwnerID;
9888 }
9889 else
9890 {
9891 return;
9892 }
9893 }
9894
9343 ScenePresence avatar = World.GetScenePresence(detectedParams.Key); 9895 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
9344 if (avatar != null) 9896 if (avatar != null)
9345 { 9897 {
@@ -9347,6 +9899,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9347 new Vector3((float)pos.x, (float)pos.y, (float)pos.z), 9899 new Vector3((float)pos.x, (float)pos.y, (float)pos.z),
9348 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z)); 9900 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z));
9349 } 9901 }
9902
9350 ScriptSleep(1000); 9903 ScriptSleep(1000);
9351 } 9904 }
9352 9905
@@ -9426,14 +9979,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9426 if (objectID == UUID.Zero) return; 9979 if (objectID == UUID.Zero) return;
9427 9980
9428 UUID agentID; 9981 UUID agentID;
9429 lock (m_host.TaskInventory) 9982 m_host.TaskInventory.LockItemsForRead(true);
9430 { 9983 // we need the permission first, to know which avatar we want to set the camera for
9431 // we need the permission first, to know which avatar we want to set the camera for 9984 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9432 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9433 9985
9434 if (agentID == UUID.Zero) return; 9986 if (agentID == UUID.Zero)
9435 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; 9987 {
9988 m_host.TaskInventory.LockItemsForRead(false);
9989 return;
9990 }
9991 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
9992 {
9993 m_host.TaskInventory.LockItemsForRead(false);
9994 return;
9436 } 9995 }
9996 m_host.TaskInventory.LockItemsForRead(false);
9437 9997
9438 ScenePresence presence = World.GetScenePresence(agentID); 9998 ScenePresence presence = World.GetScenePresence(agentID);
9439 9999
@@ -9483,12 +10043,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9483 10043
9484 // we need the permission first, to know which avatar we want to clear the camera for 10044 // we need the permission first, to know which avatar we want to clear the camera for
9485 UUID agentID; 10045 UUID agentID;
9486 lock (m_host.TaskInventory) 10046 m_host.TaskInventory.LockItemsForRead(true);
10047 agentID = m_host.TaskInventory[invItemID].PermsGranter;
10048 if (agentID == UUID.Zero)
10049 {
10050 m_host.TaskInventory.LockItemsForRead(false);
10051 return;
10052 }
10053 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
9487 { 10054 {
9488 agentID = m_host.TaskInventory[invItemID].PermsGranter; 10055 m_host.TaskInventory.LockItemsForRead(false);
9489 if (agentID == UUID.Zero) return; 10056 return;
9490 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
9491 } 10057 }
10058 m_host.TaskInventory.LockItemsForRead(false);
9492 10059
9493 ScenePresence presence = World.GetScenePresence(agentID); 10060 ScenePresence presence = World.GetScenePresence(agentID);
9494 10061
@@ -9555,19 +10122,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9555 public LSL_String llXorBase64StringsCorrect(string str1, string str2) 10122 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
9556 { 10123 {
9557 m_host.AddScriptLPS(1); 10124 m_host.AddScriptLPS(1);
9558 string ret = String.Empty; 10125
9559 string src1 = llBase64ToString(str1); 10126 if (str1 == String.Empty)
9560 string src2 = llBase64ToString(str2); 10127 return String.Empty;
9561 int c = 0; 10128 if (str2 == String.Empty)
9562 for (int i = 0; i < src1.Length; i++) 10129 return str1;
10130
10131 byte[] data1 = Convert.FromBase64String(str1);
10132 byte[] data2 = Convert.FromBase64String(str2);
10133
10134 byte[] d2 = new Byte[data1.Length];
10135 int pos = 0;
10136
10137 if (data1.Length <= data2.Length)
9563 { 10138 {
9564 ret += (char) (src1[i] ^ src2[c]); 10139 Array.Copy(data2, 0, d2, 0, data1.Length);
10140 }
10141 else
10142 {
10143 while (pos < data1.Length)
10144 {
10145 int len = data1.Length - pos;
10146 if (len > data2.Length)
10147 len = data2.Length;
9565 10148
9566 c++; 10149 Array.Copy(data2, 0, d2, pos, len);
9567 if (c >= src2.Length) 10150 pos += len;
9568 c = 0; 10151 }
9569 } 10152 }
9570 return llStringToBase64(ret); 10153
10154 for (pos = 0 ; pos < data1.Length ; pos++ )
10155 data1[pos] ^= d2[pos];
10156
10157 return Convert.ToBase64String(data1);
9571 } 10158 }
9572 10159
9573 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body) 10160 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
@@ -9945,15 +10532,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9945 10532
9946 internal UUID ScriptByName(string name) 10533 internal UUID ScriptByName(string name)
9947 { 10534 {
9948 lock (m_host.TaskInventory) 10535 m_host.TaskInventory.LockItemsForRead(true);
10536
10537 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
9949 { 10538 {
9950 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 10539 if (item.Type == 10 && item.Name == name)
9951 { 10540 {
9952 if (item.Type == 10 && item.Name == name) 10541 m_host.TaskInventory.LockItemsForRead(false);
9953 return item.ItemID; 10542 return item.ItemID;
9954 } 10543 }
9955 } 10544 }
9956 10545
10546 m_host.TaskInventory.LockItemsForRead(false);
10547
9957 return UUID.Zero; 10548 return UUID.Zero;
9958 } 10549 }
9959 10550
@@ -9994,6 +10585,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9994 { 10585 {
9995 m_host.AddScriptLPS(1); 10586 m_host.AddScriptLPS(1);
9996 10587
10588 //Clone is thread safe
9997 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10589 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
9998 10590
9999 UUID assetID = UUID.Zero; 10591 UUID assetID = UUID.Zero;
@@ -10056,6 +10648,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10056 { 10648 {
10057 m_host.AddScriptLPS(1); 10649 m_host.AddScriptLPS(1);
10058 10650
10651 //Clone is thread safe
10059 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10652 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10060 10653
10061 UUID assetID = UUID.Zero; 10654 UUID assetID = UUID.Zero;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 477c52d..6827ede 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -129,6 +129,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
129 internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow; 129 internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow;
130 internal float m_ScriptDelayFactor = 1.0f; 130 internal float m_ScriptDelayFactor = 1.0f;
131 internal float m_ScriptDistanceFactor = 1.0f; 131 internal float m_ScriptDistanceFactor = 1.0f;
132 internal bool m_debuggerSafe = false;
132 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >(); 133 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >();
133 134
134 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) 135 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
@@ -137,6 +138,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
137 m_host = host; 138 m_host = host;
138 m_localID = localID; 139 m_localID = localID;
139 m_itemID = itemID; 140 m_itemID = itemID;
141 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
140 142
141 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) 143 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false))
142 m_OSFunctionsEnabled = true; 144 m_OSFunctionsEnabled = true;
@@ -195,7 +197,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
195 197
196 internal void OSSLError(string msg) 198 internal void OSSLError(string msg)
197 { 199 {
198 throw new Exception("OSSL Runtime Error: " + msg); 200 if (m_debuggerSafe)
201 {
202 OSSLShoutError(msg);
203 }
204 else
205 {
206 throw new Exception("OSSL Runtime Error: " + msg);
207 }
199 } 208 }
200 209
201 private void InitLSL() 210 private void InitLSL()
@@ -767,18 +776,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
767 if (target != null) 776 if (target != null)
768 { 777 {
769 UUID animID=UUID.Zero; 778 UUID animID=UUID.Zero;
770 lock (m_host.TaskInventory) 779 m_host.TaskInventory.LockItemsForRead(true);
780 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
771 { 781 {
772 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 782 if (inv.Value.Name == animation)
773 { 783 {
774 if (inv.Value.Name == animation) 784 if (inv.Value.Type == (int)AssetType.Animation)
775 { 785 animID = inv.Value.AssetID;
776 if (inv.Value.Type == (int)AssetType.Animation) 786 continue;
777 animID = inv.Value.AssetID;
778 continue;
779 }
780 } 787 }
781 } 788 }
789 m_host.TaskInventory.LockItemsForRead(false);
782 if (animID == UUID.Zero) 790 if (animID == UUID.Zero)
783 target.Animator.AddAnimation(animation, m_host.UUID); 791 target.Animator.AddAnimation(animation, m_host.UUID);
784 else 792 else
@@ -800,18 +808,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
800 if (target != null) 808 if (target != null)
801 { 809 {
802 UUID animID=UUID.Zero; 810 UUID animID=UUID.Zero;
803 lock (m_host.TaskInventory) 811 m_host.TaskInventory.LockItemsForRead(true);
812 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
804 { 813 {
805 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 814 if (inv.Value.Name == animation)
806 { 815 {
807 if (inv.Value.Name == animation) 816 if (inv.Value.Type == (int)AssetType.Animation)
808 { 817 animID = inv.Value.AssetID;
809 if (inv.Value.Type == (int)AssetType.Animation) 818 continue;
810 animID = inv.Value.AssetID;
811 continue;
812 }
813 } 819 }
814 } 820 }
821 m_host.TaskInventory.LockItemsForRead(false);
815 822
816 if (animID == UUID.Zero) 823 if (animID == UUID.Zero)
817 target.Animator.RemoveAnimation(animation); 824 target.Animator.RemoveAnimation(animation);
@@ -1662,6 +1669,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1662 1669
1663 if (!UUID.TryParse(name, out assetID)) 1670 if (!UUID.TryParse(name, out assetID))
1664 { 1671 {
1672 m_host.TaskInventory.LockItemsForRead(true);
1665 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1673 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1666 { 1674 {
1667 if (item.Type == 7 && item.Name == name) 1675 if (item.Type == 7 && item.Name == name)
@@ -1669,6 +1677,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1669 assetID = item.AssetID; 1677 assetID = item.AssetID;
1670 } 1678 }
1671 } 1679 }
1680 m_host.TaskInventory.LockItemsForRead(false);
1672 } 1681 }
1673 1682
1674 if (assetID == UUID.Zero) 1683 if (assetID == UUID.Zero)
@@ -1715,6 +1724,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1715 1724
1716 if (!UUID.TryParse(name, out assetID)) 1725 if (!UUID.TryParse(name, out assetID))
1717 { 1726 {
1727 m_host.TaskInventory.LockItemsForRead(true);
1718 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1728 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1719 { 1729 {
1720 if (item.Type == 7 && item.Name == name) 1730 if (item.Type == 7 && item.Name == name)
@@ -1722,6 +1732,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1722 assetID = item.AssetID; 1732 assetID = item.AssetID;
1723 } 1733 }
1724 } 1734 }
1735 m_host.TaskInventory.LockItemsForRead(false);
1725 } 1736 }
1726 1737
1727 if (assetID == UUID.Zero) 1738 if (assetID == UUID.Zero)
@@ -1772,6 +1783,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1772 1783
1773 if (!UUID.TryParse(name, out assetID)) 1784 if (!UUID.TryParse(name, out assetID))
1774 { 1785 {
1786 m_host.TaskInventory.LockItemsForRead(true);
1775 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1787 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1776 { 1788 {
1777 if (item.Type == 7 && item.Name == name) 1789 if (item.Type == 7 && item.Name == name)
@@ -1779,6 +1791,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1779 assetID = item.AssetID; 1791 assetID = item.AssetID;
1780 } 1792 }
1781 } 1793 }
1794 m_host.TaskInventory.LockItemsForRead(false);
1782 } 1795 }
1783 1796
1784 if (assetID == UUID.Zero) 1797 if (assetID == UUID.Zero)
@@ -2216,9 +2229,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2216 { 2229 {
2217 if (avatar.IsChildAgent == false) 2230 if (avatar.IsChildAgent == false)
2218 { 2231 {
2219 result.Add(avatar.UUID); 2232 result.Add(new LSL_Key(avatar.UUID.ToString()));
2220 result.Add(avatar.AbsolutePosition); 2233 result.Add(new LSL_Vector(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z));
2221 result.Add(avatar.Name); 2234 result.Add(new LSL_String(avatar.Name));
2222 } 2235 }
2223 } 2236 }
2224 }); 2237 });
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index fefbb35..3b7de53 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -204,7 +204,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
204 // Is the sensor type is AGENT and not SCRIPTED then include agents 204 // Is the sensor type is AGENT and not SCRIPTED then include agents
205 if ((ts.type & AGENT) != 0 && (ts.type & SCRIPTED) == 0) 205 if ((ts.type & AGENT) != 0 && (ts.type & SCRIPTED) == 0)
206 { 206 {
207 sensedEntities.AddRange(doAgentSensor(ts)); 207 sensedEntities.AddRange(doAgentSensor(ts));
208 } 208 }
209 209
210 // If SCRIPTED or PASSIVE or ACTIVE check objects 210 // If SCRIPTED or PASSIVE or ACTIVE check objects
@@ -309,6 +309,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
309 // in mouselook. 309 // in mouselook.
310 310
311 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar); 311 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar);
312 fromRegionPos = avatar.AbsolutePosition;
312 q = avatar.Rotation; 313 q = avatar.Rotation;
313 } 314 }
314 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 315 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
@@ -422,6 +423,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
422 SceneObjectPart SensePoint = ts.host; 423 SceneObjectPart SensePoint = ts.host;
423 Vector3 fromRegionPos = SensePoint.AbsolutePosition; 424 Vector3 fromRegionPos = SensePoint.AbsolutePosition;
424 Quaternion q = SensePoint.RotationOffset; 425 Quaternion q = SensePoint.RotationOffset;
426 if (SensePoint.ParentGroup.RootPart.IsAttachment)
427 {
428 // In attachments, the sensor cone always orients with the
429 // avatar rotation. This may include a nonzero elevation if
430 // in mouselook.
431
432 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar);
433 fromRegionPos = avatar.AbsolutePosition;
434 q = avatar.Rotation;
435 }
425 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 436 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
426 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); 437 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
427 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); 438 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
index eeb59d9..2fd33fe 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs
@@ -109,25 +109,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
109 if (Timers.Count == 0) 109 if (Timers.Count == 0)
110 return; 110 return;
111 111
112 Dictionary<string, TimerClass>.ValueCollection tvals;
112 lock (TimerListLock) 113 lock (TimerListLock)
113 { 114 {
114 // Go through all timers 115 // Go through all timers
115 Dictionary<string, TimerClass>.ValueCollection tvals = Timers.Values; 116 tvals = Timers.Values;
116 foreach (TimerClass ts in tvals) 117 }
118
119 foreach (TimerClass ts in tvals)
120 {
121 // Time has passed?
122 if (ts.next < DateTime.Now.Ticks)
117 { 123 {
118 // Time has passed? 124 //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next);
119 if (ts.next < DateTime.Now.Ticks) 125 // Add it to queue
120 { 126 m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
121 //m_log.Debug("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next); 127 new EventParams("timer", new Object[0],
122 // Add it to queue 128 new DetectParams[0]));
123 m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID, 129 // set next interval
124 new EventParams("timer", new Object[0], 130
125 new DetectParams[0])); 131 //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
126 // set next interval 132 ts.next = DateTime.Now.Ticks + ts.interval;
127
128 //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
129 ts.next = DateTime.Now.Ticks + ts.interval;
130 }
131 } 133 }
132 } 134 }
133 } 135 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 78ee43c..c8f3623 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -81,7 +81,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
81 // Avatar Info Commands 81 // Avatar Info Commands
82 string osGetAgentIP(string agent); 82 string osGetAgentIP(string agent);
83 LSL_List osGetAgents(); 83 LSL_List osGetAgents();
84 84
85 // Teleport commands 85 // Teleport commands
86 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 86 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat);
87 void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 87 void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs
index 9615315..943d7a2 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics; //for [DebuggerNonUserCode]
30using System.Reflection; 31using System.Reflection;
31using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
32using OpenSim.Region.ScriptEngine.Shared; 33using OpenSim.Region.ScriptEngine.Shared;
@@ -132,6 +133,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
132 return (eventFlags); 133 return (eventFlags);
133 } 134 }
134 135
136 [DebuggerNonUserCode]
135 public void ExecuteEvent(string state, string FunctionName, object[] args) 137 public void ExecuteEvent(string state, string FunctionName, object[] args)
136 { 138 {
137 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. 139 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
index 5da6bb9..6e8435d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -279,6 +279,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
279 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART 279 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART
280 public const int CHANGED_MEDIA = 2048; 280 public const int CHANGED_MEDIA = 2048;
281 public const int CHANGED_ANIMATION = 16384; 281 public const int CHANGED_ANIMATION = 16384;
282 public const int CHANGED_POSITION = 32768;
282 public const int TYPE_INVALID = 0; 283 public const int TYPE_INVALID = 0;
283 public const int TYPE_INTEGER = 1; 284 public const int TYPE_INTEGER = 1;
284 public const int TYPE_FLOAT = 2; 285 public const int TYPE_FLOAT = 2;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
index 451163f..f14967e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Diagnostics; //for [DebuggerNonUserCode]
29using System.Runtime.Remoting.Lifetime; 30using System.Runtime.Remoting.Lifetime;
30using System.Threading; 31using System.Threading;
31using System.Reflection; 32using System.Reflection;
@@ -309,6 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
309 m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel); 310 m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel);
310 } 311 }
311 312
313 [DebuggerNonUserCode]
312 public void llDie() 314 public void llDie()
313 { 315 {
314 m_LSL_Functions.llDie(); 316 m_LSL_Functions.llDie();
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs
index f8dbe03..8280ca5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs
@@ -72,5 +72,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
72 { 72 {
73 return m_LS_Functions.lsSetWindlightSceneTargeted(rules, target); 73 return m_LS_Functions.lsSetWindlightSceneTargeted(rules, target);
74 } 74 }
75
76 public LSL_List cmGetWindlightScene(LSL_List rules)
77 {
78 return m_LS_Functions.lsGetWindlightScene(rules);
79 }
80
81 public int cmSetWindlightScene(LSL_List rules)
82 {
83 return m_LS_Functions.lsSetWindlightScene(rules);
84 }
85
86 public int cmSetWindlightSceneTargeted(LSL_List rules, key target)
87 {
88 return m_LS_Functions.lsSetWindlightSceneTargeted(rules, target);
89 }
75 } 90 }
76} 91}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
index edbbc2a..b138da3 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs
@@ -33,6 +33,7 @@ using System.Threading;
33using System.Reflection; 33using System.Reflection;
34using System.Collections; 34using System.Collections;
35using System.Collections.Generic; 35using System.Collections.Generic;
36using System.Diagnostics; //for [DebuggerNonUserCode]
36using OpenSim.Region.ScriptEngine.Interfaces; 37using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared; 38using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Region.ScriptEngine.Shared.Api.Runtime; 39using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
@@ -90,6 +91,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
90 return (int)m_Executor.GetStateEventFlags(state); 91 return (int)m_Executor.GetStateEventFlags(state);
91 } 92 }
92 93
94 [DebuggerNonUserCode]
93 public void ExecuteEvent(string state, string FunctionName, object[] args) 95 public void ExecuteEvent(string state, string FunctionName, object[] args)
94 { 96 {
95 m_Executor.ExecuteEvent(state, FunctionName, args); 97 m_Executor.ExecuteEvent(state, FunctionName, args);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 6663aa5..623cb7d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.IO; 29using System.IO;
30using System.Diagnostics; //for [DebuggerNonUserCode]
30using System.Runtime.Remoting; 31using System.Runtime.Remoting;
31using System.Runtime.Remoting.Lifetime; 32using System.Runtime.Remoting.Lifetime;
32using System.Threading; 33using System.Threading;
@@ -55,7 +56,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
55{ 56{
56 public class ScriptInstance : MarshalByRefObject, IScriptInstance 57 public class ScriptInstance : MarshalByRefObject, IScriptInstance
57 { 58 {
58 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59 60
60 private IScriptEngine m_Engine; 61 private IScriptEngine m_Engine;
61 private IScriptWorkItem m_CurrentResult = null; 62 private IScriptWorkItem m_CurrentResult = null;
@@ -238,13 +239,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
238 239
239 if (part != null) 240 if (part != null)
240 { 241 {
241 lock (part.TaskInventory) 242 part.TaskInventory.LockItemsForRead(true);
243 if (part.TaskInventory.ContainsKey(m_ItemID))
242 { 244 {
243 if (part.TaskInventory.ContainsKey(m_ItemID)) 245 m_thisScriptTask = part.TaskInventory[m_ItemID];
244 {
245 m_thisScriptTask = part.TaskInventory[m_ItemID];
246 }
247 } 246 }
247 part.TaskInventory.LockItemsForRead(false);
248 } 248 }
249 249
250 ApiManager am = new ApiManager(); 250 ApiManager am = new ApiManager();
@@ -271,9 +271,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
271 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass); 271 //RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
272// lease.Register(this); 272// lease.Register(this);
273 } 273 }
274 catch (Exception) 274 catch (Exception e)
275 { 275 {
276 // m_log.ErrorFormat("[Script] Error loading assembly {0}\n"+e.ToString(), assembly); 276 m_log.ErrorFormat("[Script] Error loading assembly {0}\n"+e.ToString(), assembly);
277 throw;
277 } 278 }
278 279
279 try 280 try
@@ -429,14 +430,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
429 { 430 {
430 int permsMask; 431 int permsMask;
431 UUID permsGranter; 432 UUID permsGranter;
432 lock (part.TaskInventory) 433 part.TaskInventory.LockItemsForRead(true);
434 if (!part.TaskInventory.ContainsKey(m_ItemID))
433 { 435 {
434 if (!part.TaskInventory.ContainsKey(m_ItemID)) 436 part.TaskInventory.LockItemsForRead(false);
435 return; 437 return;
436
437 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
438 permsMask = part.TaskInventory[m_ItemID].PermsMask;
439 } 438 }
439 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
440 permsMask = part.TaskInventory[m_ItemID].PermsMask;
441 part.TaskInventory.LockItemsForRead(false);
440 442
441 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) 443 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
442 { 444 {
@@ -545,6 +547,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
545 return true; 547 return true;
546 } 548 }
547 549
550 [DebuggerNonUserCode] //Prevents the debugger from farting in this function
548 public void SetState(string state) 551 public void SetState(string state)
549 { 552 {
550 if (state == State) 553 if (state == State)
@@ -556,7 +559,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
556 new DetectParams[0])); 559 new DetectParams[0]));
557 PostEvent(new EventParams("state_entry", new Object[0], 560 PostEvent(new EventParams("state_entry", new Object[0],
558 new DetectParams[0])); 561 new DetectParams[0]));
559 562
560 throw new EventAbortException(); 563 throw new EventAbortException();
561 } 564 }
562 565
@@ -639,14 +642,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
639 /// <returns></returns> 642 /// <returns></returns>
640 public object EventProcessor() 643 public object EventProcessor()
641 { 644 {
642 if (m_Suspended) 645 EventParams data = null;
643 return 0;
644 646
645 lock (m_Script) 647 lock (m_EventQueue)
646 { 648 {
647 EventParams data = null; 649 if (m_Suspended)
650 return 0;
648 651
649 lock (m_EventQueue) 652 lock (m_Script)
650 { 653 {
651 data = (EventParams) m_EventQueue.Dequeue(); 654 data = (EventParams) m_EventQueue.Dequeue();
652 if (data == null) // Shouldn't happen 655 if (data == null) // Shouldn't happen
@@ -672,6 +675,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
672 if (data.EventName == "collision") 675 if (data.EventName == "collision")
673 m_CollisionInQueue = false; 676 m_CollisionInQueue = false;
674 } 677 }
678 }
679 lock(m_Script)
680 {
675 681
676 //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this); 682 //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this);
677 683
@@ -828,6 +834,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
828 new Object[0], new DetectParams[0])); 834 new Object[0], new DetectParams[0]));
829 } 835 }
830 836
837 [DebuggerNonUserCode] //Stops the VS debugger from farting in this function
831 public void ApiResetScript() 838 public void ApiResetScript()
832 { 839 {
833 // bool running = Running; 840 // bool running = Running;
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index 91e03ac..a3a2fdf 100644
--- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
@@ -83,19 +83,19 @@ namespace OpenSim.Region.ScriptEngine.Shared
83 83
84 public override string ToString() 84 public override string ToString()
85 { 85 {
86 string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", x, y, z); 86 string s=String.Format("<{0:0.000000}, {1:0.000000}, {2:0.000000}>", x, y, z);
87 return s; 87 return s;
88 } 88 }
89 89
90 public static explicit operator LSLString(Vector3 vec) 90 public static explicit operator LSLString(Vector3 vec)
91 { 91 {
92 string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); 92 string s=String.Format("<{0:0.000000}, {1:0.000000}, {2:0.000000}>", vec.x, vec.y, vec.z);
93 return new LSLString(s); 93 return new LSLString(s);
94 } 94 }
95 95
96 public static explicit operator string(Vector3 vec) 96 public static explicit operator string(Vector3 vec)
97 { 97 {
98 string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); 98 string s=String.Format("<{0:0.000000}, {1:0.000000}, {2:0.000000}>", vec.x, vec.y, vec.z);
99 return s; 99 return s;
100 } 100 }
101 101
@@ -342,19 +342,19 @@ namespace OpenSim.Region.ScriptEngine.Shared
342 342
343 public override string ToString() 343 public override string ToString()
344 { 344 {
345 string st=String.Format(Culture.FormatProvider, "<{0:0.000000},{1:0.000000},{2:0.000000},{3:0.000000}>", x, y, z, s); 345 string st=String.Format(Culture.FormatProvider, "<{0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000}>", x, y, z, s);
346 return st; 346 return st;
347 } 347 }
348 348
349 public static explicit operator string(Quaternion r) 349 public static explicit operator string(Quaternion r)
350 { 350 {
351 string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000},{3:0.000000}>", r.x, r.y, r.z, r.s); 351 string s=String.Format("<{0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000}>", r.x, r.y, r.z, r.s);
352 return s; 352 return s;
353 } 353 }
354 354
355 public static explicit operator LSLString(Quaternion r) 355 public static explicit operator LSLString(Quaternion r)
356 { 356 {
357 string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000},{3:0.000000}>", r.x, r.y, r.z, r.s); 357 string s=String.Format("<{0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000}>", r.x, r.y, r.z, r.s);
358 return new LSLString(s); 358 return new LSLString(s);
359 } 359 }
360 360
@@ -613,24 +613,16 @@ namespace OpenSim.Region.ScriptEngine.Shared
613 613
614 public static bool operator ==(list a, list b) 614 public static bool operator ==(list a, list b)
615 { 615 {
616 int la = -1; 616 int la = a.Length;
617 int lb = -1; 617 int lb = b.Length;
618 try { la = a.Length; }
619 catch (NullReferenceException) { }
620 try { lb = b.Length; }
621 catch (NullReferenceException) { }
622 618
623 return la == lb; 619 return la == lb;
624 } 620 }
625 621
626 public static bool operator !=(list a, list b) 622 public static bool operator !=(list a, list b)
627 { 623 {
628 int la = -1; 624 int la = a.Length;
629 int lb = -1; 625 int lb = b.Length;
630 try { la = a.Length; }
631 catch (NullReferenceException) { }
632 try {lb = b.Length;}
633 catch (NullReferenceException) { }
634 626
635 return la != lb; 627 return la != lb;
636 } 628 }
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 8629674..35cc65b 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -30,6 +30,7 @@ using System.IO;
30using System.Threading; 30using System.Threading;
31using System.Collections; 31using System.Collections;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Diagnostics; //for [DebuggerNonUserCode]
33using System.Security; 34using System.Security;
34using System.Security.Policy; 35using System.Security.Policy;
35using System.Reflection; 36using System.Reflection;
@@ -103,6 +104,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
103 private Dictionary<UUID, IScriptInstance> m_Scripts = 104 private Dictionary<UUID, IScriptInstance> m_Scripts =
104 new Dictionary<UUID, IScriptInstance>(); 105 new Dictionary<UUID, IScriptInstance>();
105 106
107 private OpenMetaverse.ReaderWriterLockSlim m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
108
106 // Maps the asset ID to the assembly 109 // Maps the asset ID to the assembly
107 110
108 private Dictionary<UUID, string> m_Assemblies = 111 private Dictionary<UUID, string> m_Assemblies =
@@ -125,6 +128,71 @@ namespace OpenSim.Region.ScriptEngine.XEngine
125 IWorkItemResult m_CurrentCompile = null; 128 IWorkItemResult m_CurrentCompile = null;
126 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>(); 129 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
127 130
131 private void lockScriptsForRead(bool locked)
132 {
133 if (locked)
134 {
135 if (m_scriptsLock.RecursiveReadCount > 0)
136 {
137 m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
138 m_scriptsLock.ExitReadLock();
139 }
140 if (m_scriptsLock.RecursiveWriteCount > 0)
141 {
142 m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
143 m_scriptsLock.ExitWriteLock();
144 }
145
146 while (!m_scriptsLock.TryEnterReadLock(60000))
147 {
148 m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire READ lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
149 if (m_scriptsLock.IsWriteLockHeld)
150 {
151 m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
152 }
153 }
154 }
155 else
156 {
157 if (m_scriptsLock.RecursiveReadCount > 0)
158 {
159 m_scriptsLock.ExitReadLock();
160 }
161 }
162 }
163 private void lockScriptsForWrite(bool locked)
164 {
165 if (locked)
166 {
167 if (m_scriptsLock.RecursiveReadCount > 0)
168 {
169 m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
170 m_scriptsLock.ExitReadLock();
171 }
172 if (m_scriptsLock.RecursiveWriteCount > 0)
173 {
174 m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
175 m_scriptsLock.ExitWriteLock();
176 }
177
178 while (!m_scriptsLock.TryEnterWriteLock(60000))
179 {
180 m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
181 if (m_scriptsLock.IsWriteLockHeld)
182 {
183 m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
184 }
185 }
186 }
187 else
188 {
189 if (m_scriptsLock.RecursiveWriteCount > 0)
190 {
191 m_scriptsLock.ExitWriteLock();
192 }
193 }
194 }
195
128 public string ScriptEngineName 196 public string ScriptEngineName
129 { 197 {
130 get { return "XEngine"; } 198 get { return "XEngine"; }
@@ -270,43 +338,45 @@ namespace OpenSim.Region.ScriptEngine.XEngine
270 338
271 public void RemoveRegion(Scene scene) 339 public void RemoveRegion(Scene scene)
272 { 340 {
273 lock (m_Scripts) 341 lockScriptsForRead(true);
342 foreach (IScriptInstance instance in m_Scripts.Values)
274 { 343 {
275 foreach (IScriptInstance instance in m_Scripts.Values) 344 // Force a final state save
345 //
346 if (m_Assemblies.ContainsKey(instance.AssetID))
276 { 347 {
277 // Force a final state save 348 string assembly = m_Assemblies[instance.AssetID];
278 // 349 instance.SaveState(assembly);
279 if (m_Assemblies.ContainsKey(instance.AssetID)) 350 }
280 {
281 string assembly = m_Assemblies[instance.AssetID];
282 instance.SaveState(assembly);
283 }
284 351
285 // Clear the event queue and abort the instance thread 352 // Clear the event queue and abort the instance thread
286 // 353 //
287 instance.ClearQueue(); 354 instance.ClearQueue();
288 instance.Stop(0); 355 instance.Stop(0);
289 356
290 // Release events, timer, etc 357 // Release events, timer, etc
291 // 358 //
292 instance.DestroyScriptInstance(); 359 instance.DestroyScriptInstance();
293 360
294 // Unload scripts and app domains 361 // Unload scripts and app domains
295 // Must be done explicitly because they have infinite 362 // Must be done explicitly because they have infinite
296 // lifetime 363 // lifetime
297 // 364 //
298 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); 365 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
299 if (m_DomainScripts[instance.AppDomain].Count == 0) 366 if (m_DomainScripts[instance.AppDomain].Count == 0)
300 { 367 {
301 m_DomainScripts.Remove(instance.AppDomain); 368 m_DomainScripts.Remove(instance.AppDomain);
302 UnloadAppDomain(instance.AppDomain); 369 UnloadAppDomain(instance.AppDomain);
303 }
304 } 370 }
305 m_Scripts.Clear();
306 m_PrimObjects.Clear();
307 m_Assemblies.Clear();
308 m_DomainScripts.Clear();
309 } 371 }
372 lockScriptsForRead(false);
373 lockScriptsForWrite(true);
374 m_Scripts.Clear();
375 lockScriptsForWrite(false);
376 m_PrimObjects.Clear();
377 m_Assemblies.Clear();
378 m_DomainScripts.Clear();
379
310 lock (m_ScriptEngines) 380 lock (m_ScriptEngines)
311 { 381 {
312 m_ScriptEngines.Remove(this); 382 m_ScriptEngines.Remove(this);
@@ -365,22 +435,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
365 435
366 List<IScriptInstance> instances = new List<IScriptInstance>(); 436 List<IScriptInstance> instances = new List<IScriptInstance>();
367 437
368 lock (m_Scripts) 438 lockScriptsForRead(true);
369 { 439 foreach (IScriptInstance instance in m_Scripts.Values)
370 foreach (IScriptInstance instance in m_Scripts.Values)
371 instances.Add(instance); 440 instances.Add(instance);
372 } 441 lockScriptsForRead(false);
373 442
374 foreach (IScriptInstance i in instances) 443 foreach (IScriptInstance i in instances)
375 { 444 {
376 string assembly = String.Empty; 445 string assembly = String.Empty;
377 446
378 lock (m_Scripts) 447
379 {
380 if (!m_Assemblies.ContainsKey(i.AssetID)) 448 if (!m_Assemblies.ContainsKey(i.AssetID))
381 continue; 449 continue;
382 assembly = m_Assemblies[i.AssetID]; 450 assembly = m_Assemblies[i.AssetID];
383 } 451
384 452
385 i.SaveState(assembly); 453 i.SaveState(assembly);
386 } 454 }
@@ -709,92 +777,95 @@ namespace OpenSim.Region.ScriptEngine.XEngine
709 } 777 }
710 778
711 ScriptInstance instance = null; 779 ScriptInstance instance = null;
712 lock (m_Scripts) 780 // Create the object record
781 lockScriptsForRead(true);
782 if ((!m_Scripts.ContainsKey(itemID)) ||
783 (m_Scripts[itemID].AssetID != assetID))
713 { 784 {
714 // Create the object record 785 lockScriptsForRead(false);
715 786
716 if ((!m_Scripts.ContainsKey(itemID)) || 787 UUID appDomain = assetID;
717 (m_Scripts[itemID].AssetID != assetID))
718 {
719 UUID appDomain = assetID;
720 788
721 if (part.ParentGroup.IsAttachment) 789 if (part.ParentGroup.IsAttachment)
722 appDomain = part.ParentGroup.RootPart.UUID; 790 appDomain = part.ParentGroup.RootPart.UUID;
723 791
724 if (!m_AppDomains.ContainsKey(appDomain)) 792 if (!m_AppDomains.ContainsKey(appDomain))
793 {
794 try
725 { 795 {
726 try 796 AppDomainSetup appSetup = new AppDomainSetup();
727 { 797 appSetup.PrivateBinPath = Path.Combine(
728 AppDomainSetup appSetup = new AppDomainSetup(); 798 m_ScriptEnginesPath,
729 appSetup.PrivateBinPath = Path.Combine( 799 m_Scene.RegionInfo.RegionID.ToString());
730 m_ScriptEnginesPath, 800
731 m_Scene.RegionInfo.RegionID.ToString()); 801 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
732 802 Evidence evidence = new Evidence(baseEvidence);
733 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; 803
734 Evidence evidence = new Evidence(baseEvidence); 804 AppDomain sandbox;
735 805 if (m_AppDomainLoading)
736 AppDomain sandbox; 806 sandbox = AppDomain.CreateDomain(
737 if (m_AppDomainLoading) 807 m_Scene.RegionInfo.RegionID.ToString(),
738 sandbox = AppDomain.CreateDomain( 808 evidence, appSetup);
739 m_Scene.RegionInfo.RegionID.ToString(), 809 else
740 evidence, appSetup); 810 sandbox = AppDomain.CurrentDomain;
741 else 811
742 sandbox = AppDomain.CurrentDomain; 812 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
743 813 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
744 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); 814 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
745 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); 815 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
746 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); 816 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
747 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); 817 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
748 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); 818 //sandbox.SetAppDomainPolicy(sandboxPolicy);
749 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; 819
750 //sandbox.SetAppDomainPolicy(sandboxPolicy); 820 m_AppDomains[appDomain] = sandbox;
751 821
752 m_AppDomains[appDomain] = sandbox; 822 m_AppDomains[appDomain].AssemblyResolve +=
753 823 new ResolveEventHandler(
754 m_AppDomains[appDomain].AssemblyResolve += 824 AssemblyResolver.OnAssemblyResolve);
755 new ResolveEventHandler( 825 m_DomainScripts[appDomain] = new List<UUID>();
756 AssemblyResolver.OnAssemblyResolve); 826 }
757 m_DomainScripts[appDomain] = new List<UUID>(); 827 catch (Exception e)
758 } 828 {
759 catch (Exception e) 829 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
830 m_ScriptErrorMessage += "Exception creating app domain:\n";
831 m_ScriptFailCount++;
832 lock (m_AddingAssemblies)
760 { 833 {
761 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString()); 834 m_AddingAssemblies[assembly]--;
762 m_ScriptErrorMessage += "Exception creating app domain:\n";
763 m_ScriptFailCount++;
764 lock (m_AddingAssemblies)
765 {
766 m_AddingAssemblies[assembly]--;
767 }
768 return false;
769 } 835 }
836 return false;
770 } 837 }
771 m_DomainScripts[appDomain].Add(itemID); 838 }
772 839 m_DomainScripts[appDomain].Add(itemID);
773 instance = new ScriptInstance(this, part, 840
774 itemID, assetID, assembly, 841 instance = new ScriptInstance(this, part,
775 m_AppDomains[appDomain], 842 itemID, assetID, assembly,
776 part.ParentGroup.RootPart.Name, 843 m_AppDomains[appDomain],
777 item.Name, startParam, postOnRez, 844 part.ParentGroup.RootPart.Name,
778 stateSource, m_MaxScriptQueue); 845 item.Name, startParam, postOnRez,
779 846 stateSource, m_MaxScriptQueue);
780 m_log.DebugFormat( 847
848 m_log.DebugFormat(
781 "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}", 849 "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
782 part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID, 850 part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
783 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); 851 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
784 852
785 if (presence != null) 853 if (presence != null)
786 { 854 {
787 ShowScriptSaveResponse(item.OwnerID, 855 ShowScriptSaveResponse(item.OwnerID,
788 assetID, "Compile successful", true); 856 assetID, "Compile successful", true);
789 }
790
791 instance.AppDomain = appDomain;
792 instance.LineMap = linemap;
793
794 m_Scripts[itemID] = instance;
795 } 857 }
796 }
797 858
859 instance.AppDomain = appDomain;
860 instance.LineMap = linemap;
861 lockScriptsForWrite(true);
862 m_Scripts[itemID] = instance;
863 lockScriptsForWrite(false);
864 }
865 else
866 {
867 lockScriptsForRead(false);
868 }
798 lock (m_PrimObjects) 869 lock (m_PrimObjects)
799 { 870 {
800 if (!m_PrimObjects.ContainsKey(localID)) 871 if (!m_PrimObjects.ContainsKey(localID))
@@ -813,9 +884,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
813 m_AddingAssemblies[assembly]--; 884 m_AddingAssemblies[assembly]--;
814 } 885 }
815 886
816 if (instance != null) 887 if (instance!=null)
817 instance.Init(); 888 instance.Init();
818 889
819 return true; 890 return true;
820 } 891 }
821 892
@@ -828,20 +899,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine
828 m_CompileDict.Remove(itemID); 899 m_CompileDict.Remove(itemID);
829 } 900 }
830 901
831 IScriptInstance instance = null; 902 lockScriptsForRead(true);
832 903 // Do we even have it?
833 lock (m_Scripts) 904 if (!m_Scripts.ContainsKey(itemID))
834 { 905 {
835 // Do we even have it? 906 lockScriptsForRead(false);
836 if (!m_Scripts.ContainsKey(itemID)) 907 return;
837 return;
838
839 instance=m_Scripts[itemID];
840 m_Scripts.Remove(itemID);
841 } 908 }
909
842 910
911 IScriptInstance instance=m_Scripts[itemID];
912 lockScriptsForRead(false);
913 lockScriptsForWrite(true);
914 m_Scripts.Remove(itemID);
915 lockScriptsForWrite(false);
843 instance.ClearQueue(); 916 instance.ClearQueue();
844 instance.Stop(0); 917 instance.Stop(0);
918
845// bool objectRemoved = false; 919// bool objectRemoved = false;
846 920
847 lock (m_PrimObjects) 921 lock (m_PrimObjects)
@@ -877,11 +951,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
877 ObjectRemoved handlerObjectRemoved = OnObjectRemoved; 951 ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
878 if (handlerObjectRemoved != null) 952 if (handlerObjectRemoved != null)
879 { 953 {
880 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); 954 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
881 handlerObjectRemoved(part.UUID); 955 handlerObjectRemoved(part.UUID);
882 } 956 }
883 957
884 958 CleanAssemblies();
959
885 ScriptRemoved handlerScriptRemoved = OnScriptRemoved; 960 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
886 if (handlerScriptRemoved != null) 961 if (handlerScriptRemoved != null)
887 handlerScriptRemoved(itemID); 962 handlerScriptRemoved(itemID);
@@ -1023,7 +1098,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1023 return false; 1098 return false;
1024 1099
1025 uuids = m_PrimObjects[localID]; 1100 uuids = m_PrimObjects[localID];
1026 } 1101
1027 1102
1028 foreach (UUID itemID in uuids) 1103 foreach (UUID itemID in uuids)
1029 { 1104 {
@@ -1041,6 +1116,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1041 result = true; 1116 result = true;
1042 } 1117 }
1043 } 1118 }
1119 }
1044 1120
1045 return result; 1121 return result;
1046 } 1122 }
@@ -1140,12 +1216,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1140 private IScriptInstance GetInstance(UUID itemID) 1216 private IScriptInstance GetInstance(UUID itemID)
1141 { 1217 {
1142 IScriptInstance instance; 1218 IScriptInstance instance;
1143 lock (m_Scripts) 1219 lockScriptsForRead(true);
1220 if (!m_Scripts.ContainsKey(itemID))
1144 { 1221 {
1145 if (!m_Scripts.ContainsKey(itemID)) 1222 lockScriptsForRead(false);
1146 return null; 1223 return null;
1147 instance = m_Scripts[itemID];
1148 } 1224 }
1225 instance = m_Scripts[itemID];
1226 lockScriptsForRead(false);
1149 return instance; 1227 return instance;
1150 } 1228 }
1151 1229
@@ -1169,6 +1247,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1169 return false; 1247 return false;
1170 } 1248 }
1171 1249
1250 [DebuggerNonUserCode]
1172 public void ApiResetScript(UUID itemID) 1251 public void ApiResetScript(UUID itemID)
1173 { 1252 {
1174 IScriptInstance instance = GetInstance(itemID); 1253 IScriptInstance instance = GetInstance(itemID);
@@ -1220,6 +1299,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1220 return UUID.Zero; 1299 return UUID.Zero;
1221 } 1300 }
1222 1301
1302 [DebuggerNonUserCode]
1223 public void SetState(UUID itemID, string newState) 1303 public void SetState(UUID itemID, string newState)
1224 { 1304 {
1225 IScriptInstance instance = GetInstance(itemID); 1305 IScriptInstance instance = GetInstance(itemID);
@@ -1240,11 +1320,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1240 { 1320 {
1241 List<IScriptInstance> instances = new List<IScriptInstance>(); 1321 List<IScriptInstance> instances = new List<IScriptInstance>();
1242 1322
1243 lock (m_Scripts) 1323 lockScriptsForRead(true);
1244 { 1324 foreach (IScriptInstance instance in m_Scripts.Values)
1245 foreach (IScriptInstance instance in m_Scripts.Values)
1246 instances.Add(instance); 1325 instances.Add(instance);
1247 } 1326 lockScriptsForRead(false);
1248 1327
1249 foreach (IScriptInstance i in instances) 1328 foreach (IScriptInstance i in instances)
1250 { 1329 {