aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Application/OpenSim.cs4
-rw-r--r--OpenSim/Region/Application/OpenSimBase.cs91
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs709
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs10
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs4
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs4
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs71
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs16
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs127
-rw-r--r--OpenSim/Region/CoreModules/Agent/Capabilities/CapabilitiesModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs11
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs66
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs115
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs17
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs204
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs26
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs102
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs62
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs7
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs6
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs63
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs60
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs107
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs16
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs34
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs74
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs23
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs15
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs6
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs12
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs15
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs18
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs56
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs495
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs37
-rw-r--r--OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RestartModule.cs35
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs2
-rw-r--r--OpenSim/Region/Examples/SimpleModule/ComplexObject.cs5
-rw-r--r--OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs20
-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/IEstateModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IInterregionComms.cs8
-rw-r--r--OpenSim/Region/Framework/Interfaces/IScriptModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISnmpModule.cs27
-rw-r--r--OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs13
-rw-r--r--OpenSim/Region/Framework/ModuleLoader.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs226
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs34
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs267
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Permissions.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs511
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs50
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs224
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs700
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs294
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs754
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs1070
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneViewer.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs16
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs168
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs8
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs22
-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/MoneyModule/SampleMoneyModule.cs4
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs9
-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.cs3873
-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.cs3846
-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/CM_Api.cs118
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs2143
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs53
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs16
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Timer.cs32
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs46
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs71
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/Executor.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs21
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/ScriptBase.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Helpers.cs8
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs52
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs32
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs353
119 files changed, 17139 insertions, 3146 deletions
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index ec1fb04..3f4ee59 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -448,7 +448,7 @@ namespace OpenSim
448 if (alert != null) 448 if (alert != null)
449 presence.ControllingClient.Kick(alert); 449 presence.ControllingClient.Kick(alert);
450 else 450 else
451 presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); 451 presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n");
452 452
453 // ...and close on our side 453 // ...and close on our side
454 presence.Scene.IncomingCloseAgent(presence.UUID); 454 presence.Scene.IncomingCloseAgent(presence.UUID);
@@ -1134,7 +1134,7 @@ namespace OpenSim
1134 MainConsole.Instance.Output(String.Format("loadOffsets <X,Y,Z> = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z)); 1134 MainConsole.Instance.Output(String.Format("loadOffsets <X,Y,Z> = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z));
1135 } 1135 }
1136 } 1136 }
1137 m_sceneManager.LoadCurrentSceneFromXml(cmdparams[2], generateNewIDS, loadOffset); 1137 m_sceneManager.LoadCurrentSceneFromXml(cmdparams[0], generateNewIDS, loadOffset);
1138 } 1138 }
1139 else 1139 else
1140 { 1140 {
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index ea9edf6..503123e 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
@@ -213,6 +222,12 @@ namespace OpenSim
213 m_moduleLoader = new ModuleLoader(m_config.Source); 222 m_moduleLoader = new ModuleLoader(m_config.Source);
214 223
215 LoadPlugins(); 224 LoadPlugins();
225
226 if (m_plugins.Count == 0) // We failed to load any modules. Mono Addins glitch!
227 {
228 Environment.Exit(1);
229 }
230
216 foreach (IApplicationPlugin plugin in m_plugins) 231 foreach (IApplicationPlugin plugin in m_plugins)
217 { 232 {
218 plugin.PostInitialise(); 233 plugin.PostInitialise();
@@ -360,7 +375,41 @@ namespace OpenSim
360 } 375 }
361 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing..."); 376 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing...");
362 377
378 if (m_securePermissionsLoading)
379 {
380 foreach (string s in m_permsModules)
381 {
382 if (!scene.RegionModules.ContainsKey(s))
383 {
384 bool found = false;
385 foreach (IRegionModule m in modules)
386 {
387 if (m.Name == s)
388 {
389 found = true;
390 }
391 }
392 if (!found)
393 {
394 m_log.Fatal("[MODULES]: Required module " + s + " not found.");
395 Environment.Exit(0);
396 }
397 }
398 }
399 }
400
363 scene.SetModuleInterfaces(); 401 scene.SetModuleInterfaces();
402// First Step of bootreport sequence
403 if (scene.SnmpService != null)
404 {
405 scene.SnmpService.ColdStart(1,scene);
406 scene.SnmpService.LinkDown(scene);
407 }
408
409 if (scene.SnmpService != null)
410 {
411 scene.SnmpService.BootInfo("Loading prins", scene);
412 }
364 413
365 // Prims have to be loaded after module configuration since some modules may be invoked during the load 414 // Prims have to be loaded after module configuration since some modules may be invoked during the load
366 scene.LoadPrimsFromStorage(regionInfo.originRegionID); 415 scene.LoadPrimsFromStorage(regionInfo.originRegionID);
@@ -368,6 +417,10 @@ namespace OpenSim
368 // TODO : Try setting resource for region xstats here on scene 417 // TODO : Try setting resource for region xstats here on scene
369 MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo)); 418 MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo));
370 419
420 if (scene.SnmpService != null)
421 {
422 scene.SnmpService.BootInfo("Grid Registration in progress", scene);
423 }
371 try 424 try
372 { 425 {
373 scene.RegisterRegionWithGrid(); 426 scene.RegisterRegionWithGrid();
@@ -378,11 +431,20 @@ namespace OpenSim
378 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}", 431 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}",
379 e.Message, e.StackTrace); 432 e.Message, e.StackTrace);
380 433
434 if (scene.SnmpService != null)
435 {
436 scene.SnmpService.Critical("Grid registration failed. Startup aborted.", scene);
437 }
381 // Carrying on now causes a lot of confusion down the 438 // Carrying on now causes a lot of confusion down the
382 // line - we need to get the user's attention 439 // line - we need to get the user's attention
383 Environment.Exit(1); 440 Environment.Exit(1);
384 } 441 }
385 442
443 if (scene.SnmpService != null)
444 {
445 scene.SnmpService.BootInfo("Grid Registration done", scene);
446 }
447
386 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID); 448 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
387 scene.EventManager.TriggerParcelPrimCountUpdate(); 449 scene.EventManager.TriggerParcelPrimCountUpdate();
388 450
@@ -390,6 +452,11 @@ namespace OpenSim
390 // scripting engines. 452 // scripting engines.
391 scene.CreateScriptInstances(); 453 scene.CreateScriptInstances();
392 454
455 if (scene.SnmpService != null)
456 {
457 scene.SnmpService.BootInfo("ScriptEngine started", scene);
458 }
459
393 m_sceneManager.Add(scene); 460 m_sceneManager.Add(scene);
394 461
395 if (m_autoCreateClientStack) 462 if (m_autoCreateClientStack)
@@ -398,6 +465,10 @@ namespace OpenSim
398 clientServer.Start(); 465 clientServer.Start();
399 } 466 }
400 467
468 if (scene.SnmpService != null)
469 {
470 scene.SnmpService.BootInfo("Initializing region modules", scene);
471 }
401 if (do_post_init) 472 if (do_post_init)
402 { 473 {
403 foreach (IRegionModule module in modules) 474 foreach (IRegionModule module in modules)
@@ -409,6 +480,12 @@ namespace OpenSim
409 480
410 mscene = scene; 481 mscene = scene;
411 482
483 if (scene.SnmpService != null)
484 {
485 scene.SnmpService.BootInfo("The region is operational", scene);
486 scene.SnmpService.LinkUp(scene);
487 }
488
412 scene.StartTimer(); 489 scene.StartTimer();
413 490
414 return clientServer; 491 return clientServer;
@@ -417,6 +494,11 @@ namespace OpenSim
417 private void ShutdownRegion(Scene scene) 494 private void ShutdownRegion(Scene scene)
418 { 495 {
419 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName); 496 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName);
497 if (scene.SnmpService != null)
498 {
499 scene.SnmpService.BootInfo("The region is shutting down", scene);
500 scene.SnmpService.LinkDown(scene);
501 }
420 IRegionModulesController controller; 502 IRegionModulesController controller;
421 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller)) 503 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller))
422 { 504 {
@@ -860,7 +942,7 @@ namespace OpenSim
860 = MainConsole.Instance.CmdPrompt( 942 = MainConsole.Instance.CmdPrompt(
861 string.Format( 943 string.Format(
862 "Do you wish to join region {0} to an existing estate (yes/no)?", regInfo.RegionName), 944 "Do you wish to join region {0} to an existing estate (yes/no)?", regInfo.RegionName),
863 "yes", 945 "no",
864 new List<string>() { "yes", "no" }); 946 new List<string>() { "yes", "no" });
865 947
866 if (response == "no") 948 if (response == "no")
@@ -876,12 +958,15 @@ namespace OpenSim
876 = MainConsole.Instance.CmdPrompt( 958 = MainConsole.Instance.CmdPrompt(
877 string.Format( 959 string.Format(
878 "Name of estate to join. Existing estate names are ({0})", string.Join(", ", estateNames.ToArray())), 960 "Name of estate to join. Existing estate names are ({0})", string.Join(", ", estateNames.ToArray())),
879 estateNames[0]); 961 "None");
962
963 if (response == "None")
964 continue;
880 965
881 List<int> estateIDs = EstateDataService.GetEstates(response); 966 List<int> estateIDs = EstateDataService.GetEstates(response);
882 if (estateIDs.Count < 1) 967 if (estateIDs.Count < 1)
883 { 968 {
884 MainConsole.Instance.Output("The name you have entered matches no known estate. Please try again."); 969 MainConsole.Instance.Output("The name you have entered matches no known estate. Please try again.");
885 continue; 970 continue;
886 } 971 }
887 972
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 34d72ac..789e86c 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;
@@ -327,7 +328,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
327 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 328 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
328 /// ownerless phantom. 329 /// ownerless phantom.
329 /// 330 ///
330 /// All manipulation of this set has to occur under a lock 331 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
331 /// 332 ///
332 /// </value> 333 /// </value>
333 protected HashSet<uint> m_killRecord; 334 protected HashSet<uint> m_killRecord;
@@ -335,6 +336,7 @@ 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;
@@ -378,6 +380,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
378 get { return m_startpos; } 380 get { return m_startpos; }
379 set { m_startpos = value; } 381 set { m_startpos = value; }
380 } 382 }
383 public bool DeliverPackets
384 {
385 get { return m_deliverPackets; }
386 set {
387 m_deliverPackets = value;
388 m_udpClient.m_deliverPackets = value;
389 }
390 }
381 public UUID AgentId { get { return m_agentId; } } 391 public UUID AgentId { get { return m_agentId; } }
382 public UUID ActiveGroupId { get { return m_activeGroupID; } } 392 public UUID ActiveGroupId { get { return m_activeGroupID; } }
383 public string ActiveGroupName { get { return m_activeGroupName; } } 393 public string ActiveGroupName { get { return m_activeGroupName; } }
@@ -476,18 +486,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
476 486
477 #region Client Methods 487 #region Client Methods
478 488
489
479 /// <summary> 490 /// <summary>
480 /// Shut down the client view 491 /// Shut down the client view
481 /// </summary> 492 /// </summary>
482 public void Close() 493 public void Close()
483 { 494 {
495 Close(true);
496 }
497
498 /// <summary>
499 /// Shut down the client view
500 /// </summary>
501 public void Close(bool sendStop)
502 {
484 m_log.DebugFormat( 503 m_log.DebugFormat(
485 "[CLIENT]: Close has been called for {0} attached to scene {1}", 504 "[CLIENT]: Close has been called for {0} attached to scene {1}",
486 Name, m_scene.RegionInfo.RegionName); 505 Name, m_scene.RegionInfo.RegionName);
487 506
488 // Send the STOP packet 507 if (sendStop)
489 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 508 {
490 OutPacket(disable, ThrottleOutPacketType.Unknown); 509 // Send the STOP packet
510 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
511 OutPacket(disable, ThrottleOutPacketType.Unknown);
512 }
491 513
492 IsActive = false; 514 IsActive = false;
493 515
@@ -768,7 +790,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
768 reply.ChatData.OwnerID = fromAgentID; 790 reply.ChatData.OwnerID = fromAgentID;
769 reply.ChatData.SourceID = fromAgentID; 791 reply.ChatData.SourceID = fromAgentID;
770 792
771 OutPacket(reply, ThrottleOutPacketType.Task); 793 OutPacket(reply, ThrottleOutPacketType.Unknown);
772 } 794 }
773 795
774 /// <summary> 796 /// <summary>
@@ -1054,6 +1076,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1054 public virtual void SendLayerData(float[] map) 1076 public virtual void SendLayerData(float[] map)
1055 { 1077 {
1056 Util.FireAndForget(DoSendLayerData, map); 1078 Util.FireAndForget(DoSendLayerData, map);
1079
1080 // Send it sync, and async. It's not that much data
1081 // and it improves user experience just so much!
1082 DoSendLayerData(map);
1057 } 1083 }
1058 1084
1059 /// <summary> 1085 /// <summary>
@@ -1066,16 +1092,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1066 1092
1067 try 1093 try
1068 { 1094 {
1069 //for (int y = 0; y < 16; y++) 1095 for (int y = 0; y < 16; y++)
1070 //{ 1096 {
1071 // for (int x = 0; x < 16; x++) 1097 for (int x = 0; x < 16; x+=4)
1072 // { 1098 {
1073 // SendLayerData(x, y, map); 1099 SendLayerPacket(x, y, map);
1074 // } 1100 }
1075 //} 1101 }
1076
1077 // Send LayerData in a spiral pattern. Fun!
1078 SendLayerTopRight(map, 0, 0, 15, 15);
1079 } 1102 }
1080 catch (Exception e) 1103 catch (Exception e)
1081 { 1104 {
@@ -1083,51 +1106,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1083 } 1106 }
1084 } 1107 }
1085 1108
1086 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1087 {
1088 // Row
1089 for (int i = x1; i <= x2; i++)
1090 SendLayerData(i, y1, map);
1091
1092 // Column
1093 for (int j = y1 + 1; j <= y2; j++)
1094 SendLayerData(x2, j, map);
1095
1096 if (x2 - x1 > 0)
1097 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1098 }
1099
1100 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1101 {
1102 // Row in reverse
1103 for (int i = x2; i >= x1; i--)
1104 SendLayerData(i, y2, map);
1105
1106 // Column in reverse
1107 for (int j = y2 - 1; j >= y1; j--)
1108 SendLayerData(x1, j, map);
1109
1110 if (x2 - x1 > 0)
1111 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1112 }
1113
1114 /// <summary> 1109 /// <summary>
1115 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1110 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1116 /// </summary> 1111 /// </summary>
1117 /// <param name="map">heightmap</param> 1112 /// <param name="map">heightmap</param>
1118 /// <param name="px">X coordinate for patches 0..12</param> 1113 /// <param name="px">X coordinate for patches 0..12</param>
1119 /// <param name="py">Y coordinate for patches 0..15</param> 1114 /// <param name="py">Y coordinate for patches 0..15</param>
1120 // private void SendLayerPacket(float[] map, int y, int x) 1115 private void SendLayerPacket(int x, int y, float[] map)
1121 // { 1116 {
1122 // int[] patches = new int[4]; 1117 int[] patches = new int[4];
1123 // patches[0] = x + 0 + y * 16; 1118 patches[0] = x + 0 + y * 16;
1124 // patches[1] = x + 1 + y * 16; 1119 patches[1] = x + 1 + y * 16;
1125 // patches[2] = x + 2 + y * 16; 1120 patches[2] = x + 2 + y * 16;
1126 // patches[3] = x + 3 + y * 16; 1121 patches[3] = x + 3 + y * 16;
1127 1122
1128 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1123 float[] heightmap = (map.Length == 65536) ?
1129 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1124 map :
1130 // } 1125 LLHeightFieldMoronize(map);
1126
1127 try
1128 {
1129 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1130 OutPacket(layerpack, ThrottleOutPacketType.Land);
1131 }
1132 catch
1133 {
1134 for (int px = x ; px < x + 4 ; px++)
1135 SendLayerData(px, y, map);
1136 }
1137 }
1131 1138
1132 /// <summary> 1139 /// <summary>
1133 /// Sends a specified patch to a client 1140 /// Sends a specified patch to a client
@@ -1147,7 +1154,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1147 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1154 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1148 layerpack.Header.Reliable = true; 1155 layerpack.Header.Reliable = true;
1149 1156
1150 OutPacket(layerpack, ThrottleOutPacketType.Land); 1157 OutPacket(layerpack, ThrottleOutPacketType.Task);
1151 } 1158 }
1152 catch (Exception e) 1159 catch (Exception e)
1153 { 1160 {
@@ -1508,37 +1515,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1508 OutPacket(pc, ThrottleOutPacketType.Unknown); 1515 OutPacket(pc, ThrottleOutPacketType.Unknown);
1509 } 1516 }
1510 1517
1511 public void SendKillObject(ulong regionHandle, uint localID) 1518 public void SendKillObject(ulong regionHandle, List<uint> localIDs)
1512 { 1519 {
1513// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle); 1520// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, localID, regionHandle);
1514 1521
1515 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1522 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1516 // TODO: don't create new blocks if recycling an old packet 1523 // TODO: don't create new blocks if recycling an old packet
1517 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1]; 1524 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
1518 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock(); 1525 for (int i = 0 ; i < localIDs.Count ; i++ )
1519 kill.ObjectData[0].ID = localID; 1526 {
1527 kill.ObjectData[i] = new KillObjectPacket.ObjectDataBlock();
1528 kill.ObjectData[i].ID = localIDs[i];
1529 }
1520 kill.Header.Reliable = true; 1530 kill.Header.Reliable = true;
1521 kill.Header.Zerocoded = true; 1531 kill.Header.Zerocoded = true;
1522 1532
1523 if (m_scene.GetScenePresence(localID) == null) 1533 lock (m_killRecord)
1524 { 1534 {
1525 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 1535 if (localIDs.Count == 1)
1526 // condition where a kill can be processed before an out-of-date update for the same object.
1527 lock (m_killRecord)
1528 { 1536 {
1529 m_killRecord.Add(localID); 1537 if (m_scene.GetScenePresence(localIDs[0]) != null)
1530 1538 {
1531 // The throttle queue used here must match that being used for updates. Otherwise, there is a 1539 OutPacket(kill, ThrottleOutPacketType.State);
1532 // chance that a kill packet put on a separate queue will be sent to the client before an existing 1540 return;
1533 // update packet on another queue. Receiving updates after kills results in unowned and undeletable 1541 }
1534 // scene objects in a viewer until that viewer is relogged in. 1542 m_killRecord.Add(localIDs[0]);
1535 OutPacket(kill, ThrottleOutPacketType.Task); 1543 }
1544 else
1545 {
1546 lock (m_entityUpdates.SyncRoot)
1547 {
1548 foreach (uint localID in localIDs)
1549 m_killRecord.Add(localID);
1550 }
1536 } 1551 }
1537 } 1552 }
1538 else 1553
1539 { 1554 // The throttle queue used here must match that being used for
1540 OutPacket(kill, ThrottleOutPacketType.State); 1555 // updates. Otherwise, there is a chance that a kill packet put
1541 } 1556 // on a separate queue will be sent to the client before an
1557 // existing update packet on another queue. Receiving updates
1558 // after kills results in unowned and undeletable
1559 // scene objects in a viewer until that viewer is relogged in.
1560 OutPacket(kill, ThrottleOutPacketType.Task);
1542 } 1561 }
1543 1562
1544 /// <summary> 1563 /// <summary>
@@ -2251,6 +2270,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2251 OutPacket(sound, ThrottleOutPacketType.Task); 2270 OutPacket(sound, ThrottleOutPacketType.Task);
2252 } 2271 }
2253 2272
2273 public void SendTransferAbort(TransferRequestPacket transferRequest)
2274 {
2275 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2276 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2277 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2278 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2279 OutPacket(abort, ThrottleOutPacketType.Task);
2280 }
2281
2254 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2282 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2255 { 2283 {
2256 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2284 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -3553,6 +3581,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3553 /// </summary> 3581 /// </summary>
3554 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3582 public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3555 { 3583 {
3584 if (entity is SceneObjectPart)
3585 {
3586 SceneObjectPart e = (SceneObjectPart)entity;
3587 SceneObjectGroup g = e.ParentGroup;
3588 if (g.RootPart.Shape.State > 30) // HUD
3589 if (g.OwnerID != AgentId)
3590 return; // Don't send updates for other people's HUDs
3591 }
3592
3556 double priority = m_prioritizer.GetUpdatePriority(this, entity); 3593 double priority = m_prioritizer.GetUpdatePriority(this, entity);
3557 3594
3558 lock (m_entityUpdates.SyncRoot) 3595 lock (m_entityUpdates.SyncRoot)
@@ -3569,232 +3606,257 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3569 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue; 3606 if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
3570 int updatesThisCall = 0; 3607 int updatesThisCall = 0;
3571 3608
3572 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3609 float avgTimeDilation = 0;
3573 // condition where a kill can be processed before an out-of-date update for the same object. 3610
3574 lock (m_killRecord) 3611 EntityUpdate update;
3612 while (updatesThisCall < maxUpdates)
3575 { 3613 {
3576 float avgTimeDilation = 1.0f; 3614 lock (m_entityUpdates.SyncRoot)
3577 EntityUpdate update; 3615 if (!m_entityUpdates.TryDequeue(out update))
3578 while (updatesThisCall < maxUpdates) 3616 break;
3617
3618 avgTimeDilation += update.TimeDilation;
3619 avgTimeDilation *= 0.5f;
3620
3621 if (update.Entity is SceneObjectPart)
3579 { 3622 {
3580 lock (m_entityUpdates.SyncRoot) 3623 SceneObjectPart part = (SceneObjectPart)update.Entity;
3581 if (!m_entityUpdates.TryDequeue(out update))
3582 break;
3583 avgTimeDilation += update.TimeDilation;
3584 avgTimeDilation *= 0.5f;
3585 3624
3586 if (update.Entity is SceneObjectPart) 3625 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3626 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3627 // safety measure.
3628 //
3629 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3630 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3631 // updates and kills on different threads with different scheduling strategies, hence this protection.
3632 //
3633 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3634 // after the root prim has been deleted.
3635 lock (m_killRecord)
3587 { 3636 {
3588 SceneObjectPart part = (SceneObjectPart)update.Entity;
3589
3590 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3591 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3592 // safety measure.
3593 //
3594 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3595 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3596 // updates and kills on different threads with different scheduling strategies, hence this protection.
3597 //
3598 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3599 // after the root prim has been deleted.
3600 if (m_killRecord.Contains(part.LocalId)) 3637 if (m_killRecord.Contains(part.LocalId))
3601 {
3602 // m_log.WarnFormat(
3603 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
3604 // part.LocalId, Name);
3605 continue; 3638 continue;
3606 } 3639 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3607 3640 continue;
3608 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3641 }
3642
3643 if (part.ParentGroup.IsDeleted)
3644 continue;
3645
3646 if (part.ParentGroup.IsAttachment)
3647 { // Someone else's HUD, why are we getting these?
3648 if (part.ParentGroup.OwnerID != AgentId &&
3649 part.ParentGroup.RootPart.Shape.State >= 30)
3650 continue;
3651 ScenePresence sp;
3652 // Owner is not in the sim, don't update it to
3653 // anyone
3654 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3655 continue;
3656
3657 List<SceneObjectGroup> atts = sp.Attachments;
3658 bool found = false;
3659 foreach (SceneObjectGroup att in atts)
3609 { 3660 {
3610 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3661 if (att == part.ParentGroup)
3611 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3612 { 3662 {
3613 part.Shape.LightEntry = false; 3663 found = true;
3664 break;
3614 } 3665 }
3615 } 3666 }
3667
3668 // It's an attachment of a valid avatar, but
3669 // doesn't seem to be attached, skip
3670 if (!found)
3671 continue;
3616 } 3672 }
3617 3673
3618 ++updatesThisCall; 3674 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3619
3620 #region UpdateFlags to packet type conversion
3621
3622 PrimUpdateFlags updateFlags = update.Flags;
3623
3624 bool canUseCompressed = true;
3625 bool canUseImproved = true;
3626
3627 // Compressed object updates only make sense for LL primitives
3628 if (!(update.Entity is SceneObjectPart))
3629 {
3630 canUseCompressed = false;
3631 }
3632
3633 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3634 {
3635 canUseCompressed = false;
3636 canUseImproved = false;
3637 }
3638 else
3639 { 3675 {
3640 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3676 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3641 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 3677 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3642 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3643 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3644 { 3678 {
3645 canUseCompressed = false; 3679 part.Shape.LightEntry = false;
3646 }
3647
3648 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3649 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3650 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3651 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3652 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3653 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3654 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3655 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3656 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3657 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3658 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3659 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3660 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3661 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3662 {
3663 canUseImproved = false;
3664 } 3680 }
3665 } 3681 }
3666 3682 }
3667 #endregion UpdateFlags to packet type conversion 3683
3668 3684 ++updatesThisCall;
3669 #region Block Construction 3685
3670 3686 #region UpdateFlags to packet type conversion
3671 // TODO: Remove this once we can build compressed updates 3687
3688 PrimUpdateFlags updateFlags = update.Flags;
3689
3690 bool canUseCompressed = true;
3691 bool canUseImproved = true;
3692
3693 // Compressed object updates only make sense for LL primitives
3694 if (!(update.Entity is SceneObjectPart))
3695 {
3672 canUseCompressed = false; 3696 canUseCompressed = false;
3673 3697 }
3674 if (!canUseImproved && !canUseCompressed) 3698
3699 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3700 {
3701 canUseCompressed = false;
3702 canUseImproved = false;
3703 }
3704 else
3705 {
3706 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3707 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3708 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3709 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3675 { 3710 {
3676 if (update.Entity is ScenePresence) 3711 canUseCompressed = false;
3677 {
3678 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3679 }
3680 else
3681 {
3682 // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3683 // {
3684 // SceneObjectPart sop = (SceneObjectPart)update.Entity;
3685 // string text = sop.Text;
3686 // if (text.IndexOf("\n") >= 0)
3687 // text = text.Remove(text.IndexOf("\n"));
3688 //
3689 // if (m_attachmentsSent.Contains(sop.ParentID))
3690 // {
3691 //// m_log.DebugFormat(
3692 //// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3693 //// sop.LocalId, text);
3694 //
3695 // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3696 //
3697 // m_attachmentsSent.Add(sop.LocalId);
3698 // }
3699 // else
3700 // {
3701 // m_log.DebugFormat(
3702 // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3703 // sop.LocalId, text, sop.ParentID);
3704 //
3705 // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3706 // }
3707 // }
3708 // else
3709 // {
3710 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3711 // }
3712 }
3713 } 3712 }
3714 else if (!canUseImproved) 3713
3714 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3715 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3716 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3717 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3718 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3719 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3720 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3721 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3722 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3723 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3724 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3725 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3726 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3727 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3715 { 3728 {
3716 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3729 canUseImproved = false;
3730 }
3731 }
3732
3733 #endregion UpdateFlags to packet type conversion
3734
3735 #region Block Construction
3736
3737 // TODO: Remove this once we can build compressed updates
3738 canUseCompressed = false;
3739
3740 if (!canUseImproved && !canUseCompressed)
3741 {
3742 if (update.Entity is ScenePresence)
3743 {
3744 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3717 } 3745 }
3718 else 3746 else
3719 { 3747 {
3720 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3748// if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
3721 // Self updates go into a special list 3749// {
3722 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3750// SceneObjectPart sop = (SceneObjectPart)update.Entity;
3723 else 3751// string text = sop.Text;
3724 // Everything else goes here 3752// if (text.IndexOf("\n") >= 0)
3725 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3753// text = text.Remove(text.IndexOf("\n"));
3754//
3755// if (m_attachmentsSent.Contains(sop.ParentID))
3756// {
3757//// m_log.DebugFormat(
3758//// "[CLIENT]: Sending full info about attached prim {0} text {1}",
3759//// sop.LocalId, text);
3760//
3761// objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
3762//
3763// m_attachmentsSent.Add(sop.LocalId);
3764// }
3765// else
3766// {
3767// m_log.DebugFormat(
3768// "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
3769// sop.LocalId, text, sop.ParentID);
3770//
3771// m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
3772// }
3773// }
3774// else
3775// {
3776 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3777// }
3726 } 3778 }
3727
3728 #endregion Block Construction
3729 } 3779 }
3780 else if (!canUseImproved)
3781 {
3782 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3783 }
3784 else
3785 {
3786 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3787 // Self updates go into a special list
3788 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3789 else
3790 // Everything else goes here
3791 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3792 }
3793
3794 #endregion Block Construction
3795 }
3796
3797 #region Packet Sending
3730 3798
3731 #region Packet Sending 3799 const float TIME_DILATION = 1.0f;
3732 3800 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3733 //const float TIME_DILATION = 1.0f; 3801
3802 if (terseAgentUpdateBlocks.IsValueCreated)
3803 {
3804 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3805
3806 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3807 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3808 packet.RegionData.TimeDilation = timeDilation;
3809 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3810
3811 for (int i = 0; i < blocks.Count; i++)
3812 packet.ObjectData[i] = blocks[i];
3734 3813
3814 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3815 }
3735 3816
3736 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3817 if (objectUpdateBlocks.IsValueCreated)
3818 {
3819 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3737 3820
3738 if (terseAgentUpdateBlocks.IsValueCreated) 3821 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3739 { 3822 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3740 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3823 packet.RegionData.TimeDilation = timeDilation;
3824 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3825
3826 for (int i = 0; i < blocks.Count; i++)
3827 packet.ObjectData[i] = blocks[i];
3741 3828
3742 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3829 OutPacket(packet, ThrottleOutPacketType.Task, true);
3743 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3830 }
3744 packet.RegionData.TimeDilation = timeDilation;
3745 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3746 3831
3747 for (int i = 0; i < blocks.Count; i++) 3832 if (compressedUpdateBlocks.IsValueCreated)
3748 packet.ObjectData[i] = blocks[i]; 3833 {
3834 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3835
3836 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3837 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3838 packet.RegionData.TimeDilation = timeDilation;
3839 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3749 3840
3750 3841 for (int i = 0; i < blocks.Count; i++)
3751 OutPacket(packet, ThrottleOutPacketType.Unknown, true); 3842 packet.ObjectData[i] = blocks[i];
3752 }
3753 3843
3754 if (objectUpdateBlocks.IsValueCreated) 3844 OutPacket(packet, ThrottleOutPacketType.Task, true);
3755 { 3845 }
3756 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3846
3757 3847 if (terseUpdateBlocks.IsValueCreated)
3758 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3848 {
3759 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3849 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3760 packet.RegionData.TimeDilation = timeDilation; 3850
3761 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3851 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3762 3852 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3763 for (int i = 0; i < blocks.Count; i++) 3853 packet.RegionData.TimeDilation = timeDilation;
3764 packet.ObjectData[i] = blocks[i]; 3854 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3765 3855
3766 OutPacket(packet, ThrottleOutPacketType.Task, true); 3856 for (int i = 0; i < blocks.Count; i++)
3767 } 3857 packet.ObjectData[i] = blocks[i];
3768 3858
3769 if (compressedUpdateBlocks.IsValueCreated) 3859 OutPacket(packet, ThrottleOutPacketType.Task, true);
3770 {
3771 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3772
3773 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3774 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3775 packet.RegionData.TimeDilation = timeDilation;
3776 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3777
3778 for (int i = 0; i < blocks.Count; i++)
3779 packet.ObjectData[i] = blocks[i];
3780
3781 OutPacket(packet, ThrottleOutPacketType.Task, true);
3782 }
3783
3784 if (terseUpdateBlocks.IsValueCreated)
3785 {
3786 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3787
3788 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3789 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3790 packet.RegionData.TimeDilation = timeDilation;
3791 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3792
3793 for (int i = 0; i < blocks.Count; i++)
3794 packet.ObjectData[i] = blocks[i];
3795
3796 OutPacket(packet, ThrottleOutPacketType.Task, true);
3797 }
3798 } 3860 }
3799 3861
3800 #endregion Packet Sending 3862 #endregion Packet Sending
@@ -4060,6 +4122,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4060 { 4122 {
4061 m_propertiesPacketTimer.Stop(); 4123 m_propertiesPacketTimer.Stop();
4062 4124
4125 if (m_propertiesBlocks.Count == 0)
4126 return;
4127
4063 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; 4128 proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count];
4064 4129
4065 int index = 0; 4130 int index = 0;
@@ -4461,14 +4526,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4461 4526
4462 if (notifyCount > 0) 4527 if (notifyCount > 0)
4463 { 4528 {
4464 if (notifyCount > 32) 4529// if (notifyCount > 32)
4465 { 4530// {
4466 m_log.InfoFormat( 4531// m_log.InfoFormat(
4467 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4532// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4468 + " - a developer might want to investigate whether this is a hard limit", 32); 4533// + " - a developer might want to investigate whether this is a hard limit", 32);
4469 4534//
4470 notifyCount = 32; 4535// notifyCount = 32;
4471 } 4536// }
4472 4537
4473 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4538 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4474 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4539 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -4976,6 +5041,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4976 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5041 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
4977 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5042 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
4978 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5043 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5044 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
4979 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5045 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
4980 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5046 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
4981 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5047 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5075,6 +5141,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5075 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5141 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5076 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5142 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5077 (x.ControlFlags != lastarg.ControlFlags) || 5143 (x.ControlFlags != lastarg.ControlFlags) ||
5144 (x.ControlFlags != 0) ||
5078 (x.Far != lastarg.Far) || 5145 (x.Far != lastarg.Far) ||
5079 (x.Flags != lastarg.Flags) || 5146 (x.Flags != lastarg.Flags) ||
5080 (x.State != lastarg.State) || 5147 (x.State != lastarg.State) ||
@@ -5448,7 +5515,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5448 args.Channel = ch; 5515 args.Channel = ch;
5449 args.From = String.Empty; 5516 args.From = String.Empty;
5450 args.Message = Utils.BytesToString(msg); 5517 args.Message = Utils.BytesToString(msg);
5451 args.Type = ChatTypeEnum.Shout; 5518 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5452 args.Position = new Vector3(); 5519 args.Position = new Vector3();
5453 args.Scene = Scene; 5520 args.Scene = Scene;
5454 args.Sender = this; 5521 args.Sender = this;
@@ -9436,7 +9503,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9436 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 9503 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9437 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 9504 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9438 UpdateMuteListEntry.MuteData.MuteType, 9505 UpdateMuteListEntry.MuteData.MuteType,
9439 UpdateMuteListEntry.AgentData.AgentID); 9506 UpdateMuteListEntry.MuteData.MuteFlags);
9440 return true; 9507 return true;
9441 } 9508 }
9442 return false; 9509 return false;
@@ -9451,8 +9518,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9451 { 9518 {
9452 handlerRemoveMuteListEntry(this, 9519 handlerRemoveMuteListEntry(this,
9453 RemoveMuteListEntry.MuteData.MuteID, 9520 RemoveMuteListEntry.MuteData.MuteID,
9454 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 9521 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9455 RemoveMuteListEntry.AgentData.AgentID);
9456 return true; 9522 return true;
9457 } 9523 }
9458 return false; 9524 return false;
@@ -9500,6 +9566,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9500 { 9566 {
9501 return true; 9567 return true;
9502 } 9568 }
9569
9570 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9571 {
9572 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9573
9574 #region Packet Session and User Check
9575 if (m_checkPackets)
9576 {
9577 if (packet.AgentData.SessionID != SessionId ||
9578 packet.AgentData.AgentID != AgentId)
9579 return true;
9580 }
9581 #endregion
9582 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9583 List<InventoryItemBase> items = new List<InventoryItemBase>();
9584 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9585 {
9586 InventoryItemBase b = new InventoryItemBase();
9587 b.ID = n.OldItemID;
9588 b.Folder = n.OldFolderID;
9589 items.Add(b);
9590 }
9591
9592 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9593 if (handlerMoveItemsAndLeaveCopy != null)
9594 {
9595 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9596 }
9597
9598 return true;
9599 }
9503 9600
9504 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9601 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9505 { 9602 {
@@ -9926,6 +10023,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9926 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10023 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
9927 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10024 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
9928 10025
10026 Scene scene = (Scene)m_scene;
10027 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10028 {
10029 ScenePresence p;
10030 if (scene.TryGetScenePresence(sender.AgentId, out p))
10031 {
10032 if (p.GodLevel >= 200)
10033 {
10034 groupProfileReply.GroupData.OpenEnrollment = true;
10035 groupProfileReply.GroupData.MembershipFee = 0;
10036 }
10037 }
10038 }
10039
9929 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10040 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
9930 } 10041 }
9931 return true; 10042 return true;
@@ -10498,11 +10609,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10498 10609
10499 StartLure handlerStartLure = OnStartLure; 10610 StartLure handlerStartLure = OnStartLure;
10500 if (handlerStartLure != null) 10611 if (handlerStartLure != null)
10501 handlerStartLure(startLureRequest.Info.LureType, 10612 {
10502 Utils.BytesToString( 10613 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10503 startLureRequest.Info.Message), 10614 {
10504 startLureRequest.TargetData[0].TargetID, 10615 handlerStartLure(startLureRequest.Info.LureType,
10505 this); 10616 Utils.BytesToString(
10617 startLureRequest.Info.Message),
10618 startLureRequest.TargetData[i].TargetID,
10619 this);
10620 }
10621 }
10506 return true; 10622 return true;
10507 } 10623 }
10508 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10624 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10997,7 +11113,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10997 { 11113 {
10998 // It's a ghost! tell the client to delete it from view. 11114 // It's a ghost! tell the client to delete it from view.
10999 simClient.SendKillObject(Scene.RegionInfo.RegionHandle, 11115 simClient.SendKillObject(Scene.RegionInfo.RegionHandle,
11000 localId); 11116 new List<uint>() { localId });
11001 } 11117 }
11002 else 11118 else
11003 { 11119 {
@@ -11370,22 +11486,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11370 /// <param name="Pack">OpenMetaverse.packet</param> 11486 /// <param name="Pack">OpenMetaverse.packet</param>
11371 public void ProcessInPacket(Packet packet) 11487 public void ProcessInPacket(Packet packet)
11372 { 11488 {
11373 if (m_debugPacketLevel > 0) 11489 if (m_debugPacketLevel >= 255)
11374 { 11490 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11375 bool outputPacket = true;
11376
11377 if (m_debugPacketLevel <= 255 && packet.Type == PacketType.AgentUpdate)
11378 outputPacket = false;
11379
11380 if (m_debugPacketLevel <= 200 && packet.Type == PacketType.RequestImage)
11381 outputPacket = false;
11382
11383 if (m_debugPacketLevel <= 100 && (packet.Type == PacketType.ViewerEffect || packet.Type == PacketType.AgentAnimation))
11384 outputPacket = false;
11385
11386 if (outputPacket)
11387 m_log.DebugFormat("[CLIENT]: Packet IN {0}", packet.Type);
11388 }
11389 11491
11390 if (!ProcessPacketMethod(packet)) 11492 if (!ProcessPacketMethod(packet))
11391 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type); 11493 m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
@@ -11627,7 +11729,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11627 11729
11628// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 11730// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11629 11731
11732
11733 //Note, the bool returned from the below function is useless since it is always false.
11630 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 11734 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
11735
11631 } 11736 }
11632 11737
11633 /// <summary> 11738 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 65a8fe3..d6159cd 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -151,6 +151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
151 151
152 private int m_defaultRTO = 3000; 152 private int m_defaultRTO = 3000;
153 private int m_maxRTO = 60000; 153 private int m_maxRTO = 60000;
154 public bool m_deliverPackets = true;
154 155
155 /// <summary> 156 /// <summary>
156 /// Default constructor 157 /// Default constructor
@@ -418,6 +419,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
418 if (category >= 0 && category < m_packetOutboxes.Length) 419 if (category >= 0 && category < m_packetOutboxes.Length)
419 { 420 {
420 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 421 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
422
423 if (m_deliverPackets == false)
424 {
425 queue.Enqueue(packet);
426 return true;
427 }
428
421 TokenBucket bucket = m_throttleCategories[category]; 429 TokenBucket bucket = m_throttleCategories[category];
422 430
423 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) 431 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
@@ -457,6 +465,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
457 /// <returns>True if any packets were sent, otherwise false</returns> 465 /// <returns>True if any packets were sent, otherwise false</returns>
458 public bool DequeueOutgoing() 466 public bool DequeueOutgoing()
459 { 467 {
468 if (m_deliverPackets == false) return false;
469
460 OutgoingPacket packet; 470 OutgoingPacket packet;
461 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 471 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
462 TokenBucket bucket; 472 TokenBucket bucket;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 583214c..c865c0f 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -960,7 +960,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
960 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 960 if (m_scene.TryGetClient(udpClient.AgentID, out client))
961 { 961 {
962 client.IsLoggingOut = true; 962 client.IsLoggingOut = true;
963 client.Close(); 963 client.Close(false);
964 } 964 }
965 } 965 }
966 966
@@ -972,6 +972,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
972 972
973 while (base.IsRunning) 973 while (base.IsRunning)
974 { 974 {
975 m_scene.ThreadAlive(1);
975 try 976 try
976 { 977 {
977 IncomingPacket incomingPacket = null; 978 IncomingPacket incomingPacket = null;
@@ -1014,6 +1015,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1014 1015
1015 while (base.IsRunning) 1016 while (base.IsRunning)
1016 { 1017 {
1018 m_scene.ThreadAlive(2);
1017 try 1019 try
1018 { 1020 {
1019 m_packetSent = false; 1021 m_packetSent = false;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
index 6eebd9d..d2779ba 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OpenSimUDPBase.cs
@@ -100,10 +100,6 @@ namespace OpenMetaverse
100 const int SIO_UDP_CONNRESET = -1744830452; 100 const int SIO_UDP_CONNRESET = -1744830452;
101 101
102 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); 102 IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort);
103
104 m_log.DebugFormat(
105 "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}",
106 ipep.Address, ipep.Port);
107 103
108 m_udpSocket = new Socket( 104 m_udpSocket = new Socket(
109 AddressFamily.InterNetwork, 105 AddressFamily.InterNetwork,
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index 0a8331f..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,30 +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
201 if (deltaMS <= 0)
202 {
203 if (deltaMS < 0)
204 lastDrip = now;
205 return false;
206 }
207 186
208 int dripAmount = deltaMS * tokensPerMS; 187 int now = Environment.TickCount;
188 int deltaMS = now - lastDrip;
189 lastDrip = now;
209 190
210 content = Math.Min(content + dripAmount, maxBurst); 191 if (deltaMS <= 0)
211 lastDrip = now; 192 {
212 193 return false;
213 if (dripAmount < 0 || content < 0) 194 }
214 // sim has been idle for too long, integer has overflown
215 // previous calculation is meaningless, let's put it at correct max
216 content = maxBurst;
217 195
218 return true; 196 long dripAmount = (long)deltaMS * (long)tokensPerMS + (long)content;
197 if (dripAmount > maxBurst)
198 {
199 dripAmount = maxBurst;
219 } 200 }
201 content = (int)dripAmount;
202 return true;
220 } 203 }
221 } 204 }
222} 205}
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
index 771038e..4255c79 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AgentAssetsTransactions.cs
@@ -167,6 +167,19 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
167 { 167 {
168 if (XferUploaders.ContainsKey(transactionID)) 168 if (XferUploaders.ContainsKey(transactionID))
169 { 169 {
170// m_log.DebugFormat("[XFER]: Asked to update item {0} ({1})",
171// item.Name, item.ID);
172
173 // Here we need to get the old asset to extract the
174 // texture UUIDs if it's a wearable.
175 if (item.AssetType == (int)AssetType.Bodypart ||
176 item.AssetType == (int)AssetType.Clothing)
177 {
178 AssetBase oldAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
179 if (oldAsset != null)
180 XferUploaders[transactionID].SetOldData(oldAsset.Data);
181 }
182
170 AssetBase asset = GetTransactionAsset(transactionID); 183 AssetBase asset = GetTransactionAsset(transactionID);
171 184
172 if (asset != null) 185 if (asset != null)
@@ -181,6 +194,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
181 194
182 IInventoryService invService = m_Scene.InventoryService; 195 IInventoryService invService = m_Scene.InventoryService;
183 invService.UpdateItem(item); 196 invService.UpdateItem(item);
197
198// m_log.DebugFormat("[XFER]: Updated item {0} ({1}) with asset {2}",
199// item.Name, item.ID, asset.FullID);
184 } 200 }
185 } 201 }
186 } 202 }
diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
index a7929ba..a5dcdcc 100644
--- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
+++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
@@ -28,6 +28,7 @@
28using System; 28using System;
29using System.IO; 29using System.IO;
30using System.Reflection; 30using System.Reflection;
31using System.Collections.Generic;
31using log4net; 32using log4net;
32using OpenMetaverse; 33using OpenMetaverse;
33using OpenSim.Framework; 34using OpenSim.Framework;
@@ -38,6 +39,13 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
38{ 39{
39 public class AssetXferUploader 40 public class AssetXferUploader
40 { 41 {
42 // Viewer's notion of the default texture
43 private List<UUID> defaultIDs = new List<UUID> {
44 new UUID("5748decc-f629-461c-9a36-a35a221fe21f"),
45 new UUID("7ca39b4c-bd19-4699-aff7-f93fd03d3e7b"),
46 new UUID("6522e74d-1660-4e7f-b601-6f48c1659a77"),
47 new UUID("c228d1cf-4b5d-4ba8-84f4-899a0796aa97")
48 };
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 50
43 private AssetBase m_asset; 51 private AssetBase m_asset;
@@ -55,6 +63,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
55 private UUID TransactionID = UUID.Zero; 63 private UUID TransactionID = UUID.Zero;
56 private sbyte type = 0; 64 private sbyte type = 0;
57 private byte wearableType = 0; 65 private byte wearableType = 0;
66 private byte[] m_oldData = null;
58 public ulong XferID; 67 public ulong XferID;
59 private Scene m_Scene; 68 private Scene m_Scene;
60 69
@@ -219,6 +228,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
219 228
220 private void DoCreateItem(uint callbackID) 229 private void DoCreateItem(uint callbackID)
221 { 230 {
231 ValidateAssets();
222 m_Scene.AssetService.Store(m_asset); 232 m_Scene.AssetService.Store(m_asset);
223 233
224 InventoryItemBase item = new InventoryItemBase(); 234 InventoryItemBase item = new InventoryItemBase();
@@ -239,12 +249,84 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
239 item.Flags = (uint) wearableType; 249 item.Flags = (uint) wearableType;
240 item.CreationDate = Util.UnixTimeSinceEpoch(); 250 item.CreationDate = Util.UnixTimeSinceEpoch();
241 251
252 m_log.DebugFormat("[XFER]: Created item {0} with asset {1}",
253 item.ID, item.AssetID);
254
242 if (m_Scene.AddInventoryItem(item)) 255 if (m_Scene.AddInventoryItem(item))
243 ourClient.SendInventoryItemCreateUpdate(item, callbackID); 256 ourClient.SendInventoryItemCreateUpdate(item, callbackID);
244 else 257 else
245 ourClient.SendAlertMessage("Unable to create inventory item"); 258 ourClient.SendAlertMessage("Unable to create inventory item");
246 } 259 }
247 260
261 private void ValidateAssets()
262 {
263 if (m_asset.Type == (sbyte)AssetType.Clothing ||
264 m_asset.Type == (sbyte)AssetType.Bodypart)
265 {
266 string content = System.Text.Encoding.ASCII.GetString(m_asset.Data);
267 string[] lines = content.Split(new char[] {'\n'});
268
269 List<string> validated = new List<string>();
270
271 Dictionary<int, UUID> allowed = ExtractTexturesFromOldData();
272
273 int textures = 0;
274
275 foreach (string line in lines)
276 {
277 try
278 {
279 if (line.StartsWith("textures "))
280 {
281 textures = Convert.ToInt32(line.Substring(9));
282 validated.Add(line);
283 }
284 else if (textures > 0)
285 {
286 string[] parts = line.Split(new char[] {' '});
287
288 UUID tx = new UUID(parts[1]);
289 int id = Convert.ToInt32(parts[0]);
290
291 if (defaultIDs.Contains(tx) || tx == UUID.Zero ||
292 (allowed.ContainsKey(id) && allowed[id] == tx))
293 {
294 validated.Add(parts[0] + " " + tx.ToString());
295 }
296 else
297 {
298 int perms = m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, tx);
299 int full = (int)(PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Copy);
300
301 if ((perms & full) != full)
302 {
303 m_log.ErrorFormat("[ASSET UPLOADER]: REJECTED update with texture {0} from {1} because they do not own the texture", tx, ourClient.AgentId);
304 validated.Add(parts[0] + " " + UUID.Zero.ToString());
305 }
306 else
307 {
308 validated.Add(line);
309 }
310 }
311 textures--;
312 }
313 else
314 {
315 validated.Add(line);
316 }
317 }
318 catch
319 {
320 // If it's malformed, skip it
321 }
322 }
323
324 string final = String.Join("\n", validated.ToArray());
325
326 m_asset.Data = System.Text.Encoding.ASCII.GetBytes(final);
327 }
328 }
329
248 /// <summary> 330 /// <summary>
249 /// Get the asset data uploaded in this transfer. 331 /// Get the asset data uploaded in this transfer.
250 /// </summary> 332 /// </summary>
@@ -253,10 +335,55 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
253 { 335 {
254 if (m_finished) 336 if (m_finished)
255 { 337 {
338 ValidateAssets();
256 return m_asset; 339 return m_asset;
257 } 340 }
258 341
259 return null; 342 return null;
260 } 343 }
344
345 public void SetOldData(byte[] d)
346 {
347 m_oldData = d;
348 }
349
350 private Dictionary<int,UUID> ExtractTexturesFromOldData()
351 {
352 Dictionary<int,UUID> result = new Dictionary<int,UUID>();
353 if (m_oldData == null)
354 return result;
355
356 string content = System.Text.Encoding.ASCII.GetString(m_oldData);
357 string[] lines = content.Split(new char[] {'\n'});
358
359 int textures = 0;
360
361 foreach (string line in lines)
362 {
363 try
364 {
365 if (line.StartsWith("textures "))
366 {
367 textures = Convert.ToInt32(line.Substring(9));
368 }
369 else if (textures > 0)
370 {
371 string[] parts = line.Split(new char[] {' '});
372
373 UUID tx = new UUID(parts[1]);
374 int id = Convert.ToInt32(parts[0]);
375 result[id] = tx;
376 textures--;
377 }
378 }
379 catch
380 {
381 // If it's malformed, skip it
382 }
383 }
384
385 return result;
386 }
261 } 387 }
262} 388}
389
diff --git a/OpenSim/Region/CoreModules/Agent/Capabilities/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Agent/Capabilities/CapabilitiesModule.cs
index 1d8e70e..7526bd2 100644
--- a/OpenSim/Region/CoreModules/Agent/Capabilities/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Agent/Capabilities/CapabilitiesModule.cs
@@ -95,7 +95,8 @@ namespace OpenSim.Region.CoreModules.Agent.Capabilities
95 95
96 public void AddCapsHandler(UUID agentId) 96 public void AddCapsHandler(UUID agentId)
97 { 97 {
98 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) 98 int flags = m_scene.GetUserFlags(agentId);
99 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags))
99 return; 100 return;
100 101
101 String capsObjectPath = GetCapsPath(agentId); 102 String capsObjectPath = GetCapsPath(agentId);
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 9adb68b..7cba702 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -262,7 +262,16 @@ namespace Flotsam.RegionModules.AssetCache
262 // If the file is already cached, don't cache it, just touch it so access time is updated 262 // If the file is already cached, don't cache it, just touch it so access time is updated
263 if (File.Exists(filename)) 263 if (File.Exists(filename))
264 { 264 {
265 File.SetLastAccessTime(filename, DateTime.Now); 265 // We don't really want to know about sharing
266 // violations here. If the file is locked, then
267 // the other thread has updated the time for us.
268 try
269 {
270 File.SetLastAccessTime(filename, DateTime.Now);
271 }
272 catch
273 {
274 }
266 } else { 275 } else {
267 276
268 // Once we start writing, make sure we flag that we're writing 277 // Once we start writing, make sure we flag that we're writing
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index ff26264..dc33dbb 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;
@@ -118,6 +119,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
118 return; 119 return;
119 } 120 }
120 121
122 if (part.OwnerID != remoteClient.AgentId) // Not ours
123 {
124 remoteClient.SendAgentAlertMessage(
125 "You don't have sufficient permissions to attach this object", false);
126 return;
127 }
128
121 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 129 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
122 // be removed when that functionality is implemented in opensim 130 // be removed when that functionality is implemented in opensim
123 AttachmentPt &= 0x7f; 131 AttachmentPt &= 0x7f;
@@ -226,15 +234,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
226 public UUID RezSingleAttachmentFromInventory( 234 public UUID RezSingleAttachmentFromInventory(
227 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) 235 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
228 { 236 {
229 m_log.DebugFormat( 237 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null);
230 "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", 238 }
231 (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); 239
232 240 public UUID RezSingleAttachmentFromInventory(
241 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc)
242 {
233 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 243 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
234 // be removed when that functionality is implemented in opensim 244 // be removed when that functionality is implemented in opensim
235 AttachmentPt &= 0x7f; 245 AttachmentPt &= 0x7f;
236 246
237 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt); 247 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt, doc);
238 248
239 if (updateInventoryStatus) 249 if (updateInventoryStatus)
240 { 250 {
@@ -251,7 +261,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
251 } 261 }
252 262
253 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 263 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
254 IClientAPI remoteClient, UUID itemID, uint AttachmentPt) 264 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, XmlDocument doc)
255 { 265 {
256 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 266 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
257 if (invAccess != null) 267 if (invAccess != null)
@@ -289,13 +299,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
289 if (tainted) 299 if (tainted)
290 objatt.HasGroupChanged = true; 300 objatt.HasGroupChanged = true;
291 301
302 if (doc != null)
303 {
304 objatt.LoadScriptState(doc);
305 objatt.ResetOwnerChangeFlag();
306 }
307
292 // Fire after attach, so we don't get messy perms dialogs 308 // Fire after attach, so we don't get messy perms dialogs
293 // 4 == AttachedRez 309 // 4 == AttachedRez
294 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 310 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
295 objatt.ResumeScripts(); 311 objatt.ResumeScripts();
296 312
297 // Do this last so that event listeners have access to all the effects of the attachment 313 // Do this last so that event listeners have access to all the effects of the attachment
298 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); 314 //m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId);
299 } 315 }
300 else 316 else
301 { 317 {
@@ -332,7 +348,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
332 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 348 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
333 { 349 {
334 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 350 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
335 item = m_scene.InventoryService.GetItem(item); 351 if (m_scene.InventoryService != null)
352 item = m_scene.InventoryService.GetItem(item);
336 353
337 bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 354 bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
338 if (changed && m_scene.AvatarFactory != null) 355 if (changed && m_scene.AvatarFactory != null)
@@ -379,6 +396,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
379 { 396 {
380 // XXYY!! 397 // XXYY!!
381 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 398 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
399 if (item == null)
400 m_log.Error("[ATTACHMENT]: item == null");
401 if (m_scene == null)
402 m_log.Error("[ATTACHMENT]: m_scene == null");
403 if (m_scene.InventoryService == null)
404 m_log.Error("[ATTACHMENT]: m_scene.InventoryService == null");
382 item = m_scene.InventoryService.GetItem(item); 405 item = m_scene.InventoryService.GetItem(item);
383 bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 406 bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
384 if (changed && m_scene.AvatarFactory != null) 407 if (changed && m_scene.AvatarFactory != null)
@@ -465,6 +488,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
465 if (group.GetFromItemID() == itemID) 488 if (group.GetFromItemID() == itemID)
466 { 489 {
467 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); 490 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
491 // CM / XMREngine!!!! Needed to conclude attach event
492 //SceneObjectSerializer.ToOriginalXmlFormat(group);
468 group.DetachToInventoryPrep(); 493 group.DetachToInventoryPrep();
469 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 494 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
470 495
@@ -482,22 +507,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
482 } 507 }
483 } 508 }
484 509
485 public void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos)
486 {
487 // First we save the
488 // attachment point information, then we update the relative
489 // positioning. Then we have to mark the object as NOT an
490 // attachment. This is necessary in order to correctly save
491 // and retrieve GroupPosition information for the attachment.
492 // Finally, we restore the object's attachment status.
493 byte attachmentPoint = sog.GetAttachmentPoint();
494 sog.UpdateGroupPosition(pos);
495 sog.RootPart.IsAttachment = false;
496 sog.AbsolutePosition = sog.RootPart.AttachedPos;
497 sog.SetAttachmentPoint(attachmentPoint);
498 sog.HasGroupChanged = true;
499 }
500
501 /// <summary> 510 /// <summary>
502 /// Update the attachment asset for the new sog details if they have changed. 511 /// Update the attachment asset for the new sog details if they have changed.
503 /// </summary> 512 /// </summary>
@@ -601,15 +610,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
601 610
602 if (!silent) 611 if (!silent)
603 { 612 {
604 // Killing it here will cause the client to deselect it
605 // It then reappears on the avatar, deselected
606 // through the full update below
607 //
608 if (so.IsSelected)
609 {
610 m_scene.SendKillObject(so.RootPart.LocalId);
611 }
612
613 so.IsSelected = false; // fudge.... 613 so.IsSelected = false; // fudge....
614 so.ScheduleGroupForFullUpdate(); 614 so.ScheduleGroupForFullUpdate();
615 } 615 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index 4359c01..35a3f43 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:
@@ -231,8 +245,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
231 s.ForEachScenePresence( 245 s.ForEachScenePresence(
232 delegate(ScenePresence presence) 246 delegate(ScenePresence presence)
233 { 247 {
234 if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType)) 248 ILandObject Presencecheck = s.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
235 receiverIDs.Add(presence.UUID); 249 if (Presencecheck != null)
250 {
251 // This will pass all chat from objects. Not
252 // perfect, but it will do. For now. Better
253 // than the prior behavior of muting all
254 // objects on a parcel with access restrictions
255 if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true)
256 {
257 if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromNamePrefix + fromName, c.Type, message, sourceType))
258 receiverIDs.Add(presence.UUID);
259 }
260 }
261
236 } 262 }
237 ); 263 );
238 } 264 }
@@ -276,31 +302,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
276 } 302 }
277 303
278 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); 304 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
279
280 HashSet<UUID> receiverIDs = new HashSet<UUID>(); 305 HashSet<UUID> receiverIDs = new HashSet<UUID>();
281 306
282 ((Scene)c.Scene).ForEachScenePresence( 307 if (c.Scene != null)
283 delegate(ScenePresence presence) 308 {
284 { 309 ((Scene)c.Scene).ForEachScenePresence
285 // ignore chat from child agents 310 (
286 if (presence.IsChildAgent) return; 311 delegate(ScenePresence presence)
287 312 {
288 IClientAPI client = presence.ControllingClient; 313 // ignore chat from child agents
289 314 if (presence.IsChildAgent) return;
290 // don't forward SayOwner chat from objects to 315
291 // non-owner agents 316 IClientAPI client = presence.ControllingClient;
292 if ((c.Type == ChatTypeEnum.Owner) && 317
293 (null != c.SenderObject) && 318 // don't forward SayOwner chat from objects to
294 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) 319 // non-owner agents
295 return; 320 if ((c.Type == ChatTypeEnum.Owner) &&
296 321 (null != c.SenderObject) &&
297 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, 322 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
298 (byte)sourceType, (byte)ChatAudibleLevel.Fully); 323 return;
299 receiverIDs.Add(presence.UUID); 324
300 }); 325 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
301 326 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
302 (c.Scene as Scene).EventManager.TriggerOnChatToClients( 327 receiverIDs.Add(presence.UUID);
303 fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); 328 }
329 );
330 (c.Scene as Scene).EventManager.TriggerOnChatToClients(
331 fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully);
332 }
304 } 333 }
305 334
306 /// <summary> 335 /// <summary>
@@ -343,5 +372,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
343 372
344 return true; 373 return true;
345 } 374 }
375
376 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
377 public void ParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
378 {
379 System.Threading.Timer Timer;
380 if (flags == 0)
381 {
382 FreezeCache.Add(target.ToString());
383 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
384 Timer = new System.Threading.Timer(timeCB, target, 30000, 0);
385 Timers.Add(target, Timer);
386 }
387 else
388 {
389 FreezeCache.Remove(target.ToString());
390 Timers.TryGetValue(target, out Timer);
391 Timers.Remove(target);
392 Timer.Dispose();
393 }
394 }
395
396 private void OnEndParcelFrozen(object avatar)
397 {
398 UUID target = (UUID)avatar;
399 FreezeCache.Remove(target.ToString());
400 System.Threading.Timer Timer;
401 Timers.TryGetValue(target, out Timer);
402 Timers.Remove(target);
403 Timer.Dispose();
404 }
346 } 405 }
347} 406}
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index 8a977c9..ded8743 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -215,4 +215,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
215 return result; 215 return result;
216 } 216 }
217 } 217 }
218} \ No newline at end of file 218}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 4d74b2a..3148871 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);
@@ -516,6 +516,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
516 FriendsService.StoreFriend(agentID, friendID.ToString(), 1); 516 FriendsService.StoreFriend(agentID, friendID.ToString(), 1);
517 FriendsService.StoreFriend(friendID, agentID.ToString(), 1); 517 FriendsService.StoreFriend(friendID, agentID.ToString(), 1);
518 518
519 ICallingCardModule ccm = client.Scene.RequestModuleInterface<ICallingCardModule>();
520 if (ccm != null)
521 {
522 ccm.CreateCallingCard(agentID, friendID, UUID.Zero);
523 }
524
519 // Update the local cache 525 // Update the local cache
520 UpdateFriendsCache(agentID); 526 UpdateFriendsCache(agentID);
521 527
@@ -679,6 +685,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
679 (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero); 685 (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero);
680 friendClient.SendInstantMessage(im); 686 friendClient.SendInstantMessage(im);
681 687
688 ICallingCardModule ccm = friendClient.Scene.RequestModuleInterface<ICallingCardModule>();
689 if (ccm != null)
690 {
691 ccm.CreateCallingCard(friendID, userID, UUID.Zero);
692 }
693
694
682 // Update the local cache 695 // Update the local cache
683 UpdateFriendsCache(friendID); 696 UpdateFriendsCache(friendID);
684 697
@@ -701,7 +714,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
701 // we're done 714 // we're done
702 return true; 715 return true;
703 } 716 }
704 717
705 return false; 718 return false;
706 } 719 }
707 720
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 5ec64d5..a83b3df 100644
--- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
@@ -31,16 +31,40 @@ using OpenMetaverse;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework.Scenes; 32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Region.Framework.Interfaces; 33using OpenSim.Region.Framework.Interfaces;
34using System;
35using System.Reflection;
36using System.Collections;
37using System.Collections.Specialized;
38using System.Reflection;
39using System.IO;
40using System.Web;
41using System.Xml;
42using log4net;
43using Mono.Addins;
44using OpenMetaverse.Messages.Linden;
45using OpenMetaverse.StructuredData;
46using OpenSim.Framework.Capabilities;
47using OpenSim.Framework.Servers;
48using OpenSim.Framework.Servers.HttpServer;
49using Caps = OpenSim.Framework.Capabilities.Caps;
50using OSDArray = OpenMetaverse.StructuredData.OSDArray;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
34 52
35namespace OpenSim.Region.CoreModules.Avatar.Gods 53namespace OpenSim.Region.CoreModules.Avatar.Gods
36{ 54{
37 public class GodsModule : IRegionModule, IGodsModule 55 public class GodsModule : IRegionModule, IGodsModule
38 { 56 {
57 private static readonly ILog m_log =
58 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
39 /// <summary>Special UUID for actions that apply to all agents</summary> 60 /// <summary>Special UUID for actions that apply to all agents</summary>
40 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb"); 61 private static readonly UUID ALL_AGENTS = new UUID("44e87126-e794-4ded-05b3-7c42da3d5cdb");
41 62
42 protected Scene m_scene; 63 protected Scene m_scene;
43 protected IDialogModule m_dialogModule; 64 protected IDialogModule m_dialogModule;
65
66 protected Dictionary<UUID, string> m_capsDict =
67 new Dictionary<UUID, string>();
44 68
45 public void Initialise(Scene scene, IConfigSource source) 69 public void Initialise(Scene scene, IConfigSource source)
46 { 70 {
@@ -48,6 +72,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
48 m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>(); 72 m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
49 m_scene.RegisterModuleInterface<IGodsModule>(this); 73 m_scene.RegisterModuleInterface<IGodsModule>(this);
50 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 74 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
75 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
76 m_scene.EventManager.OnClientClosed += OnClientClosed;
77 scene.EventManager.OnIncomingInstantMessage +=
78 OnIncomingInstantMessage;
51 } 79 }
52 80
53 public void PostInitialise() {} 81 public void PostInitialise() {}
@@ -67,6 +95,54 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
67 client.OnRequestGodlikePowers -= RequestGodlikePowers; 95 client.OnRequestGodlikePowers -= RequestGodlikePowers;
68 } 96 }
69 97
98 private void OnClientClosed(UUID agentID, Scene scene)
99 {
100 m_capsDict.Remove(agentID);
101 }
102
103 private void OnRegisterCaps(UUID agentID, Caps caps)
104 {
105 string uri = "/CAPS/" + UUID.Random();
106 m_capsDict[agentID] = uri;
107
108 caps.RegisterHandler("UntrustedSimulatorMessage",
109 new RestStreamHandler("POST", uri,
110 HandleUntrustedSimulatorMessage));
111 }
112
113 private string HandleUntrustedSimulatorMessage(string request,
114 string path, string param, OSHttpRequest httpRequest,
115 OSHttpResponse httpResponse)
116 {
117 OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
118
119 string message = osd["message"].AsString();
120
121 if (message == "GodKickUser")
122 {
123 OSDMap body = (OSDMap)osd["body"];
124 OSDArray userInfo = (OSDArray)body["UserInfo"];
125 OSDMap userData = (OSDMap)userInfo[0];
126
127 UUID agentID = userData["AgentID"].AsUUID();
128 UUID godID = userData["GodID"].AsUUID();
129 UUID godSessionID = userData["GodSessionID"].AsUUID();
130 uint kickFlags = userData["KickFlags"].AsUInteger();
131 string reason = userData["Reason"].AsString();
132
133 ScenePresence god = m_scene.GetScenePresence(godID);
134 if (god == null || god.ControllingClient.SessionId != godSessionID)
135 return String.Empty;
136
137 KickUser(godID, godSessionID, agentID, kickFlags, Util.StringToBytes1024(reason));
138 }
139 else
140 {
141 m_log.ErrorFormat("[GOD]: Unhandled UntrustedSimulatorMessage: {0}", message);
142 }
143 return String.Empty;
144 }
145
70 public void RequestGodlikePowers( 146 public void RequestGodlikePowers(
71 UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient) 147 UUID agentID, UUID sessionID, UUID token, bool godLike, IClientAPI controllingClient)
72 { 148 {
@@ -115,71 +191,85 @@ namespace OpenSim.Region.CoreModules.Avatar.Gods
115 /// <param name="reason">The message to send to the user after it's been turned into a field</param> 191 /// <param name="reason">The message to send to the user after it's been turned into a field</param>
116 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason) 192 public void KickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
117 { 193 {
118 UUID kickUserID = ALL_AGENTS; 194 if (!m_scene.Permissions.IsGod(godID))
119 195 return;
196
120 ScenePresence sp = m_scene.GetScenePresence(agentID); 197 ScenePresence sp = m_scene.GetScenePresence(agentID);
121 198
122 if (sp != null || agentID == kickUserID) 199 if (sp == null && agentID != ALL_AGENTS)
123 { 200 {
124 if (m_scene.Permissions.IsGod(godID)) 201 IMessageTransferModule transferModule =
202 m_scene.RequestModuleInterface<IMessageTransferModule>();
203 if (transferModule != null)
125 { 204 {
126 if (kickflags == 0) 205 m_log.DebugFormat("[GODS]: Sending nonlocal kill for agent {0}", agentID);
127 { 206 transferModule.SendInstantMessage(new GridInstantMessage(
128 if (agentID == kickUserID) 207 m_scene, godID, "God", agentID, (byte)250, false,
129 { 208 Utils.BytesToString(reason), UUID.Zero, true,
130 string reasonStr = Utils.BytesToString(reason); 209 new Vector3(), new byte[] {(byte)kickflags}),
131 210 delegate(bool success) {} );
132 m_scene.ForEachClient( 211 }
133 delegate(IClientAPI controller) 212 return;
134 { 213 }
135 if (controller.AgentId != godID)
136 controller.Kick(reasonStr);
137 }
138 );
139
140 // This is a bit crude. It seems the client will be null before it actually stops the thread
141 // The thread will kill itself eventually :/
142 // Is there another way to make sure *all* clients get this 'inter region' message?
143 m_scene.ForEachScenePresence(
144 delegate(ScenePresence p)
145 {
146 if (p.UUID != godID && !p.IsChildAgent)
147 {
148 // Possibly this should really be p.Close() though that method doesn't send a close
149 // to the client
150 p.ControllingClient.Close();
151 }
152 }
153 );
154 }
155 else
156 {
157 m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
158 214
159 sp.ControllingClient.Kick(Utils.BytesToString(reason)); 215 switch (kickflags)
160 sp.ControllingClient.Close(); 216 {
161 } 217 case 0:
162 } 218 if (sp != null)
163 219 {
164 if (kickflags == 1) 220 KickPresence(sp, Utils.BytesToString(reason));
165 {
166 sp.AllowMovement = false;
167 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
168 m_dialogModule.SendAlertToUser(godID, "User Frozen");
169 }
170
171 if (kickflags == 2)
172 {
173 sp.AllowMovement = true;
174 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
175 m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
176 }
177 } 221 }
178 else 222 else if (agentID == ALL_AGENTS)
179 { 223 {
180 m_dialogModule.SendAlertToUser(godID, "Kick request denied"); 224 m_scene.ForEachScenePresence(
225 delegate(ScenePresence p)
226 {
227 if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID)))
228 KickPresence(p, Utils.BytesToString(reason));
229 }
230 );
181 } 231 }
232 break;
233 case 1:
234 if (sp != null)
235 {
236 sp.AllowMovement = false;
237 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
238 m_dialogModule.SendAlertToUser(godID, "User Frozen");
239 }
240 break;
241 case 2:
242 if (sp != null)
243 {
244 sp.AllowMovement = true;
245 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
246 m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
247 }
248 break;
249 default:
250 break;
251 }
252 }
253
254 private void KickPresence(ScenePresence sp, string reason)
255 {
256 if (sp.IsChildAgent)
257 return;
258 sp.ControllingClient.Kick(reason);
259 sp.Scene.IncomingCloseAgent(sp.UUID);
260 }
261
262 private void OnIncomingInstantMessage(GridInstantMessage msg)
263 {
264 if (msg.dialog == (uint)250) // Nonlocal kick
265 {
266 UUID agentID = new UUID(msg.toAgentID);
267 string reason = msg.message;
268 UUID godID = new UUID(msg.fromAgentID);
269 uint kickMode = (uint)msg.binaryBucket[0];
270
271 KickUser(godID, UUID.Zero, agentID, kickMode, Util.StringToBytes1024(reason));
182 } 272 }
183 } 273 }
184 } 274 }
185} \ No newline at end of file 275}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
index af39565..feb5fb8 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -156,6 +156,32 @@ 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 // If client is null, this message comes from storage and IS offline
179 if (client != null)
180 im.offline = 0;
181
182 if (im.offline == 0)
183 im.timestamp = (uint)Util.UnixTimeSinceEpoch();
184
159 if (m_TransferModule != null) 185 if (m_TransferModule != null)
160 { 186 {
161 if (client != null) 187 if (client != null)
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 77c7147..c1caf44 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -47,6 +47,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private bool m_Enabled = false; 49 private bool m_Enabled = false;
50 protected string m_MessageKey = String.Empty;
50 protected List<Scene> m_Scenes = new List<Scene>(); 51 protected List<Scene> m_Scenes = new List<Scene>();
51 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>(); 52 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>();
52 53
@@ -66,14 +67,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
66 public virtual void Initialise(IConfigSource config) 67 public virtual void Initialise(IConfigSource config)
67 { 68 {
68 IConfig cnf = config.Configs["Messaging"]; 69 IConfig cnf = config.Configs["Messaging"];
69 if (cnf != null && cnf.GetString( 70 if (cnf != null)
70 "MessageTransferModule", "MessageTransferModule") !=
71 "MessageTransferModule")
72 { 71 {
73 m_log.Debug("[MESSAGE TRANSFER]: Disabled by configuration"); 72 if (cnf.GetString("MessageTransferModule",
74 return; 73 "MessageTransferModule") != "MessageTransferModule")
75 } 74 {
75 return;
76 }
76 77
78 m_MessageKey = cnf.GetString("MessageKey", String.Empty);
79 }
80 m_log.Debug("[MESSAGE TRANSFER]: Module enabled");
77 m_Enabled = true; 81 m_Enabled = true;
78 } 82 }
79 83
@@ -145,8 +149,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
145 ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; 149 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
146 if (!user.IsChildAgent) 150 if (!user.IsChildAgent)
147 { 151 {
148 // Local message 152 // 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); 153 user.ControllingClient.SendInstantMessage(im);
151 154
152 // Message sent 155 // Message sent
@@ -168,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
168 // Local message 171 // Local message
169 ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; 172 ScenePresence user = (ScenePresence) scene.Entities[toAgentID];
170 173
171// m_log.DebugFormat("[INSTANT MESSAGE]: Delivering IM to child agent {0} {1}", user.Name, toAgentID); 174 // m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client");
172 user.ControllingClient.SendInstantMessage(im); 175 user.ControllingClient.SendInstantMessage(im);
173 176
174 // Message sent 177 // Message sent
@@ -251,6 +254,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
251 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") 254 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
252 && requestData.ContainsKey("binary_bucket")) 255 && requestData.ContainsKey("binary_bucket"))
253 { 256 {
257 if (m_MessageKey != String.Empty)
258 {
259 XmlRpcResponse error_resp = new XmlRpcResponse();
260 Hashtable error_respdata = new Hashtable();
261 error_respdata["success"] = "FALSE";
262 error_resp.Value = error_respdata;
263
264 if (!requestData.Contains("message_key"))
265 return error_resp;
266 if (m_MessageKey != (string)requestData["message_key"])
267 return error_resp;
268 }
269
254 // Do the easy way of validating the UUIDs 270 // Do the easy way of validating the UUIDs
255 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); 271 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
256 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); 272 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
@@ -433,24 +449,37 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
433 return resp; 449 return resp;
434 } 450 }
435 451
436 /// <summary> 452 private delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result);
437 /// delegate for sending a grid instant message asynchronously
438 /// </summary>
439 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID);
440 453
441 protected virtual void GridInstantMessageCompleted(IAsyncResult iar) 454 private class GIM {
442 { 455 public GridInstantMessage im;
443 GridInstantMessageDelegate icon = 456 public MessageResultNotification result;
444 (GridInstantMessageDelegate)iar.AsyncState; 457 };
445 icon.EndInvoke(iar);
446 }
447 458
459 private Queue<GIM> pendingInstantMessages = new Queue<GIM>();
460 private int numInstantMessageThreads = 0;
448 461
449 protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) 462 private void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result)
450 { 463 {
451 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; 464 lock (pendingInstantMessages) {
465 if (numInstantMessageThreads >= 4) {
466 GIM gim = new GIM();
467 gim.im = im;
468 gim.result = result;
469 pendingInstantMessages.Enqueue(gim);
470 } else {
471 ++ numInstantMessageThreads;
472 //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: ++numInstantMessageThreads={0}", numInstantMessageThreads);
473 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsyncMain;
474 d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
475 }
476 }
477 }
452 478
453 d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); 479 private void GridInstantMessageCompleted(IAsyncResult iar)
480 {
481 GridInstantMessageDelegate d = (GridInstantMessageDelegate)iar.AsyncState;
482 d.EndInvoke(iar);
454 } 483 }
455 484
456 /// <summary> 485 /// <summary>
@@ -465,8 +494,31 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
465 /// Pass in 0 the first time this method is called. It will be called recursively with the last 494 /// Pass in 0 the first time this method is called. It will be called recursively with the last
466 /// regionhandle tried 495 /// regionhandle tried
467 /// </param> 496 /// </param>
468 protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) 497 private void SendGridInstantMessageViaXMLRPCAsyncMain(GridInstantMessage im, MessageResultNotification result)
469 { 498 {
499 GIM gim;
500 do {
501 try {
502 SendGridInstantMessageViaXMLRPCAsync(im, result, UUID.Zero);
503 } catch (Exception e) {
504 m_log.Error("[SendGridInstantMessageViaXMLRPC]: exception " + e.Message);
505 }
506 lock (pendingInstantMessages) {
507 if (pendingInstantMessages.Count > 0) {
508 gim = pendingInstantMessages.Dequeue();
509 im = gim.im;
510 result = gim.result;
511 } else {
512 gim = null;
513 -- numInstantMessageThreads;
514 //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: --numInstantMessageThreads={0}", numInstantMessageThreads);
515 }
516 }
517 } while (gim != null);
518 }
519 private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
520 {
521
470 UUID toAgentID = new UUID(im.toAgentID); 522 UUID toAgentID = new UUID(im.toAgentID);
471 523
472 PresenceInfo upd = null; 524 PresenceInfo upd = null;
@@ -533,7 +585,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
533 585
534 if (upd != null) 586 if (upd != null)
535 { 587 {
536 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, 588 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(UUID.Zero,
537 upd.RegionID); 589 upd.RegionID);
538 if (reginfo != null) 590 if (reginfo != null)
539 { 591 {
@@ -682,6 +734,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
682 gim["position_z"] = msg.Position.Z.ToString(); 734 gim["position_z"] = msg.Position.Z.ToString();
683 gim["region_id"] = msg.RegionID.ToString(); 735 gim["region_id"] = msg.RegionID.ToString();
684 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); 736 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
737 if (m_MessageKey != String.Empty)
738 gim["message_key"] = m_MessageKey;
685 return gim; 739 return gim;
686 } 740 }
687 741
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index fdfcd10..164ae50 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,9 @@ 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
192 Scene s = FindScene(client.AgentId); 198 Scene s = FindScene(client.AgentId);
193 if (s != null) 199 if (s != null)
194 s.EventManager.TriggerIncomingInstantMessage(im); 200 s.EventManager.TriggerIncomingInstantMessage(im);
@@ -198,26 +204,38 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
198 204
199 private void UndeliveredMessage(GridInstantMessage im) 205 private void UndeliveredMessage(GridInstantMessage im)
200 { 206 {
201 if ((im.offline != 0) 207 if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
202 && (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) 208 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
209 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
210 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
211 im.dialog != (byte)InstantMessageDialog.InventoryOffered)
203 { 212 {
204 bool success = SynchronousRestObjectPoster.BeginPostObject<GridInstantMessage, bool>( 213 return;
205 "POST", m_RestURL+"/SaveMessage/", im); 214 }
206 215
207 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) 216 // It's not delivered. Make sure the scope id is saved
208 { 217 // We don't need the imSessionID here anymore, overwrite it
209 IClientAPI client = FindClient(new UUID(im.fromAgentID)); 218 Scene scene = FindScene(new UUID(im.fromAgentID));
210 if (client == null) 219 if (scene == null)
211 return; 220 scene = m_SceneList[0];
212 221
213 client.SendInstantMessage(new GridInstantMessage( 222 bool success = SynchronousRestObjectPoster.BeginPostObject<GridInstantMessage, bool>(
214 null, new UUID(im.toAgentID), 223 "POST", m_RestURL+"/SaveMessage/?scope=" +
215 "System", new UUID(im.fromAgentID), 224 scene.RegionInfo.ScopeID.ToString(), im);
216 (byte)InstantMessageDialog.MessageFromAgent, 225
217 "User is not logged in. "+ 226 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
218 (success ? "Message saved." : "Message not saved"), 227 {
219 false, new Vector3())); 228 IClientAPI client = FindClient(new UUID(im.fromAgentID));
220 } 229 if (client == null)
230 return;
231
232 client.SendInstantMessage(new GridInstantMessage(
233 null, new UUID(im.toAgentID),
234 "System", new UUID(im.fromAgentID),
235 (byte)InstantMessageDialog.MessageFromAgent,
236 "User is not logged in. "+
237 (success ? "Message saved." : "Message not saved"),
238 false, new Vector3()));
221 } 239 }
222 } 240 }
223 } 241 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index 01170aa..9b98de3 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -77,12 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
77 /// </value> 77 /// </value>
78 private Stream m_loadStream; 78 private Stream m_loadStream;
79 79
80 /// <summary> 80 protected bool m_controlFileLoaded;
81 /// FIXME: Do not perform this check since older versions of OpenSim do save the control file after other things
82 /// (I thought they weren't). We will need to bump the version number and perform this check on all
83 /// subsequent IAR versions only
84 /// </summary>
85 protected bool m_controlFileLoaded = true;
86 protected bool m_assetsLoaded; 81 protected bool m_assetsLoaded;
87 protected bool m_inventoryNodesLoaded; 82 protected bool m_inventoryNodesLoaded;
88 83
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index dc4900f..5e5f6c0 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -139,9 +139,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
139 139
140 protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary<string, object> options, IUserAccountService userAccountService) 140 protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary<string, object> options, IUserAccountService userAccountService)
141 { 141 {
142 if (options.ContainsKey("verbose"))
143 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saving item {0} with asset {1}", inventoryItem.ID, inventoryItem.AssetID);
144
145 string filename = path + CreateArchiveItemName(inventoryItem); 142 string filename = path + CreateArchiveItemName(inventoryItem);
146 143
147 // Record the creator of this item for user record purposes (which might go away soon) 144 // Record the creator of this item for user record purposes (which might go away soon)
@@ -165,9 +162,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
165 InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself, 162 InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself,
166 Dictionary<string, object> options, IUserAccountService userAccountService) 163 Dictionary<string, object> options, IUserAccountService userAccountService)
167 { 164 {
168 if (options.ContainsKey("verbose"))
169 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saving folder {0}", inventoryFolder.Name);
170
171 if (saveThisFolderItself) 165 if (saveThisFolderItself)
172 { 166 {
173 path += CreateArchiveFolderName(inventoryFolder); 167 path += CreateArchiveFolderName(inventoryFolder);
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
index 576a154..613f0ed 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
@@ -122,7 +122,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
122 122
123 scene.AddCommand( 123 scene.AddCommand(
124 this, "save iar", 124 this, "save iar",
125 "save iar [--p|-profile=<url>] <first> <last> <inventory path> <password> [<IAR path>] [--v|-verbose]", 125 "save iar [--p|-profile=<url>] <first> <last> <inventory path> <password> [<IAR path>]",
126 "Save user inventory archive (IAR).", 126 "Save user inventory archive (IAR).",
127 "<first> is the user's first name." + Environment.NewLine 127 "<first> is the user's first name." + Environment.NewLine
128 + "<last> is the user's last name." + Environment.NewLine 128 + "<last> is the user's last name." + Environment.NewLine
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index e3d4969..528bc8d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
@@ -175,8 +175,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
175 if (im.binaryBucket.Length < 17) // Invalid 175 if (im.binaryBucket.Length < 17) // Invalid
176 return; 176 return;
177 177
178 UUID receipientID = new UUID(im.toAgentID); 178 UUID recipientID = new UUID(im.toAgentID);
179 ScenePresence user = scene.GetScenePresence(receipientID); 179 ScenePresence user = scene.GetScenePresence(recipientID);
180 UUID copyID; 180 UUID copyID;
181 181
182 // First byte is the asset type 182 // First byte is the asset type
@@ -191,7 +191,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
191 folderID, new UUID(im.toAgentID)); 191 folderID, new UUID(im.toAgentID));
192 192
193 InventoryFolderBase folderCopy 193 InventoryFolderBase folderCopy
194 = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero); 194 = scene.GiveInventoryFolder(recipientID, client.AgentId, folderID, UUID.Zero);
195 195
196 if (folderCopy == null) 196 if (folderCopy == null)
197 { 197 {
@@ -248,6 +248,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
248 im.imSessionID = itemID.Guid; 248 im.imSessionID = itemID.Guid;
249 } 249 }
250 250
251 im.offline = 1; // Remember these
252
251 // Send the IM to the recipient. The item is already 253 // Send the IM to the recipient. The item is already
252 // in their inventory, so it will not be lost if 254 // in their inventory, so it will not be lost if
253 // they are offline. 255 // they are offline.
@@ -417,22 +419,67 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
417 /// 419 ///
418 /// </summary> 420 /// </summary>
419 /// <param name="msg"></param> 421 /// <param name="msg"></param>
420 private void OnGridInstantMessage(GridInstantMessage msg) 422 private void OnGridInstantMessage(GridInstantMessage im)
421 { 423 {
422 // Check if this is ours to handle 424 // Check if this is ours to handle
423 // 425 //
424 Scene scene = FindClientScene(new UUID(msg.toAgentID)); 426 Scene scene = FindClientScene(new UUID(im.toAgentID));
425 427
426 if (scene == null) 428 if (scene == null)
427 return; 429 return;
428 430
429 // Find agent to deliver to 431 // Find agent to deliver to
430 // 432 //
431 ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); 433 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
434 if (user == null)
435 return;
436
437 // This requires a little bit of processing because we have to make the
438 // new item visible in the recipient's inventory here
439 //
440 if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
441 {
442 if (im.binaryBucket.Length < 17) // Invalid
443 return;
444
445 UUID recipientID = new UUID(im.toAgentID);
446
447 // First byte is the asset type
448 AssetType assetType = (AssetType)im.binaryBucket[0];
449
450 if (AssetType.Folder == assetType)
451 {
452 UUID folderID = new UUID(im.binaryBucket, 1);
453
454 InventoryFolderBase given =
455 new InventoryFolderBase(folderID, recipientID);
456 InventoryFolderBase folder =
457 scene.InventoryService.GetFolder(given);
458
459 if (folder != null)
460 user.ControllingClient.SendBulkUpdateInventory(folder);
461 }
462 else
463 {
464 UUID itemID = new UUID(im.binaryBucket, 1);
432 465
433 // Just forward to local handling 466 InventoryItemBase given =
434 OnInstantMessage(user.ControllingClient, msg); 467 new InventoryItemBase(itemID, recipientID);
468 InventoryItemBase item =
469 scene.InventoryService.GetItem(given);
435 470
471 if (item != null)
472 {
473 user.ControllingClient.SendBulkUpdateInventory(item);
474 }
475 }
476 user.ControllingClient.SendInstantMessage(im);
477 }
478 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted ||
479 im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
480 {
481 user.ControllingClient.SendInstantMessage(im);
482 }
436 } 483 }
437 } 484 }
438} 485}
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index d1d7df2..a12b57a 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -146,16 +146,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
146 scene.RegionInfo.RegionHandle, 146 scene.RegionInfo.RegionHandle,
147 (uint)presence.AbsolutePosition.X, 147 (uint)presence.AbsolutePosition.X,
148 (uint)presence.AbsolutePosition.Y, 148 (uint)presence.AbsolutePosition.Y,
149 (uint)presence.AbsolutePosition.Z); 149 (uint)presence.AbsolutePosition.Z + 2);
150 150
151 m_log.DebugFormat("TP invite with message {0}", message); 151 m_log.DebugFormat("[LURE]: TP invite with message {0}", message);
152
153 GridInstantMessage m;
154
155 if (scene.Permissions.IsAdministrator(client.AgentId) && presence.GodLevel >= 200 && (!scene.Permissions.IsAdministrator(targetid)))
156 {
157 m = new GridInstantMessage(scene, client.AgentId,
158 client.FirstName+" "+client.LastName, targetid,
159 (byte)InstantMessageDialog.GodLikeRequestTeleport, false,
160 message, dest, false, presence.AbsolutePosition,
161 new Byte[0]);
162 }
163 else
164 {
165 m = new GridInstantMessage(scene, client.AgentId,
166 client.FirstName+" "+client.LastName, targetid,
167 (byte)InstantMessageDialog.RequestTeleport, false,
168 message, dest, false, presence.AbsolutePosition,
169 new Byte[0]);
170 }
152 171
153 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId,
154 client.FirstName+" "+client.LastName, targetid,
155 (byte)InstantMessageDialog.RequestTeleport, false,
156 message, dest, false, presence.AbsolutePosition,
157 new Byte[0]);
158
159 if (m_TransferModule != null) 172 if (m_TransferModule != null)
160 { 173 {
161 m_TransferModule.SendInstantMessage(m, 174 m_TransferModule.SendInstantMessage(m,
@@ -190,7 +203,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
190 { 203 {
191 // Forward remote teleport requests 204 // Forward remote teleport requests
192 // 205 //
193 if (msg.dialog != 22) 206 if (msg.dialog != (byte)InstantMessageDialog.RequestTeleport &&
207 msg.dialog != (byte)InstantMessageDialog.GodLikeRequestTeleport)
194 return; 208 return;
195 209
196 if (m_TransferModule != null) 210 if (m_TransferModule != null)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index c88be7d..138556f 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -102,7 +102,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
102 102
103 protected virtual void OnNewClient(IClientAPI client) 103 protected virtual void OnNewClient(IClientAPI client)
104 { 104 {
105 client.OnTeleportHomeRequest += TeleportHome; 105 client.OnTeleportHomeRequest += TeleportHomeFired;
106 } 106 }
107 107
108 public virtual void Close() 108 public virtual void Close()
@@ -180,6 +180,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
180 sp.ControllingClient.SendTeleportStart(teleportFlags); 180 sp.ControllingClient.SendTeleportStart(teleportFlags);
181 181
182 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); 182 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
183 sp.TeleportFlags = (TeleportFlags)teleportFlags;
183 sp.Teleport(position); 184 sp.Teleport(position);
184 185
185 foreach (SceneObjectGroup grp in sp.Attachments) 186 foreach (SceneObjectGroup grp in sp.Attachments)
@@ -271,7 +272,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
271 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 272 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
272 // it's actually doing a lot of work. 273 // it's actually doing a lot of work.
273 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 274 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
274 if (endPoint.Address != null) 275 if (endPoint != null && endPoint.Address != null)
275 { 276 {
276 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 277 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
277 // both regions 278 // both regions
@@ -519,7 +520,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
519 520
520 protected void KillEntity(Scene scene, uint localID) 521 protected void KillEntity(Scene scene, uint localID)
521 { 522 {
522 scene.SendKillObject(localID); 523 scene.SendKillObject(new List<uint>() { localID });
523 } 524 }
524 525
525 protected virtual GridRegion GetFinalDestination(GridRegion region) 526 protected virtual GridRegion GetFinalDestination(GridRegion region)
@@ -557,7 +558,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
557 558
558 #region Teleport Home 559 #region Teleport Home
559 560
560 public virtual void TeleportHome(UUID id, IClientAPI client) 561 public void TeleportHomeFired(UUID id, IClientAPI client)
562 {
563 TeleportHome(id, client);
564 }
565
566 public virtual bool TeleportHome(UUID id, IClientAPI client)
561 { 567 {
562 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 568 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
563 569
@@ -566,12 +572,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
566 572
567 if (uinfo != null) 573 if (uinfo != null)
568 { 574 {
575 if (uinfo.HomeRegionID == UUID.Zero)
576 {
577 // can't find the Home region: Tell viewer and abort
578 client.SendTeleportFailed("You don't have a home position set.");
579 return false;
580 }
569 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 581 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
570 if (regionInfo == null) 582 if (regionInfo == null)
571 { 583 {
572 // can't find the Home region: Tell viewer and abort 584 // can't find the Home region: Tell viewer and abort
573 client.SendTeleportFailed("Your home region could not be found."); 585 client.SendTeleportFailed("Your home region could not be found.");
574 return; 586 return false;
575 } 587 }
576 588
577 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})", 589 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})",
@@ -582,6 +594,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
582 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 594 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
583 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 595 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
584 } 596 }
597 else
598 {
599 // can't find the Home region: Tell viewer and abort
600 client.SendTeleportFailed("Your home region could not be found.");
601 return false;
602 }
603 return true;
585 } 604 }
586 605
587 #endregion 606 #endregion
@@ -916,15 +935,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
916 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); 935 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
917 936
918 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>(); 937 IEventQueue eq = agent.Scene.RequestModuleInterface<IEventQueue>();
919 if (eq != null) 938 IPEndPoint neighbourExternal = neighbourRegion.ExternalEndPoint;
920 { 939 if (neighbourExternal != null)
921 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
922 capsPath, agent.UUID, agent.ControllingClient.SessionId);
923 }
924 else
925 { 940 {
926 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint, 941 if (eq != null)
927 capsPath); 942 {
943 eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourExternal,
944 capsPath, agent.UUID, agent.ControllingClient.SessionId);
945 }
946 else
947 {
948 agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourExternal,
949 capsPath);
950 }
928 } 951 }
929 952
930 if (!WaitForCallback(agent.UUID)) 953 if (!WaitForCallback(agent.UUID))
@@ -1028,10 +1051,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1028 agent.Id0 = currentAgentCircuit.Id0; 1051 agent.Id0 = currentAgentCircuit.Id0;
1029 } 1052 }
1030 1053
1031 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1054 IPEndPoint external = region.ExternalEndPoint;
1032 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 1055 if (external != null)
1056 {
1057 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1058 d.BeginInvoke(sp, agent, region, external, true,
1033 InformClientOfNeighbourCompleted, 1059 InformClientOfNeighbourCompleted,
1034 d); 1060 d);
1061 }
1035 } 1062 }
1036 #endregion 1063 #endregion
1037 1064
@@ -1164,6 +1191,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1164 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1191 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1165 try 1192 try
1166 { 1193 {
1194 //neighbour.ExternalEndPoint may return null, which will be caught
1167 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, 1195 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
1168 InformClientOfNeighbourCompleted, 1196 InformClientOfNeighbourCompleted,
1169 d); 1197 d);
@@ -1267,8 +1295,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1267 1295
1268 m_log.Debug("[ENTITY TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString()); 1296 m_log.Debug("[ENTITY TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString());
1269 } 1297 }
1270 if (!regionAccepted)
1271 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Region {0} did not accept agent: {1}", reg.RegionName, reason);
1272 } 1298 }
1273 1299
1274 /// <summary> 1300 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 79e76b4..5a80100 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
@@ -177,7 +177,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
177 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason); 177 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason);
178 } 178 }
179 179
180 public override void TeleportHome(UUID id, IClientAPI client) 180 public void TeleportHomeFired(UUID id, IClientAPI client)
181 {
182 TeleportHome(id, client);
183 }
184
185 public override bool TeleportHome(UUID id, IClientAPI client)
181 { 186 {
182 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 187 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
183 188
@@ -187,8 +192,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
187 { 192 {
188 // local grid user 193 // local grid user
189 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 194 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
190 base.TeleportHome(id, client); 195 return base.TeleportHome(id, client);
191 return;
192 } 196 }
193 197
194 // Foreign user wants to go home 198 // Foreign user wants to go home
@@ -198,7 +202,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
198 { 202 {
199 client.SendTeleportFailed("Your information has been lost"); 203 client.SendTeleportFailed("Your information has been lost");
200 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 204 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
201 return; 205 return false;
202 } 206 }
203 207
204 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 208 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
@@ -208,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
208 { 212 {
209 client.SendTeleportFailed("Your home region could not be found"); 213 client.SendTeleportFailed("Your home region could not be found");
210 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 214 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
211 return; 215 return false;
212 } 216 }
213 217
214 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 218 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -216,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
216 { 220 {
217 client.SendTeleportFailed("Internal error"); 221 client.SendTeleportFailed("Internal error");
218 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 222 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
219 return; 223 return false;
220 } 224 }
221 225
222 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); 226 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
@@ -226,6 +230,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
226 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName); 230 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ExternalHostName, homeGatekeeper.HttpPort, homeGatekeeper.RegionName);
227 231
228 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); 232 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq);
233 return true;
229 } 234 }
230 #endregion 235 #endregion
231 236
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 9fbfc34..0fbd5e7 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -247,6 +247,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
247 247
248 Vector3 originalPosition = objectGroup.AbsolutePosition; 248 Vector3 originalPosition = objectGroup.AbsolutePosition;
249 249
250 // Restore attachment data after trip through the sim
251 if (objectGroup.RootPart.AttachPoint > 0)
252 inventoryStoredPosition = objectGroup.RootPart.AttachOffset;
253 objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint;
254
250 objectGroup.AbsolutePosition = inventoryStoredPosition; 255 objectGroup.AbsolutePosition = inventoryStoredPosition;
251 256
252 // Make sure all bits but the ones we want are clear 257 // Make sure all bits but the ones we want are clear
@@ -425,7 +430,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
425 // 430 //
426 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 431 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
427 { 432 {
428 if (objlist[0].RootPart.FromFolderID != UUID.Zero) 433 if (objlist[0].RootPart.FromFolderID != UUID.Zero && objlist[0].OwnerID == remoteClient.AgentId)
429 { 434 {
430 InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID); 435 InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID);
431 folder = m_Scene.InventoryService.GetFolder(f); 436 folder = m_Scene.InventoryService.GetFolder(f);
@@ -445,9 +450,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
445 item = new InventoryItemBase(); 450 item = new InventoryItemBase();
446 // Can't know creator is the same, so null it in inventory 451 // Can't know creator is the same, so null it in inventory
447 if (objlist.Count > 1) 452 if (objlist.Count > 1)
453 {
448 item.CreatorId = UUID.Zero.ToString(); 454 item.CreatorId = UUID.Zero.ToString();
455 item.CreatorData = String.Empty;
456 }
449 else 457 else
458 {
450 item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); 459 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
460 item.CreatorData = objlist[0].RootPart.CreatorData;
461 }
451 item.ID = UUID.Random(); 462 item.ID = UUID.Random();
452 item.InvType = (int)InventoryType.Object; 463 item.InvType = (int)InventoryType.Object;
453 item.Folder = folder.ID; 464 item.Folder = folder.ID;
@@ -503,10 +514,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
503 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask; 514 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask;
504 item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask; 515 item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask;
505 516
506 // Magic number badness. Maybe this deserves an enum. 517 item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
507 // bit 4 (16) is the "Slam" bit, it means treat as passed
508 // and apply next owner perms on rez
509 item.CurrentPermissions |= 16; // Slam!
510 } 518 }
511 else 519 else
512 { 520 {
@@ -595,6 +603,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
595 603
596 if (item != null) 604 if (item != null)
597 { 605 {
606 if (item.ID == UUID.Zero)
607 {
608 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 1");
609 }
598 item.Owner = remoteClient.AgentId; 610 item.Owner = remoteClient.AgentId;
599 611
600 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); 612 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
@@ -623,6 +635,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
623 } 635 }
624 } 636 }
625 637
638 if (item.ID == UUID.Zero)
639 {
640 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 2");
641 }
642
626 string xmlData = Utils.BytesToString(rezAsset.Data); 643 string xmlData = Utils.BytesToString(rezAsset.Data);
627 List<SceneObjectGroup> objlist = 644 List<SceneObjectGroup> objlist =
628 new List<SceneObjectGroup>(); 645 new List<SceneObjectGroup>();
@@ -713,21 +730,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
713 foreach (SceneObjectPart child in group.Parts) 730 foreach (SceneObjectPart child in group.Parts)
714 child.CreateSelected = true; 731 child.CreateSelected = true;
715 } 732 }
733
716 group.ResetIDs(); 734 group.ResetIDs();
717 735
718 if (attachment) 736 if (attachment)
719 { 737 {
720 group.RootPart.Flags |= PrimFlags.Phantom; 738 group.RootPart.Flags |= PrimFlags.Phantom;
721 group.RootPart.IsAttachment = true; 739 group.RootPart.IsAttachment = true;
722 }
723 740
724 // If we're rezzing an attachment then don't ask 741 // If we're rezzing an attachment then don't ask
725 // AddNewSceneObject() to update the client since 742 // AddNewSceneObject() to update the client since
726 // we'll be doing that later on. Scheduling more than 743 // we'll be doing that later on. Scheduling more
727 // one full update during the attachment 744 // than one full update during the attachment
728 // process causes some clients to fail to display the 745 // process causes some clients to fail to display
729 // attachment properly. 746 // the attachment properly.
730 m_Scene.AddNewSceneObject(group, true, false); 747 // Also, don't persist attachments.
748 m_Scene.AddNewSceneObject(group, false, false);
749 }
750 else
751 {
752 m_Scene.AddNewSceneObject(group, true, false);
753 }
731 754
732 // if attachment we set it's asset id so object updates 755 // if attachment we set it's asset id so object updates
733 // can reflect that, if not, we set it's position in world. 756 // can reflect that, if not, we set it's position in world.
@@ -762,14 +785,24 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
762 // affect the name stored in the serialization, transfer 785 // affect the name stored in the serialization, transfer
763 // the correct name from the inventory to the 786 // the correct name from the inventory to the
764 // object itself before we rez. 787 // object itself before we rez.
765 rootPart.Name = item.Name; 788 // On coalesced objects, this has no effect.
766 rootPart.Description = item.Description; 789 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
767 rootPart.ObjectSaleType = item.SaleType; 790 {
768 rootPart.SalePrice = item.SalePrice; 791 rootPart.Name = item.Name;
792 rootPart.Description = item.Description;
793 }
794 if ((item.Flags & (uint)InventoryItemFlags.ObjectSlamSale) != 0)
795 {
796 rootPart.ObjectSaleType = item.SaleType;
797 rootPart.SalePrice = item.SalePrice;
798 }
769 799
770 group.SetGroup(remoteClient.ActiveGroupId, remoteClient); 800 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
801 // TODO: Remove the magic number badness
802
771 if ((rootPart.OwnerID != item.Owner) || 803 if ((rootPart.OwnerID != item.Owner) ||
772 (item.CurrentPermissions & 16) != 0) 804 (item.CurrentPermissions & 16) != 0 || // Magic number
805 (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0)
773 { 806 {
774 //Need to kill the for sale here 807 //Need to kill the for sale here
775 rootPart.ObjectSaleType = 0; 808 rootPart.ObjectSaleType = 0;
@@ -781,28 +814,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
781 { 814 {
782 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) 815 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
783 { 816 {
784 part.EveryoneMask = item.EveryOnePermissions; 817 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
785 part.NextOwnerMask = item.NextPermissions; 818 part.EveryoneMask = item.EveryOnePermissions;
819 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
820 part.NextOwnerMask = item.NextPermissions;
821 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
822 part.GroupMask = item.GroupPermissions;
786 } 823 }
787 part.GroupMask = 0; // DO NOT propagate here
788 } 824 }
789 825
826 foreach (SceneObjectPart part in group.Parts)
827 {
828 part.LastOwnerID = part.OwnerID;
829 part.OwnerID = item.Owner;
830 part.Inventory.ChangeInventoryOwner(item.Owner);
831 }
832
790 group.ApplyNextOwnerPermissions(); 833 group.ApplyNextOwnerPermissions();
791 } 834 }
792 } 835 }
793 836
794 foreach (SceneObjectPart part in group.Parts) 837 foreach (SceneObjectPart part in group.Parts)
795 { 838 {
796 if ((part.OwnerID != item.Owner) || 839 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
797 (item.CurrentPermissions & 16) != 0) 840 part.EveryoneMask = item.EveryOnePermissions;
798 { 841 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
799 part.LastOwnerID = part.OwnerID; 842 part.NextOwnerMask = item.NextPermissions;
800 part.OwnerID = item.Owner; 843 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
801 part.Inventory.ChangeInventoryOwner(item.Owner); 844 part.GroupMask = item.GroupPermissions;
802 part.GroupMask = 0; // DO NOT propagate here
803 }
804 part.EveryoneMask = item.EveryOnePermissions;
805 part.NextOwnerMask = item.NextPermissions;
806 } 845 }
807 846
808 rootPart.TrimPermissions(); 847 rootPart.TrimPermissions();
@@ -810,7 +849,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
810 if (!attachment) 849 if (!attachment)
811 { 850 {
812 if (group.RootPart.Shape.PCode == (byte)PCode.Prim) 851 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
852 {
853 // Save attachment data
854 group.RootPart.AttachPoint = group.RootPart.Shape.State;
855 group.RootPart.AttachOffset = storedPosition;
856
813 group.ClearPartAttachmentData(); 857 group.ClearPartAttachmentData();
858 }
814 859
815 // Fire on_rez 860 // Fire on_rez
816 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); 861 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index d78931a..51742ff 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -341,6 +341,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
341 try 341 try
342 { 342 {
343 Request = (HttpWebRequest) WebRequest.Create(Url); 343 Request = (HttpWebRequest) WebRequest.Create(Url);
344
345 //This works around some buggy HTTP Servers like Lighttpd
346 Request.ServicePoint.Expect100Continue = false;
347
344 Request.Method = HttpMethod; 348 Request.Method = HttpMethod;
345 Request.ContentType = HttpMIMEType; 349 Request.ContentType = HttpMIMEType;
346 350
@@ -404,7 +408,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
404 { 408 {
405 HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response; 409 HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response;
406 Status = (int)webRsp.StatusCode; 410 Status = (int)webRsp.StatusCode;
407 ResponseBody = webRsp.StatusDescription; 411 try
412 {
413 using (Stream responseStream = webRsp.GetResponseStream())
414 {
415 ResponseBody = responseStream.GetStreamString();
416 }
417 }
418 catch
419 {
420 ResponseBody = webRsp.StatusDescription;
421 }
408 } 422 }
409 else 423 else
410 { 424 {
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 9b565ed..bdbd0c2 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -60,6 +60,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
60 //public ManualResetEvent ev; 60 //public ManualResetEvent ev;
61 public bool requestDone; 61 public bool requestDone;
62 public int startTime; 62 public int startTime;
63 public bool responseSent;
63 public string uri; 64 public string uri;
64 } 65 }
65 66
@@ -76,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
76 new Dictionary<string, UrlData>(); 77 new Dictionary<string, UrlData>();
77 78
78 79
79 private int m_TotalUrls = 100; 80 private int m_TotalUrls = 5000;
80 81
81 private IHttpServer m_HttpServer = null; 82 private IHttpServer m_HttpServer = null;
82 83
@@ -142,7 +143,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
142 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 143 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
143 return urlcode; 144 return urlcode;
144 } 145 }
145 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/"; 146 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString();
146 147
147 UrlData urlData = new UrlData(); 148 UrlData urlData = new UrlData();
148 urlData.hostID = host.UUID; 149 urlData.hostID = host.UUID;
@@ -152,10 +153,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
152 urlData.urlcode = urlcode; 153 urlData.urlcode = urlcode;
153 urlData.requests = new Dictionary<UUID, RequestData>(); 154 urlData.requests = new Dictionary<UUID, RequestData>();
154 155
155
156 m_UrlMap[url] = urlData; 156 m_UrlMap[url] = urlData;
157 157
158 string uri = "/lslhttp/" + urlcode.ToString() + "/"; 158 string uri = "/lslhttp/" + urlcode.ToString();
159 159
160 m_HttpServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll, 160 m_HttpServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll,
161 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents, 161 new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents,
@@ -200,10 +200,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
200 if (m_RequestMap.ContainsKey(request)) 200 if (m_RequestMap.ContainsKey(request))
201 { 201 {
202 UrlData urlData = m_RequestMap[request]; 202 UrlData urlData = m_RequestMap[request];
203 urlData.requests[request].responseCode = status; 203 if (!urlData.requests[request].responseSent)
204 urlData.requests[request].responseBody = body; 204 {
205 //urlData.requests[request].ev.Set(); 205 urlData.requests[request].responseCode = status;
206 urlData.requests[request].requestDone =true; 206 urlData.requests[request].responseBody = body;
207 //urlData.requests[request].ev.Set();
208 urlData.requests[request].requestDone = true;
209 urlData.requests[request].responseSent = true;
210 }
207 } 211 }
208 else 212 else
209 { 213 {
@@ -386,6 +390,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
386 390
387 return response; 391 return response;
388 } 392 }
393
389 public void HttpRequestHandler(UUID requestID, Hashtable request) 394 public void HttpRequestHandler(UUID requestID, Hashtable request)
390 { 395 {
391 lock (request) 396 lock (request)
@@ -400,8 +405,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
400 405
401 int pos1 = uri.IndexOf("/");// /lslhttp 406 int pos1 = uri.IndexOf("/");// /lslhttp
402 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ 407 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/
403 int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp/<UUID>/ 408 int pos3 = pos2 + 37; // /lslhttp/urlcode
404 string uri_tmp = uri.Substring(0, pos3 + 1); 409 string uri_tmp = uri.Substring(0, pos3);
405 //HTTP server code doesn't provide us with QueryStrings 410 //HTTP server code doesn't provide us with QueryStrings
406 string pathInfo; 411 string pathInfo;
407 string queryString; 412 string queryString;
@@ -439,7 +444,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
439 if (request.ContainsKey(key)) 444 if (request.ContainsKey(key))
440 { 445 {
441 string val = (String)request[key]; 446 string val = (String)request[key];
442 queryString = queryString + key + "=" + val + "&"; 447 if (key != "")
448 {
449 queryString = queryString + key + "=" + val + "&";
450 }
451 else
452 {
453 queryString = queryString + val + "&";
454 }
443 } 455 }
444 } 456 }
445 if (queryString.Length > 1) 457 if (queryString.Length > 1)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index 18db9fa..7128d2b 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -56,9 +56,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
56 config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector"); 56 config.Configs["Modules"].Set("GridServices", "LocalGridServicesConnector");
57 config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService"); 57 config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Services.GridService.dll:GridService");
58 config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); 58 config.Configs["GridService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
59 config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion"); 59 config.Configs["GridService"].Set("Region_Test_Region_1", "DefaultRegion");
60 config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion"); 60 config.Configs["GridService"].Set("Region_Test_Region_2", "FallbackRegion");
61 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion"); 61 config.Configs["GridService"].Set("Region_Test_Region_3", "FallbackRegion");
62 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion"); 62 config.Configs["GridService"].Set("Region_Other_Region_4", "FallbackRegion");
63 63
64 m_LocalConnector = new LocalGridServicesConnector(config); 64 m_LocalConnector = new LocalGridServicesConnector(config);
@@ -127,8 +127,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
127 Assert.IsNotNull(result, "Retrieved GetRegionByName is null"); 127 Assert.IsNotNull(result, "Retrieved GetRegionByName is null");
128 Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match"); 128 Assert.That(result.RegionName, Is.EqualTo("Test Region 1"), "Retrieved region's name does not match");
129 129
130 m_LocalConnector.RegisterRegion(UUID.Zero, r2); 130 m_LocalConnector.RegisterRegion(UUID.Zero, r2);
131 m_LocalConnector.RegisterRegion(UUID.Zero, r3); 131 m_LocalConnector.RegisterRegion(UUID.Zero, r3);
132 m_LocalConnector.RegisterRegion(UUID.Zero, r4); 132 m_LocalConnector.RegisterRegion(UUID.Zero, r4);
133 133
134 result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1)); 134 result = m_LocalConnector.GetRegionByUUID(UUID.Zero, new UUID(1));
@@ -153,38 +153,38 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
153 Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null"); 153 Assert.IsNotNull(results, "Retrieved GetRegionRange collection is null");
154 Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected"); 154 Assert.That(results.Count, Is.EqualTo(2), "Retrieved neighbour collection is not the number expected");
155 155
156 results = m_LocalConnector.GetDefaultRegions(UUID.Zero); 156 results = m_LocalConnector.GetDefaultRegions(UUID.Zero);
157 Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null"); 157 Assert.IsNotNull(results, "Retrieved GetDefaultRegions collection is null");
158 Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size"); 158 Assert.That(results.Count, Is.EqualTo(1), "Retrieved default regions collection has not the expected size");
159 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match"); 159 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(1)), "Retrieved default region's UUID does not match");
160 160
161 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY); 161 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r1.RegionLocX, r1.RegionLocY);
162 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null"); 162 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 1 is null");
163 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size"); 163 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 1 has not the expected size");
164 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"); 164 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[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 165 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[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions for default region are not in the expected order 2-4-3"); 166 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 167
168 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY); 168 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r2.RegionLocX, r2.RegionLocY);
169 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null"); 169 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 2 is null");
170 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size"); 170 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 2 has not the expected size");
171 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 2-4-3"); 171 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[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 2-4-3"); 172 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[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3"); 173 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 2-4-3");
174 174
175 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY); 175 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r3.RegionLocX, r3.RegionLocY);
176 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null"); 176 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 3 is null");
177 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size"); 177 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 3 has not the expected size");
178 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 3-4-2"); 178 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[1].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 3-4-2"); 179 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[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2"); 180 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 3-4-2");
181 181
182 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY); 182 results = m_LocalConnector.GetFallbackRegions(UUID.Zero, r4.RegionLocX, r4.RegionLocY);
183 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null"); 183 Assert.IsNotNull(results, "Retrieved GetFallbackRegions collection for region 4 is null");
184 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size"); 184 Assert.That(results.Count, Is.EqualTo(3), "Retrieved fallback regions collection for region 4 has not the expected size");
185 Assert.That(results[0].RegionID, Is.EqualTo(new UUID(4)), "Retrieved fallback regions are not in the expected order 4-3-2"); 185 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[1].RegionID, Is.EqualTo(new UUID(3)), "Retrieved fallback regions are not in the expected order 4-3-2"); 186 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[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2"); 187 Assert.That(results[2].RegionID, Is.EqualTo(new UUID(2)), "Retrieved fallback regions are not in the expected order 4-3-2");
188 188
189 results = m_LocalConnector.GetHyperlinks(UUID.Zero); 189 results = m_LocalConnector.GetHyperlinks(UUID.Zero);
190 Assert.IsNotNull(results, "Retrieved GetHyperlinks list is null"); 190 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 a298b65..41dbffb 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -268,7 +268,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
268 if (s.RegionInfo.RegionID == destination.RegionID) 268 if (s.RegionInfo.RegionID == destination.RegionID)
269 return s.QueryAccess(id, position, out reason); 269 return s.QueryAccess(id, position, out reason);
270 } 270 }
271 //m_log.Debug("[LOCAL COMMS]: region not found for QueryAccess");
272 return false; 271 return false;
273 } 272 }
274 273
@@ -298,10 +297,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
298 if (s.RegionInfo.RegionID == destination.RegionID) 297 if (s.RegionInfo.RegionID == destination.RegionID)
299 { 298 {
300 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent"); 299 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent");
301 // Let's spawn a threadlet right here, because this may take 300 return s.IncomingCloseAgent(id);
302 // a while 301 }
303 Util.FireAndForget(delegate { s.IncomingCloseAgent(id); }); 302 }
304 return true; 303 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
304 return false;
305 }
306
307 public bool CloseChildAgent(GridRegion destination, UUID id)
308 {
309 if (destination == null)
310 return false;
311
312 foreach (Scene s in m_sceneList)
313 {
314 if (s.RegionInfo.RegionID == destination.RegionID)
315 {
316 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent");
317 return s.IncomingCloseChildAgent(id);
305 } 318 }
306 } 319 }
307 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); 320 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
index 67f4d60..97833f3 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -260,6 +260,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
260 return false; 260 return false;
261 } 261 }
262 262
263 public bool CloseChildAgent(GridRegion destination, UUID id)
264 {
265 if (destination == null)
266 return false;
267
268 // Try local first
269 if (m_localBackend.CloseChildAgent(destination, id))
270 return true;
271
272 // else do the remote thing
273 if (!m_localBackend.IsLocalRegion(destination.RegionHandle))
274 return m_remoteConnector.CloseChildAgent(destination, id);
275
276 return false;
277 }
263 278
264 public bool CloseAgent(GridRegion destination, UUID id) 279 public bool CloseAgent(GridRegion destination, UUID id)
265 { 280 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
index 30ebb21..535a637 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
@@ -120,6 +120,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
120 return; 120 return;
121 121
122 scene.RegisterModuleInterface<IUserAccountService>(m_UserService); 122 scene.RegisterModuleInterface<IUserAccountService>(m_UserService);
123 scene.RegisterModuleInterface<IUserAccountCacheModule>(m_Cache);
123 } 124 }
124 125
125 public void RemoveRegion(Scene scene) 126 public void RemoveRegion(Scene scene)
@@ -172,6 +173,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
172 return m_UserService.GetUserAccount(scopeID, Email); 173 return m_UserService.GetUserAccount(scopeID, Email);
173 } 174 }
174 175
176 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query)
177 {
178 return null;
179 }
180
175 public List<UserAccount> GetUserAccounts(UUID scopeID, string query) 181 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
176 { 182 {
177 return m_UserService.GetUserAccounts(scopeID, query); 183 return m_UserService.GetUserAccounts(scopeID, query);
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs
index 3321b38..f6b6aeb 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs
@@ -33,6 +33,7 @@ using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes; 33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Services.Interfaces; 34using OpenSim.Services.Interfaces;
35using OpenSim.Services.Connectors; 35using OpenSim.Services.Connectors;
36using OpenSim.Framework;
36 37
37using OpenMetaverse; 38using OpenMetaverse;
38 39
@@ -101,6 +102,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
101 return; 102 return;
102 103
103 scene.RegisterModuleInterface<IUserAccountService>(this); 104 scene.RegisterModuleInterface<IUserAccountService>(this);
105 scene.RegisterModuleInterface<IUserAccountCacheModule>(m_Cache);
106
107 scene.EventManager.OnNewClient += OnNewClient;
104 } 108 }
105 109
106 public void RemoveRegion(Scene scene) 110 public void RemoveRegion(Scene scene)
@@ -115,6 +119,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
115 return; 119 return;
116 } 120 }
117 121
122 // When a user actually enters the sim, clear them from
123 // cache so the sim will have the current values for
124 // flags, title, etc. And country, don't forget country!
125 private void OnNewClient(IClientAPI client)
126 {
127 m_Cache.Remove(client.Name);
128 }
129
118 #region Overwritten methods from IUserAccountService 130 #region Overwritten methods from IUserAccountService
119 131
120 public override UserAccount GetUserAccount(UUID scopeID, UUID userID) 132 public override UserAccount GetUserAccount(UUID scopeID, UUID userID)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
index ddef75f..cbe2eaa 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs
@@ -34,7 +34,7 @@ using log4net;
34 34
35namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts 35namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
36{ 36{
37 public class UserAccountCache 37 public class UserAccountCache : IUserAccountCacheModule
38 { 38 {
39 private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! 39 private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours!
40 40
@@ -92,5 +92,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
92 92
93 return null; 93 return null;
94 } 94 }
95
96 public void Remove(string name)
97 {
98 if (!m_NameCache.Contains(name))
99 return;
100
101 UUID uuid = UUID.Zero;
102 if (m_NameCache.TryGetValue(name, out uuid))
103 {
104 m_NameCache.Remove(name);
105 m_UUIDCache.Remove(uuid);
106 }
107 }
95 } 108 }
96} 109}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index fd8f546..b1dec4c 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -287,6 +287,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
287 // being no copy/no mod for everyone 287 // being no copy/no mod for everyone
288 lock (part.TaskInventory) 288 lock (part.TaskInventory)
289 { 289 {
290 if (!ResolveUserUuid(part.CreatorID))
291 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
292
293 if (!ResolveUserUuid(part.OwnerID))
294 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
295
296 if (!ResolveUserUuid(part.LastOwnerID))
297 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
298
299 // And zap any troublesome sit target information
300 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
301 part.SitTargetPosition = new Vector3(0, 0, 0);
302
303 // Fix ownership/creator of inventory items
304 // Not doing so results in inventory items
305 // being no copy/no mod for everyone
306 part.TaskInventory.LockItemsForRead(true);
290 TaskInventoryDictionary inv = part.TaskInventory; 307 TaskInventoryDictionary inv = part.TaskInventory;
291 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) 308 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
292 { 309 {
@@ -302,6 +319,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
302 if (UserManager != null) 319 if (UserManager != null)
303 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); 320 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
304 } 321 }
322 part.TaskInventory.LockItemsForRead(false);
305 } 323 }
306 } 324 }
307 325
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index b888698..5da1656 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -249,18 +249,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
249 249
250 if (asset != null) 250 if (asset != null)
251 { 251 {
252 if (m_options.ContainsKey("verbose")) 252// m_log.DebugFormat("[ARCHIVER]: Writing asset {0}", id);
253 m_log.InfoFormat("[ARCHIVER]: Writing asset {0}", id);
254
255 m_foundAssetUuids.Add(asset.FullID); 253 m_foundAssetUuids.Add(asset.FullID);
256 254
257 m_assetsArchiver.WriteAsset(PostProcess(asset)); 255 m_assetsArchiver.WriteAsset(PostProcess(asset));
258 } 256 }
259 else 257 else
260 { 258 {
261 if (m_options.ContainsKey("verbose")) 259// m_log.DebugFormat("[ARCHIVER]: Recording asset {0} as not found", id);
262 m_log.InfoFormat("[ARCHIVER]: Recording asset {0} as not found", id);
263
264 m_notFoundAssetUuids.Add(new UUID(id)); 260 m_notFoundAssetUuids.Add(new UUID(id));
265 } 261 }
266 262
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index b6d64ac..6d9cb7f 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -30,6 +30,7 @@ using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Reflection; 31using System.Reflection;
32using System.Security; 32using System.Security;
33using System.Timers;
33using log4net; 34using log4net;
34using Mono.Addins; 35using Mono.Addins;
35using Nini.Config; 36using Nini.Config;
@@ -47,6 +48,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
47 48
48 private delegate void LookupUUIDS(List<UUID> uuidLst); 49 private delegate void LookupUUIDS(List<UUID> uuidLst);
49 50
51 private Timer m_regionChangeTimer = new Timer();
50 public Scene Scene { get; private set; } 52 public Scene Scene { get; private set; }
51 public IUserManagement UserManager { get; private set; } 53 public IUserManagement UserManager { get; private set; }
52 54
@@ -253,7 +255,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
253 timeInSeconds -= 15; 255 timeInSeconds -= 15;
254 } 256 }
255 257
256 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); 258 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false);
257 } 259 }
258 } 260 }
259 261
@@ -456,7 +458,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
456 { 458 {
457 if (!s.IsChildAgent) 459 if (!s.IsChildAgent)
458 { 460 {
459 Scene.TeleportClientHome(user, s.ControllingClient); 461 if (!Scene.TeleportClientHome(user, s.ControllingClient))
462 {
463 s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
464 s.ControllingClient.Close();
465 }
460 } 466 }
461 } 467 }
462 468
@@ -465,7 +471,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
465 { 471 {
466 remote_client.SendAlertMessage("User is already on the region ban list"); 472 remote_client.SendAlertMessage("User is already on the region ban list");
467 } 473 }
468 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 474 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
469 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 475 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
470 } 476 }
471 else 477 else
@@ -520,7 +526,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
520 remote_client.SendAlertMessage("User is not on the region ban list"); 526 remote_client.SendAlertMessage("User is not on the region ban list");
521 } 527 }
522 528
523 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 529 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
524 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 530 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
525 } 531 }
526 else 532 else
@@ -641,7 +647,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
641 ScenePresence s = Scene.GetScenePresence(prey); 647 ScenePresence s = Scene.GetScenePresence(prey);
642 if (s != null) 648 if (s != null)
643 { 649 {
644 Scene.TeleportClientHome(prey, s.ControllingClient); 650 if (!Scene.TeleportClientHome(prey, s.ControllingClient))
651 {
652 s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
653 s.ControllingClient.Close();
654 }
645 } 655 }
646 } 656 }
647 } 657 }
@@ -660,7 +670,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
660 // Also make sure they are actually in the region 670 // Also make sure they are actually in the region
661 if (p != null && !p.IsChildAgent) 671 if (p != null && !p.IsChildAgent)
662 { 672 {
663 Scene.TeleportClientHome(p.UUID, p.ControllingClient); 673 if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
674 {
675 p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
676 p.ControllingClient.Close();
677 }
664 } 678 }
665 } 679 }
666 }); 680 });
@@ -911,7 +925,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
911 925
912 for (int i = 0; i < uuidarr.Length; i++) 926 for (int i = 0; i < uuidarr.Length; i++)
913 { 927 {
914 // string lookupname = m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]); 928 // string lookupname = Scene.CommsManager.UUIDNameRequestString(uuidarr[i]);
915 929
916 IUserManagement userManager = Scene.RequestModuleInterface<IUserManagement>(); 930 IUserManagement userManager = Scene.RequestModuleInterface<IUserManagement>();
917 if (userManager != null) 931 if (userManager != null)
@@ -1048,6 +1062,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
1048 1062
1049 public void AddRegion(Scene scene) 1063 public void AddRegion(Scene scene)
1050 { 1064 {
1065 m_regionChangeTimer.AutoReset = false;
1066 m_regionChangeTimer.Interval = 2000;
1067 m_regionChangeTimer.Elapsed += RaiseRegionInfoChange;
1068
1051 Scene = scene; 1069 Scene = scene;
1052 Scene.RegisterModuleInterface<IEstateModule>(this); 1070 Scene.RegisterModuleInterface<IEstateModule>(this);
1053 Scene.EventManager.OnNewClient += EventManager_OnNewClient; 1071 Scene.EventManager.OnNewClient += EventManager_OnNewClient;
@@ -1154,11 +1172,15 @@ namespace OpenSim.Region.CoreModules.World.Estate
1154 flags |= RegionFlags.Sandbox; 1172 flags |= RegionFlags.Sandbox;
1155 if (Scene.RegionInfo.EstateSettings.AllowVoice) 1173 if (Scene.RegionInfo.EstateSettings.AllowVoice)
1156 flags |= RegionFlags.AllowVoice; 1174 flags |= RegionFlags.AllowVoice;
1175 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
1176 flags |= RegionFlags.AllowLandmark;
1177 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
1178 flags |= RegionFlags.AllowSetHome;
1179 if (Scene.RegionInfo.EstateSettings.BlockDwell)
1180 flags |= RegionFlags.BlockDwell;
1181 if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport)
1182 flags |= RegionFlags.ResetHomeOnTeleport;
1157 1183
1158 // Fudge these to always on, so the menu options activate
1159 //
1160 flags |= RegionFlags.AllowLandmark;
1161 flags |= RegionFlags.AllowSetHome;
1162 1184
1163 // TODO: SkipUpdateInterestList 1185 // TODO: SkipUpdateInterestList
1164 1186
@@ -1199,6 +1221,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1199 flags |= RegionFlags.ResetHomeOnTeleport; 1221 flags |= RegionFlags.ResetHomeOnTeleport;
1200 if (Scene.RegionInfo.EstateSettings.TaxFree) 1222 if (Scene.RegionInfo.EstateSettings.TaxFree)
1201 flags |= RegionFlags.TaxFree; 1223 flags |= RegionFlags.TaxFree;
1224 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
1225 flags |= RegionFlags.AllowLandmark;
1226 if (Scene.RegionInfo.EstateSettings.AllowParcelChanges)
1227 flags |= RegionFlags.AllowParcelChanges;
1228 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
1229 flags |= RegionFlags.AllowSetHome;
1202 if (Scene.RegionInfo.EstateSettings.DenyMinors) 1230 if (Scene.RegionInfo.EstateSettings.DenyMinors)
1203 flags |= (RegionFlags)(1 << 30); 1231 flags |= (RegionFlags)(1 << 30);
1204 1232
@@ -1219,6 +1247,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1219 1247
1220 public void TriggerRegionInfoChange() 1248 public void TriggerRegionInfoChange()
1221 { 1249 {
1250 m_regionChangeTimer.Stop();
1251 m_regionChangeTimer.Start();
1252 }
1253
1254 protected void RaiseRegionInfoChange(object sender, ElapsedEventArgs e)
1255 {
1222 ChangeDelegate change = OnRegionInfoChange; 1256 ChangeDelegate change = OnRegionInfoChange;
1223 1257
1224 if (change != null) 1258 if (change != null)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index bfab7b8..f28faed 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -91,11 +91,11 @@ namespace OpenSim.Region.CoreModules.World.Land
91 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 91 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
92 92
93 private bool m_allowedForcefulBans = true; 93 private bool m_allowedForcefulBans = true;
94 private UUID DefaultGodParcelGroup;
95 private string DefaultGodParcelName;
94 96
95 // caches ExtendedLandData 97 // caches ExtendedLandData
96 private Cache parcelInfoCache; 98 private Cache parcelInfoCache;
97 private Dictionary<UUID, Vector3> forcedPosition =
98 new Dictionary<UUID, Vector3>();
99 99
100 #region INonSharedRegionModule Members 100 #region INonSharedRegionModule Members
101 101
@@ -106,6 +106,12 @@ namespace OpenSim.Region.CoreModules.World.Land
106 106
107 public void Initialise(IConfigSource source) 107 public void Initialise(IConfigSource source)
108 { 108 {
109 IConfig cnf = source.Configs["LandManagement"];
110 if (cnf != null)
111 {
112 DefaultGodParcelGroup = new UUID(cnf.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString()));
113 DefaultGodParcelName = cnf.GetString("DefaultAdministratorParcelName", "Default Parcel");
114 }
109 } 115 }
110 116
111 public void AddRegion(Scene scene) 117 public void AddRegion(Scene scene)
@@ -157,13 +163,6 @@ namespace OpenSim.Region.CoreModules.World.Land
157 m_scene.UnregisterModuleCommander(m_commander.Name); 163 m_scene.UnregisterModuleCommander(m_commander.Name);
158 } 164 }
159 165
160// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
161// {
162// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
163// reason = "You are not allowed to enter this sim.";
164// return nearestParcel != null;
165// }
166
167 /// <summary> 166 /// <summary>
168 /// Processes commandline input. Do not call directly. 167 /// Processes commandline input. Do not call directly.
169 /// </summary> 168 /// </summary>
@@ -215,36 +214,6 @@ namespace OpenSim.Region.CoreModules.World.Land
215 214
216 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) 215 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
217 { 216 {
218 //If we are forcing a position for them to go
219 if (forcedPosition.ContainsKey(remoteClient.AgentId))
220 {
221 ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId);
222
223 //Putting the user into flying, both keeps the avatar in fligth when it bumps into something and stopped from going another direction AND
224 //When the avatar walks into a ban line on the ground, it prevents getting stuck
225 agentData.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
226
227
228 //Make sure we stop if they get about to the right place to prevent yoyo and prevents getting stuck on banlines
229 if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) < .2)
230 {
231 Debug.WriteLine(string.Format("Stopping force position because {0} is close enough to position {1}", forcedPosition[remoteClient.AgentId], clientAvatar.AbsolutePosition));
232 forcedPosition.Remove(remoteClient.AgentId);
233 }
234 //if we are far away, teleport
235 else if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) > 3)
236 {
237 Debug.WriteLine(string.Format("Teleporting out because {0} is too far from avatar position {1}", forcedPosition[remoteClient.AgentId], clientAvatar.AbsolutePosition));
238 clientAvatar.Teleport(forcedPosition[remoteClient.AgentId]);
239 forcedPosition.Remove(remoteClient.AgentId);
240 }
241 else
242 {
243 //Forces them toward the forced position we want if they aren't there yet
244 agentData.UseClientAgentPosition = true;
245 agentData.ClientAgentPosition = forcedPosition[remoteClient.AgentId];
246 }
247 }
248 } 217 }
249 218
250 public void Close() 219 public void Close()
@@ -363,10 +332,16 @@ namespace OpenSim.Region.CoreModules.World.Land
363 private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position) 332 private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position)
364 { 333 {
365 if (m_scene.Permissions.IsGod(avatar.UUID)) return; 334 if (m_scene.Permissions.IsGod(avatar.UUID)) return;
366 if (position.HasValue) 335
367 { 336 if (!position.HasValue)
368 forcedPosition[avatar.ControllingClient.AgentId] = (Vector3)position; 337 return;
369 } 338
339 bool isFlying = avatar.PhysicsActor.Flying;
340 avatar.RemoveFromPhysicalScene();
341
342 avatar.AbsolutePosition = (Vector3)position;
343
344 avatar.AddToPhysicalScene(isFlying);
370 } 345 }
371 346
372 public void SendYouAreRestrictedNotice(ScenePresence avatar) 347 public void SendYouAreRestrictedNotice(ScenePresence avatar)
@@ -386,29 +361,7 @@ namespace OpenSim.Region.CoreModules.World.Land
386 } 361 }
387 362
388 if (parcelAvatarIsEntering != null) 363 if (parcelAvatarIsEntering != null)
389 { 364 EnforceBans(parcelAvatarIsEntering, avatar);
390 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT)
391 {
392 if (parcelAvatarIsEntering.IsBannedFromLand(avatar.UUID))
393 {
394 SendYouAreBannedNotice(avatar);
395 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar));
396 }
397 else if (parcelAvatarIsEntering.IsRestrictedFromLand(avatar.UUID))
398 {
399 SendYouAreRestrictedNotice(avatar);
400 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar));
401 }
402 else
403 {
404 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
405 }
406 }
407 else
408 {
409 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
410 }
411 }
412 } 365 }
413 } 366 }
414 367
@@ -480,43 +433,7 @@ namespace OpenSim.Region.CoreModules.World.Land
480 SendOutNearestBanLine(remote_client); 433 SendOutNearestBanLine(remote_client);
481 ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y); 434 ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
482 if (parcel != null) 435 if (parcel != null)
483 { 436 EnforceBans(parcel, clientAvatar);
484 if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT &&
485 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
486 {
487 EventManagerOnAvatarEnteringNewParcel(clientAvatar, parcel.LandData.LocalID,
488 m_scene.RegionInfo.RegionID);
489 //They are going under the safety line!
490 if (!parcel.IsBannedFromLand(clientAvatar.UUID))
491 {
492 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
493 }
494 }
495 else if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT &&
496 parcel.IsBannedFromLand(clientAvatar.UUID))
497 {
498 //once we've sent the message once, keep going toward the target until we are done
499 if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId))
500 {
501 SendYouAreBannedNotice(clientAvatar);
502 ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar));
503 }
504 }
505 else if (parcel.IsRestrictedFromLand(clientAvatar.UUID))
506 {
507 //once we've sent the message once, keep going toward the target until we are done
508 if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId))
509 {
510 SendYouAreRestrictedNotice(clientAvatar);
511 ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar));
512 }
513 }
514 else
515 {
516 //when we are finally in a safe place, lets release the forced position lock
517 forcedPosition.Remove(clientAvatar.ControllingClient.AgentId);
518 }
519 }
520 } 437 }
521 } 438 }
522 439
@@ -722,7 +639,7 @@ namespace OpenSim.Region.CoreModules.World.Land
722 int x; 639 int x;
723 int y; 640 int y;
724 641
725 if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) 642 if (x_float > Constants.RegionSize || x_float < 0 || y_float > Constants.RegionSize || y_float < 0)
726 return null; 643 return null;
727 644
728 try 645 try
@@ -772,14 +689,13 @@ namespace OpenSim.Region.CoreModules.World.Land
772 { 689 {
773 try 690 try
774 { 691 {
775 return m_landList[m_landIDList[x / 4, y / 4]]; 692 //if (m_landList.ContainsKey(m_landIDList[x / 4, y / 4]))
693 return m_landList[m_landIDList[x / 4, y / 4]];
694 //else
695 // return null;
776 } 696 }
777 catch (IndexOutOfRangeException) 697 catch (IndexOutOfRangeException)
778 { 698 {
779// m_log.WarnFormat(
780// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
781// x, y, m_scene.RegionInfo.RegionName);
782
783 return null; 699 return null;
784 } 700 }
785 } 701 }
@@ -1062,6 +978,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1062 //Owner Flag 978 //Owner Flag
1063 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 979 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1064 } 980 }
981 else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID))
982 {
983 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_GROUP);
984 }
1065 else if (currentParcelBlock.LandData.SalePrice > 0 && 985 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1066 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || 986 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1067 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) 987 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
@@ -1362,18 +1282,31 @@ namespace OpenSim.Region.CoreModules.World.Land
1362 1282
1363 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1283 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1364 { 1284 {
1365 for (int i = 0; i < data.Count; i++) 1285 lock (m_landList)
1366 { 1286 {
1367 IncomingLandObjectFromStorage(data[i]); 1287 //Remove all the land objects in the sim and then process our new data
1288 foreach (int n in m_landList.Keys)
1289 {
1290 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[n].LandData.GlobalID);
1291 }
1292 m_landIDList.Initialize();
1293 m_landList.Clear();
1294
1295 for (int i = 0; i < data.Count; i++)
1296 {
1297 IncomingLandObjectFromStorage(data[i]);
1298 }
1368 } 1299 }
1369 } 1300 }
1370 1301
1371 public void IncomingLandObjectFromStorage(LandData data) 1302 public void IncomingLandObjectFromStorage(LandData data)
1372 { 1303 {
1304
1373 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1305 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1374 new_land.LandData = data.Copy(); 1306 new_land.LandData = data.Copy();
1375 new_land.SetLandBitmapFromByteArray(); 1307 new_land.SetLandBitmapFromByteArray();
1376 AddLandObject(new_land); 1308 AddLandObject(new_land);
1309 new_land.SendLandUpdateToAvatarsOverMe();
1377 } 1310 }
1378 1311
1379 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) 1312 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
@@ -1648,6 +1581,322 @@ namespace OpenSim.Region.CoreModules.World.Land
1648 1581
1649 UpdateLandObject(localID, land.LandData); 1582 UpdateLandObject(localID, land.LandData);
1650 } 1583 }
1584
1585 public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
1586 {
1587 ILandObject land = null;
1588 List<ILandObject> Land = ((Scene)client.Scene).LandChannel.AllParcels();
1589 foreach (ILandObject landObject in Land)
1590 {
1591 if (landObject.LandData.LocalID == landID)
1592 {
1593 land = landObject;
1594 }
1595 }
1596 land.DeedToGroup(DefaultGodParcelGroup);
1597 land.LandData.Name = DefaultGodParcelName;
1598 land.SendLandUpdateToAvatarsOverMe();
1599 }
1600
1601 private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID)
1602 {
1603 ScenePresence SP;
1604 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out SP);
1605 List<SceneObjectGroup> returns = new List<SceneObjectGroup>();
1606 if (SP.UserLevel != 0)
1607 {
1608 if (flags == 0) //All parcels, scripted or not
1609 {
1610 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1611 {
1612 if (e.OwnerID == targetID)
1613 {
1614 returns.Add(e);
1615 }
1616 }
1617 );
1618 }
1619 if (flags == 4) //All parcels, scripted object
1620 {
1621 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1622 {
1623 if (e.OwnerID == targetID)
1624 {
1625 if (e.scriptScore >= 0.01)
1626 {
1627 returns.Add(e);
1628 }
1629 }
1630 }
1631 );
1632 }
1633 if (flags == 4) //not target parcel, scripted object
1634 {
1635 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1636 {
1637 if (e.OwnerID == targetID)
1638 {
1639 ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y);
1640 if (landobject.LandData.OwnerID != e.OwnerID)
1641 {
1642 if (e.scriptScore >= 0.01)
1643 {
1644 returns.Add(e);
1645 }
1646 }
1647 }
1648 }
1649 );
1650 }
1651 foreach (SceneObjectGroup ol in returns)
1652 {
1653 ReturnObject(ol, client);
1654 }
1655 }
1656 }
1657 public void ReturnObject(SceneObjectGroup obj, IClientAPI client)
1658 {
1659 SceneObjectGroup[] objs = new SceneObjectGroup[1];
1660 objs[0] = obj;
1661 ((Scene)client.Scene).returnObjects(objs, client.AgentId);
1662 }
1663
1664 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1665
1666 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1667 {
1668 ScenePresence targetAvatar = null;
1669 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1670 ScenePresence parcelManager = null;
1671 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1672 System.Threading.Timer Timer;
1673
1674 if (targetAvatar.UserLevel == 0)
1675 {
1676 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1677 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1678 return;
1679 if (flags == 0)
1680 {
1681 targetAvatar.AllowMovement = false;
1682 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1683 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1684 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1685 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1686 Timers.Add(targetAvatar.UUID, Timer);
1687 }
1688 else
1689 {
1690 targetAvatar.AllowMovement = true;
1691 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1692 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1693 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1694 Timers.Remove(targetAvatar.UUID);
1695 Timer.Dispose();
1696 }
1697 }
1698 }
1699 private void OnEndParcelFrozen(object avatar)
1700 {
1701 ScenePresence targetAvatar = (ScenePresence)avatar;
1702 targetAvatar.AllowMovement = true;
1703 System.Threading.Timer Timer;
1704 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1705 Timers.Remove(targetAvatar.UUID);
1706 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1707 }
1708
1709
1710 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1711 {
1712 ScenePresence targetAvatar = null;
1713 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1714 ScenePresence parcelManager = null;
1715 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1716 //Just eject
1717 if (flags == 0)
1718 {
1719 if (targetAvatar.UserLevel == 0)
1720 {
1721 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1722 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1723 return;
1724
1725 Vector3 position = new Vector3(0, 0, 0);
1726 List<ILandObject> allParcels = new List<ILandObject>();
1727 allParcels = AllParcels();
1728 if (allParcels.Count != 1)
1729 {
1730 foreach (ILandObject parcel in allParcels)
1731 {
1732 if (parcel.LandData.GlobalID != land.LandData.GlobalID)
1733 {
1734 if (parcel.IsEitherBannedOrRestricted(targetAvatar.UUID) != true)
1735 {
1736 for (int x = 1; x <= Constants.RegionSize; x += 2)
1737 {
1738 for (int y = 1; y <= Constants.RegionSize; y += 2)
1739 {
1740 if (parcel.ContainsPoint(x, y))
1741 {
1742 position = new Vector3(x, y, targetAvatar.AbsolutePosition.Z);
1743 targetAvatar.TeleportWithMomentum(position);
1744 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1745 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1746 return;
1747 }
1748 }
1749 }
1750 }
1751 }
1752 }
1753 }
1754 Vector3 targetVector;
1755 if (targetAvatar.AbsolutePosition.X > targetAvatar.AbsolutePosition.Y)
1756 {
1757 if (targetAvatar.AbsolutePosition.X > .5 * Constants.RegionSize)
1758 {
1759 targetVector = new Vector3(Constants.RegionSize, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1760 targetAvatar.TeleportWithMomentum(targetVector);
1761 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1762 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1763 return;
1764 }
1765 else
1766 {
1767 targetVector = new Vector3(0, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1768 targetAvatar.TeleportWithMomentum(targetVector);
1769 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1770 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1771 return;
1772 }
1773 }
1774 else
1775 {
1776 if (targetAvatar.AbsolutePosition.Y > .5 * Constants.RegionSize)
1777 {
1778 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, Constants.RegionSize, targetAvatar.AbsolutePosition.Z); ;
1779 targetAvatar.TeleportWithMomentum(targetVector);
1780 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1781 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1782 return;
1783 }
1784 else
1785 {
1786 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, 0, targetAvatar.AbsolutePosition.Z); ;
1787 targetAvatar.TeleportWithMomentum(targetVector);
1788 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1789 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1790 return;
1791 }
1792 }
1793 }
1794 }
1795 //Eject and ban
1796 if (flags == 1)
1797 {
1798 if (targetAvatar.UserLevel == 0)
1799 {
1800 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1801 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1802 return;
1803
1804 Vector3 position = new Vector3(0, 0, 0);
1805 List<ILandObject> allParcels = new List<ILandObject>();
1806 allParcels = AllParcels();
1807 if (allParcels.Count != 1)
1808 {
1809 foreach (ILandObject parcel in allParcels)
1810 {
1811 if (parcel.LandData.GlobalID != land.LandData.GlobalID)
1812 {
1813 if (parcel.IsEitherBannedOrRestricted(targetAvatar.UUID) != true)
1814 {
1815 for (int x = 1; x <= Constants.RegionSize; x += 2)
1816 {
1817 for (int y = 1; y <= Constants.RegionSize; y += 2)
1818 {
1819 if (parcel.ContainsPoint(x, y))
1820 {
1821 position = new Vector3(x, y, targetAvatar.AbsolutePosition.Z);
1822 targetAvatar.TeleportWithMomentum(position);
1823 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1824 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1825 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1826 entry.AgentID = targetAvatar.UUID;
1827 entry.Flags = AccessList.Ban;
1828 entry.Time = new DateTime();
1829 land.LandData.ParcelAccessList.Add(entry);
1830 return;
1831 }
1832 }
1833 }
1834 }
1835 }
1836 }
1837 }
1838 Vector3 targetVector;
1839 if (targetAvatar.AbsolutePosition.X > targetAvatar.AbsolutePosition.Y)
1840 {
1841 if (targetAvatar.AbsolutePosition.X > .5 * Constants.RegionSize)
1842 {
1843 targetVector = new Vector3(Constants.RegionSize, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1844 targetAvatar.TeleportWithMomentum(targetVector);
1845 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1846 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1847 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1848 entry.AgentID = targetAvatar.UUID;
1849 entry.Flags = AccessList.Ban;
1850 entry.Time = new DateTime();
1851 land.LandData.ParcelAccessList.Add(entry);
1852 return;
1853 }
1854 else
1855 {
1856 targetVector = new Vector3(0, targetAvatar.AbsolutePosition.Y, targetAvatar.AbsolutePosition.Z); ;
1857 targetAvatar.TeleportWithMomentum(targetVector);
1858 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1859 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1860 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1861 entry.AgentID = targetAvatar.UUID;
1862 entry.Flags = AccessList.Ban;
1863 entry.Time = new DateTime();
1864 land.LandData.ParcelAccessList.Add(entry);
1865 return;
1866 }
1867 }
1868 else
1869 {
1870 if (targetAvatar.AbsolutePosition.Y > .5 * Constants.RegionSize)
1871 {
1872 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, Constants.RegionSize, targetAvatar.AbsolutePosition.Z); ;
1873 targetAvatar.TeleportWithMomentum(targetVector);
1874 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1875 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1876 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1877 entry.AgentID = targetAvatar.UUID;
1878 entry.Flags = AccessList.Ban;
1879 entry.Time = new DateTime();
1880 land.LandData.ParcelAccessList.Add(entry);
1881 return;
1882 }
1883 else
1884 {
1885 targetVector = new Vector3(targetAvatar.AbsolutePosition.X, 0, targetAvatar.AbsolutePosition.Z); ;
1886 targetAvatar.TeleportWithMomentum(targetVector);
1887 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected and banned by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1888 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected and Banned.");
1889 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
1890 entry.AgentID = targetAvatar.UUID;
1891 entry.Flags = AccessList.Ban;
1892 entry.Time = new DateTime();
1893 land.LandData.ParcelAccessList.Add(entry);
1894 return;
1895 }
1896 }
1897 }
1898 }
1899 }
1651 1900
1652 protected void InstallInterfaces() 1901 protected void InstallInterfaces()
1653 { 1902 {
@@ -1710,5 +1959,27 @@ namespace OpenSim.Region.CoreModules.World.Land
1710 1959
1711 MainConsole.Instance.Output(report.ToString()); 1960 MainConsole.Instance.Output(report.ToString());
1712 } 1961 }
1962
1963 public void EnforceBans(ILandObject land, ScenePresence avatar)
1964 {
1965 if (avatar.AbsolutePosition.Z > LandChannel.BAN_LINE_SAFETY_HIEGHT)
1966 return;
1967
1968 if (land.IsEitherBannedOrRestricted(avatar.UUID))
1969 {
1970 if (land.ContainsPoint(Convert.ToInt32(avatar.lastKnownAllowedPosition.X), Convert.ToInt32(avatar.lastKnownAllowedPosition.Y)))
1971 {
1972 Vector3? pos = m_scene.GetNearestAllowedPosition(avatar);
1973 if (pos == null)
1974 m_scene.TeleportClientHome(avatar.UUID, avatar.ControllingClient);
1975 else
1976 ForceAvatarToPosition(avatar, (Vector3)pos);
1977 }
1978 else
1979 {
1980 ForceAvatarToPosition(avatar, avatar.lastKnownAllowedPosition);
1981 }
1982 }
1983 }
1713 } 1984 }
1714} \ No newline at end of file 1985}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index c2f104e..fe6b83a 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -415,6 +415,37 @@ namespace OpenSim.Region.CoreModules.World.Land
415 return false; 415 return false;
416 } 416 }
417 417
418 public bool HasGroupAccess(UUID avatar)
419 {
420 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
421 {
422 ScenePresence sp;
423 if (!m_scene.TryGetScenePresence(avatar, out sp))
424 {
425 IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
426 if (groupsModule == null)
427 return false;
428
429 GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
430 if (membership == null || membership.Length == 0)
431 return false;
432
433 foreach (GroupMembershipData d in membership)
434 {
435 if (d.GroupID == LandData.GroupID)
436 return true;
437 }
438 return false;
439 }
440
441 if (!sp.ControllingClient.IsGroupMember(LandData.GroupID))
442 return false;
443
444 return true;
445 }
446 return false;
447 }
448
418 public bool IsBannedFromLand(UUID avatar) 449 public bool IsBannedFromLand(UUID avatar)
419 { 450 {
420 if (m_scene.Permissions.IsAdministrator(avatar)) 451 if (m_scene.Permissions.IsAdministrator(avatar))
@@ -451,9 +482,13 @@ namespace OpenSim.Region.CoreModules.World.Land
451 return false; 482 return false;
452 }) == -1 && LandData.OwnerID != avatar) 483 }) == -1 && LandData.OwnerID != avatar)
453 { 484 {
454 return true; 485 if (!HasGroupAccess(avatar))
486 {
487 return true;
488 }
455 } 489 }
456 } 490 }
491
457 return false; 492 return false;
458 } 493 }
459 494
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
index dca842a..f466194 100644
--- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
@@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.World.Land
206 if (m_ParcelCounts.TryGetValue(landData.GlobalID, out parcelCounts)) 206 if (m_ParcelCounts.TryGetValue(landData.GlobalID, out parcelCounts))
207 { 207 {
208 UUID landOwner = landData.OwnerID; 208 UUID landOwner = landData.OwnerID;
209 int partCount = obj.Parts.Length; 209 int partCount = obj.GetPartCount();
210 210
211 m_SimwideCounts[landOwner] += partCount; 211 m_SimwideCounts[landOwner] += partCount;
212 if (parcelCounts.Users.ContainsKey(obj.OwnerID)) 212 if (parcelCounts.Users.ContainsKey(obj.OwnerID))
@@ -593,4 +593,4 @@ namespace OpenSim.Region.CoreModules.World.Land
593 } 593 }
594 } 594 }
595 } 595 }
596} \ No newline at end of file 596}
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 170c35f..a098ff6 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -362,7 +362,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
362 362
363 public string Name 363 public string Name
364 { 364 {
365 get { return "PermissionsModule"; } 365 get { return "DefaultPermissionsModule"; }
366 } 366 }
367 367
368 public bool IsSharedModule 368 public bool IsSharedModule
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
index ab6a598..19ee7f5 100644
--- a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
+++ b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
@@ -28,6 +28,8 @@
28using System; 28using System;
29using System.Reflection; 29using System.Reflection;
30using System.Timers; 30using System.Timers;
31using System.IO;
32using System.Diagnostics;
31using System.Threading; 33using System.Threading;
32using System.Collections.Generic; 34using System.Collections.Generic;
33using log4net; 35using log4net;
@@ -56,13 +58,23 @@ namespace OpenSim.Region.CoreModules.World.Region
56 protected UUID m_Initiator; 58 protected UUID m_Initiator;
57 protected bool m_Notice = false; 59 protected bool m_Notice = false;
58 protected IDialogModule m_DialogModule = null; 60 protected IDialogModule m_DialogModule = null;
61 protected string m_MarkerPath = String.Empty;
59 62
60 public void Initialise(IConfigSource config) 63 public void Initialise(IConfigSource config)
61 { 64 {
65 IConfig restartConfig = config.Configs["RestartModule"];
66 if (restartConfig != null)
67 {
68 m_MarkerPath = restartConfig.GetString("MarkerPath", String.Empty);
69 }
62 } 70 }
63 71
64 public void AddRegion(Scene scene) 72 public void AddRegion(Scene scene)
65 { 73 {
74 if (m_MarkerPath != String.Empty)
75 File.Delete(Path.Combine(m_MarkerPath,
76 scene.RegionInfo.RegionID.ToString()));
77
66 m_Scene = scene; 78 m_Scene = scene;
67 scene.RegisterModuleInterface<IRestartModule>(this); 79 scene.RegisterModuleInterface<IRestartModule>(this);
68 MainConsole.Instance.Commands.AddCommand("RestartModule", 80 MainConsole.Instance.Commands.AddCommand("RestartModule",
@@ -114,6 +126,7 @@ namespace OpenSim.Region.CoreModules.World.Region
114 126
115 if (alerts == null) 127 if (alerts == null)
116 { 128 {
129 CreateMarkerFile();
117 m_Scene.RestartNow(); 130 m_Scene.RestartNow();
118 return; 131 return;
119 } 132 }
@@ -127,6 +140,7 @@ namespace OpenSim.Region.CoreModules.World.Region
127 140
128 if (m_Alerts[0] == 0) 141 if (m_Alerts[0] == 0)
129 { 142 {
143 CreateMarkerFile();
130 m_Scene.RestartNow(); 144 m_Scene.RestartNow();
131 return; 145 return;
132 } 146 }
@@ -140,6 +154,7 @@ namespace OpenSim.Region.CoreModules.World.Region
140 { 154 {
141 if (m_Alerts.Count == 0 || m_Alerts[0] == 0) 155 if (m_Alerts.Count == 0 || m_Alerts[0] == 0)
142 { 156 {
157 CreateMarkerFile();
143 m_Scene.RestartNow(); 158 m_Scene.RestartNow();
144 return 0; 159 return 0;
145 } 160 }
@@ -259,5 +274,25 @@ namespace OpenSim.Region.CoreModules.World.Region
259 274
260 ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice); 275 ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice);
261 } 276 }
277
278 protected void CreateMarkerFile()
279 {
280 if (m_MarkerPath == String.Empty)
281 return;
282
283 string path = Path.Combine(m_MarkerPath, m_Scene.RegionInfo.RegionID.ToString());
284 try
285 {
286 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
287 FileStream fs = File.Create(path);
288 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
289 Byte[] buf = enc.GetBytes(pidstring);
290 fs.Write(buf, 0, buf.Length);
291 fs.Close();
292 }
293 catch (Exception)
294 {
295 }
296 }
262 } 297 }
263} 298}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 8a79d78..9d968e7 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -551,6 +551,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
551 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); 551 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
552 m_scene.SaveTerrain(); 552 m_scene.SaveTerrain();
553 553
554 m_scene.EventManager.TriggerTerrainUpdate();
555
554 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. 556 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
555 //m_scene.CreateTerrainTexture(true); 557 //m_scene.CreateTerrainTexture(true);
556 } 558 }
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index f9ef286..d0aa53e 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
@@ -86,9 +86,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
86 86
87 private void OnMapNameRequest(IClientAPI remoteClient, string mapName) 87 private void OnMapNameRequest(IClientAPI remoteClient, string mapName)
88 { 88 {
89 if (mapName.Length < 3) 89 if (mapName.Length < 2)
90 { 90 {
91 remoteClient.SendAlertMessage("Use a search string with at least 3 characters"); 91 remoteClient.SendAlertMessage("Use a search string with at least 2 characters");
92 return; 92 return;
93 } 93 }
94 94
@@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
106 else if (regionInfos.Count == 0 && mapName.StartsWith("http://")) 106 else if (regionInfos.Count == 0 && mapName.StartsWith("http://"))
107 remoteClient.SendAlertMessage("Hyperlink could not be established."); 107 remoteClient.SendAlertMessage("Hyperlink could not be established.");
108 108
109 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count); 109 //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count);
110 List<MapBlockData> blocks = new List<MapBlockData>(); 110 List<MapBlockData> blocks = new List<MapBlockData>();
111 111
112 MapBlockData data; 112 MapBlockData data;
@@ -132,15 +132,13 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
132 data.Agents = 0; 132 data.Agents = 0;
133 data.Access = 255; 133 data.Access = 255;
134 data.MapImageId = UUID.Zero; 134 data.MapImageId = UUID.Zero;
135 data.Name = ""; // mapName; 135 data.Name = mapName;
136 data.RegionFlags = 0; 136 data.RegionFlags = 0;
137 data.WaterHeight = 0; // not used 137 data.WaterHeight = 0; // not used
138 data.X = 0; 138 data.X = 0;
139 data.Y = 0; 139 data.Y = 0;
140 blocks.Add(data); 140 blocks.Add(data);
141 141
142 // not sure what the flags do here, but seems to be necessary
143 // to set to "2" for viewer 2
144 remoteClient.SendMapBlock(blocks, 2); 142 remoteClient.SendMapBlock(blocks, 2);
145 } 143 }
146 144
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index 1094970..b05aef8 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -1056,7 +1056,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1056 } 1056 }
1057 else 1057 else
1058 { 1058 {
1059 OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount()); 1059 OSDArray responsearr = new OSDArray(); // Don't preallocate. MT (m_scene.GetRootAgentCount());
1060 m_scene.ForEachScenePresence(delegate(ScenePresence sp) 1060 m_scene.ForEachScenePresence(delegate(ScenePresence sp)
1061 { 1061 {
1062 OSDMap responsemapdata = new OSDMap(); 1062 OSDMap responsemapdata = new OSDMap();
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 d939329..df12d69 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 GenericCall1 OnRequestWearables; 85 public event GenericCall1 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
@@ -833,6 +833,11 @@ namespace OpenSim.Region.Examples.SimpleModule
833 833
834 public void Close() 834 public void Close()
835 { 835 {
836 Close(true);
837 }
838
839 public void Close(bool sendStop)
840 {
836 } 841 }
837 842
838 public void Start() 843 public void Start()
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 6cc64c6..788f42b 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>
@@ -113,18 +118,15 @@ namespace OpenSim.Region.Framework.Interfaces
113 /// <summary> 118 /// <summary>
114 /// Update the user inventory to show a detach. 119 /// Update the user inventory to show a detach.
115 /// </summary> 120 /// </summary>
116 /// <param name="itemID">/param> 121 /// <param name="itemID">
117 /// <param name="remoteClient"></param> 122 /// A <see cref="UUID"/>
123 /// </param>
124 /// <param name="remoteClient">
125 /// A <see cref="IClientAPI"/>
126 /// </param>
118 void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient); 127 void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient);
119 128
120 /// <summary> 129 /// <summary>
121 /// Update the position of an attachment.
122 /// </summary>
123 /// <param name="sog"></param>
124 /// <param name="pos"></param>
125 void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos);
126
127 /// <summary>
128 /// Update the user inventory with a changed attachment 130 /// Update the user inventory with a changed attachment
129 /// </summary> 131 /// </summary>
130 /// <param name="remoteClient"> 132 /// <param name="remoteClient">
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs
index 15060fd..4b17b9a 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>
@@ -229,5 +231,6 @@ namespace OpenSim.Region.Framework.Interfaces
229 /// A <see cref="Dictionary`2"/> 231 /// A <see cref="Dictionary`2"/>
230 /// </returns> 232 /// </returns>
231 Dictionary<UUID, string> GetScriptStates(); 233 Dictionary<UUID, string> GetScriptStates();
234 Dictionary<UUID, string> GetScriptStates(bool oldIDs);
232 } 235 }
233} 236}
diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
index 8b96de4..3eb38b8 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 bool Cross(ScenePresence agent, bool isFlying); 45 bool Cross(ScenePresence agent, bool isFlying);
46 46
diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
index 721f0ee..72e79ed 100644
--- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
@@ -45,5 +45,7 @@ namespace OpenSim.Region.Framework.Interfaces
45 /// Tell all clients about the current state of the region (terrain textures, water height, etc.). 45 /// Tell all clients about the current state of the region (terrain textures, water height, etc.).
46 /// </summary> 46 /// </summary>
47 void sendRegionHandshakeToAll(); 47 void sendRegionHandshakeToAll();
48 void TriggerEstateInfoChange();
49 void TriggerRegionInfoChange();
48 } 50 }
49} 51}
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/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
index fecdd1b..4a3c634 100644
--- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
@@ -50,5 +50,7 @@ namespace OpenSim.Region.Framework.Interfaces
50 void ResumeScript(UUID itemID); 50 void ResumeScript(UUID itemID);
51 51
52 ArrayList GetScriptErrors(UUID itemID); 52 ArrayList GetScriptErrors(UUID itemID);
53
54 bool HasScript(UUID itemID, out bool running);
53 } 55 }
54} 56}
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/Interfaces/IUserAccountCacheModule.cs b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs
new file mode 100644
index 0000000..d1a4d8e
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/IUserAccountCacheModule.cs
@@ -0,0 +1,13 @@
1///////////////////////////////////////////////////////////////////
2//
3// (c) Careminster Limited, Melanie Thielker and the Meta7 Team
4//
5// This file is not open source. All rights reserved
6//
7
8using OpenSim.Region.Framework.Scenes;
9
10public interface IUserAccountCacheModule
11{
12 void Remove(string name);
13}
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 4865481..9c103cb 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,48 +230,127 @@ 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) && (m_scenePresence.m_wasFlying)) // 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 else if (m_animTickJump == -1)
237 {
238 m_animTickJump = 0;
239 return "STAND";
240 }
241 257
242 return m_movementAnimation; 258 return m_movementAnimation;
243 } 259 }
244 260
245 #endregion Falling/Floating/Landing 261 #endregion Falling/Floating/Landing
246 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
247 #region Ground Movement 315 #region Ground Movement
248 316
249 if (m_movementAnimation == "FALLDOWN") 317 if (m_movementAnimation == "FALLDOWN")
250 { 318 {
319 m_falling = false;
251 m_animTickFall = Environment.TickCount; 320 m_animTickFall = Environment.TickCount;
252
253 // TODO: SOFT_LAND support 321 // TODO: SOFT_LAND support
254 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
255 } 330 }
256 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"))
257 { 335 {
258 float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; 336 int landElapsed = Environment.TickCount - m_animTickFall; // add for jumping
259 if ((m_animTickFall != 0) && (landElapsed <= FALL_DELAY)) 337 int limit = 1000; // add for jumping
260 return "LAND"; 338 if(m_movementAnimation == "LAND") limit = 350; // add for jumping
261 } 339 // NB if the above is set too long a weird anim reset from some place prevents STAND from being sent to client
262 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
263 m_animTickFall = 0; 354 m_animTickFall = 0;
264 355
265 if (move.Z > 0f) 356 if (move.Z > 0f)
@@ -271,7 +362,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
271 m_animTickJump = Environment.TickCount; 362 m_animTickJump = Environment.TickCount;
272 return "PREJUMP"; 363 return "PREJUMP";
273 } 364 }
274 else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 1000.0f) 365 else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 800.0f)
275 { 366 {
276 // Start actual jump 367 // Start actual jump
277 if (m_animTickJump == -1) 368 if (m_animTickJump == -1)
@@ -284,37 +375,40 @@ namespace OpenSim.Region.Framework.Scenes.Animation
284 m_animTickJump = -1; 375 m_animTickJump = -1;
285 return "JUMP"; 376 return "JUMP";
286 } 377 }
287 else
288 return "JUMP";
289 } 378 }
290 else 379 else
291 { 380 {
292 // Not jumping 381 // Not jumping
293 m_animTickJump = 0; 382 m_animTickJump = 0;
294 383 */
295 if (move.X != 0f || move.Y != 0f) 384 // next section moved outside paren. and realigned for jumping
296 { 385 if (move.X != 0f || move.Y != 0f)
297 // Walking / crouchwalking / running 386 {
298 if (move.Z < 0f) 387 m_fallHeight = actor.Position.Z; // save latest flying height
299 return "CROUCHWALK"; 388 m_falling = false; // Add for falling
300 else if (m_scenePresence.SetAlwaysRun) 389 // Walking / crouchwalking / running
301 return "RUN"; 390 if (move.Z < 0f)
302 else 391 return "CROUCHWALK";
303 return "WALK"; 392 else if (m_scenePresence.SetAlwaysRun)
304 } 393 return "RUN";
305 else 394 else
306 { 395 return "WALK";
307 // Not walking
308 if (move.Z < 0f)
309 return "CROUCH";
310 else
311 return "STAND";
312 }
313 } 396 }
314 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
315 #endregion Ground Movement 408 #endregion Ground Movement
316 409
317 //return m_movementAnimation; 410 m_falling = false; // Add for falling
411 return m_movementAnimation;
318 } 412 }
319 413
320 /// <summary> 414 /// <summary>
@@ -323,7 +417,15 @@ namespace OpenSim.Region.Framework.Scenes.Animation
323 public void UpdateMovementAnimations() 417 public void UpdateMovementAnimations()
324 { 418 {
325 m_movementAnimation = GetMovementAnimation(); 419 m_movementAnimation = GetMovementAnimation();
326 TrySetMovementAnimation(m_movementAnimation); 420/* if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump)
421 {
422 // This was the previous behavior before PREJUMP
423 TrySetMovementAnimation("JUMP");
424 }
425 else
426 { removed for jumping */
427 TrySetMovementAnimation(m_movementAnimation);
428// rm for jumping }
327 } 429 }
328 430
329 public UUID[] GetAnimationArray() 431 public UUID[] GetAnimationArray()
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
index 8feb022..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
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index fd62535..4ce7a6c 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;
@@ -766,6 +770,26 @@ namespace OpenSim.Region.Framework.Scenes
766 } 770 }
767 } 771 }
768 } 772 }
773 public void TriggerTerrainUpdate()
774 {
775 OnTerrainUpdateDelegate handlerTerrainUpdate = OnTerrainUpdate;
776 if (handlerTerrainUpdate != null)
777 {
778 foreach (OnTerrainUpdateDelegate d in handlerTerrainUpdate.GetInvocationList())
779 {
780 try
781 {
782 d();
783 }
784 catch (Exception e)
785 {
786 m_log.ErrorFormat(
787 "[EVENT MANAGER]: Delegate for TriggerTerrainUpdate failed - continuing. {0} {1}",
788 e.Message, e.StackTrace);
789 }
790 }
791 }
792 }
769 793
770 public void TriggerTerrainTick() 794 public void TriggerTerrainTick()
771 { 795 {
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index f9599f5..cde8d3f 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 {
@@ -224,22 +225,16 @@ namespace OpenSim.Region.Framework.Scenes
224 if (entity == null) 225 if (entity == null)
225 return double.NaN; 226 return double.NaN;
226 227
227 // Use group position for child prims 228 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
228 Vector3 entityPos = entity.AbsolutePosition; 229 if (presence != null)
229 if (entity is SceneObjectPart)
230 { 230 {
231 SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; 231 // Use group position for child prims
232 if (group != null) 232 Vector3 entityPos;
233 entityPos = group.AbsolutePosition; 233 if (entity is SceneObjectPart)
234 entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
234 else 235 else
235 entityPos = entity.AbsolutePosition; 236 entityPos = entity.AbsolutePosition;
236 }
237 else
238 entityPos = entity.AbsolutePosition;
239 237
240 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
241 if (presence != null)
242 {
243 if (!presence.IsChildAgent) 238 if (!presence.IsChildAgent)
244 { 239 {
245 if (entity is ScenePresence) 240 if (entity is ScenePresence)
@@ -259,12 +254,19 @@ namespace OpenSim.Region.Framework.Scenes
259 254
260 if (entity is SceneObjectPart) 255 if (entity is SceneObjectPart)
261 { 256 {
262 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
263 if (physActor == null || !physActor.IsPhysical)
264 priority += 100;
265
266 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) 257 if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
258 {
267 priority = 1.0; 259 priority = 1.0;
260 }
261 else
262 {
263 PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
264 if (physActor == null || !physActor.IsPhysical)
265 priority += 100;
266 }
267
268 if (((SceneObjectPart)entity).ParentGroup.RootPart != (SceneObjectPart)entity)
269 priority +=1;
268 } 270 }
269 return priority; 271 return priority;
270 } 272 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 73dd531..0748954 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;
@@ -328,6 +310,7 @@ namespace OpenSim.Region.Framework.Scenes
328 { 310 {
329 if (UUID.Zero == transactionID) 311 if (UUID.Zero == transactionID)
330 { 312 {
313 item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255);
331 item.Name = itemUpd.Name; 314 item.Name = itemUpd.Name;
332 item.Description = itemUpd.Description; 315 item.Description = itemUpd.Description;
333 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) 316 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
@@ -700,6 +683,8 @@ namespace OpenSim.Region.Framework.Scenes
700 return; 683 return;
701 } 684 }
702 685
686 if (newName == null) newName = item.Name;
687
703 AssetBase asset = AssetService.Get(item.AssetID.ToString()); 688 AssetBase asset = AssetService.Get(item.AssetID.ToString());
704 689
705 if (asset != null) 690 if (asset != null)
@@ -753,6 +738,24 @@ namespace OpenSim.Region.Framework.Scenes
753 } 738 }
754 739
755 /// <summary> 740 /// <summary>
741 /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit)
742 /// </summary>
743 public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List<InventoryItemBase> items, UUID destfolder)
744 {
745 List<InventoryItemBase> moveitems = new List<InventoryItemBase>();
746 foreach (InventoryItemBase b in items)
747 {
748 CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null);
749 InventoryItemBase n = InventoryService.GetItem(b);
750 n.Folder = destfolder;
751 moveitems.Add(n);
752 remoteClient.SendInventoryItemCreateUpdate(n, 0);
753 }
754
755 MoveInventoryItem(remoteClient, moveitems);
756 }
757
758 /// <summary>
756 /// Move an item within the agent's inventory. 759 /// Move an item within the agent's inventory.
757 /// </summary> 760 /// </summary>
758 /// <param name="remoteClient"></param> 761 /// <param name="remoteClient"></param>
@@ -985,8 +988,12 @@ namespace OpenSim.Region.Framework.Scenes
985 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID) 988 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
986 { 989 {
987 SceneObjectPart part = GetSceneObjectPart(localID); 990 SceneObjectPart part = GetSceneObjectPart(localID);
988 SceneObjectGroup group = part.ParentGroup; 991 SceneObjectGroup group = null;
989 if (group != null) 992 if (part != null)
993 {
994 group = part.ParentGroup;
995 }
996 if (part != null && group != null)
990 { 997 {
991 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)) 998 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
992 return; 999 return;
@@ -1222,6 +1229,10 @@ namespace OpenSim.Region.Framework.Scenes
1222 if ((part.OwnerID != destPart.OwnerID) && ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)) 1229 if ((part.OwnerID != destPart.OwnerID) && ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
1223 return; 1230 return;
1224 1231
1232 bool overrideNoMod = false;
1233 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) != 0)
1234 overrideNoMod = true;
1235
1225 if (part.OwnerID != destPart.OwnerID && (part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0) 1236 if (part.OwnerID != destPart.OwnerID && (part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0)
1226 { 1237 {
1227 // object cannot copy items to an object owned by a different owner 1238 // object cannot copy items to an object owned by a different owner
@@ -1231,7 +1242,7 @@ namespace OpenSim.Region.Framework.Scenes
1231 } 1242 }
1232 1243
1233 // must have both move and modify permission to put an item in an object 1244 // must have both move and modify permission to put an item in an object
1234 if ((part.OwnerMask & ((uint)PermissionMask.Move | (uint)PermissionMask.Modify)) == 0) 1245 if (((part.OwnerMask & (uint)PermissionMask.Modify) == 0) && (!overrideNoMod))
1235 { 1246 {
1236 return; 1247 return;
1237 } 1248 }
@@ -1290,6 +1301,14 @@ namespace OpenSim.Region.Framework.Scenes
1290 1301
1291 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items) 1302 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items)
1292 { 1303 {
1304 SceneObjectPart destPart = GetSceneObjectPart(destID);
1305 if (destPart != null) // Move into a prim
1306 {
1307 foreach(UUID itemID in items)
1308 MoveTaskInventoryItem(destID, host, itemID);
1309 return destID; // Prim folder ID == prim ID
1310 }
1311
1293 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID); 1312 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
1294 1313
1295 UUID newFolderID = UUID.Random(); 1314 UUID newFolderID = UUID.Random();
@@ -1435,13 +1454,6 @@ namespace OpenSim.Region.Framework.Scenes
1435 { 1454 {
1436 agentTransactions.HandleTaskItemUpdateFromTransaction( 1455 agentTransactions.HandleTaskItemUpdateFromTransaction(
1437 remoteClient, part, transactionID, currentItem); 1456 remoteClient, part, transactionID, currentItem);
1438
1439 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1440 remoteClient.SendAgentAlertMessage("Notecard saved", false);
1441 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1442 remoteClient.SendAgentAlertMessage("Script saved", false);
1443 else
1444 remoteClient.SendAgentAlertMessage("Item saved", false);
1445 } 1457 }
1446 1458
1447 // Base ALWAYS has move 1459 // Base ALWAYS has move
@@ -1582,7 +1594,7 @@ namespace OpenSim.Region.Framework.Scenes
1582 return; 1594 return;
1583 1595
1584 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1596 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
1585 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), 1597 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"),
1586 remoteClient.AgentId); 1598 remoteClient.AgentId);
1587 AssetService.Store(asset); 1599 AssetService.Store(asset);
1588 1600
@@ -1735,23 +1747,32 @@ namespace OpenSim.Region.Framework.Scenes
1735 // build a list of eligible objects 1747 // build a list of eligible objects
1736 List<uint> deleteIDs = new List<uint>(); 1748 List<uint> deleteIDs = new List<uint>();
1737 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>(); 1749 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>();
1738 1750 List<SceneObjectGroup> takeGroups = new List<SceneObjectGroup>();
1739 // Start with true for both, then remove the flags if objects
1740 // that we can't derez are part of the selection
1741 bool permissionToTake = true;
1742 bool permissionToTakeCopy = true;
1743 bool permissionToDelete = true;
1744 1751
1745 foreach (uint localID in localIDs) 1752 foreach (uint localID in localIDs)
1746 { 1753 {
1754 // Start with true for both, then remove the flags if objects
1755 // that we can't derez are part of the selection
1756 bool permissionToTake = true;
1757 bool permissionToTakeCopy = true;
1758 bool permissionToDelete = true;
1759
1747 // Invalid id 1760 // Invalid id
1748 SceneObjectPart part = GetSceneObjectPart(localID); 1761 SceneObjectPart part = GetSceneObjectPart(localID);
1749 if (part == null) 1762 if (part == null)
1763 {
1764 //Client still thinks the object exists, kill it
1765 deleteIDs.Add(localID);
1750 continue; 1766 continue;
1767 }
1751 1768
1752 // Already deleted by someone else 1769 // Already deleted by someone else
1753 if (part.ParentGroup == null || part.ParentGroup.IsDeleted) 1770 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
1771 {
1772 //Client still thinks the object exists, kill it
1773 deleteIDs.Add(localID);
1754 continue; 1774 continue;
1775 }
1755 1776
1756 // Can't delete child prims 1777 // Can't delete child prims
1757 if (part != part.ParentGroup.RootPart) 1778 if (part != part.ParentGroup.RootPart)
@@ -1759,9 +1780,6 @@ namespace OpenSim.Region.Framework.Scenes
1759 1780
1760 SceneObjectGroup grp = part.ParentGroup; 1781 SceneObjectGroup grp = part.ParentGroup;
1761 1782
1762 deleteIDs.Add(localID);
1763 deleteGroups.Add(grp);
1764
1765 if (remoteClient == null) 1783 if (remoteClient == null)
1766 { 1784 {
1767 // Autoreturn has a null client. Nothing else does. So 1785 // Autoreturn has a null client. Nothing else does. So
@@ -1778,80 +1796,104 @@ namespace OpenSim.Region.Framework.Scenes
1778 } 1796 }
1779 else 1797 else
1780 { 1798 {
1781 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId)) 1799 if (action == DeRezAction.TakeCopy)
1800 {
1801 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId))
1802 permissionToTakeCopy = false;
1803 }
1804 else
1805 {
1782 permissionToTakeCopy = false; 1806 permissionToTakeCopy = false;
1783 1807 }
1784 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId)) 1808 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId))
1785 permissionToTake = false; 1809 permissionToTake = false;
1786 1810
1787 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId)) 1811 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId))
1788 permissionToDelete = false; 1812 permissionToDelete = false;
1789 } 1813 }
1790 }
1791 1814
1792 // Handle god perms 1815 // Handle god perms
1793 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) 1816 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId))
1794 { 1817 {
1795 permissionToTake = true; 1818 permissionToTake = true;
1796 permissionToTakeCopy = true; 1819 permissionToTakeCopy = true;
1797 permissionToDelete = true; 1820 permissionToDelete = true;
1798 } 1821 }
1799 1822
1800 // If we're re-saving, we don't even want to delete 1823 // If we're re-saving, we don't even want to delete
1801 if (action == DeRezAction.SaveToExistingUserInventoryItem) 1824 if (action == DeRezAction.SaveToExistingUserInventoryItem)
1802 permissionToDelete = false; 1825 permissionToDelete = false;
1803 1826
1804 // if we want to take a copy, we also don't want to delete 1827 // if we want to take a copy, we also don't want to delete
1805 // Note: after this point, the permissionToTakeCopy flag 1828 // Note: after this point, the permissionToTakeCopy flag
1806 // becomes irrelevant. It already includes the permissionToTake 1829 // becomes irrelevant. It already includes the permissionToTake
1807 // permission and after excluding no copy items here, we can 1830 // permission and after excluding no copy items here, we can
1808 // just use that. 1831 // just use that.
1809 if (action == DeRezAction.TakeCopy) 1832 if (action == DeRezAction.TakeCopy)
1810 { 1833 {
1811 // If we don't have permission, stop right here 1834 // If we don't have permission, stop right here
1812 if (!permissionToTakeCopy) 1835 if (!permissionToTakeCopy)
1813 return; 1836 return;
1814 1837
1815 permissionToTake = true; 1838 permissionToTake = true;
1816 // Don't delete 1839 // Don't delete
1817 permissionToDelete = false; 1840 permissionToDelete = false;
1818 } 1841 }
1819 1842
1820 if (action == DeRezAction.Return) 1843 if (action == DeRezAction.Return)
1821 {
1822 if (remoteClient != null)
1823 { 1844 {
1824 if (Permissions.CanReturnObjects( 1845 if (remoteClient != null)
1825 null,
1826 remoteClient.AgentId,
1827 deleteGroups))
1828 { 1846 {
1829 permissionToTake = true; 1847 if (Permissions.CanReturnObjects(
1830 permissionToDelete = true; 1848 null,
1831 1849 remoteClient.AgentId,
1832 foreach (SceneObjectGroup g in deleteGroups) 1850 deleteGroups))
1833 { 1851 {
1834 AddReturn(g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return"); 1852 permissionToTake = true;
1853 permissionToDelete = true;
1854
1855 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
1835 } 1856 }
1836 } 1857 }
1858 else // Auto return passes through here with null agent
1859 {
1860 permissionToTake = true;
1861 permissionToDelete = true;
1862 }
1837 } 1863 }
1838 else // Auto return passes through here with null agent 1864
1865 if (permissionToTake && (!permissionToDelete))
1866 takeGroups.Add(grp);
1867
1868 if (permissionToDelete)
1839 { 1869 {
1840 permissionToTake = true; 1870 if (permissionToTake)
1841 permissionToDelete = true; 1871 deleteGroups.Add(grp);
1872 deleteIDs.Add(grp.LocalId);
1842 } 1873 }
1843 } 1874 }
1844 1875
1845 if (permissionToTake) 1876 SendKillObject(deleteIDs);
1877
1878 if (deleteGroups.Count > 0)
1846 { 1879 {
1880 foreach (SceneObjectGroup g in deleteGroups)
1881 deleteIDs.Remove(g.LocalId);
1882
1847 m_asyncSceneObjectDeleter.DeleteToInventory( 1883 m_asyncSceneObjectDeleter.DeleteToInventory(
1848 action, destinationID, deleteGroups, remoteClient, 1884 action, destinationID, deleteGroups, remoteClient,
1849 permissionToDelete); 1885 true);
1886 }
1887 if (takeGroups.Count > 0)
1888 {
1889 m_asyncSceneObjectDeleter.DeleteToInventory(
1890 action, destinationID, takeGroups, remoteClient,
1891 false);
1850 } 1892 }
1851 else if (permissionToDelete) 1893 if (deleteIDs.Count > 0)
1852 { 1894 {
1853 foreach (SceneObjectGroup g in deleteGroups) 1895 foreach (SceneObjectGroup g in deleteGroups)
1854 DeleteSceneObject(g, false); 1896 DeleteSceneObject(g, true);
1855 } 1897 }
1856 } 1898 }
1857 1899
@@ -1903,21 +1945,29 @@ namespace OpenSim.Region.Framework.Scenes
1903 else // oopsies 1945 else // oopsies
1904 item.Folder = UUID.Zero; 1946 item.Folder = UUID.Zero;
1905 1947
1948 // Set up base perms properly
1949 uint permsBase = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify);
1950 permsBase &= grp.RootPart.BaseMask;
1951 permsBase |= (uint)PermissionMask.Move;
1952
1953 // Make sure we don't lock it
1954 grp.RootPart.NextOwnerMask |= (uint)PermissionMask.Move;
1955
1906 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions()) 1956 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions())
1907 { 1957 {
1908 item.BasePermissions = grp.RootPart.NextOwnerMask; 1958 item.BasePermissions = permsBase & grp.RootPart.NextOwnerMask;
1909 item.CurrentPermissions = grp.RootPart.NextOwnerMask; 1959 item.CurrentPermissions = permsBase & grp.RootPart.NextOwnerMask;
1910 item.NextPermissions = grp.RootPart.NextOwnerMask; 1960 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
1911 item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; 1961 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
1912 item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; 1962 item.GroupPermissions = permsBase & grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
1913 } 1963 }
1914 else 1964 else
1915 { 1965 {
1916 item.BasePermissions = grp.RootPart.BaseMask; 1966 item.BasePermissions = permsBase;
1917 item.CurrentPermissions = grp.RootPart.OwnerMask; 1967 item.CurrentPermissions = permsBase & grp.RootPart.OwnerMask;
1918 item.NextPermissions = grp.RootPart.NextOwnerMask; 1968 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
1919 item.EveryOnePermissions = grp.RootPart.EveryoneMask; 1969 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask;
1920 item.GroupPermissions = grp.RootPart.GroupMask; 1970 item.GroupPermissions = permsBase & grp.RootPart.GroupMask;
1921 } 1971 }
1922 item.CreationDate = Util.UnixTimeSinceEpoch(); 1972 item.CreationDate = Util.UnixTimeSinceEpoch();
1923 1973
@@ -2023,6 +2073,9 @@ namespace OpenSim.Region.Framework.Scenes
2023 2073
2024 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running) 2074 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running)
2025 { 2075 {
2076 if (!Permissions.CanEditScript(itemID, objectID, controllingClient.AgentId))
2077 return;
2078
2026 SceneObjectPart part = GetSceneObjectPart(objectID); 2079 SceneObjectPart part = GetSceneObjectPart(objectID);
2027 if (part == null) 2080 if (part == null)
2028 return; 2081 return;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs
index e1fedf4..48beb9c 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs
@@ -49,6 +49,7 @@ namespace OpenSim.Region.Framework.Scenes
49 public delegate bool DuplicateObjectHandler(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition); 49 public delegate bool DuplicateObjectHandler(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition);
50 public delegate bool EditObjectHandler(UUID objectID, UUID editorID, Scene scene); 50 public delegate bool EditObjectHandler(UUID objectID, UUID editorID, Scene scene);
51 public delegate bool EditObjectInventoryHandler(UUID objectID, UUID editorID, Scene scene); 51 public delegate bool EditObjectInventoryHandler(UUID objectID, UUID editorID, Scene scene);
52 public delegate bool ViewObjectInventoryHandler(UUID objectID, UUID editorID, Scene scene);
52 public delegate bool MoveObjectHandler(UUID objectID, UUID moverID, Scene scene); 53 public delegate bool MoveObjectHandler(UUID objectID, UUID moverID, Scene scene);
53 public delegate bool ObjectEntryHandler(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene); 54 public delegate bool ObjectEntryHandler(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene);
54 public delegate bool ReturnObjectsHandler(ILandObject land, UUID user, List<SceneObjectGroup> objects, Scene scene); 55 public delegate bool ReturnObjectsHandler(ILandObject land, UUID user, List<SceneObjectGroup> objects, Scene scene);
@@ -116,6 +117,7 @@ namespace OpenSim.Region.Framework.Scenes
116 public event DuplicateObjectHandler OnDuplicateObject; 117 public event DuplicateObjectHandler OnDuplicateObject;
117 public event EditObjectHandler OnEditObject; 118 public event EditObjectHandler OnEditObject;
118 public event EditObjectInventoryHandler OnEditObjectInventory; 119 public event EditObjectInventoryHandler OnEditObjectInventory;
120 public event ViewObjectInventoryHandler OnViewObjectInventory;
119 public event MoveObjectHandler OnMoveObject; 121 public event MoveObjectHandler OnMoveObject;
120 public event ObjectEntryHandler OnObjectEntry; 122 public event ObjectEntryHandler OnObjectEntry;
121 public event ReturnObjectsHandler OnReturnObjects; 123 public event ReturnObjectsHandler OnReturnObjects;
@@ -401,6 +403,21 @@ namespace OpenSim.Region.Framework.Scenes
401 return true; 403 return true;
402 } 404 }
403 405
406 public bool CanViewObjectInventory(UUID objectID, UUID editorID)
407 {
408 ViewObjectInventoryHandler handler = OnViewObjectInventory;
409 if (handler != null)
410 {
411 Delegate[] list = handler.GetInvocationList();
412 foreach (ViewObjectInventoryHandler h in list)
413 {
414 if (h(objectID, editorID, m_scene) == false)
415 return false;
416 }
417 }
418 return true;
419 }
420
404 #endregion 421 #endregion
405 422
406 #region MOVE OBJECT 423 #region MOVE OBJECT
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index f0acc38..0e3cffb 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -93,6 +93,7 @@ namespace OpenSim.Region.Framework.Scenes
93 // TODO: need to figure out how allow client agents but deny 93 // TODO: need to figure out how allow client agents but deny
94 // root agents when ACL denies access to root agent 94 // root agents when ACL denies access to root agent
95 public bool m_strictAccessControl = true; 95 public bool m_strictAccessControl = true;
96 public bool m_seeIntoBannedRegion = false;
96 public int MaxUndoCount = 5; 97 public int MaxUndoCount = 5;
97 public bool LoginsDisabled = true; 98 public bool LoginsDisabled = true;
98 public bool LoadingPrims; 99 public bool LoadingPrims;
@@ -111,6 +112,7 @@ namespace OpenSim.Region.Framework.Scenes
111 protected ModuleLoader m_moduleLoader; 112 protected ModuleLoader m_moduleLoader;
112 protected AgentCircuitManager m_authenticateHandler; 113 protected AgentCircuitManager m_authenticateHandler;
113 protected SceneCommunicationService m_sceneGridService; 114 protected SceneCommunicationService m_sceneGridService;
115 protected ISnmpModule m_snmpService = null;
114 116
115 protected ISimulationDataService m_SimulationDataService; 117 protected ISimulationDataService m_SimulationDataService;
116 protected IEstateDataService m_EstateDataService; 118 protected IEstateDataService m_EstateDataService;
@@ -167,7 +169,7 @@ namespace OpenSim.Region.Framework.Scenes
167 private int m_update_events = 1; 169 private int m_update_events = 1;
168 private int m_update_backup = 200; 170 private int m_update_backup = 200;
169 private int m_update_terrain = 50; 171 private int m_update_terrain = 50;
170// private int m_update_land = 1; 172 private int m_update_land = 10;
171 private int m_update_coarse_locations = 50; 173 private int m_update_coarse_locations = 50;
172 174
173 private int frameMS; 175 private int frameMS;
@@ -181,6 +183,7 @@ namespace OpenSim.Region.Framework.Scenes
181 private int landMS; 183 private int landMS;
182 private int lastCompletedFrame; 184 private int lastCompletedFrame;
183 185
186 public bool CombineRegions = false;
184 private bool m_physics_enabled = true; 187 private bool m_physics_enabled = true;
185 private bool m_scripts_enabled = true; 188 private bool m_scripts_enabled = true;
186 private string m_defaultScriptEngine; 189 private string m_defaultScriptEngine;
@@ -189,6 +192,8 @@ namespace OpenSim.Region.Framework.Scenes
189 private volatile bool shuttingdown; 192 private volatile bool shuttingdown;
190 193
191 private int m_lastUpdate; 194 private int m_lastUpdate;
195 private int m_lastIncoming;
196 private int m_lastOutgoing;
192 private bool m_firstHeartbeat = true; 197 private bool m_firstHeartbeat = true;
193 198
194 private object m_deleting_scene_object = new object(); 199 private object m_deleting_scene_object = new object();
@@ -240,6 +245,19 @@ namespace OpenSim.Region.Framework.Scenes
240 get { return m_sceneGridService; } 245 get { return m_sceneGridService; }
241 } 246 }
242 247
248 public ISnmpModule SnmpService
249 {
250 get
251 {
252 if (m_snmpService == null)
253 {
254 m_snmpService = RequestModuleInterface<ISnmpModule>();
255 }
256
257 return m_snmpService;
258 }
259 }
260
243 public ISimulationDataService SimulationDataService 261 public ISimulationDataService SimulationDataService
244 { 262 {
245 get 263 get
@@ -563,7 +581,10 @@ namespace OpenSim.Region.Framework.Scenes
563 m_regInfo = regInfo; 581 m_regInfo = regInfo;
564 m_regionHandle = m_regInfo.RegionHandle; 582 m_regionHandle = m_regInfo.RegionHandle;
565 m_regionName = m_regInfo.RegionName; 583 m_regionName = m_regInfo.RegionName;
584 m_datastore = m_regInfo.DataStore;
566 m_lastUpdate = Util.EnvironmentTickCount(); 585 m_lastUpdate = Util.EnvironmentTickCount();
586 m_lastIncoming = 0;
587 m_lastOutgoing = 0;
567 588
568 m_physicalPrim = physicalPrim; 589 m_physicalPrim = physicalPrim;
569 m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor; 590 m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor;
@@ -577,6 +598,8 @@ namespace OpenSim.Region.Framework.Scenes
577 #region Region Settings 598 #region Region Settings
578 599
579 // Load region settings 600 // Load region settings
601 m_regInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(m_regInfo.RegionID);
602
580 m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID); 603 m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID);
581 if (estateDataService != null) 604 if (estateDataService != null)
582 m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); 605 m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false);
@@ -638,9 +661,10 @@ namespace OpenSim.Region.Framework.Scenes
638 //Animation states 661 //Animation states
639 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false); 662 m_useFlySlow = startupConfig.GetBoolean("enableflyslow", false);
640 // TODO: Change default to true once the feature is supported 663 // TODO: Change default to true once the feature is supported
641 m_usePreJump = startupConfig.GetBoolean("enableprejump", false); 664 m_usePreJump = startupConfig.GetBoolean("enableprejump", true);
642
643 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys); 665 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", m_maxNonphys);
666
667 m_log.DebugFormat("[SCENE]: prejump is {0}", m_usePreJump ? "ON" : "OFF");
644 if (RegionInfo.NonphysPrimMax > 0) 668 if (RegionInfo.NonphysPrimMax > 0)
645 { 669 {
646 m_maxNonphys = RegionInfo.NonphysPrimMax; 670 m_maxNonphys = RegionInfo.NonphysPrimMax;
@@ -672,6 +696,7 @@ namespace OpenSim.Region.Framework.Scenes
672 m_persistAfter *= 10000000; 696 m_persistAfter *= 10000000;
673 697
674 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 698 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
699 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
675 700
676 IConfig packetConfig = m_config.Configs["PacketPool"]; 701 IConfig packetConfig = m_config.Configs["PacketPool"];
677 if (packetConfig != null) 702 if (packetConfig != null)
@@ -681,6 +706,8 @@ namespace OpenSim.Region.Framework.Scenes
681 } 706 }
682 707
683 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 708 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
709 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
710 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
684 711
685 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); 712 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
686 if (m_generateMaptiles) 713 if (m_generateMaptiles)
@@ -705,9 +732,9 @@ namespace OpenSim.Region.Framework.Scenes
705 } 732 }
706 } 733 }
707 } 734 }
708 catch 735 catch (Exception e)
709 { 736 {
710 m_log.Warn("[SCENE]: Failed to load StartupConfig"); 737 m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString());
711 } 738 }
712 739
713 #endregion Region Config 740 #endregion Region Config
@@ -1078,7 +1105,9 @@ namespace OpenSim.Region.Framework.Scenes
1078 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat); 1105 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
1079 if (HeartbeatThread != null) 1106 if (HeartbeatThread != null)
1080 { 1107 {
1108 m_log.ErrorFormat("[SCENE]: Restarting heartbeat thread because it hasn't reported in in region {0}", RegionInfo.RegionName);
1081 HeartbeatThread.Abort(); 1109 HeartbeatThread.Abort();
1110 Watchdog.RemoveThread(HeartbeatThread.ManagedThreadId);
1082 HeartbeatThread = null; 1111 HeartbeatThread = null;
1083 } 1112 }
1084 m_lastUpdate = Util.EnvironmentTickCount(); 1113 m_lastUpdate = Util.EnvironmentTickCount();
@@ -1202,9 +1231,6 @@ namespace OpenSim.Region.Framework.Scenes
1202 { 1231 {
1203 while (!shuttingdown) 1232 while (!shuttingdown)
1204 Update(); 1233 Update();
1205
1206 m_lastUpdate = Util.EnvironmentTickCount();
1207 m_firstHeartbeat = false;
1208 } 1234 }
1209 catch (ThreadAbortException) 1235 catch (ThreadAbortException)
1210 { 1236 {
@@ -1311,12 +1337,12 @@ namespace OpenSim.Region.Framework.Scenes
1311 terrainMS = Util.EnvironmentTickCountSubtract(terMS); 1337 terrainMS = Util.EnvironmentTickCountSubtract(terMS);
1312 } 1338 }
1313 1339
1314 //if (Frame % m_update_land == 0) 1340 // if (Frame % m_update_land == 0)
1315 //{ 1341 // {
1316 // int ldMS = Util.EnvironmentTickCount(); 1342 // int ldMS = Util.EnvironmentTickCount();
1317 // UpdateLand(); 1343 // UpdateLand();
1318 // landMS = Util.EnvironmentTickCountSubtract(ldMS); 1344 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1319 //} 1345 // }
1320 1346
1321 frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS); 1347 frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS);
1322 otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; 1348 otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS;
@@ -1382,12 +1408,16 @@ namespace OpenSim.Region.Framework.Scenes
1382 maintc = Util.EnvironmentTickCountSubtract(maintc); 1408 maintc = Util.EnvironmentTickCountSubtract(maintc);
1383 maintc = (int)(m_timespan * 1000) - maintc; 1409 maintc = (int)(m_timespan * 1000) - maintc;
1384 1410
1411
1412 m_lastUpdate = Util.EnvironmentTickCount();
1413 m_firstHeartbeat = false;
1414
1385 if (maintc > 0) 1415 if (maintc > 0)
1386 Thread.Sleep(maintc); 1416 Thread.Sleep(maintc);
1387 1417
1388 // Tell the watchdog that this thread is still alive 1418 // Tell the watchdog that this thread is still alive
1389 Watchdog.UpdateThread(); 1419 Watchdog.UpdateThread();
1390 } 1420 }
1391 1421
1392 public void AddGroupTarget(SceneObjectGroup grp) 1422 public void AddGroupTarget(SceneObjectGroup grp)
1393 { 1423 {
@@ -1403,9 +1433,9 @@ namespace OpenSim.Region.Framework.Scenes
1403 1433
1404 private void CheckAtTargets() 1434 private void CheckAtTargets()
1405 { 1435 {
1406 Dictionary<UUID, SceneObjectGroup>.ValueCollection objs; 1436 List<SceneObjectGroup> objs = new List<SceneObjectGroup>();
1407 lock (m_groupsWithTargets) 1437 lock (m_groupsWithTargets)
1408 objs = m_groupsWithTargets.Values; 1438 objs = new List<SceneObjectGroup>(m_groupsWithTargets.Values);
1409 1439
1410 foreach (SceneObjectGroup entry in objs) 1440 foreach (SceneObjectGroup entry in objs)
1411 entry.checkAtTargets(); 1441 entry.checkAtTargets();
@@ -1728,14 +1758,24 @@ namespace OpenSim.Region.Framework.Scenes
1728 /// <returns></returns> 1758 /// <returns></returns>
1729 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) 1759 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1730 { 1760 {
1761
1762 float wheight = (float)RegionInfo.RegionSettings.WaterHeight;
1763 Vector3 wpos = Vector3.Zero;
1764 // Check for water surface intersection from above
1765 if ( (RayStart.Z > wheight) && (RayEnd.Z < wheight) )
1766 {
1767 float ratio = (RayStart.Z - wheight) / (RayStart.Z - RayEnd.Z);
1768 wpos.X = RayStart.X - (ratio * (RayStart.X - RayEnd.X));
1769 wpos.Y = RayStart.Y - (ratio * (RayStart.Y - RayEnd.Y));
1770 wpos.Z = wheight;
1771 }
1772
1731 Vector3 pos = Vector3.Zero; 1773 Vector3 pos = Vector3.Zero;
1732 if (RayEndIsIntersection == (byte)1) 1774 if (RayEndIsIntersection == (byte)1)
1733 { 1775 {
1734 pos = RayEnd; 1776 pos = RayEnd;
1735 return pos;
1736 } 1777 }
1737 1778 else if (RayTargetID != UUID.Zero)
1738 if (RayTargetID != UUID.Zero)
1739 { 1779 {
1740 SceneObjectPart target = GetSceneObjectPart(RayTargetID); 1780 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1741 1781
@@ -1757,7 +1797,7 @@ namespace OpenSim.Region.Framework.Scenes
1757 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); 1797 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1758 1798
1759 // Un-comment out the following line to Get Raytrace results printed to the console. 1799 // Un-comment out the following line to Get Raytrace results printed to the console.
1760 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 1800 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1761 float ScaleOffset = 0.5f; 1801 float ScaleOffset = 0.5f;
1762 1802
1763 // If we hit something 1803 // If we hit something
@@ -1780,13 +1820,10 @@ namespace OpenSim.Region.Framework.Scenes
1780 //pos.Z -= 0.25F; 1820 //pos.Z -= 0.25F;
1781 1821
1782 } 1822 }
1783
1784 return pos;
1785 } 1823 }
1786 else 1824 else
1787 { 1825 {
1788 // We don't have a target here, so we're going to raytrace all the objects in the scene. 1826 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1789
1790 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); 1827 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1791 1828
1792 // Un-comment the following line to print the raytrace results to the console. 1829 // Un-comment the following line to print the raytrace results to the console.
@@ -1795,13 +1832,12 @@ namespace OpenSim.Region.Framework.Scenes
1795 if (ei.HitTF) 1832 if (ei.HitTF)
1796 { 1833 {
1797 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 1834 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1798 } else 1835 }
1836 else
1799 { 1837 {
1800 // fall back to our stupid functionality 1838 // fall back to our stupid functionality
1801 pos = RayEnd; 1839 pos = RayEnd;
1802 } 1840 }
1803
1804 return pos;
1805 } 1841 }
1806 } 1842 }
1807 else 1843 else
@@ -1812,8 +1848,12 @@ namespace OpenSim.Region.Framework.Scenes
1812 //increase height so its above the ground. 1848 //increase height so its above the ground.
1813 //should be getting the normal of the ground at the rez point and using that? 1849 //should be getting the normal of the ground at the rez point and using that?
1814 pos.Z += scale.Z / 2f; 1850 pos.Z += scale.Z / 2f;
1815 return pos; 1851// return pos;
1816 } 1852 }
1853
1854 // check against posible water intercept
1855 if (wpos.Z > pos.Z) pos = wpos;
1856 return pos;
1817 } 1857 }
1818 1858
1819 1859
@@ -1893,7 +1933,10 @@ namespace OpenSim.Region.Framework.Scenes
1893 public bool AddRestoredSceneObject( 1933 public bool AddRestoredSceneObject(
1894 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 1934 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
1895 { 1935 {
1896 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 1936 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates);
1937 if (result)
1938 sceneObject.IsDeleted = false;
1939 return result;
1897 } 1940 }
1898 1941
1899 /// <summary> 1942 /// <summary>
@@ -1982,6 +2025,15 @@ namespace OpenSim.Region.Framework.Scenes
1982 /// </summary> 2025 /// </summary>
1983 public void DeleteAllSceneObjects() 2026 public void DeleteAllSceneObjects()
1984 { 2027 {
2028 DeleteAllSceneObjects(false);
2029 }
2030
2031 /// <summary>
2032 /// Delete every object from the scene. This does not include attachments worn by avatars.
2033 /// </summary>
2034 public void DeleteAllSceneObjects(bool exceptNoCopy)
2035 {
2036 List<SceneObjectGroup> toReturn = new List<SceneObjectGroup>();
1985 lock (Entities) 2037 lock (Entities)
1986 { 2038 {
1987 EntityBase[] entities = Entities.GetEntities(); 2039 EntityBase[] entities = Entities.GetEntities();
@@ -1990,11 +2042,24 @@ namespace OpenSim.Region.Framework.Scenes
1990 if (e is SceneObjectGroup) 2042 if (e is SceneObjectGroup)
1991 { 2043 {
1992 SceneObjectGroup sog = (SceneObjectGroup)e; 2044 SceneObjectGroup sog = (SceneObjectGroup)e;
1993 if (!sog.IsAttachment) 2045 if (sog != null && !sog.IsAttachment)
1994 DeleteSceneObject((SceneObjectGroup)e, false); 2046 {
2047 if (!exceptNoCopy || ((sog.GetEffectivePermissions() & (uint)PermissionMask.Copy) != 0))
2048 {
2049 DeleteSceneObject((SceneObjectGroup)e, false);
2050 }
2051 else
2052 {
2053 toReturn.Add((SceneObjectGroup)e);
2054 }
2055 }
1995 } 2056 }
1996 } 2057 }
1997 } 2058 }
2059 if (toReturn.Count > 0)
2060 {
2061 returnObjects(toReturn.ToArray(), UUID.Zero);
2062 }
1998 } 2063 }
1999 2064
2000 /// <summary> 2065 /// <summary>
@@ -2043,6 +2108,8 @@ namespace OpenSim.Region.Framework.Scenes
2043 } 2108 }
2044 2109
2045 group.DeleteGroupFromScene(silent); 2110 group.DeleteGroupFromScene(silent);
2111 if (!silent)
2112 SendKillObject(new List<uint>() { group.LocalId });
2046 2113
2047// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2114// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2048 } 2115 }
@@ -2373,10 +2440,17 @@ namespace OpenSim.Region.Framework.Scenes
2373 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns> 2440 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2374 public bool AddSceneObject(SceneObjectGroup sceneObject) 2441 public bool AddSceneObject(SceneObjectGroup sceneObject)
2375 { 2442 {
2443 if (sceneObject.OwnerID == UUID.Zero)
2444 {
2445 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero", sceneObject.UUID);
2446 return false;
2447 }
2448
2376 // If the user is banned, we won't let any of their objects 2449 // If the user is banned, we won't let any of their objects
2377 // enter. Period. 2450 // enter. Period.
2378 // 2451 //
2379 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID)) 2452 int flags = GetUserFlags(sceneObject.OwnerID);
2453 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID, flags))
2380 { 2454 {
2381 m_log.Info("[INTERREGION]: Denied prim crossing for " + 2455 m_log.Info("[INTERREGION]: Denied prim crossing for " +
2382 "banned avatar"); 2456 "banned avatar");
@@ -2420,15 +2494,28 @@ namespace OpenSim.Region.Framework.Scenes
2420 2494
2421 if (AttachmentsModule != null) 2495 if (AttachmentsModule != null)
2422 AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false); 2496 AttachmentsModule.AttachObject(sp.ControllingClient, grp, 0, false);
2497
2498 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was found, attaching", sceneObject.UUID);
2423 } 2499 }
2424 else 2500 else
2425 { 2501 {
2502 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was not found, setting to temp", sceneObject.UUID);
2426 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2503 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2427 RootPrim.AddFlag(PrimFlags.TemporaryOnRez); 2504 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2428 } 2505 }
2506 if (sceneObject.OwnerID == UUID.Zero)
2507 {
2508 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero after attachment processing. BUG!", sceneObject.UUID);
2509 return false;
2510 }
2429 } 2511 }
2430 else 2512 else
2431 { 2513 {
2514 if (sceneObject.OwnerID == UUID.Zero)
2515 {
2516 m_log.ErrorFormat("[SCENE]: Owner ID for non-attachment {0} was zero", sceneObject.UUID);
2517 return false;
2518 }
2432 AddRestoredSceneObject(sceneObject, true, false); 2519 AddRestoredSceneObject(sceneObject, true, false);
2433 2520
2434 if (!Permissions.CanObjectEntry(sceneObject.UUID, 2521 if (!Permissions.CanObjectEntry(sceneObject.UUID,
@@ -2467,6 +2554,24 @@ namespace OpenSim.Region.Framework.Scenes
2467 return 2; // StateSource.PrimCrossing 2554 return 2; // StateSource.PrimCrossing
2468 } 2555 }
2469 2556
2557 public int GetUserFlags(UUID user)
2558 {
2559 //Unfortunately the SP approach means that the value is cached until region is restarted
2560 /*
2561 ScenePresence sp;
2562 if (TryGetScenePresence(user, out sp))
2563 {
2564 return sp.UserFlags;
2565 }
2566 else
2567 {
2568 */
2569 UserAccount uac = UserAccountService.GetUserAccount(RegionInfo.ScopeID, user);
2570 if (uac == null)
2571 return 0;
2572 return uac.UserFlags;
2573 //}
2574 }
2470 #endregion 2575 #endregion
2471 2576
2472 #region Add/Remove Avatar Methods 2577 #region Add/Remove Avatar Methods
@@ -2487,6 +2592,7 @@ namespace OpenSim.Region.Framework.Scenes
2487 (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2592 (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2488 2593
2489 CheckHeartbeat(); 2594 CheckHeartbeat();
2595 ScenePresence presence;
2490 2596
2491 if (GetScenePresence(client.AgentId) == null) // ensure there is no SP here 2597 if (GetScenePresence(client.AgentId) == null) // ensure there is no SP here
2492 { 2598 {
@@ -2510,12 +2616,19 @@ namespace OpenSim.Region.Framework.Scenes
2510 } 2616 }
2511 } 2617 }
2512 2618
2513 if (GetScenePresence(client.AgentId) != null) 2619 if (TryGetScenePresence(client.AgentId, out presence))
2514 { 2620 {
2515 m_LastLogin = Util.EnvironmentTickCount(); 2621 m_LastLogin = Util.EnvironmentTickCount();
2516 EventManager.TriggerOnNewClient(client); 2622 EventManager.TriggerOnNewClient(client);
2517 if (vialogin) 2623 if (vialogin)
2624 {
2518 EventManager.TriggerOnClientLogin(client); 2625 EventManager.TriggerOnClientLogin(client);
2626
2627 // Send initial parcel data
2628 Vector3 pos = presence.AbsolutePosition;
2629 ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
2630 land.SendLandUpdateToClient(presence.ControllingClient);
2631 }
2519 } 2632 }
2520 } 2633 }
2521 2634
@@ -2566,19 +2679,12 @@ namespace OpenSim.Region.Framework.Scenes
2566 // and the scene presence and the client, if they exist 2679 // and the scene presence and the client, if they exist
2567 try 2680 try
2568 { 2681 {
2569 // We need to wait for the client to make UDP contact first. 2682 ScenePresence sp = GetScenePresence(agentID);
2570 // It's the UDP contact that creates the scene presence 2683 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2571 ScenePresence sp = WaitGetScenePresence(agentID); 2684
2572 if (sp != null) 2685 if (sp != null)
2573 {
2574 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2575
2576 sp.ControllingClient.Close(); 2686 sp.ControllingClient.Close();
2577 } 2687
2578 else
2579 {
2580 m_log.WarnFormat("[SCENE]: Could not find scene presence for {0}", agentID);
2581 }
2582 // BANG! SLASH! 2688 // BANG! SLASH!
2583 m_authenticateHandler.RemoveCircuit(agentID); 2689 m_authenticateHandler.RemoveCircuit(agentID);
2584 2690
@@ -2678,6 +2784,7 @@ namespace OpenSim.Region.Framework.Scenes
2678 client.OnFetchInventory += HandleFetchInventory; 2784 client.OnFetchInventory += HandleFetchInventory;
2679 client.OnUpdateInventoryItem += UpdateInventoryItemAsset; 2785 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2680 client.OnCopyInventoryItem += CopyInventoryItem; 2786 client.OnCopyInventoryItem += CopyInventoryItem;
2787 client.OnMoveItemsAndLeaveCopy += MoveInventoryItemsLeaveCopy;
2681 client.OnMoveInventoryItem += MoveInventoryItem; 2788 client.OnMoveInventoryItem += MoveInventoryItem;
2682 client.OnRemoveInventoryItem += RemoveInventoryItem; 2789 client.OnRemoveInventoryItem += RemoveInventoryItem;
2683 client.OnRemoveInventoryFolder += RemoveInventoryFolder; 2790 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
@@ -2856,15 +2963,16 @@ namespace OpenSim.Region.Framework.Scenes
2856 /// </summary> 2963 /// </summary>
2857 /// <param name="agentId">The avatar's Unique ID</param> 2964 /// <param name="agentId">The avatar's Unique ID</param>
2858 /// <param name="client">The IClientAPI for the client</param> 2965 /// <param name="client">The IClientAPI for the client</param>
2859 public virtual void TeleportClientHome(UUID agentId, IClientAPI client) 2966 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
2860 { 2967 {
2861 if (m_teleportModule != null) 2968 if (m_teleportModule != null)
2862 m_teleportModule.TeleportHome(agentId, client); 2969 return m_teleportModule.TeleportHome(agentId, client);
2863 else 2970 else
2864 { 2971 {
2865 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 2972 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
2866 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 2973 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
2867 } 2974 }
2975 return false;
2868 } 2976 }
2869 2977
2870 /// <summary> 2978 /// <summary>
@@ -2963,6 +3071,16 @@ namespace OpenSim.Region.Framework.Scenes
2963 /// <param name="flags"></param> 3071 /// <param name="flags"></param>
2964 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) 3072 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2965 { 3073 {
3074 //Add half the avatar's height so that the user doesn't fall through prims
3075 ScenePresence presence;
3076 if (TryGetScenePresence(remoteClient.AgentId, out presence))
3077 {
3078 if (presence.Appearance != null)
3079 {
3080 position.Z = position.Z + (presence.Appearance.AvatarHeight / 2);
3081 }
3082 }
3083
2966 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) 3084 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
2967 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. 3085 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2968 m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); 3086 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
@@ -3039,7 +3157,9 @@ namespace OpenSim.Region.Framework.Scenes
3039 regions.Remove(RegionInfo.RegionHandle); 3157 regions.Remove(RegionInfo.RegionHandle);
3040 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3158 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3041 } 3159 }
3160 m_log.Debug("[Scene] Beginning ClientClosed");
3042 m_eventManager.TriggerClientClosed(agentID, this); 3161 m_eventManager.TriggerClientClosed(agentID, this);
3162 m_log.Debug("[Scene] Finished ClientClosed");
3043 } 3163 }
3044 catch (NullReferenceException) 3164 catch (NullReferenceException)
3045 { 3165 {
@@ -3047,7 +3167,12 @@ namespace OpenSim.Region.Framework.Scenes
3047 // Avatar is already disposed :/ 3167 // Avatar is already disposed :/
3048 } 3168 }
3049 3169
3170 m_log.Debug("[Scene] Beginning OnRemovePresence");
3050 m_eventManager.TriggerOnRemovePresence(agentID); 3171 m_eventManager.TriggerOnRemovePresence(agentID);
3172 m_log.Debug("[Scene] Finished OnRemovePresence");
3173
3174 if (avatar != null && (!avatar.IsChildAgent))
3175 avatar.SaveChangedAttachments();
3051 3176
3052 if (avatar != null && (!avatar.IsChildAgent)) 3177 if (avatar != null && (!avatar.IsChildAgent))
3053 avatar.SaveChangedAttachments(); 3178 avatar.SaveChangedAttachments();
@@ -3056,7 +3181,7 @@ namespace OpenSim.Region.Framework.Scenes
3056 delegate(IClientAPI client) 3181 delegate(IClientAPI client)
3057 { 3182 {
3058 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway 3183 //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway
3059 try { client.SendKillObject(avatar.RegionHandle, avatar.LocalId); } 3184 try { client.SendKillObject(avatar.RegionHandle, new List<uint>() { avatar.LocalId}); }
3060 catch (NullReferenceException) { } 3185 catch (NullReferenceException) { }
3061 }); 3186 });
3062 3187
@@ -3067,8 +3192,11 @@ namespace OpenSim.Region.Framework.Scenes
3067 } 3192 }
3068 3193
3069 // Remove the avatar from the scene 3194 // Remove the avatar from the scene
3195 m_log.Debug("[Scene] Begin RemoveScenePresence");
3070 m_sceneGraph.RemoveScenePresence(agentID); 3196 m_sceneGraph.RemoveScenePresence(agentID);
3197 m_log.Debug("[Scene] Finished RemoveScenePresence. Removing the client manager");
3071 m_clientManager.Remove(agentID); 3198 m_clientManager.Remove(agentID);
3199 m_log.Debug("[Scene] Removed the client manager. Firing avatar.close");
3072 3200
3073 try 3201 try
3074 { 3202 {
@@ -3082,9 +3210,10 @@ namespace OpenSim.Region.Framework.Scenes
3082 { 3210 {
3083 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString()); 3211 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString());
3084 } 3212 }
3085 3213 m_log.Debug("[Scene] Done. Firing RemoveCircuit");
3086 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3214 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
3087 CleanDroppedAttachments(); 3215 CleanDroppedAttachments();
3216 m_log.Debug("[Scene] The avatar has left the building");
3088 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 3217 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3089 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); 3218 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3090 } 3219 }
@@ -3115,18 +3244,24 @@ namespace OpenSim.Region.Framework.Scenes
3115 3244
3116 #region Entities 3245 #region Entities
3117 3246
3118 public void SendKillObject(uint localID) 3247 public void SendKillObject(List<uint> localIDs)
3119 { 3248 {
3120 SceneObjectPart part = GetSceneObjectPart(localID); 3249 List<uint> deleteIDs = new List<uint>();
3121 if (part != null) // It is a prim 3250
3251 foreach (uint localID in localIDs)
3122 { 3252 {
3123 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid 3253 SceneObjectPart part = GetSceneObjectPart(localID);
3254 if (part != null) // It is a prim
3124 { 3255 {
3125 if (part.ParentGroup.RootPart != part) // Child part 3256 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
3126 return; 3257 {
3258 if (part.ParentGroup.RootPart != part) // Child part
3259 continue;
3260 }
3127 } 3261 }
3262 deleteIDs.Add(localID);
3128 } 3263 }
3129 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); 3264 ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); });
3130 } 3265 }
3131 3266
3132 #endregion 3267 #endregion
@@ -3144,7 +3279,6 @@ namespace OpenSim.Region.Framework.Scenes
3144 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate; 3279 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
3145 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar; 3280 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar;
3146 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid; 3281 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid;
3147 m_sceneGridService.KiPrimitive += SendKillObject;
3148 m_sceneGridService.OnGetLandData += GetLandData; 3282 m_sceneGridService.OnGetLandData += GetLandData;
3149 } 3283 }
3150 3284
@@ -3153,7 +3287,6 @@ namespace OpenSim.Region.Framework.Scenes
3153 /// </summary> 3287 /// </summary>
3154 public void UnRegisterRegionWithComms() 3288 public void UnRegisterRegionWithComms()
3155 { 3289 {
3156 m_sceneGridService.KiPrimitive -= SendKillObject;
3157 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid; 3290 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid;
3158 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar; 3291 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar;
3159 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate; 3292 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
@@ -3233,13 +3366,16 @@ namespace OpenSim.Region.Framework.Scenes
3233 sp = null; 3366 sp = null;
3234 } 3367 }
3235 3368
3236 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3237 3369
3238 //On login test land permisions 3370 //On login test land permisions
3239 if (vialogin) 3371 if (vialogin)
3240 { 3372 {
3241 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3373 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
3374 if (cache != null)
3375 cache.Remove(agent.firstname + " " + agent.lastname);
3376 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3242 { 3377 {
3378 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3243 return false; 3379 return false;
3244 } 3380 }
3245 } 3381 }
@@ -3262,8 +3398,13 @@ namespace OpenSim.Region.Framework.Scenes
3262 3398
3263 try 3399 try
3264 { 3400 {
3265 if (!AuthorizeUser(agent, out reason)) 3401 // Always check estate if this is a login. Always
3266 return false; 3402 // check if banned regions are to be blacked out.
3403 if (vialogin || (!m_seeIntoBannedRegion))
3404 {
3405 if (!AuthorizeUser(agent.AgentID, out reason))
3406 return false;
3407 }
3267 } 3408 }
3268 catch (Exception e) 3409 catch (Exception e)
3269 { 3410 {
@@ -3366,6 +3507,8 @@ namespace OpenSim.Region.Framework.Scenes
3366 } 3507 }
3367 } 3508 }
3368 // Honor parcel landing type and position. 3509 // Honor parcel landing type and position.
3510 /*
3511 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3369 if (land != null) 3512 if (land != null)
3370 { 3513 {
3371 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3514 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
@@ -3373,26 +3516,34 @@ namespace OpenSim.Region.Framework.Scenes
3373 agent.startpos = land.LandData.UserLocation; 3516 agent.startpos = land.LandData.UserLocation;
3374 } 3517 }
3375 } 3518 }
3519 */// This is now handled properly in ScenePresence.MakeRootAgent
3376 } 3520 }
3377 3521
3378 return true; 3522 return true;
3379 } 3523 }
3380 3524
3381 private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason) 3525 private bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
3382 { 3526 {
3383 3527 reason = String.Empty;
3384 bool banned = land.IsBannedFromLand(agent.AgentID); 3528 if (Permissions.IsGod(agentID))
3385 bool restricted = land.IsRestrictedFromLand(agent.AgentID); 3529 return true;
3530
3531 ILandObject land = LandChannel.GetLandObject(posX, posY);
3532 if (land == null)
3533 return false;
3534
3535 bool banned = land.IsBannedFromLand(agentID);
3536 bool restricted = land.IsRestrictedFromLand(agentID);
3386 3537
3387 if (banned || restricted) 3538 if (banned || restricted)
3388 { 3539 {
3389 ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y); 3540 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
3390 if (nearestParcel != null) 3541 if (nearestParcel != null)
3391 { 3542 {
3392 //Move agent to nearest allowed 3543 //Move agent to nearest allowed
3393 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); 3544 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
3394 agent.startpos.X = newPosition.X; 3545 posX = newPosition.X;
3395 agent.startpos.Y = newPosition.Y; 3546 posY = newPosition.Y;
3396 } 3547 }
3397 else 3548 else
3398 { 3549 {
@@ -3448,19 +3599,19 @@ namespace OpenSim.Region.Framework.Scenes
3448 /// <param name="reason">outputs the reason to this string</param> 3599 /// <param name="reason">outputs the reason to this string</param>
3449 /// <returns>True if the region accepts this agent. False if it does not. False will 3600 /// <returns>True if the region accepts this agent. False if it does not. False will
3450 /// also return a reason.</returns> 3601 /// also return a reason.</returns>
3451 protected virtual bool AuthorizeUser(AgentCircuitData agent, out string reason) 3602 protected virtual bool AuthorizeUser(UUID agentID, out string reason)
3452 { 3603 {
3453 reason = String.Empty; 3604 reason = String.Empty;
3454 3605
3455 if (!m_strictAccessControl) return true; 3606 if (!m_strictAccessControl) return true;
3456 if (Permissions.IsGod(agent.AgentID)) return true; 3607 if (Permissions.IsGod(agentID)) return true;
3457 3608
3458 if (AuthorizationService != null) 3609 if (AuthorizationService != null)
3459 { 3610 {
3460 if (!AuthorizationService.IsAuthorizedForRegion(agent.AgentID.ToString(), RegionInfo.RegionID.ToString(),out reason)) 3611 if (!AuthorizationService.IsAuthorizedForRegion(agentID.ToString(), RegionInfo.RegionID.ToString(),out reason))
3461 { 3612 {
3462 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region", 3613 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} at {1} because the user does not have access to the region",
3463 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3614 agentID, RegionInfo.RegionName);
3464 //reason = String.Format("You are not currently on the access list for {0}",RegionInfo.RegionName); 3615 //reason = String.Format("You are not currently on the access list for {0}",RegionInfo.RegionName);
3465 return false; 3616 return false;
3466 } 3617 }
@@ -3468,10 +3619,26 @@ namespace OpenSim.Region.Framework.Scenes
3468 3619
3469 if (m_regInfo.EstateSettings != null) 3620 if (m_regInfo.EstateSettings != null)
3470 { 3621 {
3471 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID)) 3622 int flags = GetUserFlags(agentID);
3623 if (m_regInfo.EstateSettings.IsBanned(agentID, flags))
3472 { 3624 {
3473 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", 3625 //Add some more info to help users
3474 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3626 if (!m_regInfo.EstateSettings.IsBanned(agentID, 32))
3627 {
3628 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} at {1} because the region requires age verification",
3629 agentID, RegionInfo.RegionName);
3630 reason = String.Format("Denied access to region {0}: Region requires age verification", RegionInfo.RegionName);
3631 return false;
3632 }
3633 if (!m_regInfo.EstateSettings.IsBanned(agentID, 4))
3634 {
3635 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} {1} because the region requires payment info on file",
3636 agentID, RegionInfo.RegionName);
3637 reason = String.Format("Denied access to region {0}: Region requires payment info on file", RegionInfo.RegionName);
3638 return false;
3639 }
3640 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} at {3} because the user is on the banlist",
3641 agentID, RegionInfo.RegionName);
3475 reason = String.Format("Denied access to region {0}: You have been banned from that region.", 3642 reason = String.Format("Denied access to region {0}: You have been banned from that region.",
3476 RegionInfo.RegionName); 3643 RegionInfo.RegionName);
3477 return false; 3644 return false;
@@ -3488,7 +3655,7 @@ namespace OpenSim.Region.Framework.Scenes
3488 if (groupsModule != null) 3655 if (groupsModule != null)
3489 { 3656 {
3490 GroupMembershipData[] GroupMembership = 3657 GroupMembershipData[] GroupMembership =
3491 groupsModule.GetMembershipData(agent.AgentID); 3658 groupsModule.GetMembershipData(agentID);
3492 3659
3493 if (GroupMembership != null) 3660 if (GroupMembership != null)
3494 { 3661 {
@@ -3517,44 +3684,16 @@ namespace OpenSim.Region.Framework.Scenes
3517 m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); 3684 m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!");
3518 3685
3519 if (!m_regInfo.EstateSettings.PublicAccess && 3686 if (!m_regInfo.EstateSettings.PublicAccess &&
3520 !m_regInfo.EstateSettings.HasAccess(agent.AgentID) && 3687 !m_regInfo.EstateSettings.HasAccess(agentID) &&
3521 !groupAccess) 3688 !groupAccess)
3522 { 3689 {
3523 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", 3690 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} at {1} because the user does not have access to the estate",
3524 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3691 agentID, RegionInfo.RegionName);
3525 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.", 3692 reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
3526 RegionInfo.RegionName); 3693 RegionInfo.RegionName);
3527 return false; 3694 return false;
3528 } 3695 }
3529 3696
3530 // TODO: estate/region settings are not properly hooked up
3531 // to ILandObject.isRestrictedFromLand()
3532 // if (null != LandChannel)
3533 // {
3534 // // region seems to have local Id of 1
3535 // ILandObject land = LandChannel.GetLandObject(1);
3536 // if (null != land)
3537 // {
3538 // if (land.isBannedFromLand(agent.AgentID))
3539 // {
3540 // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user has been banned from land",
3541 // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
3542 // reason = String.Format("Denied access to private region {0}: You are banned from that region.",
3543 // RegionInfo.RegionName);
3544 // return false;
3545 // }
3546
3547 // if (land.isRestrictedFromLand(agent.AgentID))
3548 // {
3549 // m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region",
3550 // agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
3551 // reason = String.Format("Denied access to private region {0}: You are not on the access list for that region.",
3552 // RegionInfo.RegionName);
3553 // return false;
3554 // }
3555 // }
3556 // }
3557
3558 return true; 3697 return true;
3559 } 3698 }
3560 3699
@@ -3658,6 +3797,13 @@ namespace OpenSim.Region.Framework.Scenes
3658 3797
3659 // We have to wait until the viewer contacts this region after receiving EAC. 3798 // We have to wait until the viewer contacts this region after receiving EAC.
3660 // That calls AddNewClient, which finally creates the ScenePresence 3799 // That calls AddNewClient, which finally creates the ScenePresence
3800 int flags = GetUserFlags(cAgentData.AgentID);
3801 if (m_regInfo.EstateSettings.IsBanned(cAgentData.AgentID, flags))
3802 {
3803 m_log.DebugFormat("[SCENE]: Denying root agent entry to {0}: banned", cAgentData.AgentID);
3804 return false;
3805 }
3806
3661 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); 3807 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
3662 if (nearestParcel == null) 3808 if (nearestParcel == null)
3663 { 3809 {
@@ -3665,6 +3811,14 @@ namespace OpenSim.Region.Framework.Scenes
3665 return false; 3811 return false;
3666 } 3812 }
3667 3813
3814 int num = m_sceneGraph.GetNumberOfScenePresences();
3815
3816 if (num >= RegionInfo.RegionSettings.AgentLimit)
3817 {
3818 if (!Permissions.IsAdministrator(cAgentData.AgentID))
3819 return false;
3820 }
3821
3668 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); 3822 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
3669 3823
3670 if (childAgentUpdate != null) 3824 if (childAgentUpdate != null)
@@ -3731,12 +3885,22 @@ namespace OpenSim.Region.Framework.Scenes
3731 return false; 3885 return false;
3732 } 3886 }
3733 3887
3888 public bool IncomingCloseAgent(UUID agentID)
3889 {
3890 return IncomingCloseAgent(agentID, false);
3891 }
3892
3893 public bool IncomingCloseChildAgent(UUID agentID)
3894 {
3895 return IncomingCloseAgent(agentID, true);
3896 }
3897
3734 /// <summary> 3898 /// <summary>
3735 /// Tell a single agent to disconnect from the region. 3899 /// Tell a single agent to disconnect from the region.
3736 /// </summary> 3900 /// </summary>
3737 /// <param name="regionHandle"></param>
3738 /// <param name="agentID"></param> 3901 /// <param name="agentID"></param>
3739 public bool IncomingCloseAgent(UUID agentID) 3902 /// <param name="childOnly"></param>
3903 public bool IncomingCloseAgent(UUID agentID, bool childOnly)
3740 { 3904 {
3741 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 3905 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
3742 3906
@@ -3748,7 +3912,7 @@ namespace OpenSim.Region.Framework.Scenes
3748 { 3912 {
3749 m_sceneGraph.removeUserCount(false); 3913 m_sceneGraph.removeUserCount(false);
3750 } 3914 }
3751 else 3915 else if (!childOnly)
3752 { 3916 {
3753 m_sceneGraph.removeUserCount(true); 3917 m_sceneGraph.removeUserCount(true);
3754 } 3918 }
@@ -3764,9 +3928,12 @@ namespace OpenSim.Region.Framework.Scenes
3764 } 3928 }
3765 else 3929 else
3766 presence.ControllingClient.SendShutdownConnectionNotice(); 3930 presence.ControllingClient.SendShutdownConnectionNotice();
3931 presence.ControllingClient.Close(false);
3932 }
3933 else if (!childOnly)
3934 {
3935 presence.ControllingClient.Close(true);
3767 } 3936 }
3768
3769 presence.ControllingClient.Close();
3770 return true; 3937 return true;
3771 } 3938 }
3772 3939
@@ -4376,34 +4543,66 @@ namespace OpenSim.Region.Framework.Scenes
4376 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID); 4543 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID);
4377 } 4544 }
4378 4545
4379 public int GetHealth() 4546 public int GetHealth(out int flags, out string message)
4380 { 4547 {
4381 // Returns: 4548 // Returns:
4382 // 1 = sim is up and accepting http requests. The heartbeat has 4549 // 1 = sim is up and accepting http requests. The heartbeat has
4383 // stopped and the sim is probably locked up, but a remote 4550 // stopped and the sim is probably locked up, but a remote
4384 // admin restart may succeed 4551 // admin restart may succeed
4385 // 4552 //
4386 // 2 = Sim is up and the heartbeat is running. The sim is likely 4553 // 2 = Sim is up and the heartbeat is running. The sim is likely
4387 // usable for people within and logins _may_ work 4554 // usable for people within
4388 // 4555 //
4389 // 3 = We have seen a new user enter within the past 4 minutes 4556 // 3 = Sim is up and one packet thread is running. Sim is
4557 // unstable and will not accept new logins
4558 //
4559 // 4 = Sim is up and both packet threads are running. Sim is
4560 // likely usable
4561 //
4562 // 5 = We have seen a new user enter within the past 4 minutes
4390 // which can be seen as positive confirmation of sim health 4563 // which can be seen as positive confirmation of sim health
4391 // 4564 //
4565
4566 flags = 0;
4567 message = String.Empty;
4568
4569 CheckHeartbeat();
4570
4571 if (m_firstHeartbeat || (m_lastIncoming == 0 && m_lastOutgoing == 0))
4572 {
4573 // We're still starting
4574 // 0 means "in startup", it can't happen another way, since
4575 // to get here, we must be able to accept http connections
4576 return 0;
4577 }
4578
4392 int health=1; // Start at 1, means we're up 4579 int health=1; // Start at 1, means we're up
4393 4580
4394 if ((Util.EnvironmentTickCountSubtract(m_lastUpdate)) < 1000) 4581 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) < 1000)
4582 {
4395 health+=1; 4583 health+=1;
4396 else 4584 flags |= 1;
4585 }
4586
4587 if (Util.EnvironmentTickCountSubtract(m_lastIncoming) < 1000)
4588 {
4589 health+=1;
4590 flags |= 2;
4591 }
4592
4593 if (Util.EnvironmentTickCountSubtract(m_lastOutgoing) < 1000)
4594 {
4595 health+=1;
4596 flags |= 4;
4597 }
4598
4599 if (flags != 7)
4397 return health; 4600 return health;
4398 4601
4399 // A login in the last 4 mins? We can't be doing too badly 4602 // A login in the last 4 mins? We can't be doing too badly
4400 // 4603 //
4401 if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000) 4604 if (Util.EnvironmentTickCountSubtract(m_LastLogin) < 240000)
4402 health++; 4605 health++;
4403 else
4404 return health;
4405
4406 CheckHeartbeat();
4407 4606
4408 return health; 4607 return health;
4409 } 4608 }
@@ -4596,7 +4795,7 @@ namespace OpenSim.Region.Framework.Scenes
4596 if (m_firstHeartbeat) 4795 if (m_firstHeartbeat)
4597 return; 4796 return;
4598 4797
4599 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) > 2000) 4798 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) > 10000)
4600 StartTimer(); 4799 StartTimer();
4601 } 4800 }
4602 4801
@@ -4934,10 +5133,28 @@ namespace OpenSim.Region.Framework.Scenes
4934 }); 5133 });
4935 } 5134 }
4936 5135
4937 foreach (SceneObjectGroup grp in objectsToDelete) 5136 if (objectsToDelete.Count > 0)
4938 { 5137 {
4939 m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID); 5138 m_log.DebugFormat("[SCENE]: Starting delete of {0} dropped attachments", objectsToDelete.Count);
4940 DeleteSceneObject(grp, true); 5139 foreach (SceneObjectGroup grp in objectsToDelete)
5140 {
5141 m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID);
5142 DeleteSceneObject(grp, true);
5143 }
5144 m_log.Debug("[SCENE]: Finished dropped attachment deletion");
5145 }
5146 }
5147
5148 public void ThreadAlive(int threadCode)
5149 {
5150 switch(threadCode)
5151 {
5152 case 1: // Incoming
5153 m_lastIncoming = Util.EnvironmentTickCount();
5154 break;
5155 case 2: // Incoming
5156 m_lastOutgoing = Util.EnvironmentTickCount();
5157 break;
4941 } 5158 }
4942 } 5159 }
4943 5160
@@ -4949,6 +5166,44 @@ namespace OpenSim.Region.Framework.Scenes
4949 // child agent creation, thereby emulating the SL behavior. 5166 // child agent creation, thereby emulating the SL behavior.
4950 public bool QueryAccess(UUID agentID, Vector3 position, out string reason) 5167 public bool QueryAccess(UUID agentID, Vector3 position, out string reason)
4951 { 5168 {
5169 reason = "You are banned from the region";
5170
5171 if (Permissions.IsGod(agentID))
5172 {
5173 reason = String.Empty;
5174 return true;
5175 }
5176
5177 if (!AuthorizeUser(agentID, out reason))
5178 {
5179 // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5180 return false;
5181 }
5182
5183 if (position == Vector3.Zero) // Teleport
5184 {
5185 float posX = 128.0f;
5186 float posY = 128.0f;
5187
5188 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5189 {
5190 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5191 return false;
5192 }
5193 }
5194 else // Walking
5195 {
5196 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5197 if (land == null)
5198 return false;
5199
5200 bool banned = land.IsBannedFromLand(agentID);
5201 bool restricted = land.IsRestrictedFromLand(agentID);
5202
5203 if (banned || restricted)
5204 return false;
5205 }
5206
4952 reason = String.Empty; 5207 reason = String.Empty;
4953 return true; 5208 return true;
4954 } 5209 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index c4547f2..f343bc8 100644
--- a/OpenSim/Region/Framework/Scenes/SceneBase.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -136,6 +136,8 @@ namespace OpenSim.Region.Framework.Scenes
136 get { return m_permissions; } 136 get { return m_permissions; }
137 } 137 }
138 138
139 protected string m_datastore;
140
139 /* Used by the loadbalancer plugin on GForge */ 141 /* Used by the loadbalancer plugin on GForge */
140 protected RegionStatus m_regStatus; 142 protected RegionStatus m_regStatus;
141 public RegionStatus RegionStatus 143 public RegionStatus RegionStatus
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 837e655..19cb0c1 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;
@@ -259,46 +255,42 @@ namespace OpenSim.Region.Framework.Scenes
259 255
260 } 256 }
261 257
262 //public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle); 258 public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle);
263 //private void SendCloseChildAgentCompleted(IAsyncResult iar)
264 //{
265 // SendCloseChildAgentDelegate icon = (SendCloseChildAgentDelegate)iar.AsyncState;
266 // icon.EndInvoke(iar);
267 //}
268 259
269 /// <summary> 260 /// <summary>
270 /// Closes a child agent on a given region 261 /// This Closes child agents on neighboring regions
262 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
271 /// </summary> 263 /// </summary>
272 protected void SendCloseChildAgent(UUID agentID, ulong regionHandle) 264 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
273 { 265 {
274 266
275 m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle); 267 //m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
276 // let's do our best, but there's not much we can do if the neighbour doesn't accept. 268 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
277 269
278 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); 270 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
279 uint x = 0, y = 0; 271 uint x = 0, y = 0;
280 Utils.LongToUInts(regionHandle, out x, out y); 272 Utils.LongToUInts(regionHandle, out x, out y);
281 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 273 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
282 m_scene.SimulationService.CloseAgent(destination, agentID); 274 m_scene.SimulationService.CloseChildAgent(destination, agentID);
275 }
276
277 private void SendCloseChildAgentCompleted(IAsyncResult iar)
278 {
279 SendCloseChildAgentDelegate icon = (SendCloseChildAgentDelegate)iar.AsyncState;
280 icon.EndInvoke(iar);
283 } 281 }
284 282
285 /// <summary>
286 /// Closes a child agents in a collection of regions. Does so asynchronously
287 /// so that the caller doesn't wait.
288 /// </summary>
289 /// <param name="agentID"></param>
290 /// <param name="regionslst"></param>
291 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst) 283 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst)
292 { 284 {
293 Util.FireAndForget(delegate 285 foreach (ulong handle in regionslst)
294 { 286 {
295 foreach (ulong handle in regionslst) 287 SendCloseChildAgentDelegate d = SendCloseChildAgentAsync;
296 { 288 d.BeginInvoke(agentID, handle,
297 SendCloseChildAgent(agentID, handle); 289 SendCloseChildAgentCompleted,
298 } 290 d);
299 }); 291 }
300 } 292 }
301 293
302 public List<GridRegion> RequestNamedRegions(string name, int maxNumber) 294 public List<GridRegion> RequestNamedRegions(string name, int maxNumber)
303 { 295 {
304 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); 296 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 97af0a0..6773e08 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
@@ -135,13 +144,18 @@ namespace OpenSim.Region.Framework.Scenes
135 144
136 protected internal void Close() 145 protected internal void Close()
137 { 146 {
138 lock (m_presenceLock) 147 m_scenePresencesLock.EnterWriteLock();
148 try
139 { 149 {
140 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); 150 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
141 List<ScenePresence> newlist = new List<ScenePresence>(); 151 List<ScenePresence> newlist = new List<ScenePresence>();
142 m_scenePresenceMap = newmap; 152 m_scenePresenceMap = newmap;
143 m_scenePresenceArray = newlist; 153 m_scenePresenceArray = newlist;
144 } 154 }
155 finally
156 {
157 m_scenePresencesLock.ExitWriteLock();
158 }
145 159
146 lock (SceneObjectGroupsByFullID) 160 lock (SceneObjectGroupsByFullID)
147 SceneObjectGroupsByFullID.Clear(); 161 SceneObjectGroupsByFullID.Clear();
@@ -273,6 +287,33 @@ namespace OpenSim.Region.Framework.Scenes
273 protected internal bool AddRestoredSceneObject( 287 protected internal bool AddRestoredSceneObject(
274 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 288 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
275 { 289 {
290 if (!m_parentScene.CombineRegions)
291 {
292 // KF: Check for out-of-region, move inside and make static.
293 Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
294 sceneObject.RootPart.GroupPosition.Y,
295 sceneObject.RootPart.GroupPosition.Z);
296 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 ||
297 npos.X > Constants.RegionSize ||
298 npos.Y > Constants.RegionSize))
299 {
300 if (npos.X < 0.0) npos.X = 1.0f;
301 if (npos.Y < 0.0) npos.Y = 1.0f;
302 if (npos.Z < 0.0) npos.Z = 0.0f;
303 if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f;
304 if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f;
305
306 foreach (SceneObjectPart part in sceneObject.Parts)
307 {
308 part.GroupPosition = npos;
309 }
310 sceneObject.RootPart.Velocity = Vector3.Zero;
311 sceneObject.RootPart.AngularVelocity = Vector3.Zero;
312 sceneObject.RootPart.Acceleration = Vector3.Zero;
313 sceneObject.RootPart.Velocity = Vector3.Zero;
314 }
315 }
316
276 if (attachToBackup && (!alreadyPersisted)) 317 if (attachToBackup && (!alreadyPersisted))
277 { 318 {
278 sceneObject.ForceInventoryPersistence(); 319 sceneObject.ForceInventoryPersistence();
@@ -482,6 +523,30 @@ namespace OpenSim.Region.Framework.Scenes
482 m_updateList[obj.UUID] = obj; 523 m_updateList[obj.UUID] = obj;
483 } 524 }
484 525
526 public void FireAttachToBackup(SceneObjectGroup obj)
527 {
528 if (OnAttachToBackup != null)
529 {
530 OnAttachToBackup(obj);
531 }
532 }
533
534 public void FireDetachFromBackup(SceneObjectGroup obj)
535 {
536 if (OnDetachFromBackup != null)
537 {
538 OnDetachFromBackup(obj);
539 }
540 }
541
542 public void FireChangeBackup(SceneObjectGroup obj)
543 {
544 if (OnChangeBackup != null)
545 {
546 OnChangeBackup(obj);
547 }
548 }
549
485 /// <summary> 550 /// <summary>
486 /// Process all pending updates 551 /// Process all pending updates
487 /// </summary> 552 /// </summary>
@@ -617,7 +682,8 @@ namespace OpenSim.Region.Framework.Scenes
617 682
618 Entities[presence.UUID] = presence; 683 Entities[presence.UUID] = presence;
619 684
620 lock (m_presenceLock) 685 m_scenePresencesLock.EnterWriteLock();
686 try
621 { 687 {
622 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 688 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
623 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 689 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -641,6 +707,10 @@ namespace OpenSim.Region.Framework.Scenes
641 m_scenePresenceMap = newmap; 707 m_scenePresenceMap = newmap;
642 m_scenePresenceArray = newlist; 708 m_scenePresenceArray = newlist;
643 } 709 }
710 finally
711 {
712 m_scenePresencesLock.ExitWriteLock();
713 }
644 } 714 }
645 715
646 /// <summary> 716 /// <summary>
@@ -655,7 +725,8 @@ namespace OpenSim.Region.Framework.Scenes
655 agentID); 725 agentID);
656 } 726 }
657 727
658 lock (m_presenceLock) 728 m_scenePresencesLock.EnterWriteLock();
729 try
659 { 730 {
660 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 731 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
661 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 732 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -677,6 +748,10 @@ namespace OpenSim.Region.Framework.Scenes
677 m_log.WarnFormat("[SCENEGRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); 748 m_log.WarnFormat("[SCENEGRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
678 } 749 }
679 } 750 }
751 finally
752 {
753 m_scenePresencesLock.ExitWriteLock();
754 }
680 } 755 }
681 756
682 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) 757 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
@@ -800,6 +875,11 @@ namespace OpenSim.Region.Framework.Scenes
800 return m_scenePresenceArray; 875 return m_scenePresenceArray;
801 } 876 }
802 877
878 public int GetNumberOfScenePresences()
879 {
880 return m_scenePresenceArray.Count;
881 }
882
803 /// <summary> 883 /// <summary>
804 /// Request a scene presence by UUID. Fast, indexed lookup. 884 /// Request a scene presence by UUID. Fast, indexed lookup.
805 /// </summary> 885 /// </summary>
@@ -1307,8 +1387,13 @@ namespace OpenSim.Region.Framework.Scenes
1307 { 1387 {
1308 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1388 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1309 { 1389 {
1310 if (m_parentScene.AttachmentsModule != null) 1390 // Set the new attachment point data in the object
1311 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1391 byte attachmentPoint = group.GetAttachmentPoint();
1392 group.UpdateGroupPosition(pos);
1393 group.RootPart.IsAttachment = false;
1394 group.AbsolutePosition = group.RootPart.AttachedPos;
1395 group.SetAttachmentPoint(attachmentPoint);
1396 group.HasGroupChanged = true;
1312 } 1397 }
1313 else 1398 else
1314 { 1399 {
@@ -1552,10 +1637,13 @@ namespace OpenSim.Region.Framework.Scenes
1552 /// <param name="childPrims"></param> 1637 /// <param name="childPrims"></param>
1553 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children) 1638 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1554 { 1639 {
1640 SceneObjectGroup parentGroup = root.ParentGroup;
1641 if (parentGroup == null) return;
1555 Monitor.Enter(m_updateLock); 1642 Monitor.Enter(m_updateLock);
1643
1556 try 1644 try
1557 { 1645 {
1558 SceneObjectGroup parentGroup = root.ParentGroup; 1646 parentGroup.areUpdatesSuspended = true;
1559 1647
1560 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1648 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1561 if (parentGroup != null) 1649 if (parentGroup != null)
@@ -1567,11 +1655,6 @@ namespace OpenSim.Region.Framework.Scenes
1567 1655
1568 if (child != null) 1656 if (child != null)
1569 { 1657 {
1570 // Make sure no child prim is set for sale
1571 // So that, on delink, no prims are unwittingly
1572 // left for sale and sold off
1573 child.RootPart.ObjectSaleType = 0;
1574 child.RootPart.SalePrice = 10;
1575 childGroups.Add(child); 1658 childGroups.Add(child);
1576 } 1659 }
1577 } 1660 }
@@ -1594,12 +1677,13 @@ namespace OpenSim.Region.Framework.Scenes
1594 // occur on link to invoke this elsewhere (such as object selection) 1677 // occur on link to invoke this elsewhere (such as object selection)
1595 parentGroup.RootPart.CreateSelected = true; 1678 parentGroup.RootPart.CreateSelected = true;
1596 parentGroup.TriggerScriptChangedEvent(Changed.LINK); 1679 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1597 parentGroup.HasGroupChanged = true;
1598 parentGroup.ScheduleGroupForFullUpdate();
1599
1600 } 1680 }
1601 finally 1681 finally
1602 { 1682 {
1683 parentGroup.areUpdatesSuspended = false;
1684 parentGroup.HasGroupChanged = true;
1685 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1686 parentGroup.ScheduleGroupForFullUpdate();
1603 Monitor.Exit(m_updateLock); 1687 Monitor.Exit(m_updateLock);
1604 } 1688 }
1605 } 1689 }
@@ -1631,21 +1715,24 @@ namespace OpenSim.Region.Framework.Scenes
1631 1715
1632 SceneObjectGroup group = part.ParentGroup; 1716 SceneObjectGroup group = part.ParentGroup;
1633 if (!affectedGroups.Contains(group)) 1717 if (!affectedGroups.Contains(group))
1718 {
1719 group.areUpdatesSuspended = true;
1634 affectedGroups.Add(group); 1720 affectedGroups.Add(group);
1721 }
1635 } 1722 }
1636 } 1723 }
1637 } 1724 }
1638 1725
1639 foreach (SceneObjectPart child in childParts) 1726 if (childParts.Count > 0)
1640 { 1727 {
1641 // Unlink all child parts from their groups 1728 foreach (SceneObjectPart child in childParts)
1642 // 1729 {
1643 child.ParentGroup.DelinkFromGroup(child, true); 1730 // Unlink all child parts from their groups
1644 1731 //
1645 // These are not in affected groups and will not be 1732 child.ParentGroup.DelinkFromGroup(child, true);
1646 // handled further. Do the honors here. 1733 child.ParentGroup.HasGroupChanged = true;
1647 child.ParentGroup.HasGroupChanged = true; 1734 child.ParentGroup.ScheduleGroupForFullUpdate();
1648 child.ParentGroup.ScheduleGroupForFullUpdate(); 1735 }
1649 } 1736 }
1650 1737
1651 foreach (SceneObjectPart root in rootParts) 1738 foreach (SceneObjectPart root in rootParts)
@@ -1655,56 +1742,68 @@ namespace OpenSim.Region.Framework.Scenes
1655 // However, editing linked parts and unlinking may be different 1742 // However, editing linked parts and unlinking may be different
1656 // 1743 //
1657 SceneObjectGroup group = root.ParentGroup; 1744 SceneObjectGroup group = root.ParentGroup;
1745 group.areUpdatesSuspended = true;
1658 1746
1659 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1747 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1660 int numChildren = newSet.Count; 1748 int numChildren = newSet.Count;
1661 1749
1750 if (numChildren == 1)
1751 break;
1752
1662 // If there are prims left in a link set, but the root is 1753 // If there are prims left in a link set, but the root is
1663 // slated for unlink, we need to do this 1754 // slated for unlink, we need to do this
1755 // Unlink the remaining set
1664 // 1756 //
1665 if (numChildren != 1) 1757 bool sendEventsToRemainder = true;
1666 { 1758 if (numChildren > 1)
1667 // Unlink the remaining set 1759 sendEventsToRemainder = false;
1668 //
1669 bool sendEventsToRemainder = true;
1670 if (numChildren > 1)
1671 sendEventsToRemainder = false;
1672 1760
1673 foreach (SceneObjectPart p in newSet) 1761 foreach (SceneObjectPart p in newSet)
1762 {
1763 if (p != group.RootPart)
1674 { 1764 {
1675 if (p != group.RootPart) 1765 group.DelinkFromGroup(p, sendEventsToRemainder);
1676 group.DelinkFromGroup(p, sendEventsToRemainder); 1766 if (numChildren > 2)
1767 {
1768 p.ParentGroup.areUpdatesSuspended = true;
1769 }
1770 else
1771 {
1772 p.ParentGroup.HasGroupChanged = true;
1773 p.ParentGroup.ScheduleGroupForFullUpdate();
1774 }
1677 } 1775 }
1776 }
1777
1778 // If there is more than one prim remaining, we
1779 // need to re-link
1780 //
1781 if (numChildren > 2)
1782 {
1783 // Remove old root
1784 //
1785 if (newSet.Contains(root))
1786 newSet.Remove(root);
1678 1787
1679 // If there is more than one prim remaining, we 1788 // Preserve link ordering
1680 // need to re-link
1681 // 1789 //
1682 if (numChildren > 2) 1790 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1683 { 1791 {
1684 // Remove old root 1792 return a.LinkNum.CompareTo(b.LinkNum);
1685 // 1793 });
1686 if (newSet.Contains(root))
1687 newSet.Remove(root);
1688
1689 // Preserve link ordering
1690 //
1691 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1692 {
1693 return a.LinkNum.CompareTo(b.LinkNum);
1694 });
1695 1794
1696 // Determine new root 1795 // Determine new root
1697 // 1796 //
1698 SceneObjectPart newRoot = newSet[0]; 1797 SceneObjectPart newRoot = newSet[0];
1699 newSet.RemoveAt(0); 1798 newSet.RemoveAt(0);
1700 1799
1701 foreach (SceneObjectPart newChild in newSet) 1800 foreach (SceneObjectPart newChild in newSet)
1702 newChild.UpdateFlag = 0; 1801 newChild.UpdateFlag = 0;
1703 1802
1704 LinkObjects(newRoot, newSet); 1803 newRoot.ParentGroup.areUpdatesSuspended = true;
1705 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1804 LinkObjects(newRoot, newSet);
1706 affectedGroups.Add(newRoot.ParentGroup); 1805 if (!affectedGroups.Contains(newRoot.ParentGroup))
1707 } 1806 affectedGroups.Add(newRoot.ParentGroup);
1708 } 1807 }
1709 } 1808 }
1710 1809
@@ -1712,8 +1811,14 @@ namespace OpenSim.Region.Framework.Scenes
1712 // 1811 //
1713 foreach (SceneObjectGroup g in affectedGroups) 1812 foreach (SceneObjectGroup g in affectedGroups)
1714 { 1813 {
1814 // Child prims that have been unlinked and deleted will
1815 // return unless the root is deleted. This will remove them
1816 // from the database. They will be rewritten immediately,
1817 // minus the rows for the unlinked child prims.
1818 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1715 g.TriggerScriptChangedEvent(Changed.LINK); 1819 g.TriggerScriptChangedEvent(Changed.LINK);
1716 g.HasGroupChanged = true; // Persist 1820 g.HasGroupChanged = true; // Persist
1821 g.areUpdatesSuspended = false;
1717 g.ScheduleGroupForFullUpdate(); 1822 g.ScheduleGroupForFullUpdate();
1718 } 1823 }
1719 } 1824 }
@@ -1831,9 +1936,6 @@ namespace OpenSim.Region.Framework.Scenes
1831 child.ApplyNextOwnerPermissions(); 1936 child.ApplyNextOwnerPermissions();
1832 } 1937 }
1833 } 1938 }
1834
1835 copy.RootPart.ObjectSaleType = 0;
1836 copy.RootPart.SalePrice = 10;
1837 } 1939 }
1838 1940
1839 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 1941 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index e8095c0..0b545c4 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();
@@ -376,6 +372,9 @@ namespace OpenSim.Region.Framework.Scenes
376 372
377 public void ResumeScripts() 373 public void ResumeScripts()
378 { 374 {
375 if (m_scene.RegionInfo.RegionSettings.DisableScripts)
376 return;
377
379 SceneObjectPart[] parts = m_parts.GetArray(); 378 SceneObjectPart[] parts = m_parts.GetArray();
380 for (int i = 0; i < parts.Length; i++) 379 for (int i = 0; i < parts.Length; i++)
381 parts[i].Inventory.ResumeScripts(); 380 parts[i].Inventory.ResumeScripts();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index ca7d9d9..759fc23 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
@@ -141,8 +193,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 193 return false;
142 if (m_scene.ShuttingDown) 194 if (m_scene.ShuttingDown)
143 return true; 195 return true;
196
197 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
198 {
199 m_maxPersistTime = m_scene.m_persistAfter;
200 m_minPersistTime = m_scene.m_dontPersistBefore;
201 }
202
144 long currentTime = DateTime.Now.Ticks; 203 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 204
205 if (timeLastChanged == 0) timeLastChanged = currentTime;
206 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
207
208 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 209 return true;
147 return false; 210 return false;
148 } 211 }
@@ -185,10 +248,10 @@ namespace OpenSim.Region.Framework.Scenes
185 248
186 private bool m_scriptListens_atTarget; 249 private bool m_scriptListens_atTarget;
187 private bool m_scriptListens_notAtTarget; 250 private bool m_scriptListens_notAtTarget;
188
189 private bool m_scriptListens_atRotTarget; 251 private bool m_scriptListens_atRotTarget;
190 private bool m_scriptListens_notAtRotTarget; 252 private bool m_scriptListens_notAtRotTarget;
191 253
254 public bool m_dupeInProgress = false;
192 internal Dictionary<UUID, string> m_savedScriptState; 255 internal Dictionary<UUID, string> m_savedScriptState;
193 256
194 #region Properties 257 #region Properties
@@ -228,7 +291,13 @@ namespace OpenSim.Region.Framework.Scenes
228 public virtual Quaternion Rotation 291 public virtual Quaternion Rotation
229 { 292 {
230 get { return m_rotation; } 293 get { return m_rotation; }
231 set { m_rotation = value; } 294 set {
295 foreach(SceneObjectPart p in m_parts.GetArray())
296 {
297 p.StoreUndoState(UndoType.STATE_GROUP_ROTATION);
298 }
299 m_rotation = value;
300 }
232 } 301 }
233 302
234 public Quaternion GroupRotation 303 public Quaternion GroupRotation
@@ -302,7 +371,11 @@ namespace OpenSim.Region.Framework.Scenes
302 { 371 {
303 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 372 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
304 } 373 }
305 374
375 foreach (SceneObjectPart part in m_parts.GetArray())
376 {
377 part.IgnoreUndoUpdate = true;
378 }
306 if (RootPart.GetStatusSandbox()) 379 if (RootPart.GetStatusSandbox())
307 { 380 {
308 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 381 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -313,10 +386,31 @@ namespace OpenSim.Region.Framework.Scenes
313 return; 386 return;
314 } 387 }
315 } 388 }
316
317 SceneObjectPart[] parts = m_parts.GetArray(); 389 SceneObjectPart[] parts = m_parts.GetArray();
318 for (int i = 0; i < parts.Length; i++) 390 foreach (SceneObjectPart part in parts)
319 parts[i].GroupPosition = val; 391 {
392 part.IgnoreUndoUpdate = false;
393 part.StoreUndoState(UndoType.STATE_GROUP_POSITION);
394 part.GroupPosition = val;
395 if (!m_dupeInProgress)
396 {
397 part.TriggerScriptChangedEvent(Changed.POSITION);
398 }
399 }
400 if (!m_dupeInProgress)
401 {
402 foreach (ScenePresence av in m_linkedAvatars)
403 {
404 SceneObjectPart p;
405 if (m_parts.TryGetValue(av.LinkedPrim, out p))
406 {
407 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
408 av.AbsolutePosition += offset;
409 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
410 av.SendAvatarDataToAllAgents();
411 }
412 }
413 }
320 414
321 //if (m_rootPart.PhysActor != null) 415 //if (m_rootPart.PhysActor != null)
322 //{ 416 //{
@@ -469,6 +563,7 @@ namespace OpenSim.Region.Framework.Scenes
469 /// </summary> 563 /// </summary>
470 public SceneObjectGroup() 564 public SceneObjectGroup()
471 { 565 {
566
472 } 567 }
473 568
474 /// <summary> 569 /// <summary>
@@ -485,7 +580,7 @@ namespace OpenSim.Region.Framework.Scenes
485 /// Constructor. This object is added to the scene later via AttachToScene() 580 /// Constructor. This object is added to the scene later via AttachToScene()
486 /// </summary> 581 /// </summary>
487 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 582 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
488 { 583 {
489 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 584 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
490 } 585 }
491 586
@@ -533,6 +628,9 @@ namespace OpenSim.Region.Framework.Scenes
533 /// </summary> 628 /// </summary>
534 public virtual void AttachToBackup() 629 public virtual void AttachToBackup()
535 { 630 {
631 if (IsAttachment) return;
632 m_scene.SceneGraph.FireAttachToBackup(this);
633
536 if (InSceneBackup) 634 if (InSceneBackup)
537 { 635 {
538 //m_log.DebugFormat( 636 //m_log.DebugFormat(
@@ -648,9 +746,9 @@ namespace OpenSim.Region.Framework.Scenes
648 result.normal = inter.normal; 746 result.normal = inter.normal;
649 result.distance = inter.distance; 747 result.distance = inter.distance;
650 } 748 }
749
651 } 750 }
652 } 751 }
653
654 return result; 752 return result;
655 } 753 }
656 754
@@ -670,17 +768,19 @@ namespace OpenSim.Region.Framework.Scenes
670 minZ = 8192f; 768 minZ = 8192f;
671 769
672 SceneObjectPart[] parts = m_parts.GetArray(); 770 SceneObjectPart[] parts = m_parts.GetArray();
673 for (int i = 0; i < parts.Length; i++) 771 foreach (SceneObjectPart part in parts)
674 { 772 {
675 SceneObjectPart part = parts[i];
676
677 Vector3 worldPos = part.GetWorldPosition(); 773 Vector3 worldPos = part.GetWorldPosition();
678 Vector3 offset = worldPos - AbsolutePosition; 774 Vector3 offset = worldPos - AbsolutePosition;
679 Quaternion worldRot; 775 Quaternion worldRot;
680 if (part.ParentID == 0) 776 if (part.ParentID == 0)
777 {
681 worldRot = part.RotationOffset; 778 worldRot = part.RotationOffset;
779 }
682 else 780 else
781 {
683 worldRot = part.GetWorldRotation(); 782 worldRot = part.GetWorldRotation();
783 }
684 784
685 Vector3 frontTopLeft; 785 Vector3 frontTopLeft;
686 Vector3 frontTopRight; 786 Vector3 frontTopRight;
@@ -692,6 +792,8 @@ namespace OpenSim.Region.Framework.Scenes
692 Vector3 backBottomLeft; 792 Vector3 backBottomLeft;
693 Vector3 backBottomRight; 793 Vector3 backBottomRight;
694 794
795 // Vector3[] corners = new Vector3[8];
796
695 Vector3 orig = Vector3.Zero; 797 Vector3 orig = Vector3.Zero;
696 798
697 frontTopLeft.X = orig.X - (part.Scale.X / 2); 799 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -726,6 +828,38 @@ namespace OpenSim.Region.Framework.Scenes
726 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 828 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
727 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 829 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
728 830
831
832
833 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
834 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
835 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
836 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
837 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
838 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
839 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
840 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
841
842 //for (int i = 0; i < 8; i++)
843 //{
844 // corners[i] = corners[i] * worldRot;
845 // corners[i] += offset;
846
847 // if (corners[i].X > maxX)
848 // maxX = corners[i].X;
849 // if (corners[i].X < minX)
850 // minX = corners[i].X;
851
852 // if (corners[i].Y > maxY)
853 // maxY = corners[i].Y;
854 // if (corners[i].Y < minY)
855 // minY = corners[i].Y;
856
857 // if (corners[i].Z > maxZ)
858 // maxZ = corners[i].Y;
859 // if (corners[i].Z < minZ)
860 // minZ = corners[i].Z;
861 //}
862
729 frontTopLeft = frontTopLeft * worldRot; 863 frontTopLeft = frontTopLeft * worldRot;
730 frontTopRight = frontTopRight * worldRot; 864 frontTopRight = frontTopRight * worldRot;
731 frontBottomLeft = frontBottomLeft * worldRot; 865 frontBottomLeft = frontBottomLeft * worldRot;
@@ -747,6 +881,15 @@ namespace OpenSim.Region.Framework.Scenes
747 backTopLeft += offset; 881 backTopLeft += offset;
748 backTopRight += offset; 882 backTopRight += offset;
749 883
884 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
885 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
886 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
887 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
888 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
889 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
890 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
891 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
892
750 if (frontTopRight.X > maxX) 893 if (frontTopRight.X > maxX)
751 maxX = frontTopRight.X; 894 maxX = frontTopRight.X;
752 if (frontTopLeft.X > maxX) 895 if (frontTopLeft.X > maxX)
@@ -892,15 +1035,20 @@ namespace OpenSim.Region.Framework.Scenes
892 1035
893 public void SaveScriptedState(XmlTextWriter writer) 1036 public void SaveScriptedState(XmlTextWriter writer)
894 { 1037 {
1038 SaveScriptedState(writer, false);
1039 }
1040
1041 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1042 {
895 XmlDocument doc = new XmlDocument(); 1043 XmlDocument doc = new XmlDocument();
896 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1044 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
897 1045
898 SceneObjectPart[] parts = m_parts.GetArray(); 1046 SceneObjectPart[] parts = m_parts.GetArray();
899 for (int i = 0; i < parts.Length; i++) 1047 for (int i = 0; i < parts.Length; i++)
900 { 1048 {
901 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1049 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
902 foreach (KeyValuePair<UUID, string> kvp in pstates) 1050 foreach (KeyValuePair<UUID, string> kvp in pstates)
903 states.Add(kvp.Key, kvp.Value); 1051 states[kvp.Key] = kvp.Value;
904 } 1052 }
905 1053
906 if (states.Count > 0) 1054 if (states.Count > 0)
@@ -919,6 +1067,118 @@ namespace OpenSim.Region.Framework.Scenes
919 } 1067 }
920 } 1068 }
921 1069
1070 /// <summary>
1071 /// Add the avatar to this linkset (avatar is sat).
1072 /// </summary>
1073 /// <param name="agentID"></param>
1074 public void AddAvatar(UUID agentID)
1075 {
1076 ScenePresence presence;
1077 if (m_scene.TryGetScenePresence(agentID, out presence))
1078 {
1079 if (!m_linkedAvatars.Contains(presence))
1080 {
1081 m_linkedAvatars.Add(presence);
1082 }
1083 }
1084 }
1085
1086 /// <summary>
1087 /// Delete the avatar from this linkset (avatar is unsat).
1088 /// </summary>
1089 /// <param name="agentID"></param>
1090 public void DeleteAvatar(UUID agentID)
1091 {
1092 ScenePresence presence;
1093 if (m_scene.TryGetScenePresence(agentID, out presence))
1094 {
1095 if (m_linkedAvatars.Contains(presence))
1096 {
1097 m_linkedAvatars.Remove(presence);
1098 }
1099 }
1100 }
1101
1102 /// <summary>
1103 /// Returns the list of linked presences (avatars sat on this group)
1104 /// </summary>
1105 /// <param name="agentID"></param>
1106 public List<ScenePresence> GetLinkedAvatars()
1107 {
1108 return m_linkedAvatars;
1109 }
1110
1111 /// <summary>
1112 /// Attach this scene object to the given avatar.
1113 /// </summary>
1114 /// <param name="agentID"></param>
1115 /// <param name="attachmentpoint"></param>
1116 /// <param name="AttachOffset"></param>
1117 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
1118 {
1119 ScenePresence avatar = m_scene.GetScenePresence(agentID);
1120 if (avatar != null)
1121 {
1122 // don't attach attachments to child agents
1123 if (avatar.IsChildAgent) return;
1124
1125// m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name);
1126
1127 DetachFromBackup();
1128
1129 // Remove from database and parcel prim count
1130 m_scene.DeleteFromStorage(UUID);
1131 m_scene.EventManager.TriggerParcelPrimCountTainted();
1132
1133 m_rootPart.AttachedAvatar = agentID;
1134
1135 //Anakin Lohner bug #3839
1136 lock (m_parts)
1137 {
1138 foreach (SceneObjectPart p in m_parts.GetArray())
1139 {
1140 p.AttachedAvatar = agentID;
1141 }
1142 }
1143
1144 if (m_rootPart.PhysActor != null)
1145 {
1146 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
1147 m_rootPart.PhysActor = null;
1148 }
1149
1150 AbsolutePosition = AttachOffset;
1151 m_rootPart.AttachedPos = AttachOffset;
1152 m_rootPart.IsAttachment = true;
1153
1154 m_rootPart.SetParentLocalId(avatar.LocalId);
1155 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
1156
1157 avatar.AddAttachment(this);
1158
1159 if (!silent)
1160 {
1161 // Killing it here will cause the client to deselect it
1162 // It then reappears on the avatar, deselected
1163 // through the full update below
1164 //
1165 if (IsSelected)
1166 {
1167 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1168 }
1169
1170 IsSelected = false; // fudge....
1171 ScheduleGroupForFullUpdate();
1172 }
1173 }
1174 else
1175 {
1176 m_log.WarnFormat(
1177 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1178 UUID, agentID, Scene.RegionInfo.RegionName);
1179 }
1180 }
1181
922 public byte GetAttachmentPoint() 1182 public byte GetAttachmentPoint()
923 { 1183 {
924 return m_rootPart.Shape.State; 1184 return m_rootPart.Shape.State;
@@ -1045,7 +1305,10 @@ namespace OpenSim.Region.Framework.Scenes
1045 public void AddPart(SceneObjectPart part) 1305 public void AddPart(SceneObjectPart part)
1046 { 1306 {
1047 part.SetParent(this); 1307 part.SetParent(this);
1048 part.LinkNum = m_parts.Add(part.UUID, part); 1308 m_parts.Add(part.UUID, part);
1309
1310 part.LinkNum = m_parts.Count;
1311
1049 if (part.LinkNum == 2 && RootPart != null) 1312 if (part.LinkNum == 2 && RootPart != null)
1050 RootPart.LinkNum = 1; 1313 RootPart.LinkNum = 1;
1051 } 1314 }
@@ -1129,7 +1392,7 @@ namespace OpenSim.Region.Framework.Scenes
1129 1392
1130 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) 1393 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1131 { 1394 {
1132 part.StoreUndoState(); 1395 part.StoreUndoState(UndoType.STATE_PRIM_ALL);
1133 part.OnGrab(offsetPos, remoteClient); 1396 part.OnGrab(offsetPos, remoteClient);
1134 } 1397 }
1135 1398
@@ -1149,6 +1412,11 @@ namespace OpenSim.Region.Framework.Scenes
1149 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1412 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1150 public void DeleteGroupFromScene(bool silent) 1413 public void DeleteGroupFromScene(bool silent)
1151 { 1414 {
1415 // We need to keep track of this state in case this group is still queued for backup.
1416 m_isDeleted = true;
1417
1418 DetachFromBackup();
1419
1152 SceneObjectPart[] parts = m_parts.GetArray(); 1420 SceneObjectPart[] parts = m_parts.GetArray();
1153 for (int i = 0; i < parts.Length; i++) 1421 for (int i = 0; i < parts.Length; i++)
1154 { 1422 {
@@ -1160,13 +1428,11 @@ namespace OpenSim.Region.Framework.Scenes
1160 avatar.StandUp(); 1428 avatar.StandUp();
1161 1429
1162 if (!silent) 1430 if (!silent)
1163 {
1164 part.UpdateFlag = 0; 1431 part.UpdateFlag = 0;
1165 if (part == m_rootPart)
1166 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1167 }
1168 }); 1432 });
1169 } 1433 }
1434
1435
1170 } 1436 }
1171 1437
1172 public void AddScriptLPS(int count) 1438 public void AddScriptLPS(int count)
@@ -1263,7 +1529,12 @@ namespace OpenSim.Region.Framework.Scenes
1263 1529
1264 public void SetOwnerId(UUID userId) 1530 public void SetOwnerId(UUID userId)
1265 { 1531 {
1266 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1532 ForEachPart(delegate(SceneObjectPart part)
1533 {
1534
1535 part.OwnerID = userId;
1536
1537 });
1267 } 1538 }
1268 1539
1269 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1540 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1295,11 +1566,17 @@ namespace OpenSim.Region.Framework.Scenes
1295 return; 1566 return;
1296 } 1567 }
1297 1568
1569 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1570 return;
1571
1298 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1572 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1299 // any exception propogate upwards. 1573 // any exception propogate upwards.
1300 try 1574 try
1301 { 1575 {
1302 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1576 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1577 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1578 m_scene.LoadingPrims) // Land may not be valid yet
1579
1303 { 1580 {
1304 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1581 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1305 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1582 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1326,6 +1603,7 @@ namespace OpenSim.Region.Framework.Scenes
1326 } 1603 }
1327 } 1604 }
1328 } 1605 }
1606
1329 } 1607 }
1330 1608
1331 if (HasGroupChanged) 1609 if (HasGroupChanged)
@@ -1333,6 +1611,20 @@ namespace OpenSim.Region.Framework.Scenes
1333 // don't backup while it's selected or you're asking for changes mid stream. 1611 // don't backup while it's selected or you're asking for changes mid stream.
1334 if (isTimeToPersist() || forcedBackup) 1612 if (isTimeToPersist() || forcedBackup)
1335 { 1613 {
1614 if (m_rootPart.PhysActor != null &&
1615 (!m_rootPart.PhysActor.IsPhysical))
1616 {
1617 // Possible ghost prim
1618 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1619 {
1620 foreach (SceneObjectPart part in m_parts.GetArray())
1621 {
1622 // Re-set physics actor positions and
1623 // orientations
1624 part.GroupPosition = m_rootPart.GroupPosition;
1625 }
1626 }
1627 }
1336// m_log.DebugFormat( 1628// m_log.DebugFormat(
1337// "[SCENE]: Storing {0}, {1} in {2}", 1629// "[SCENE]: Storing {0}, {1} in {2}",
1338// Name, UUID, m_scene.RegionInfo.RegionName); 1630// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1396,81 +1688,90 @@ namespace OpenSim.Region.Framework.Scenes
1396 /// <returns></returns> 1688 /// <returns></returns>
1397 public SceneObjectGroup Copy(bool userExposed) 1689 public SceneObjectGroup Copy(bool userExposed)
1398 { 1690 {
1399 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1691 SceneObjectGroup dupe;
1400 dupe.m_isBackedUp = false; 1692 try
1401 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1693 {
1402 1694 m_dupeInProgress = true;
1403 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 1695 dupe = (SceneObjectGroup)MemberwiseClone();
1404 // attachments do not bordercross while they're being duplicated. This is hacktastic! 1696 dupe.m_isBackedUp = false;
1405 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 1697 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1406 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1407 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1408 // then restore it's attachment state
1409
1410 // This is only necessary when userExposed is false!
1411 1698
1412 bool previousAttachmentStatus = dupe.RootPart.IsAttachment; 1699 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1413 1700 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1414 if (!userExposed) 1701 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1415 dupe.RootPart.IsAttachment = true; 1702 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1703 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1704 // then restore it's attachment state
1416 1705
1417 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); 1706 // This is only necessary when userExposed is false!
1418 1707
1419 if (!userExposed) 1708 bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
1420 {
1421 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1422 }
1423 1709
1424 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1710 if (!userExposed)
1425 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1711 dupe.RootPart.IsAttachment = true;
1426 1712
1427 if (userExposed) 1713 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1428 dupe.m_rootPart.TrimPermissions();
1429 1714
1430 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1715 if (!userExposed)
1431
1432 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1433 { 1716 {
1434 return p1.LinkNum.CompareTo(p2.LinkNum); 1717 dupe.RootPart.IsAttachment = previousAttachmentStatus;
1435 } 1718 }
1436 );
1437 1719
1438 foreach (SceneObjectPart part in partList) 1720 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1439 { 1721 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1440 if (part.UUID != m_rootPart.UUID) 1722
1723 if (userExposed)
1724 dupe.m_rootPart.TrimPermissions();
1725
1726 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1727
1728 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1729 {
1730 return p1.LinkNum.CompareTo(p2.LinkNum);
1731 }
1732 );
1733
1734 foreach (SceneObjectPart part in partList)
1441 { 1735 {
1442 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 1736 if (part.UUID != m_rootPart.UUID)
1443 newPart.LinkNum = part.LinkNum; 1737 {
1444 } 1738 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1445 1739
1446 // Need to duplicate the physics actor as well 1740 newPart.LinkNum = part.LinkNum;
1447 if (part.PhysActor != null && userExposed) 1741 }
1742
1743 // Need to duplicate the physics actor as well
1744 if (part.PhysActor != null && userExposed)
1745 {
1746 PrimitiveBaseShape pbs = part.Shape;
1747
1748 part.PhysActor
1749 = m_scene.PhysicsScene.AddPrimShape(
1750 string.Format("{0}/{1}", part.Name, part.UUID),
1751 pbs,
1752 part.AbsolutePosition,
1753 part.Scale,
1754 part.RotationOffset,
1755 part.PhysActor.IsPhysical);
1756 part.PhysActor.SetMaterial((int)part.Material);
1757
1758 part.PhysActor.LocalID = part.LocalId;
1759 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1760 }
1761 }
1762 if (userExposed)
1448 { 1763 {
1449 PrimitiveBaseShape pbs = part.Shape; 1764 dupe.UpdateParentIDs();
1450 1765 dupe.HasGroupChanged = true;
1451 part.PhysActor 1766 dupe.AttachToBackup();
1452 = m_scene.PhysicsScene.AddPrimShape( 1767
1453 string.Format("{0}/{1}", part.Name, part.UUID), 1768 ScheduleGroupForFullUpdate();
1454 pbs,
1455 part.AbsolutePosition,
1456 part.Scale,
1457 part.RotationOffset,
1458 part.PhysActor.IsPhysical);
1459
1460 part.PhysActor.LocalID = part.LocalId;
1461 part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1462 } 1769 }
1463 } 1770 }
1464 1771 finally
1465 if (userExposed)
1466 { 1772 {
1467 dupe.UpdateParentIDs(); 1773 m_dupeInProgress = false;
1468 dupe.HasGroupChanged = true;
1469 dupe.AttachToBackup();
1470
1471 ScheduleGroupForFullUpdate();
1472 } 1774 }
1473
1474 return dupe; 1775 return dupe;
1475 } 1776 }
1476 1777
@@ -1615,6 +1916,7 @@ namespace OpenSim.Region.Framework.Scenes
1615 return Vector3.Zero; 1916 return Vector3.Zero;
1616 } 1917 }
1617 1918
1919 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1618 public void moveToTarget(Vector3 target, float tau) 1920 public void moveToTarget(Vector3 target, float tau)
1619 { 1921 {
1620 SceneObjectPart rootpart = m_rootPart; 1922 SceneObjectPart rootpart = m_rootPart;
@@ -1654,20 +1956,55 @@ namespace OpenSim.Region.Framework.Scenes
1654 SceneObjectPart rootpart = m_rootPart; 1956 SceneObjectPart rootpart = m_rootPart;
1655 if (rootpart != null) 1957 if (rootpart != null)
1656 { 1958 {
1657 if (rootpart.PhysActor != null) 1959 if (IsAttachment)
1960 {
1961 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1962 if (avatar != null) avatar.StopMoveToPosition();
1963 }
1964 else
1658 { 1965 {
1659 rootpart.PhysActor.PIDActive = false; 1966 if (rootpart.PhysActor != null)
1967 {
1968 rootpart.PhysActor.PIDActive = false;
1969 }
1660 } 1970 }
1661 } 1971 }
1662 } 1972 }
1663 1973
1974 public void rotLookAt(Quaternion target, float strength, float damping)
1975 {
1976 SceneObjectPart rootpart = m_rootPart;
1977 if (rootpart != null)
1978 {
1979 if (IsAttachment)
1980 {
1981 /*
1982 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1983 if (avatar != null)
1984 {
1985 Rotate the Av?
1986 } */
1987 }
1988 else
1989 {
1990 if (rootpart.PhysActor != null)
1991 { // APID must be implemented in your physics system for this to function.
1992 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
1993 rootpart.PhysActor.APIDStrength = strength;
1994 rootpart.PhysActor.APIDDamping = damping;
1995 rootpart.PhysActor.APIDActive = true;
1996 }
1997 }
1998 }
1999 }
2000
1664 public void stopLookAt() 2001 public void stopLookAt()
1665 { 2002 {
1666 SceneObjectPart rootpart = m_rootPart; 2003 SceneObjectPart rootpart = m_rootPart;
1667 if (rootpart != null) 2004 if (rootpart != null)
1668 { 2005 {
1669 if (rootpart.PhysActor != null) 2006 if (rootpart.PhysActor != null)
1670 { 2007 { // APID must be implemented in your physics system for this to function.
1671 rootpart.PhysActor.APIDActive = false; 2008 rootpart.PhysActor.APIDActive = false;
1672 } 2009 }
1673 } 2010 }
@@ -1733,6 +2070,8 @@ namespace OpenSim.Region.Framework.Scenes
1733 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2070 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1734 { 2071 {
1735 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2072 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2073 newPart.SetParent(this);
2074
1736 AddPart(newPart); 2075 AddPart(newPart);
1737 2076
1738 SetPartAsNonRoot(newPart); 2077 SetPartAsNonRoot(newPart);
@@ -1879,11 +2218,11 @@ namespace OpenSim.Region.Framework.Scenes
1879 /// Immediately send a full update for this scene object. 2218 /// Immediately send a full update for this scene object.
1880 /// </summary> 2219 /// </summary>
1881 public void SendGroupFullUpdate() 2220 public void SendGroupFullUpdate()
1882 { 2221 {
1883 if (IsDeleted) 2222 if (IsDeleted)
1884 return; 2223 return;
1885 2224
1886// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2225// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1887 2226
1888 RootPart.SendFullUpdateToAllClients(); 2227 RootPart.SendFullUpdateToAllClients();
1889 2228
@@ -2072,12 +2411,15 @@ namespace OpenSim.Region.Framework.Scenes
2072 part.LinkNum += objectGroup.PrimCount; 2411 part.LinkNum += objectGroup.PrimCount;
2073 } 2412 }
2074 } 2413 }
2414 }
2075 2415
2076 linkPart.LinkNum = 2; 2416 linkPart.LinkNum = 2;
2077 2417
2078 linkPart.SetParent(this); 2418 linkPart.SetParent(this);
2079 linkPart.CreateSelected = true; 2419 linkPart.CreateSelected = true;
2080 2420
2421 lock (m_parts.SyncRoot)
2422 {
2081 //if (linkPart.PhysActor != null) 2423 //if (linkPart.PhysActor != null)
2082 //{ 2424 //{
2083 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); 2425 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
@@ -2235,6 +2577,8 @@ namespace OpenSim.Region.Framework.Scenes
2235 /// <param name="objectGroup"></param> 2577 /// <param name="objectGroup"></param>
2236 public virtual void DetachFromBackup() 2578 public virtual void DetachFromBackup()
2237 { 2579 {
2580 m_scene.SceneGraph.FireDetachFromBackup(this);
2581
2238 if (m_isBackedUp) 2582 if (m_isBackedUp)
2239 m_scene.EventManager.OnBackup -= ProcessBackup; 2583 m_scene.EventManager.OnBackup -= ProcessBackup;
2240 2584
@@ -2253,7 +2597,8 @@ namespace OpenSim.Region.Framework.Scenes
2253 2597
2254 axPos *= parentRot; 2598 axPos *= parentRot;
2255 part.OffsetPosition = axPos; 2599 part.OffsetPosition = axPos;
2256 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2600 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2601 part.GroupPosition = newPos;
2257 part.OffsetPosition = Vector3.Zero; 2602 part.OffsetPosition = Vector3.Zero;
2258 part.RotationOffset = worldRot; 2603 part.RotationOffset = worldRot;
2259 2604
@@ -2264,7 +2609,7 @@ namespace OpenSim.Region.Framework.Scenes
2264 2609
2265 part.LinkNum = linkNum; 2610 part.LinkNum = linkNum;
2266 2611
2267 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2612 part.OffsetPosition = newPos - AbsolutePosition;
2268 2613
2269 Quaternion rootRotation = m_rootPart.RotationOffset; 2614 Quaternion rootRotation = m_rootPart.RotationOffset;
2270 2615
@@ -2274,7 +2619,7 @@ namespace OpenSim.Region.Framework.Scenes
2274 2619
2275 parentRot = m_rootPart.RotationOffset; 2620 parentRot = m_rootPart.RotationOffset;
2276 oldRot = part.RotationOffset; 2621 oldRot = part.RotationOffset;
2277 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2622 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2278 part.RotationOffset = newRot; 2623 part.RotationOffset = newRot;
2279 } 2624 }
2280 2625
@@ -2525,8 +2870,12 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 2870 }
2526 } 2871 }
2527 2872
2873 RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2528 for (int i = 0; i < parts.Length; i++) 2874 for (int i = 0; i < parts.Length; i++)
2529 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2875 {
2876 if (parts[i] != RootPart)
2877 parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2878 }
2530 } 2879 }
2531 } 2880 }
2532 2881
@@ -2539,6 +2888,17 @@ namespace OpenSim.Region.Framework.Scenes
2539 } 2888 }
2540 } 2889 }
2541 2890
2891
2892
2893 /// <summary>
2894 /// Gets the number of parts
2895 /// </summary>
2896 /// <returns></returns>
2897 public int GetPartCount()
2898 {
2899 return Parts.Count();
2900 }
2901
2542 /// <summary> 2902 /// <summary>
2543 /// Update the texture entry for this part 2903 /// Update the texture entry for this part
2544 /// </summary> 2904 /// </summary>
@@ -2600,11 +2960,9 @@ namespace OpenSim.Region.Framework.Scenes
2600 scale.Y = m_scene.m_maxNonphys; 2960 scale.Y = m_scene.m_maxNonphys;
2601 if (scale.Z > m_scene.m_maxNonphys) 2961 if (scale.Z > m_scene.m_maxNonphys)
2602 scale.Z = m_scene.m_maxNonphys; 2962 scale.Z = m_scene.m_maxNonphys;
2603
2604 SceneObjectPart part = GetChildPart(localID); 2963 SceneObjectPart part = GetChildPart(localID);
2605 if (part != null) 2964 if (part != null)
2606 { 2965 {
2607 part.Resize(scale);
2608 if (part.PhysActor != null) 2966 if (part.PhysActor != null)
2609 { 2967 {
2610 if (part.PhysActor.IsPhysical) 2968 if (part.PhysActor.IsPhysical)
@@ -2619,7 +2977,7 @@ namespace OpenSim.Region.Framework.Scenes
2619 part.PhysActor.Size = scale; 2977 part.PhysActor.Size = scale;
2620 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); 2978 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2621 } 2979 }
2622 //if (part.UUID != m_rootPart.UUID) 2980 part.Resize(scale);
2623 2981
2624 HasGroupChanged = true; 2982 HasGroupChanged = true;
2625 part.TriggerScriptChangedEvent(Changed.SCALE); 2983 part.TriggerScriptChangedEvent(Changed.SCALE);
@@ -2642,7 +3000,6 @@ namespace OpenSim.Region.Framework.Scenes
2642 SceneObjectPart part = GetChildPart(localID); 3000 SceneObjectPart part = GetChildPart(localID);
2643 if (part != null) 3001 if (part != null)
2644 { 3002 {
2645 part.IgnoreUndoUpdate = true;
2646 if (scale.X > m_scene.m_maxNonphys) 3003 if (scale.X > m_scene.m_maxNonphys)
2647 scale.X = m_scene.m_maxNonphys; 3004 scale.X = m_scene.m_maxNonphys;
2648 if (scale.Y > m_scene.m_maxNonphys) 3005 if (scale.Y > m_scene.m_maxNonphys)
@@ -2679,7 +3036,7 @@ namespace OpenSim.Region.Framework.Scenes
2679 3036
2680 if (part.PhysActor != null && part.PhysActor.IsPhysical) 3037 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2681 { 3038 {
2682 if (oldSize.X * x > m_scene.m_maxPhys) 3039 if (oldSize.X*x > m_scene.m_maxPhys)
2683 { 3040 {
2684 f = m_scene.m_maxPhys / oldSize.X; 3041 f = m_scene.m_maxPhys / oldSize.X;
2685 a = f / x; 3042 a = f / x;
@@ -2687,7 +3044,7 @@ namespace OpenSim.Region.Framework.Scenes
2687 y *= a; 3044 y *= a;
2688 z *= a; 3045 z *= a;
2689 } 3046 }
2690 if (oldSize.Y * y > m_scene.m_maxPhys) 3047 if (oldSize.Y*y > m_scene.m_maxPhys)
2691 { 3048 {
2692 f = m_scene.m_maxPhys / oldSize.Y; 3049 f = m_scene.m_maxPhys / oldSize.Y;
2693 a = f / y; 3050 a = f / y;
@@ -2695,7 +3052,7 @@ namespace OpenSim.Region.Framework.Scenes
2695 y *= a; 3052 y *= a;
2696 z *= a; 3053 z *= a;
2697 } 3054 }
2698 if (oldSize.Z * z > m_scene.m_maxPhys) 3055 if (oldSize.Z*z > m_scene.m_maxPhys)
2699 { 3056 {
2700 f = m_scene.m_maxPhys / oldSize.Z; 3057 f = m_scene.m_maxPhys / oldSize.Z;
2701 a = f / z; 3058 a = f / z;
@@ -2706,7 +3063,7 @@ namespace OpenSim.Region.Framework.Scenes
2706 } 3063 }
2707 else 3064 else
2708 { 3065 {
2709 if (oldSize.X * x > m_scene.m_maxNonphys) 3066 if (oldSize.X*x > m_scene.m_maxNonphys)
2710 { 3067 {
2711 f = m_scene.m_maxNonphys / oldSize.X; 3068 f = m_scene.m_maxNonphys / oldSize.X;
2712 a = f / x; 3069 a = f / x;
@@ -2714,7 +3071,7 @@ namespace OpenSim.Region.Framework.Scenes
2714 y *= a; 3071 y *= a;
2715 z *= a; 3072 z *= a;
2716 } 3073 }
2717 if (oldSize.Y * y > m_scene.m_maxNonphys) 3074 if (oldSize.Y*y > m_scene.m_maxNonphys)
2718 { 3075 {
2719 f = m_scene.m_maxNonphys / oldSize.Y; 3076 f = m_scene.m_maxNonphys / oldSize.Y;
2720 a = f / y; 3077 a = f / y;
@@ -2722,7 +3079,7 @@ namespace OpenSim.Region.Framework.Scenes
2722 y *= a; 3079 y *= a;
2723 z *= a; 3080 z *= a;
2724 } 3081 }
2725 if (oldSize.Z * z > m_scene.m_maxNonphys) 3082 if (oldSize.Z*z > m_scene.m_maxNonphys)
2726 { 3083 {
2727 f = m_scene.m_maxNonphys / oldSize.Z; 3084 f = m_scene.m_maxNonphys / oldSize.Z;
2728 a = f / z; 3085 a = f / z;
@@ -2732,7 +3089,6 @@ namespace OpenSim.Region.Framework.Scenes
2732 } 3089 }
2733 } 3090 }
2734 obPart.IgnoreUndoUpdate = false; 3091 obPart.IgnoreUndoUpdate = false;
2735 obPart.StoreUndoState();
2736 } 3092 }
2737 } 3093 }
2738 } 3094 }
@@ -2740,8 +3096,13 @@ namespace OpenSim.Region.Framework.Scenes
2740 Vector3 prevScale = part.Scale; 3096 Vector3 prevScale = part.Scale;
2741 prevScale.X *= x; 3097 prevScale.X *= x;
2742 prevScale.Y *= y; 3098 prevScale.Y *= y;
2743 prevScale.Z *= z; 3099 prevScale.Z *= z;;
3100
3101 part.IgnoreUndoUpdate = false;
3102 part.StoreUndoState(UndoType.STATE_GROUP_SCALE);
3103 part.IgnoreUndoUpdate = true;
2744 part.Resize(prevScale); 3104 part.Resize(prevScale);
3105 part.IgnoreUndoUpdate = false;
2745 3106
2746 parts = m_parts.GetArray(); 3107 parts = m_parts.GetArray();
2747 for (int i = 0; i < parts.Length; i++) 3108 for (int i = 0; i < parts.Length; i++)
@@ -2750,19 +3111,26 @@ namespace OpenSim.Region.Framework.Scenes
2750 obPart.IgnoreUndoUpdate = true; 3111 obPart.IgnoreUndoUpdate = true;
2751 if (obPart.UUID != m_rootPart.UUID) 3112 if (obPart.UUID != m_rootPart.UUID)
2752 { 3113 {
2753 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3114 if (obPart.UUID != m_rootPart.UUID)
2754 currentpos.X *= x; 3115 {
2755 currentpos.Y *= y; 3116 obPart.IgnoreUndoUpdate = false;
2756 currentpos.Z *= z; 3117 obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE);
2757 Vector3 newSize = new Vector3(obPart.Scale); 3118 obPart.IgnoreUndoUpdate = true;
2758 newSize.X *= x; 3119
2759 newSize.Y *= y; 3120 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2760 newSize.Z *= z; 3121 currentpos.X *= x;
2761 obPart.Resize(newSize); 3122 currentpos.Y *= y;
2762 obPart.UpdateOffSet(currentpos); 3123 currentpos.Z *= z;
3124 Vector3 newSize = new Vector3(obPart.Scale);
3125 newSize.X *= x;
3126 newSize.Y *= y;
3127 newSize.Z *= z;
3128 obPart.Resize(newSize);
3129 obPart.UpdateOffSet(currentpos);
3130 }
3131 obPart.IgnoreUndoUpdate = false;
2763 } 3132 }
2764 obPart.IgnoreUndoUpdate = false; 3133 obPart.IgnoreUndoUpdate = false;
2765 obPart.StoreUndoState();
2766 } 3134 }
2767 3135
2768 if (part.PhysActor != null) 3136 if (part.PhysActor != null)
@@ -2772,7 +3140,6 @@ namespace OpenSim.Region.Framework.Scenes
2772 } 3140 }
2773 3141
2774 part.IgnoreUndoUpdate = false; 3142 part.IgnoreUndoUpdate = false;
2775 part.StoreUndoState();
2776 HasGroupChanged = true; 3143 HasGroupChanged = true;
2777 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); 3144 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
2778 ScheduleGroupForTerseUpdate(); 3145 ScheduleGroupForTerseUpdate();
@@ -2789,14 +3156,11 @@ namespace OpenSim.Region.Framework.Scenes
2789 /// <param name="pos"></param> 3156 /// <param name="pos"></param>
2790 public void UpdateGroupPosition(Vector3 pos) 3157 public void UpdateGroupPosition(Vector3 pos)
2791 { 3158 {
2792 SceneObjectPart[] parts = m_parts.GetArray();
2793 for (int i = 0; i < parts.Length; i++)
2794 parts[i].StoreUndoState();
2795
2796 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3159 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2797 { 3160 {
2798 if (IsAttachment) 3161 if (IsAttachment)
2799 { 3162 {
3163 m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION);
2800 m_rootPart.AttachedPos = pos; 3164 m_rootPart.AttachedPos = pos;
2801 } 3165 }
2802 if (RootPart.GetStatusSandbox()) 3166 if (RootPart.GetStatusSandbox())
@@ -2830,7 +3194,7 @@ namespace OpenSim.Region.Framework.Scenes
2830 3194
2831 SceneObjectPart[] parts = m_parts.GetArray(); 3195 SceneObjectPart[] parts = m_parts.GetArray();
2832 for (int i = 0; i < parts.Length; i++) 3196 for (int i = 0; i < parts.Length; i++)
2833 parts[i].StoreUndoState(); 3197 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2834 3198
2835 if (part != null) 3199 if (part != null)
2836 { 3200 {
@@ -2855,7 +3219,7 @@ namespace OpenSim.Region.Framework.Scenes
2855 { 3219 {
2856 SceneObjectPart[] parts = m_parts.GetArray(); 3220 SceneObjectPart[] parts = m_parts.GetArray();
2857 for (int i = 0; i < parts.Length; i++) 3221 for (int i = 0; i < parts.Length; i++)
2858 parts[i].StoreUndoState(); 3222 parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION);
2859 3223
2860 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3224 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2861 Vector3 oldPos = 3225 Vector3 oldPos =
@@ -2876,10 +3240,27 @@ namespace OpenSim.Region.Framework.Scenes
2876 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3240 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2877 } 3241 }
2878 3242
2879 AbsolutePosition = newPos; 3243 //We have to set undoing here because otherwise an undo state will be saved
3244 if (!m_rootPart.Undoing)
3245 {
3246 m_rootPart.Undoing = true;
3247 AbsolutePosition = newPos;
3248 m_rootPart.Undoing = false;
3249 }
3250 else
3251 {
3252 AbsolutePosition = newPos;
3253 }
2880 3254
2881 HasGroupChanged = true; 3255 HasGroupChanged = true;
2882 ScheduleGroupForTerseUpdate(); 3256 if (m_rootPart.Undoing)
3257 {
3258 ScheduleGroupForFullUpdate();
3259 }
3260 else
3261 {
3262 ScheduleGroupForTerseUpdate();
3263 }
2883 } 3264 }
2884 3265
2885 public void OffsetForNewRegion(Vector3 offset) 3266 public void OffsetForNewRegion(Vector3 offset)
@@ -2899,7 +3280,7 @@ namespace OpenSim.Region.Framework.Scenes
2899 { 3280 {
2900 SceneObjectPart[] parts = m_parts.GetArray(); 3281 SceneObjectPart[] parts = m_parts.GetArray();
2901 for (int i = 0; i < parts.Length; i++) 3282 for (int i = 0; i < parts.Length; i++)
2902 parts[i].StoreUndoState(); 3283 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2903 3284
2904 m_rootPart.UpdateRotation(rot); 3285 m_rootPart.UpdateRotation(rot);
2905 3286
@@ -2923,7 +3304,7 @@ namespace OpenSim.Region.Framework.Scenes
2923 { 3304 {
2924 SceneObjectPart[] parts = m_parts.GetArray(); 3305 SceneObjectPart[] parts = m_parts.GetArray();
2925 for (int i = 0; i < parts.Length; i++) 3306 for (int i = 0; i < parts.Length; i++)
2926 parts[i].StoreUndoState(); 3307 parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION);
2927 3308
2928 m_rootPart.UpdateRotation(rot); 3309 m_rootPart.UpdateRotation(rot);
2929 3310
@@ -2948,10 +3329,9 @@ namespace OpenSim.Region.Framework.Scenes
2948 public void UpdateSingleRotation(Quaternion rot, uint localID) 3329 public void UpdateSingleRotation(Quaternion rot, uint localID)
2949 { 3330 {
2950 SceneObjectPart part = GetChildPart(localID); 3331 SceneObjectPart part = GetChildPart(localID);
2951
2952 SceneObjectPart[] parts = m_parts.GetArray(); 3332 SceneObjectPart[] parts = m_parts.GetArray();
2953 for (int i = 0; i < parts.Length; i++) 3333 for (int i = 0; i < parts.Length; i++)
2954 parts[i].StoreUndoState(); 3334 parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2955 3335
2956 if (part != null) 3336 if (part != null)
2957 { 3337 {
@@ -2979,15 +3359,24 @@ namespace OpenSim.Region.Framework.Scenes
2979 if (part.UUID == m_rootPart.UUID) 3359 if (part.UUID == m_rootPart.UUID)
2980 { 3360 {
2981 UpdateRootRotation(rot); 3361 UpdateRootRotation(rot);
2982 AbsolutePosition = pos; 3362 if (!m_rootPart.Undoing)
3363 {
3364 m_rootPart.Undoing = true;
3365 AbsolutePosition = pos;
3366 m_rootPart.Undoing = false;
3367 }
3368 else
3369 {
3370 AbsolutePosition = pos;
3371 }
2983 } 3372 }
2984 else 3373 else
2985 { 3374 {
3375 part.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
2986 part.IgnoreUndoUpdate = true; 3376 part.IgnoreUndoUpdate = true;
2987 part.UpdateRotation(rot); 3377 part.UpdateRotation(rot);
2988 part.OffsetPosition = pos; 3378 part.OffsetPosition = pos;
2989 part.IgnoreUndoUpdate = false; 3379 part.IgnoreUndoUpdate = false;
2990 part.StoreUndoState();
2991 } 3380 }
2992 } 3381 }
2993 } 3382 }
@@ -3001,8 +3390,16 @@ namespace OpenSim.Region.Framework.Scenes
3001 Quaternion axRot = rot; 3390 Quaternion axRot = rot;
3002 Quaternion oldParentRot = m_rootPart.RotationOffset; 3391 Quaternion oldParentRot = m_rootPart.RotationOffset;
3003 3392
3004 m_rootPart.StoreUndoState(); 3393 m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION);
3005 m_rootPart.UpdateRotation(rot); 3394 bool cancelUndo = false;
3395 if (!m_rootPart.Undoing)
3396 {
3397 m_rootPart.Undoing = true;
3398 cancelUndo = true;
3399 }
3400
3401 //Don't use UpdateRotation because it schedules an update prematurely
3402 m_rootPart.RotationOffset = rot;
3006 if (m_rootPart.PhysActor != null) 3403 if (m_rootPart.PhysActor != null)
3007 { 3404 {
3008 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3405 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -3017,28 +3414,22 @@ namespace OpenSim.Region.Framework.Scenes
3017 { 3414 {
3018 prim.IgnoreUndoUpdate = true; 3415 prim.IgnoreUndoUpdate = true;
3019 Vector3 axPos = prim.OffsetPosition; 3416 Vector3 axPos = prim.OffsetPosition;
3417
3020 axPos *= oldParentRot; 3418 axPos *= oldParentRot;
3021 axPos *= Quaternion.Inverse(axRot); 3419 axPos *= Quaternion.Inverse(axRot);
3022 prim.OffsetPosition = axPos; 3420 prim.OffsetPosition = axPos;
3023 Quaternion primsRot = prim.RotationOffset; 3421
3024 Quaternion newRot = primsRot * oldParentRot; 3422 prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset);
3025 newRot *= Quaternion.Inverse(axRot); 3423
3026 prim.RotationOffset = newRot; 3424 prim.IgnoreUndoUpdate = false;
3027 prim.ScheduleTerseUpdate();
3028 } 3425 }
3029 } 3426 }
3030 3427 if (cancelUndo == true)
3031 for (int i = 0; i < parts.Length; i++)
3032 { 3428 {
3033 SceneObjectPart childpart = parts[i]; 3429 m_rootPart.Undoing = false;
3034 if (childpart != m_rootPart)
3035 {
3036 childpart.IgnoreUndoUpdate = false;
3037 childpart.StoreUndoState();
3038 }
3039 } 3430 }
3040 3431 HasGroupChanged = true;
3041 m_rootPart.ScheduleTerseUpdate(); 3432 ScheduleGroupForFullUpdate();
3042 } 3433 }
3043 3434
3044 #endregion 3435 #endregion
@@ -3261,7 +3652,6 @@ namespace OpenSim.Region.Framework.Scenes
3261 public float GetMass() 3652 public float GetMass()
3262 { 3653 {
3263 float retmass = 0f; 3654 float retmass = 0f;
3264
3265 SceneObjectPart[] parts = m_parts.GetArray(); 3655 SceneObjectPart[] parts = m_parts.GetArray();
3266 for (int i = 0; i < parts.Length; i++) 3656 for (int i = 0; i < parts.Length; i++)
3267 retmass += parts[i].GetMass(); 3657 retmass += parts[i].GetMass();
@@ -3377,6 +3767,14 @@ namespace OpenSim.Region.Framework.Scenes
3377 SetFromItemID(uuid); 3767 SetFromItemID(uuid);
3378 } 3768 }
3379 3769
3770 public void ResetOwnerChangeFlag()
3771 {
3772 ForEachPart(delegate(SceneObjectPart part)
3773 {
3774 part.ResetOwnerChangeFlag();
3775 });
3776 }
3777
3380 #endregion 3778 #endregion
3381 } 3779 }
3382} 3780}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 4d5eedf..9b9f280 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -61,7 +61,8 @@ namespace OpenSim.Region.Framework.Scenes
61 TELEPORT = 512, 61 TELEPORT = 512,
62 REGION_RESTART = 1024, 62 REGION_RESTART = 1024,
63 MEDIA = 2048, 63 MEDIA = 2048,
64 ANIMATION = 16384 64 ANIMATION = 16384,
65 POSITION = 32768
65 } 66 }
66 67
67 // I don't really know where to put this except here. 68 // I don't really know where to put this except here.
@@ -145,10 +146,10 @@ namespace OpenSim.Region.Framework.Scenes
145 public Vector3 StatusSandboxPos; 146 public Vector3 StatusSandboxPos;
146 147
147 // TODO: This needs to be persisted in next XML version update! 148 // TODO: This needs to be persisted in next XML version update!
148 149 [XmlIgnore]
149 public readonly int[] PayPrice = {-2,-2,-2,-2,-2}; 150 public int[] PayPrice = {-2,-2,-2,-2,-2};
150 151
151 152 [XmlIgnore]
152 public PhysicsActor PhysActor 153 public PhysicsActor PhysActor
153 { 154 {
154 get { return m_physActor; } 155 get { return m_physActor; }
@@ -190,7 +191,15 @@ namespace OpenSim.Region.Framework.Scenes
190 191
191 public UUID FromFolderID; 192 public UUID FromFolderID;
192 193
193 194 // The following two are to hold the attachment data
195 // while an object is inworld
196 [XmlIgnore]
197 public byte AttachPoint = 0;
198
199 [XmlIgnore]
200 public Vector3 AttachOffset = Vector3.Zero;
201
202 [XmlIgnore]
194 public int STATUS_ROTATE_X; 203 public int STATUS_ROTATE_X;
195 204
196 205
@@ -285,6 +294,7 @@ namespace OpenSim.Region.Framework.Scenes
285 private Quaternion m_sitTargetOrientation = Quaternion.Identity; 294 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
286 private Vector3 m_sitTargetPosition; 295 private Vector3 m_sitTargetPosition;
287 private string m_sitAnimation = "SIT"; 296 private string m_sitAnimation = "SIT";
297 private bool m_occupied; // KF if any av is sitting on this prim
288 private string m_text = String.Empty; 298 private string m_text = String.Empty;
289 private string m_touchName = String.Empty; 299 private string m_touchName = String.Empty;
290 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); 300 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5);
@@ -374,7 +384,7 @@ namespace OpenSim.Region.Framework.Scenes
374 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, 384 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
375 Quaternion rotationOffset, Vector3 offsetPosition) 385 Quaternion rotationOffset, Vector3 offsetPosition)
376 { 386 {
377 m_name = "Primitive"; 387 m_name = "Object";
378 388
379 Rezzed = DateTime.UtcNow; 389 Rezzed = DateTime.UtcNow;
380 _creationDate = (int)Utils.DateTimeToUnixTime(Rezzed); 390 _creationDate = (int)Utils.DateTimeToUnixTime(Rezzed);
@@ -430,7 +440,7 @@ namespace OpenSim.Region.Framework.Scenes
430 private uint _ownerMask = (uint)PermissionMask.All; 440 private uint _ownerMask = (uint)PermissionMask.All;
431 private uint _groupMask = (uint)PermissionMask.None; 441 private uint _groupMask = (uint)PermissionMask.None;
432 private uint _everyoneMask = (uint)PermissionMask.None; 442 private uint _everyoneMask = (uint)PermissionMask.None;
433 private uint _nextOwnerMask = (uint)PermissionMask.All; 443 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
434 private PrimFlags _flags = PrimFlags.None; 444 private PrimFlags _flags = PrimFlags.None;
435 private DateTime m_expires; 445 private DateTime m_expires;
436 private DateTime m_rezzed; 446 private DateTime m_rezzed;
@@ -529,12 +539,16 @@ namespace OpenSim.Region.Framework.Scenes
529 } 539 }
530 540
531 /// <value> 541 /// <value>
532 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes 542 /// Get the inventory list
533 /// </value> 543 /// </value>
534 public TaskInventoryDictionary TaskInventory 544 public TaskInventoryDictionary TaskInventory
535 { 545 {
536 get { return m_inventory.Items; } 546 get {
537 set { m_inventory.Items = value; } 547 return m_inventory.Items;
548 }
549 set {
550 m_inventory.Items = value;
551 }
538 } 552 }
539 553
540 /// <summary> 554 /// <summary>
@@ -674,14 +688,12 @@ namespace OpenSim.Region.Framework.Scenes
674 set { m_LoopSoundSlavePrims = value; } 688 set { m_LoopSoundSlavePrims = value; }
675 } 689 }
676 690
677
678 public Byte[] TextureAnimation 691 public Byte[] TextureAnimation
679 { 692 {
680 get { return m_TextureAnimation; } 693 get { return m_TextureAnimation; }
681 set { m_TextureAnimation = value; } 694 set { m_TextureAnimation = value; }
682 } 695 }
683 696
684
685 public Byte[] ParticleSystem 697 public Byte[] ParticleSystem
686 { 698 {
687 get { return m_particleSystem; } 699 get { return m_particleSystem; }
@@ -718,9 +730,11 @@ namespace OpenSim.Region.Framework.Scenes
718 { 730 {
719 // If this is a linkset, we don't want the physics engine mucking up our group position here. 731 // If this is a linkset, we don't want the physics engine mucking up our group position here.
720 PhysicsActor actor = PhysActor; 732 PhysicsActor actor = PhysActor;
721 if (actor != null && _parentID == 0) 733 if (_parentID == 0)
722 { 734 {
723 m_groupPosition = actor.Position; 735 if (actor != null)
736 m_groupPosition = actor.Position;
737 return m_groupPosition;
724 } 738 }
725 739
726 if (IsAttachment) 740 if (IsAttachment)
@@ -730,12 +744,14 @@ namespace OpenSim.Region.Framework.Scenes
730 return sp.AbsolutePosition; 744 return sp.AbsolutePosition;
731 } 745 }
732 746
747 // use root prim's group position. Physics may have updated it
748 if (ParentGroup.RootPart != this)
749 m_groupPosition = ParentGroup.RootPart.GroupPosition;
733 return m_groupPosition; 750 return m_groupPosition;
734 } 751 }
735 set 752 set
736 { 753 {
737 m_groupPosition = value; 754 m_groupPosition = value;
738
739 PhysicsActor actor = PhysActor; 755 PhysicsActor actor = PhysActor;
740 if (actor != null) 756 if (actor != null)
741 { 757 {
@@ -755,25 +771,13 @@ namespace OpenSim.Region.Framework.Scenes
755 771
756 // Tell the physics engines that this prim changed. 772 // Tell the physics engines that this prim changed.
757 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 773 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
774
758 } 775 }
759 catch (Exception e) 776 catch (Exception e)
760 { 777 {
761 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); 778 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
762 } 779 }
763 } 780 }
764
765 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
766 if (m_sitTargetAvatar != UUID.Zero)
767 {
768 if (m_parentGroup != null) // TODO can there be a SOP without a SOG?
769 {
770 ScenePresence avatar;
771 if (m_parentGroup.Scene.TryGetScenePresence(m_sitTargetAvatar, out avatar))
772 {
773 avatar.ParentPosition = GetWorldPosition();
774 }
775 }
776 }
777 } 781 }
778 } 782 }
779 783
@@ -782,7 +786,8 @@ namespace OpenSim.Region.Framework.Scenes
782 get { return m_offsetPosition; } 786 get { return m_offsetPosition; }
783 set 787 set
784 { 788 {
785 StoreUndoState(); 789 Vector3 oldpos = m_offsetPosition;
790 StoreUndoState(UndoType.STATE_PRIM_POSITION);
786 m_offsetPosition = value; 791 m_offsetPosition = value;
787 792
788 if (ParentGroup != null && !ParentGroup.IsDeleted) 793 if (ParentGroup != null && !ParentGroup.IsDeleted)
@@ -796,7 +801,22 @@ namespace OpenSim.Region.Framework.Scenes
796 // Tell the physics engines that this prim changed. 801 // Tell the physics engines that this prim changed.
797 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 802 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
798 } 803 }
804
805 if (!m_parentGroup.m_dupeInProgress)
806 {
807 List<ScenePresence> avs = ParentGroup.GetLinkedAvatars();
808 foreach (ScenePresence av in avs)
809 {
810 if (av.LinkedPrim == m_uuid)
811 {
812 Vector3 offset = (m_offsetPosition - oldpos);
813 av.OffsetPosition += offset;
814 av.SendAvatarDataToAllAgents();
815 }
816 }
817 }
799 } 818 }
819 TriggerScriptChangedEvent(Changed.POSITION);
800 } 820 }
801 } 821 }
802 822
@@ -838,7 +858,7 @@ namespace OpenSim.Region.Framework.Scenes
838 858
839 set 859 set
840 { 860 {
841 StoreUndoState(); 861 StoreUndoState(UndoType.STATE_PRIM_ROTATION);
842 m_rotationOffset = value; 862 m_rotationOffset = value;
843 863
844 PhysicsActor actor = PhysActor; 864 PhysicsActor actor = PhysActor;
@@ -922,7 +942,16 @@ namespace OpenSim.Region.Framework.Scenes
922 /// <summary></summary> 942 /// <summary></summary>
923 public Vector3 Acceleration 943 public Vector3 Acceleration
924 { 944 {
925 get { return m_acceleration; } 945 get
946 {
947 PhysicsActor actor = PhysActor;
948 if (actor != null)
949 {
950 m_acceleration = actor.Acceleration;
951 }
952 return m_acceleration;
953 }
954
926 set { m_acceleration = value; } 955 set { m_acceleration = value; }
927 } 956 }
928 957
@@ -1013,7 +1042,7 @@ namespace OpenSim.Region.Framework.Scenes
1013 get { return m_shape.Scale; } 1042 get { return m_shape.Scale; }
1014 set 1043 set
1015 { 1044 {
1016 StoreUndoState(); 1045 StoreUndoState(UndoType.STATE_PRIM_SCALE);
1017 if (m_shape != null) 1046 if (m_shape != null)
1018 { 1047 {
1019 m_shape.Scale = value; 1048 m_shape.Scale = value;
@@ -1079,11 +1108,10 @@ namespace OpenSim.Region.Framework.Scenes
1079 1108
1080 public Vector3 AbsolutePosition 1109 public Vector3 AbsolutePosition
1081 { 1110 {
1082 get { 1111 get
1083 if (IsAttachment) 1112 {
1084 return GroupPosition; 1113 return GroupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset);
1085 1114 }
1086 return m_offsetPosition + m_groupPosition; }
1087 } 1115 }
1088 1116
1089 public SceneObjectGroup ParentGroup 1117 public SceneObjectGroup ParentGroup
@@ -1242,6 +1270,13 @@ namespace OpenSim.Region.Framework.Scenes
1242 _flags = value; 1270 _flags = value;
1243 } 1271 }
1244 } 1272 }
1273
1274 [XmlIgnore]
1275 public bool IsOccupied // KF If an av is sittingon this prim
1276 {
1277 get { return m_occupied; }
1278 set { m_occupied = value; }
1279 }
1245 1280
1246 1281
1247 public UUID SitTargetAvatar 1282 public UUID SitTargetAvatar
@@ -1317,14 +1352,6 @@ namespace OpenSim.Region.Framework.Scenes
1317 } 1352 }
1318 } 1353 }
1319 1354
1320 /// <summary>
1321 /// Clear all pending updates of parts to clients
1322 /// </summary>
1323 private void ClearUpdateSchedule()
1324 {
1325 m_updateFlag = 0;
1326 }
1327
1328 private void SendObjectPropertiesToClient(UUID AgentID) 1355 private void SendObjectPropertiesToClient(UUID AgentID)
1329 { 1356 {
1330 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar) 1357 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
@@ -1575,14 +1602,22 @@ namespace OpenSim.Region.Framework.Scenes
1575 // or flexible 1602 // or flexible
1576 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible)) 1603 if (!isPhantom && !IsAttachment && !(Shape.PathCurve == (byte) Extrusion.Flexible))
1577 { 1604 {
1578 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( 1605 try
1579 string.Format("{0}/{1}", Name, UUID), 1606 {
1580 Shape, 1607 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
1581 AbsolutePosition, 1608 string.Format("{0}/{1}", Name, UUID),
1582 Scale, 1609 Shape,
1583 RotationOffset, 1610 AbsolutePosition,
1584 RigidBody); 1611 Scale,
1585 1612 RotationOffset,
1613 RigidBody);
1614 PhysActor.SetMaterial(Material);
1615 }
1616 catch
1617 {
1618 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom.", m_uuid);
1619 PhysActor = null;
1620 }
1586 // Basic Physics returns null.. joy joy joy. 1621 // Basic Physics returns null.. joy joy joy.
1587 if (PhysActor != null) 1622 if (PhysActor != null)
1588 { 1623 {
@@ -1610,7 +1645,7 @@ namespace OpenSim.Region.Framework.Scenes
1610 { 1645 {
1611 m_redo.Clear(); 1646 m_redo.Clear();
1612 } 1647 }
1613 StoreUndoState(); 1648 StoreUndoState(UndoType.STATE_ALL);
1614 } 1649 }
1615 1650
1616 public byte ConvertScriptUintToByte(uint indata) 1651 public byte ConvertScriptUintToByte(uint indata)
@@ -1679,6 +1714,9 @@ namespace OpenSim.Region.Framework.Scenes
1679 1714
1680 // Move afterwards ResetIDs as it clears the localID 1715 // Move afterwards ResetIDs as it clears the localID
1681 dupe.LocalId = localID; 1716 dupe.LocalId = localID;
1717 if(dupe.PhysActor != null)
1718 dupe.PhysActor.LocalID = localID;
1719
1682 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. 1720 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1683 dupe._lastOwnerID = OwnerID; 1721 dupe._lastOwnerID = OwnerID;
1684 1722
@@ -1722,7 +1760,7 @@ namespace OpenSim.Region.Framework.Scenes
1722 PrimitiveBaseShape shape = PrimitiveBaseShape.Create(); 1760 PrimitiveBaseShape shape = PrimitiveBaseShape.Create();
1723 part.Shape = shape; 1761 part.Shape = shape;
1724 1762
1725 part.Name = "Primitive"; 1763 part.Name = "Object";
1726 part._ownerID = UUID.Random(); 1764 part._ownerID = UUID.Random();
1727 1765
1728 return part; 1766 return part;
@@ -2083,12 +2121,17 @@ namespace OpenSim.Region.Framework.Scenes
2083 public Vector3 GetWorldPosition() 2121 public Vector3 GetWorldPosition()
2084 { 2122 {
2085 Quaternion parentRot = ParentGroup.RootPart.RotationOffset; 2123 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
2086
2087 Vector3 axPos = OffsetPosition; 2124 Vector3 axPos = OffsetPosition;
2088
2089 axPos *= parentRot; 2125 axPos *= parentRot;
2090 Vector3 translationOffsetPosition = axPos; 2126 Vector3 translationOffsetPosition = axPos;
2091 return GroupPosition + translationOffsetPosition; 2127 if(_parentID == 0)
2128 {
2129 return GroupPosition;
2130 }
2131 else
2132 {
2133 return ParentGroup.AbsolutePosition + translationOffsetPosition; //KF: Fix child prim position
2134 }
2092 } 2135 }
2093 2136
2094 /// <summary> 2137 /// <summary>
@@ -2745,17 +2788,18 @@ namespace OpenSim.Region.Framework.Scenes
2745 //Trys to fetch sound id from prim's inventory. 2788 //Trys to fetch sound id from prim's inventory.
2746 //Prim's inventory doesn't support non script items yet 2789 //Prim's inventory doesn't support non script items yet
2747 2790
2748 lock (TaskInventory) 2791 TaskInventory.LockItemsForRead(true);
2792
2793 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2749 { 2794 {
2750 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 2795 if (item.Value.Name == sound)
2751 { 2796 {
2752 if (item.Value.Name == sound) 2797 soundID = item.Value.ItemID;
2753 { 2798 break;
2754 soundID = item.Value.ItemID;
2755 break;
2756 }
2757 } 2799 }
2758 } 2800 }
2801
2802 TaskInventory.LockItemsForRead(false);
2759 } 2803 }
2760 2804
2761 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence sp) 2805 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence sp)
@@ -2815,7 +2859,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 /// <param name="scale"></param> 2859 /// <param name="scale"></param>
2816 public void Resize(Vector3 scale) 2860 public void Resize(Vector3 scale)
2817 { 2861 {
2818 StoreUndoState(); 2862 StoreUndoState(UndoType.STATE_PRIM_SCALE);
2819 m_shape.Scale = scale; 2863 m_shape.Scale = scale;
2820 2864
2821 ParentGroup.HasGroupChanged = true; 2865 ParentGroup.HasGroupChanged = true;
@@ -2824,38 +2868,7 @@ namespace OpenSim.Region.Framework.Scenes
2824 2868
2825 public void RotLookAt(Quaternion target, float strength, float damping) 2869 public void RotLookAt(Quaternion target, float strength, float damping)
2826 { 2870 {
2827 rotLookAt(target, strength, damping); 2871 m_parentGroup.rotLookAt(target, strength, damping); // This calls method in SceneObjectGroup.
2828 }
2829
2830 public void rotLookAt(Quaternion target, float strength, float damping)
2831 {
2832 if (IsAttachment)
2833 {
2834 /*
2835 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2836 if (avatar != null)
2837 {
2838 Rotate the Av?
2839 } */
2840 }
2841 else
2842 {
2843 APIDDamp = damping;
2844 APIDStrength = strength;
2845 APIDTarget = target;
2846 }
2847 }
2848
2849 public void startLookAt(Quaternion rot, float damp, float strength)
2850 {
2851 APIDDamp = damp;
2852 APIDStrength = strength;
2853 APIDTarget = rot;
2854 }
2855
2856 public void stopLookAt()
2857 {
2858 APIDTarget = Quaternion.Identity;
2859 } 2872 }
2860 2873
2861 /// <summary> 2874 /// <summary>
@@ -2867,7 +2880,10 @@ namespace OpenSim.Region.Framework.Scenes
2867 2880
2868 if (m_parentGroup != null) 2881 if (m_parentGroup != null)
2869 { 2882 {
2870 m_parentGroup.QueueForUpdateCheck(); 2883 if (!m_parentGroup.areUpdatesSuspended)
2884 {
2885 m_parentGroup.QueueForUpdateCheck();
2886 }
2871 } 2887 }
2872 2888
2873 int timeNow = Util.UnixTimeSinceEpoch(); 2889 int timeNow = Util.UnixTimeSinceEpoch();
@@ -3084,8 +3100,8 @@ namespace OpenSim.Region.Framework.Scenes
3084 { 3100 {
3085 const float ROTATION_TOLERANCE = 0.01f; 3101 const float ROTATION_TOLERANCE = 0.01f;
3086 const float VELOCITY_TOLERANCE = 0.001f; 3102 const float VELOCITY_TOLERANCE = 0.001f;
3087 const float POSITION_TOLERANCE = 0.05f; 3103 const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary
3088 const int TIME_MS_TOLERANCE = 3000; 3104 const int TIME_MS_TOLERANCE = 200; //llSetPos has a 200ms delay. This should NOT be 3 seconds.
3089 3105
3090 if (m_updateFlag == 1) 3106 if (m_updateFlag == 1)
3091 { 3107 {
@@ -3099,7 +3115,7 @@ namespace OpenSim.Region.Framework.Scenes
3099 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE) 3115 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE)
3100 { 3116 {
3101 AddTerseUpdateToAllAvatars(); 3117 AddTerseUpdateToAllAvatars();
3102 ClearUpdateSchedule(); 3118
3103 3119
3104 // This causes the Scene to 'poll' physical objects every couple of frames 3120 // This causes the Scene to 'poll' physical objects every couple of frames
3105 // bad, so it's been replaced by an event driven method. 3121 // bad, so it's been replaced by an event driven method.
@@ -3117,16 +3133,18 @@ namespace OpenSim.Region.Framework.Scenes
3117 m_lastAngularVelocity = AngularVelocity; 3133 m_lastAngularVelocity = AngularVelocity;
3118 m_lastTerseSent = Environment.TickCount; 3134 m_lastTerseSent = Environment.TickCount;
3119 } 3135 }
3136 //Moved this outside of the if clause so updates don't get blocked.. *sigh*
3137 m_updateFlag = 0; //Why were we calling a function to do this? Inefficient! *screams*
3120 } 3138 }
3121 else 3139 else
3122 { 3140 {
3123 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes 3141 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes
3124 { 3142 {
3125 AddFullUpdateToAllAvatars(); 3143 AddFullUpdateToAllAvatars();
3126 ClearUpdateSchedule(); 3144 m_updateFlag = 0; //Same here
3127 } 3145 }
3128 } 3146 }
3129 ClearUpdateSchedule(); 3147 m_updateFlag = 0;
3130 } 3148 }
3131 3149
3132 /// <summary> 3150 /// <summary>
@@ -3154,17 +3172,16 @@ namespace OpenSim.Region.Framework.Scenes
3154 if (!UUID.TryParse(sound, out soundID)) 3172 if (!UUID.TryParse(sound, out soundID))
3155 { 3173 {
3156 // search sound file from inventory 3174 // search sound file from inventory
3157 lock (TaskInventory) 3175 TaskInventory.LockItemsForRead(true);
3176 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
3158 { 3177 {
3159 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 3178 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound)
3160 { 3179 {
3161 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) 3180 soundID = item.Value.ItemID;
3162 { 3181 break;
3163 soundID = item.Value.ItemID;
3164 break;
3165 }
3166 } 3182 }
3167 } 3183 }
3184 TaskInventory.LockItemsForRead(false);
3168 } 3185 }
3169 3186
3170 if (soundID == UUID.Zero) 3187 if (soundID == UUID.Zero)
@@ -3594,7 +3611,7 @@ namespace OpenSim.Region.Framework.Scenes
3594 3611
3595 public void StopLookAt() 3612 public void StopLookAt()
3596 { 3613 {
3597 m_parentGroup.stopLookAt(); 3614 m_parentGroup.stopLookAt(); // This calls method in SceneObjectGroup.
3598 3615
3599 m_parentGroup.ScheduleGroupForTerseUpdate(); 3616 m_parentGroup.ScheduleGroupForTerseUpdate();
3600 } 3617 }
@@ -3621,10 +3638,9 @@ namespace OpenSim.Region.Framework.Scenes
3621 m_parentGroup.ScheduleGroupForTerseUpdate(); 3638 m_parentGroup.ScheduleGroupForTerseUpdate();
3622 //m_parentGroup.ScheduleGroupForFullUpdate(); 3639 //m_parentGroup.ScheduleGroupForFullUpdate();
3623 } 3640 }
3624 3641 public void StoreUndoState(UndoType type)
3625 public void StoreUndoState()
3626 { 3642 {
3627 if (!Undoing) 3643 if (!Undoing && (m_parentGroup == null || m_parentGroup.RootPart == null || !m_parentGroup.RootPart.Undoing))
3628 { 3644 {
3629 if (!IgnoreUndoUpdate) 3645 if (!IgnoreUndoUpdate)
3630 { 3646 {
@@ -3635,17 +3651,25 @@ namespace OpenSim.Region.Framework.Scenes
3635 if (m_undo.Count > 0) 3651 if (m_undo.Count > 0)
3636 { 3652 {
3637 UndoState last = m_undo.Peek(); 3653 UndoState last = m_undo.Peek();
3638 if (last != null) 3654
3639 {
3640 if (last.Compare(this))
3641 return;
3642 }
3643 } 3655 }
3644 3656
3645 if (m_parentGroup.GetSceneMaxUndo() > 0) 3657 if (m_parentGroup.GetSceneMaxUndo() > 0)
3646 { 3658 {
3647 UndoState nUndo = new UndoState(this); 3659 UndoState lastUndo = m_undo.Peek();
3648 3660
3661 UndoState nUndo = new UndoState(this, type);
3662
3663 if (lastUndo != null)
3664 {
3665 TimeSpan ts = DateTime.Now.Subtract(lastUndo.LastUpdated);
3666 if (ts.TotalMilliseconds < 500)
3667 {
3668 //Delete the last entry since it was less than 500 milliseconds ago
3669 nUndo.Merge(lastUndo);
3670 m_undo.Pop();
3671 }
3672 }
3649 m_undo.Push(nUndo); 3673 m_undo.Push(nUndo);
3650 } 3674 }
3651 3675
@@ -4122,11 +4146,13 @@ namespace OpenSim.Region.Framework.Scenes
4122 if (m_undo.Count > 0) 4146 if (m_undo.Count > 0)
4123 { 4147 {
4124 UndoState nUndo = null; 4148 UndoState nUndo = null;
4149 UndoState goback = m_undo.Pop();
4125 if (m_parentGroup.GetSceneMaxUndo() > 0) 4150 if (m_parentGroup.GetSceneMaxUndo() > 0)
4126 { 4151 {
4127 nUndo = new UndoState(this); 4152 nUndo = new UndoState(this, goback.Type);
4128 } 4153 }
4129 UndoState goback = m_undo.Pop(); 4154
4155
4130 if (goback != null) 4156 if (goback != null)
4131 { 4157 {
4132 goback.PlaybackState(this); 4158 goback.PlaybackState(this);
@@ -4141,13 +4167,13 @@ namespace OpenSim.Region.Framework.Scenes
4141 { 4167 {
4142 lock (m_redo) 4168 lock (m_redo)
4143 { 4169 {
4170 UndoState gofwd = m_redo.Pop();
4144 if (m_parentGroup.GetSceneMaxUndo() > 0) 4171 if (m_parentGroup.GetSceneMaxUndo() > 0)
4145 { 4172 {
4146 UndoState nUndo = new UndoState(this); 4173 UndoState nUndo = new UndoState(this, gofwd.Type);
4147 4174
4148 m_undo.Push(nUndo); 4175 m_undo.Push(nUndo);
4149 } 4176 }
4150 UndoState gofwd = m_redo.Pop();
4151 if (gofwd != null) 4177 if (gofwd != null)
4152 gofwd.PlayfwdState(this); 4178 gofwd.PlayfwdState(this);
4153 } 4179 }
@@ -4411,6 +4437,7 @@ namespace OpenSim.Region.Framework.Scenes
4411 Scale, 4437 Scale,
4412 RotationOffset, 4438 RotationOffset,
4413 UsePhysics); 4439 UsePhysics);
4440 PhysActor.SetMaterial(Material);
4414 4441
4415 pa = PhysActor; 4442 pa = PhysActor;
4416 if (pa != null) 4443 if (pa != null)
@@ -4596,8 +4623,9 @@ namespace OpenSim.Region.Framework.Scenes
4596 { 4623 {
4597 m_shape.TextureEntry = textureEntry; 4624 m_shape.TextureEntry = textureEntry;
4598 TriggerScriptChangedEvent(Changed.TEXTURE); 4625 TriggerScriptChangedEvent(Changed.TEXTURE);
4599 4626 m_updateFlag = 1;
4600 ParentGroup.HasGroupChanged = true; 4627 ParentGroup.HasGroupChanged = true;
4628
4601 //This is madness.. 4629 //This is madness..
4602 //ParentGroup.ScheduleGroupForFullUpdate(); 4630 //ParentGroup.ScheduleGroupForFullUpdate();
4603 //This is sparta 4631 //This is sparta
@@ -4830,5 +4858,17 @@ namespace OpenSim.Region.Framework.Scenes
4830 Color color = Color; 4858 Color color = Color;
4831 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); 4859 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A));
4832 } 4860 }
4861
4862 public void ResetOwnerChangeFlag()
4863 {
4864 List<UUID> inv = Inventory.GetInventoryList();
4865
4866 foreach (UUID itemID in inv)
4867 {
4868 TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
4869 item.OwnerChanged = false;
4870 Inventory.UpdateInventoryItem(item, false, false);
4871 }
4872 }
4833 } 4873 }
4834} 4874}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index 3281eab..1992956 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -48,6 +48,9 @@ namespace OpenSim.Region.Framework.Scenes
48 private string m_inventoryFileName = String.Empty; 48 private string m_inventoryFileName = String.Empty;
49 private byte[] m_inventoryFileData = new byte[0]; 49 private byte[] m_inventoryFileData = new byte[0];
50 private uint m_inventoryFileNameSerial = 0; 50 private uint m_inventoryFileNameSerial = 0;
51 private bool m_inventoryPrivileged = false;
52
53 private Dictionary<UUID, ArrayList> m_scriptErrors = new Dictionary<UUID, ArrayList>();
51 54
52 /// <value> 55 /// <value>
53 /// The part to which the inventory belongs. 56 /// The part to which the inventory belongs.
@@ -84,11 +87,14 @@ namespace OpenSim.Region.Framework.Scenes
84 /// </value> 87 /// </value>
85 protected internal TaskInventoryDictionary Items 88 protected internal TaskInventoryDictionary Items
86 { 89 {
87 get { return m_items; } 90 get {
91 return m_items;
92 }
88 set 93 set
89 { 94 {
90 m_items = value; 95 m_items = value;
91 m_inventorySerial++; 96 m_inventorySerial++;
97 QueryScriptStates();
92 } 98 }
93 } 99 }
94 100
@@ -120,39 +126,45 @@ namespace OpenSim.Region.Framework.Scenes
120 /// <param name="linkNum">Link number for the part</param> 126 /// <param name="linkNum">Link number for the part</param>
121 public void ResetInventoryIDs() 127 public void ResetInventoryIDs()
122 { 128 {
123 if (null == m_part || null == m_part.ParentGroup) 129 m_items.LockItemsForWrite(true);
124 return; 130
125 131 if (Items.Count == 0)
126 lock (m_items)
127 { 132 {
128 if (0 == m_items.Count) 133 m_items.LockItemsForWrite(false);
129 return; 134 return;
135 }
130 136
131 IList<TaskInventoryItem> items = GetInventoryItems(); 137 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
132 m_items.Clear(); 138 Items.Clear();
133 139
134 foreach (TaskInventoryItem item in items) 140 foreach (TaskInventoryItem item in items)
135 { 141 {
136 item.ResetIDs(m_part.UUID); 142 item.ResetIDs(m_part.UUID);
137 m_items.Add(item.ItemID, item); 143 Items.Add(item.ItemID, item);
138 }
139 } 144 }
145 m_items.LockItemsForWrite(false);
140 } 146 }
141 147
142 public void ResetObjectID() 148 public void ResetObjectID()
143 { 149 {
144 lock (Items) 150 m_items.LockItemsForWrite(true);
151
152 if (Items.Count == 0)
145 { 153 {
146 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); 154 m_items.LockItemsForWrite(false);
147 Items.Clear(); 155 return;
148
149 foreach (TaskInventoryItem item in items)
150 {
151 item.ParentPartID = m_part.UUID;
152 item.ParentID = m_part.UUID;
153 Items.Add(item.ItemID, item);
154 }
155 } 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 m_items.LockItemsForWrite(false);
156 } 168 }
157 169
158 /// <summary> 170 /// <summary>
@@ -161,12 +173,11 @@ namespace OpenSim.Region.Framework.Scenes
161 /// <param name="ownerId"></param> 173 /// <param name="ownerId"></param>
162 public void ChangeInventoryOwner(UUID ownerId) 174 public void ChangeInventoryOwner(UUID ownerId)
163 { 175 {
164 lock (Items) 176 m_items.LockItemsForWrite(true);
177 if (0 == Items.Count)
165 { 178 {
166 if (0 == Items.Count) 179 m_items.LockItemsForWrite(false);
167 { 180 return;
168 return;
169 }
170 } 181 }
171 182
172 HasInventoryChanged = true; 183 HasInventoryChanged = true;
@@ -182,6 +193,7 @@ namespace OpenSim.Region.Framework.Scenes
182 item.PermsGranter = UUID.Zero; 193 item.PermsGranter = UUID.Zero;
183 item.OwnerChanged = true; 194 item.OwnerChanged = true;
184 } 195 }
196 m_items.LockItemsForWrite(false);
185 } 197 }
186 198
187 /// <summary> 199 /// <summary>
@@ -190,12 +202,11 @@ namespace OpenSim.Region.Framework.Scenes
190 /// <param name="groupID"></param> 202 /// <param name="groupID"></param>
191 public void ChangeInventoryGroup(UUID groupID) 203 public void ChangeInventoryGroup(UUID groupID)
192 { 204 {
193 lock (Items) 205 m_items.LockItemsForWrite(true);
206 if (0 == Items.Count)
194 { 207 {
195 if (0 == Items.Count) 208 m_items.LockItemsForWrite(false);
196 { 209 return;
197 return;
198 }
199 } 210 }
200 211
201 // Don't let this set the HasGroupChanged flag for attachments 212 // Don't let this set the HasGroupChanged flag for attachments
@@ -207,12 +218,45 @@ namespace OpenSim.Region.Framework.Scenes
207 m_part.ParentGroup.HasGroupChanged = true; 218 m_part.ParentGroup.HasGroupChanged = true;
208 } 219 }
209 220
210 List<TaskInventoryItem> items = GetInventoryItems(); 221 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
211 foreach (TaskInventoryItem item in items) 222 foreach (TaskInventoryItem item in items)
212 { 223 {
213 if (groupID != item.GroupID) 224 if (groupID != item.GroupID)
225 {
214 item.GroupID = groupID; 226 item.GroupID = groupID;
227 }
215 } 228 }
229 m_items.LockItemsForWrite(false);
230 }
231
232 private void QueryScriptStates()
233 {
234 if (m_part == null || m_part.ParentGroup == null)
235 return;
236
237 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
238 if (engines == null) // No engine at all
239 return;
240
241 Items.LockItemsForRead(true);
242 foreach (TaskInventoryItem item in Items.Values)
243 {
244 if (item.InvType == (int)InventoryType.LSL)
245 {
246 foreach (IScriptModule e in engines)
247 {
248 bool running;
249
250 if (e.HasScript(item.ItemID, out running))
251 {
252 item.ScriptRunning = running;
253 break;
254 }
255 }
256 }
257 }
258
259 Items.LockItemsForRead(false);
216 } 260 }
217 261
218 /// <summary> 262 /// <summary>
@@ -220,9 +264,14 @@ namespace OpenSim.Region.Framework.Scenes
220 /// </summary> 264 /// </summary>
221 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) 265 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
222 { 266 {
223 List<TaskInventoryItem> scripts = GetInventoryScripts(); 267 Items.LockItemsForRead(true);
224 foreach (TaskInventoryItem item in scripts) 268 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
225 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 269 Items.LockItemsForRead(false);
270 foreach (TaskInventoryItem item in items)
271 {
272 if ((int)InventoryType.LSL == item.InvType)
273 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
274 }
226 } 275 }
227 276
228 public ArrayList GetScriptErrors(UUID itemID) 277 public ArrayList GetScriptErrors(UUID itemID)
@@ -255,9 +304,18 @@ namespace OpenSim.Region.Framework.Scenes
255 /// </param> 304 /// </param>
256 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 305 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
257 { 306 {
258 List<TaskInventoryItem> scripts = GetInventoryScripts(); 307 Items.LockItemsForRead(true);
259 foreach (TaskInventoryItem item in scripts) 308 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
260 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); 309 Items.LockItemsForRead(false);
310
311 foreach (TaskInventoryItem item in items)
312 {
313 if ((int)InventoryType.LSL == item.InvType)
314 {
315 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
316 m_part.RemoveScriptEvents(item.ItemID);
317 }
318 }
261 } 319 }
262 320
263 /// <summary> 321 /// <summary>
@@ -273,7 +331,10 @@ namespace OpenSim.Region.Framework.Scenes
273 // item.Name, item.ItemID, Name, UUID); 331 // item.Name, item.ItemID, Name, UUID);
274 332
275 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) 333 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
334 {
335 StoreScriptError(item.ItemID, "no permission");
276 return; 336 return;
337 }
277 338
278 m_part.AddFlag(PrimFlags.Scripted); 339 m_part.AddFlag(PrimFlags.Scripted);
279 340
@@ -282,14 +343,13 @@ namespace OpenSim.Region.Framework.Scenes
282 if (stateSource == 2 && // Prim crossing 343 if (stateSource == 2 && // Prim crossing
283 m_part.ParentGroup.Scene.m_trustBinaries) 344 m_part.ParentGroup.Scene.m_trustBinaries)
284 { 345 {
285 lock (m_items) 346 m_items.LockItemsForWrite(true);
286 { 347 m_items[item.ItemID].PermsMask = 0;
287 m_items[item.ItemID].PermsMask = 0; 348 m_items[item.ItemID].PermsGranter = UUID.Zero;
288 m_items[item.ItemID].PermsGranter = UUID.Zero; 349 m_items.LockItemsForWrite(false);
289 }
290
291 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 350 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
292 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); 351 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
352 StoreScriptErrors(item.ItemID, null);
293 m_part.ParentGroup.AddActiveScriptCount(1); 353 m_part.ParentGroup.AddActiveScriptCount(1);
294 m_part.ScheduleFullUpdate(); 354 m_part.ScheduleFullUpdate();
295 return; 355 return;
@@ -298,6 +358,8 @@ namespace OpenSim.Region.Framework.Scenes
298 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); 358 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
299 if (null == asset) 359 if (null == asset)
300 { 360 {
361 string msg = String.Format("asset ID {0} could not be found", item.AssetID);
362 StoreScriptError(item.ItemID, msg);
301 m_log.ErrorFormat( 363 m_log.ErrorFormat(
302 "[PRIM INVENTORY]: " + 364 "[PRIM INVENTORY]: " +
303 "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", 365 "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
@@ -309,15 +371,20 @@ namespace OpenSim.Region.Framework.Scenes
309 if (m_part.ParentGroup.m_savedScriptState != null) 371 if (m_part.ParentGroup.m_savedScriptState != null)
310 RestoreSavedScriptState(item.OldItemID, item.ItemID); 372 RestoreSavedScriptState(item.OldItemID, item.ItemID);
311 373
312 lock (m_items) 374 m_items.LockItemsForWrite(true);
313 { 375
314 m_items[item.ItemID].PermsMask = 0; 376 m_items[item.ItemID].PermsMask = 0;
315 m_items[item.ItemID].PermsGranter = UUID.Zero; 377 m_items[item.ItemID].PermsGranter = UUID.Zero;
316 } 378
379 m_items.LockItemsForWrite(false);
317 380
318 string script = Utils.BytesToString(asset.Data); 381 string script = Utils.BytesToString(asset.Data);
319 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 382 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
320 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); 383 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
384 StoreScriptErrors(item.ItemID, null);
385 if (!item.ScriptRunning)
386 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(
387 m_part.LocalId, item.ItemID);
321 m_part.ParentGroup.AddActiveScriptCount(1); 388 m_part.ParentGroup.AddActiveScriptCount(1);
322 m_part.ScheduleFullUpdate(); 389 m_part.ScheduleFullUpdate();
323 } 390 }
@@ -381,21 +448,145 @@ namespace OpenSim.Region.Framework.Scenes
381 448
382 /// <summary> 449 /// <summary>
383 /// Start a script which is in this prim's inventory. 450 /// Start a script which is in this prim's inventory.
451 /// Some processing may occur in the background, but this routine returns asap.
384 /// </summary> 452 /// </summary>
385 /// <param name="itemId"> 453 /// <param name="itemId">
386 /// A <see cref="UUID"/> 454 /// A <see cref="UUID"/>
387 /// </param> 455 /// </param>
388 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) 456 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
389 { 457 {
390 TaskInventoryItem item = GetInventoryItem(itemId); 458 lock (m_scriptErrors)
391 if (item != null) 459 {
392 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 460 // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
461 m_scriptErrors.Remove(itemId);
462 }
463 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
464 }
465
466 private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
467 {
468 m_items.LockItemsForRead(true);
469 if (m_items.ContainsKey(itemId))
470 {
471 if (m_items.ContainsKey(itemId))
472 {
473 m_items.LockItemsForRead(false);
474 CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource);
475 }
476 else
477 {
478 m_items.LockItemsForRead(false);
479 string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID,
480 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
481 StoreScriptError(itemId, msg);
482 m_log.ErrorFormat(
483 "[PRIM INVENTORY]: " +
484 "Couldn't start script with ID {0} since it {1}", itemId, msg);
485 }
486 }
393 else 487 else
488 {
489 m_items.LockItemsForRead(false);
490 string msg = String.Format("couldn't be found for prim {0}, {1}", m_part.Name, m_part.UUID);
491 StoreScriptError(itemId, msg);
394 m_log.ErrorFormat( 492 m_log.ErrorFormat(
395 "[PRIM INVENTORY]: " + 493 "[PRIM INVENTORY]: " +
396 "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", 494 "Couldn't start script with ID {0} since it {1}", itemId, msg);
397 itemId, m_part.Name, m_part.UUID, 495 }
398 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 496
497 }
498
499 /// <summary>
500 /// Start a script which is in this prim's inventory and return any compilation error messages.
501 /// </summary>
502 /// <param name="itemId">
503 /// A <see cref="UUID"/>
504 /// </param>
505 public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
506 {
507 ArrayList errors;
508
509 // Indicate to CreateScriptInstanceInternal() we want it to
510 // post any compilation/loading error messages
511 lock (m_scriptErrors)
512 {
513 m_scriptErrors[itemId] = null;
514 }
515
516 // Perform compilation/loading
517 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
518
519 // Wait for and retrieve any errors
520 lock (m_scriptErrors)
521 {
522 while ((errors = m_scriptErrors[itemId]) == null)
523 {
524 if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
525 {
526 m_log.ErrorFormat(
527 "[PRIM INVENTORY]: " +
528 "timedout waiting for script {0} errors", itemId);
529 errors = m_scriptErrors[itemId];
530 if (errors == null)
531 {
532 errors = new ArrayList(1);
533 errors.Add("timedout waiting for errors");
534 }
535 break;
536 }
537 }
538 m_scriptErrors.Remove(itemId);
539 }
540 return errors;
541 }
542
543 // Signal to CreateScriptInstanceEr() that compilation/loading is complete
544 private void StoreScriptErrors(UUID itemId, ArrayList errors)
545 {
546 lock (m_scriptErrors)
547 {
548 // If compilation/loading initiated via CreateScriptInstance(),
549 // it does not want the errors, so just get out
550 if (!m_scriptErrors.ContainsKey(itemId))
551 {
552 return;
553 }
554
555 // Initiated via CreateScriptInstanceEr(), if we know what the
556 // errors are, save them and wake CreateScriptInstanceEr().
557 if (errors != null)
558 {
559 m_scriptErrors[itemId] = errors;
560 System.Threading.Monitor.PulseAll(m_scriptErrors);
561 return;
562 }
563 }
564
565 // Initiated via CreateScriptInstanceEr() but we don't know what
566 // the errors are yet, so retrieve them from the script engine.
567 // This may involve some waiting internal to GetScriptErrors().
568 errors = GetScriptErrors(itemId);
569
570 // Get a default non-null value to indicate success.
571 if (errors == null)
572 {
573 errors = new ArrayList();
574 }
575
576 // Post to CreateScriptInstanceEr() and wake it up
577 lock (m_scriptErrors)
578 {
579 m_scriptErrors[itemId] = errors;
580 System.Threading.Monitor.PulseAll(m_scriptErrors);
581 }
582 }
583
584 // Like StoreScriptErrors(), but just posts a single string message
585 private void StoreScriptError(UUID itemId, string message)
586 {
587 ArrayList errors = new ArrayList(1);
588 errors.Add(message);
589 StoreScriptErrors(itemId, errors);
399 } 590 }
400 591
401 /// <summary> 592 /// <summary>
@@ -408,15 +599,7 @@ namespace OpenSim.Region.Framework.Scenes
408 /// </param> 599 /// </param>
409 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) 600 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
410 { 601 {
411 bool scriptPresent = false; 602 if (m_items.ContainsKey(itemId))
412
413 lock (m_items)
414 {
415 if (m_items.ContainsKey(itemId))
416 scriptPresent = true;
417 }
418
419 if (scriptPresent)
420 { 603 {
421 if (!sceneObjectBeingDeleted) 604 if (!sceneObjectBeingDeleted)
422 m_part.RemoveScriptEvents(itemId); 605 m_part.RemoveScriptEvents(itemId);
@@ -441,14 +624,16 @@ namespace OpenSim.Region.Framework.Scenes
441 /// <returns></returns> 624 /// <returns></returns>
442 private bool InventoryContainsName(string name) 625 private bool InventoryContainsName(string name)
443 { 626 {
444 lock (m_items) 627 m_items.LockItemsForRead(true);
628 foreach (TaskInventoryItem item in m_items.Values)
445 { 629 {
446 foreach (TaskInventoryItem item in m_items.Values) 630 if (item.Name == name)
447 { 631 {
448 if (item.Name == name) 632 m_items.LockItemsForRead(false);
449 return true; 633 return true;
450 } 634 }
451 } 635 }
636 m_items.LockItemsForRead(false);
452 return false; 637 return false;
453 } 638 }
454 639
@@ -490,8 +675,9 @@ namespace OpenSim.Region.Framework.Scenes
490 /// <param name="item"></param> 675 /// <param name="item"></param>
491 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) 676 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
492 { 677 {
493 List<TaskInventoryItem> il = GetInventoryItems(); 678 m_items.LockItemsForRead(true);
494 679 List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
680 m_items.LockItemsForRead(false);
495 foreach (TaskInventoryItem i in il) 681 foreach (TaskInventoryItem i in il)
496 { 682 {
497 if (i.Name == item.Name) 683 if (i.Name == item.Name)
@@ -529,14 +715,14 @@ namespace OpenSim.Region.Framework.Scenes
529 item.Name = name; 715 item.Name = name;
530 item.GroupID = m_part.GroupID; 716 item.GroupID = m_part.GroupID;
531 717
532 lock (m_items) 718 m_items.LockItemsForWrite(true);
533 m_items.Add(item.ItemID, item); 719 m_items.Add(item.ItemID, item);
534 720 m_items.LockItemsForWrite(false);
535 if (allowedDrop) 721 if (allowedDrop)
536 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); 722 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
537 else 723 else
538 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 724 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
539 725
540 m_inventorySerial++; 726 m_inventorySerial++;
541 //m_inventorySerial += 2; 727 //m_inventorySerial += 2;
542 HasInventoryChanged = true; 728 HasInventoryChanged = true;
@@ -552,15 +738,15 @@ namespace OpenSim.Region.Framework.Scenes
552 /// <param name="items"></param> 738 /// <param name="items"></param>
553 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) 739 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
554 { 740 {
555 lock (m_items) 741 m_items.LockItemsForWrite(true);
742 foreach (TaskInventoryItem item in items)
556 { 743 {
557 foreach (TaskInventoryItem item in items) 744 m_items.Add(item.ItemID, item);
558 { 745// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
559 m_items.Add(item.ItemID, item);
560// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
561 }
562 m_inventorySerial++;
563 } 746 }
747 m_items.LockItemsForWrite(false);
748
749 m_inventorySerial++;
564 } 750 }
565 751
566 /// <summary> 752 /// <summary>
@@ -571,10 +757,9 @@ namespace OpenSim.Region.Framework.Scenes
571 public TaskInventoryItem GetInventoryItem(UUID itemId) 757 public TaskInventoryItem GetInventoryItem(UUID itemId)
572 { 758 {
573 TaskInventoryItem item; 759 TaskInventoryItem item;
574 760 m_items.LockItemsForRead(true);
575 lock (m_items) 761 m_items.TryGetValue(itemId, out item);
576 m_items.TryGetValue(itemId, out item); 762 m_items.LockItemsForRead(false);
577
578 return item; 763 return item;
579 } 764 }
580 765
@@ -590,15 +775,16 @@ namespace OpenSim.Region.Framework.Scenes
590 { 775 {
591 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(); 776 IList<TaskInventoryItem> items = new List<TaskInventoryItem>();
592 777
593 lock (m_items) 778 m_items.LockItemsForRead(true);
779
780 foreach (TaskInventoryItem item in m_items.Values)
594 { 781 {
595 foreach (TaskInventoryItem item in m_items.Values) 782 if (item.Name == name)
596 { 783 items.Add(item);
597 if (item.Name == name)
598 items.Add(item);
599 }
600 } 784 }
601 785
786 m_items.LockItemsForRead(false);
787
602 return items; 788 return items;
603 } 789 }
604 790
@@ -691,9 +877,9 @@ namespace OpenSim.Region.Framework.Scenes
691 877
692 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) 878 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
693 { 879 {
694 TaskInventoryItem it = GetInventoryItem(item.ItemID); 880 m_items.LockItemsForWrite(true);
695 if (it != null)
696 881
882 if (m_items.ContainsKey(item.ItemID))
697 { 883 {
698 item.ParentID = m_part.UUID; 884 item.ParentID = m_part.UUID;
699 item.ParentPartID = m_part.UUID; 885 item.ParentPartID = m_part.UUID;
@@ -704,14 +890,10 @@ namespace OpenSim.Region.Framework.Scenes
704 item.GroupID = m_part.GroupID; 890 item.GroupID = m_part.GroupID;
705 891
706 if (item.AssetID == UUID.Zero) 892 if (item.AssetID == UUID.Zero)
707 item.AssetID = it.AssetID; 893 item.AssetID = m_items[item.ItemID].AssetID;
708
709 lock (m_items)
710 {
711 m_items[item.ItemID] = item;
712 m_inventorySerial++;
713 }
714 894
895 m_items[item.ItemID] = item;
896 m_inventorySerial++;
715 if (fireScriptEvents) 897 if (fireScriptEvents)
716 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 898 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
717 if (considerChanged) 899 if (considerChanged)
@@ -719,6 +901,7 @@ namespace OpenSim.Region.Framework.Scenes
719 HasInventoryChanged = true; 901 HasInventoryChanged = true;
720 m_part.ParentGroup.HasGroupChanged = true; 902 m_part.ParentGroup.HasGroupChanged = true;
721 } 903 }
904 m_items.LockItemsForWrite(false);
722 return true; 905 return true;
723 } 906 }
724 else 907 else
@@ -729,8 +912,9 @@ namespace OpenSim.Region.Framework.Scenes
729 item.ItemID, m_part.Name, m_part.UUID, 912 item.ItemID, m_part.Name, m_part.UUID,
730 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 913 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
731 } 914 }
732 return false; 915 m_items.LockItemsForWrite(false);
733 916
917 return false;
734 } 918 }
735 919
736 /// <summary> 920 /// <summary>
@@ -741,107 +925,68 @@ namespace OpenSim.Region.Framework.Scenes
741 /// in this prim's inventory.</returns> 925 /// in this prim's inventory.</returns>
742 public int RemoveInventoryItem(UUID itemID) 926 public int RemoveInventoryItem(UUID itemID)
743 { 927 {
744 TaskInventoryItem item = GetInventoryItem(itemID); 928 m_items.LockItemsForRead(true);
745 if (item != null) 929
930 if (m_items.ContainsKey(itemID))
746 { 931 {
747 int type = m_items[itemID].InvType; 932 int type = m_items[itemID].InvType;
933 m_items.LockItemsForRead(false);
748 if (type == 10) // Script 934 if (type == 10) // Script
749 { 935 {
750 m_part.RemoveScriptEvents(itemID);
751 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); 936 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
752 } 937 }
938 m_items.LockItemsForWrite(true);
753 m_items.Remove(itemID); 939 m_items.Remove(itemID);
940 m_items.LockItemsForWrite(false);
754 m_inventorySerial++; 941 m_inventorySerial++;
755 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 942 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
756 943
757 HasInventoryChanged = true; 944 HasInventoryChanged = true;
758 m_part.ParentGroup.HasGroupChanged = true; 945 m_part.ParentGroup.HasGroupChanged = true;
759 946
760 if (!ContainsScripts()) 947 int scriptcount = 0;
948 m_items.LockItemsForRead(true);
949 foreach (TaskInventoryItem item in m_items.Values)
950 {
951 if (item.Type == 10)
952 {
953 scriptcount++;
954 }
955 }
956 m_items.LockItemsForRead(false);
957
958
959 if (scriptcount <= 0)
960 {
761 m_part.RemFlag(PrimFlags.Scripted); 961 m_part.RemFlag(PrimFlags.Scripted);
962 }
762 963
763 m_part.ScheduleFullUpdate(); 964 m_part.ScheduleFullUpdate();
764 965
765 return type; 966 return type;
766
767 } 967 }
768 else 968 else
769 { 969 {
970 m_items.LockItemsForRead(false);
770 m_log.ErrorFormat( 971 m_log.ErrorFormat(
771 "[PRIM INVENTORY]: " + 972 "[PRIM INVENTORY]: " +
772 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", 973 "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
773 itemID, m_part.Name, m_part.UUID, 974 itemID, m_part.Name, m_part.UUID);
774 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
775 } 975 }
776 976
777 return -1; 977 return -1;
778 } 978 }
779 979
780 private bool CreateInventoryFile() 980 private bool CreateInventoryFileName()
781 { 981 {
782 if (m_inventoryFileName == String.Empty || 982 if (m_inventoryFileName == String.Empty ||
783 m_inventoryFileNameSerial < m_inventorySerial) 983 m_inventoryFileNameSerial < m_inventorySerial)
784 { 984 {
785 // Something changed, we need to create a new file
786 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; 985 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
787 m_inventoryFileNameSerial = m_inventorySerial; 986 m_inventoryFileNameSerial = m_inventorySerial;
788
789 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
790
791 lock (m_items)
792 {
793 foreach (TaskInventoryItem item in m_items.Values)
794 {
795 UUID ownerID = item.OwnerID;
796 uint everyoneMask = 0;
797 uint baseMask = item.BasePermissions;
798 uint ownerMask = item.CurrentPermissions;
799 uint groupMask = item.GroupPermissions;
800
801 invString.AddItemStart();
802 invString.AddNameValueLine("item_id", item.ItemID.ToString());
803 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
804
805 invString.AddPermissionsStart();
806
807 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
808 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
809 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
810 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
811 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
812
813 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
814 invString.AddNameValueLine("owner_id", ownerID.ToString());
815
816 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
817
818 invString.AddNameValueLine("group_id", item.GroupID.ToString());
819 invString.AddSectionEnd();
820
821 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
822 invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
823 invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
824 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
825
826 invString.AddSaleStart();
827 invString.AddNameValueLine("sale_type", "not");
828 invString.AddNameValueLine("sale_price", "0");
829 invString.AddSectionEnd();
830
831 invString.AddNameValueLine("name", item.Name + "|");
832 invString.AddNameValueLine("desc", item.Description + "|");
833
834 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
835 invString.AddSectionEnd();
836 }
837 }
838
839 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
840
841 return true; 987 return true;
842 } 988 }
843 989
844 // No need to recreate, the existing file is fine
845 return false; 990 return false;
846 } 991 }
847 992
@@ -851,26 +996,99 @@ namespace OpenSim.Region.Framework.Scenes
851 /// <param name="xferManager"></param> 996 /// <param name="xferManager"></param>
852 public void RequestInventoryFile(IClientAPI client, IXfer xferManager) 997 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
853 { 998 {
854 CreateInventoryFile(); 999 bool changed = CreateInventoryFileName();
1000
1001 bool includeAssets = false;
1002 if (m_part.ParentGroup.Scene.Permissions.CanEditObjectInventory(m_part.UUID, client.AgentId))
1003 includeAssets = true;
1004
1005 if (m_inventoryPrivileged != includeAssets)
1006 changed = true;
1007
1008 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
1009
1010 Items.LockItemsForRead(true);
855 1011
856 if (m_inventorySerial == 0) // No inventory 1012 if (m_inventorySerial == 0) // No inventory
857 { 1013 {
858 client.SendTaskInventory(m_part.UUID, 0, new byte[0]); 1014 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
1015 Items.LockItemsForRead(false);
859 return; 1016 return;
860 } 1017 }
861 1018
862 // In principle, we should only do the rest if the inventory changed; 1019 if (!changed)
863 // by sending m_inventorySerial to the client, it ought to know 1020 {
864 // that nothing changed and that it doesn't need to request the file. 1021 if (m_inventoryFileData.Length > 2)
865 // Unfortunately, it doesn't look like the client optimizes this; 1022 {
866 // the client seems to always come back and request the Xfer, 1023 xferManager.AddNewFile(m_inventoryFileName,
867 // no matter what value m_inventorySerial has. 1024 m_inventoryFileData);
1025 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
1026 Util.StringToBytes256(m_inventoryFileName));
1027
1028 Items.LockItemsForRead(false);
1029 return;
1030 }
1031 }
1032
1033 m_inventoryPrivileged = includeAssets;
1034
1035 foreach (TaskInventoryItem item in m_items.Values)
1036 {
1037 UUID ownerID = item.OwnerID;
1038 uint everyoneMask = 0;
1039 uint baseMask = item.BasePermissions;
1040 uint ownerMask = item.CurrentPermissions;
1041 uint groupMask = item.GroupPermissions;
1042
1043 invString.AddItemStart();
1044 invString.AddNameValueLine("item_id", item.ItemID.ToString());
1045 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
1046
1047 invString.AddPermissionsStart();
1048
1049 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
1050 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
1051 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
1052 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
1053 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
1054
1055 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
1056 invString.AddNameValueLine("owner_id", ownerID.ToString());
1057
1058 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
1059
1060 invString.AddNameValueLine("group_id", item.GroupID.ToString());
1061 invString.AddSectionEnd();
1062
1063 if (includeAssets)
1064 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
1065 else
1066 invString.AddNameValueLine("asset_id", UUID.Zero.ToString());
1067 invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
1068 invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
1069 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
1070
1071 invString.AddSaleStart();
1072 invString.AddNameValueLine("sale_type", "not");
1073 invString.AddNameValueLine("sale_price", "0");
1074 invString.AddSectionEnd();
1075
1076 invString.AddNameValueLine("name", item.Name + "|");
1077 invString.AddNameValueLine("desc", item.Description + "|");
1078
1079 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
1080 invString.AddSectionEnd();
1081 }
1082
1083 Items.LockItemsForRead(false);
1084
1085 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
868 1086
869 if (m_inventoryFileData.Length > 2) 1087 if (m_inventoryFileData.Length > 2)
870 // Add the file for Xfer 1088 {
871 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); 1089 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
1090 }
872 1091
873 // Tell the client we're ready to Xfer the file
874 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial, 1092 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
875 Util.StringToBytes256(m_inventoryFileName)); 1093 Util.StringToBytes256(m_inventoryFileName));
876 } 1094 }
@@ -883,10 +1101,11 @@ namespace OpenSim.Region.Framework.Scenes
883 { 1101 {
884 if (HasInventoryChanged) 1102 if (HasInventoryChanged)
885 { 1103 {
886 HasInventoryChanged = false; 1104 Items.LockItemsForRead(true);
887 List<TaskInventoryItem> items = GetInventoryItems(); 1105 datastore.StorePrimInventory(m_part.UUID, Items.Values);
888 datastore.StorePrimInventory(m_part.UUID, items); 1106 Items.LockItemsForRead(false);
889 1107
1108 HasInventoryChanged = false;
890 } 1109 }
891 } 1110 }
892 1111
@@ -953,82 +1172,63 @@ namespace OpenSim.Region.Framework.Scenes
953 { 1172 {
954 uint mask=0x7fffffff; 1173 uint mask=0x7fffffff;
955 1174
956 lock (m_items) 1175 foreach (TaskInventoryItem item in m_items.Values)
957 { 1176 {
958 foreach (TaskInventoryItem item in m_items.Values) 1177 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1178 mask &= ~((uint)PermissionMask.Copy >> 13);
1179 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1180 mask &= ~((uint)PermissionMask.Transfer >> 13);
1181 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1182 mask &= ~((uint)PermissionMask.Modify >> 13);
1183
1184 if (item.InvType == (int)InventoryType.Object)
959 { 1185 {
960 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) 1186 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
961 mask &= ~((uint)PermissionMask.Copy >> 13); 1187 mask &= ~((uint)PermissionMask.Copy >> 13);
962 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) 1188 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
963 mask &= ~((uint)PermissionMask.Transfer >> 13); 1189 mask &= ~((uint)PermissionMask.Transfer >> 13);
964 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) 1190 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
965 mask &= ~((uint)PermissionMask.Modify >> 13); 1191 mask &= ~((uint)PermissionMask.Modify >> 13);
966
967 if (item.InvType != (int)InventoryType.Object)
968 {
969 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
970 mask &= ~((uint)PermissionMask.Copy >> 13);
971 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
972 mask &= ~((uint)PermissionMask.Transfer >> 13);
973 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
974 mask &= ~((uint)PermissionMask.Modify >> 13);
975 }
976 else
977 {
978 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
979 mask &= ~((uint)PermissionMask.Copy >> 13);
980 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
981 mask &= ~((uint)PermissionMask.Transfer >> 13);
982 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
983 mask &= ~((uint)PermissionMask.Modify >> 13);
984 }
985
986 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
987 mask &= ~(uint)PermissionMask.Copy;
988 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
989 mask &= ~(uint)PermissionMask.Transfer;
990 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
991 mask &= ~(uint)PermissionMask.Modify;
992 } 1192 }
1193
1194 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1195 mask &= ~(uint)PermissionMask.Copy;
1196 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1197 mask &= ~(uint)PermissionMask.Transfer;
1198 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1199 mask &= ~(uint)PermissionMask.Modify;
993 } 1200 }
994
995 return mask; 1201 return mask;
996 } 1202 }
997 1203
998 public void ApplyNextOwnerPermissions() 1204 public void ApplyNextOwnerPermissions()
999 { 1205 {
1000 lock (m_items) 1206 foreach (TaskInventoryItem item in m_items.Values)
1001 { 1207 {
1002 foreach (TaskInventoryItem item in m_items.Values) 1208 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
1003 { 1209 {
1004 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) 1210 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1005 { 1211 item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
1006 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1212 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1007 item.CurrentPermissions &= ~(uint)PermissionMask.Copy; 1213 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
1008 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1214 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1009 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; 1215 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1010 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1011 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1012 }
1013 item.CurrentPermissions &= item.NextPermissions;
1014 item.BasePermissions &= item.NextPermissions;
1015 item.EveryonePermissions &= item.NextPermissions;
1016 item.OwnerChanged = true;
1017 item.PermsMask = 0;
1018 item.PermsGranter = UUID.Zero;
1019 } 1216 }
1217 item.OwnerChanged = true;
1218 item.CurrentPermissions &= item.NextPermissions;
1219 item.BasePermissions &= item.NextPermissions;
1220 item.EveryonePermissions &= item.NextPermissions;
1221 item.PermsMask = 0;
1222 item.PermsGranter = UUID.Zero;
1020 } 1223 }
1021 } 1224 }
1022 1225
1023 public void ApplyGodPermissions(uint perms) 1226 public void ApplyGodPermissions(uint perms)
1024 { 1227 {
1025 lock (m_items) 1228 foreach (TaskInventoryItem item in m_items.Values)
1026 { 1229 {
1027 foreach (TaskInventoryItem item in m_items.Values) 1230 item.CurrentPermissions = perms;
1028 { 1231 item.BasePermissions = perms;
1029 item.CurrentPermissions = perms;
1030 item.BasePermissions = perms;
1031 }
1032 } 1232 }
1033 m_inventorySerial++; 1233 m_inventorySerial++;
1034 HasInventoryChanged = true; 1234 HasInventoryChanged = true;
@@ -1036,17 +1236,13 @@ namespace OpenSim.Region.Framework.Scenes
1036 1236
1037 public bool ContainsScripts() 1237 public bool ContainsScripts()
1038 { 1238 {
1039 lock (m_items) 1239 foreach (TaskInventoryItem item in m_items.Values)
1040 { 1240 {
1041 foreach (TaskInventoryItem item in m_items.Values) 1241 if (item.InvType == (int)InventoryType.LSL)
1042 { 1242 {
1043 if (item.InvType == (int)InventoryType.LSL) 1243 return true;
1044 {
1045 return true;
1046 }
1047 } 1244 }
1048 } 1245 }
1049
1050 return false; 1246 return false;
1051 } 1247 }
1052 1248
@@ -1054,11 +1250,8 @@ namespace OpenSim.Region.Framework.Scenes
1054 { 1250 {
1055 List<UUID> ret = new List<UUID>(); 1251 List<UUID> ret = new List<UUID>();
1056 1252
1057 lock (m_items) 1253 foreach (TaskInventoryItem item in m_items.Values)
1058 { 1254 ret.Add(item.ItemID);
1059 foreach (TaskInventoryItem item in m_items.Values)
1060 ret.Add(item.ItemID);
1061 }
1062 1255
1063 return ret; 1256 return ret;
1064 } 1257 }
@@ -1089,6 +1282,11 @@ namespace OpenSim.Region.Framework.Scenes
1089 1282
1090 public Dictionary<UUID, string> GetScriptStates() 1283 public Dictionary<UUID, string> GetScriptStates()
1091 { 1284 {
1285 return GetScriptStates(false);
1286 }
1287
1288 public Dictionary<UUID, string> GetScriptStates(bool oldIDs)
1289 {
1092 Dictionary<UUID, string> ret = new Dictionary<UUID, string>(); 1290 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1093 1291
1094 if (m_part.ParentGroup.Scene == null) // Group not in a scene 1292 if (m_part.ParentGroup.Scene == null) // Group not in a scene
@@ -1099,25 +1297,35 @@ namespace OpenSim.Region.Framework.Scenes
1099 if (engines == null) // No engine at all 1297 if (engines == null) // No engine at all
1100 return ret; 1298 return ret;
1101 1299
1102 List<TaskInventoryItem> scripts = GetInventoryScripts(); 1300 Items.LockItemsForRead(true);
1103 1301 foreach (TaskInventoryItem item in m_items.Values)
1104 foreach (TaskInventoryItem item in scripts)
1105 { 1302 {
1106 foreach (IScriptModule e in engines) 1303 if (item.InvType == (int)InventoryType.LSL)
1107 { 1304 {
1108 if (e != null) 1305 foreach (IScriptModule e in engines)
1109 { 1306 {
1110 string n = e.GetXMLState(item.ItemID); 1307 if (e != null)
1111 if (n != String.Empty)
1112 { 1308 {
1113 if (!ret.ContainsKey(item.ItemID)) 1309 string n = e.GetXMLState(item.ItemID);
1114 ret[item.ItemID] = n; 1310 if (n != String.Empty)
1115 break; 1311 {
1312 if (oldIDs)
1313 {
1314 if (!ret.ContainsKey(item.OldItemID))
1315 ret[item.OldItemID] = n;
1316 }
1317 else
1318 {
1319 if (!ret.ContainsKey(item.ItemID))
1320 ret[item.ItemID] = n;
1321 }
1322 break;
1323 }
1116 } 1324 }
1117 } 1325 }
1118 } 1326 }
1119 } 1327 }
1120 1328 Items.LockItemsForRead(false);
1121 return ret; 1329 return ret;
1122 } 1330 }
1123 1331
@@ -1127,21 +1335,27 @@ namespace OpenSim.Region.Framework.Scenes
1127 if (engines == null) 1335 if (engines == null)
1128 return; 1336 return;
1129 1337
1130 List<TaskInventoryItem> scripts = GetInventoryScripts();
1131 1338
1132 foreach (TaskInventoryItem item in scripts) 1339 Items.LockItemsForRead(true);
1340
1341 foreach (TaskInventoryItem item in m_items.Values)
1133 { 1342 {
1134 foreach (IScriptModule engine in engines) 1343 if (item.InvType == (int)InventoryType.LSL)
1135 { 1344 {
1136 if (engine != null) 1345 foreach (IScriptModule engine in engines)
1137 { 1346 {
1138 if (item.OwnerChanged) 1347 if (engine != null)
1139 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); 1348 {
1140 item.OwnerChanged = false; 1349 if (item.OwnerChanged)
1141 engine.ResumeScript(item.ItemID); 1350 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
1351 item.OwnerChanged = false;
1352 engine.ResumeScript(item.ItemID);
1353 }
1142 } 1354 }
1143 } 1355 }
1144 } 1356 }
1357
1358 Items.LockItemsForRead(false);
1145 } 1359 }
1146 } 1360 }
1147} 1361}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 00a1487..3a5b05d 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[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); 79// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
@@ -87,7 +88,9 @@ namespace OpenSim.Region.Framework.Scenes
87 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis 88 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
88 /// issue #1716 89 /// issue #1716
89 /// </summary> 90 /// </summary>
90 private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f); 91// private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.1f, 0.0f, 0.3f);
92 // Value revised by KF 091121 by comparison with SL.
93 private static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f);
91 94
92 public UUID currentParcelUUID = UUID.Zero; 95 public UUID currentParcelUUID = UUID.Zero;
93 96
@@ -110,6 +113,7 @@ namespace OpenSim.Region.Framework.Scenes
110 { 113 {
111 get { return m_attachments; } 114 get { return m_attachments; }
112 } 115 }
116
113 protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>(); 117 protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>();
114 118
115 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>(); 119 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>();
@@ -119,10 +123,12 @@ namespace OpenSim.Region.Framework.Scenes
119 private SceneObjectGroup proxyObjectGroup; 123 private SceneObjectGroup proxyObjectGroup;
120 //private SceneObjectPart proxyObjectPart = null; 124 //private SceneObjectPart proxyObjectPart = null;
121 public Vector3 lastKnownAllowedPosition; 125 public Vector3 lastKnownAllowedPosition;
122 public bool sentMessageAboutRestrictedParcelFlyingDown;
123 public Vector4 CollisionPlane = Vector4.UnitW; 126 public Vector4 CollisionPlane = Vector4.UnitW;
124 127
128 private Vector3 m_avInitialPos; // used to calculate unscripted sit rotation
129 private Vector3 m_avUnscriptedSitPos; // for non-scripted prims
125 private Vector3 m_lastPosition; 130 private Vector3 m_lastPosition;
131 private Vector3 m_lastWorldPosition;
126 private Quaternion m_lastRotation; 132 private Quaternion m_lastRotation;
127 private Vector3 m_lastVelocity; 133 private Vector3 m_lastVelocity;
128 //private int m_lastTerseSent; 134 //private int m_lastTerseSent;
@@ -130,6 +136,11 @@ namespace OpenSim.Region.Framework.Scenes
130 private bool m_updateflag; 136 private bool m_updateflag;
131 private byte m_movementflag; 137 private byte m_movementflag;
132 private Vector3? m_forceToApply; 138 private Vector3? m_forceToApply;
139 private int m_userFlags;
140 public int UserFlags
141 {
142 get { return m_userFlags; }
143 }
133 private TeleportFlags m_teleportFlags; 144 private TeleportFlags m_teleportFlags;
134 public TeleportFlags TeleportFlags 145 public TeleportFlags TeleportFlags
135 { 146 {
@@ -160,9 +171,10 @@ namespace OpenSim.Region.Framework.Scenes
160 private int m_perfMonMS; 171 private int m_perfMonMS;
161 172
162 private bool m_setAlwaysRun; 173 private bool m_setAlwaysRun;
163
164 private bool m_forceFly; 174 private bool m_forceFly;
165 private bool m_flyDisabled; 175 private bool m_flyDisabled;
176 private bool m_flyingOld; // add for fly velocity control
177 public bool m_wasFlying; // add for fly velocity control
166 178
167 private float m_speedModifier = 1.0f; 179 private float m_speedModifier = 1.0f;
168 180
@@ -181,7 +193,8 @@ namespace OpenSim.Region.Framework.Scenes
181 protected RegionInfo m_regionInfo; 193 protected RegionInfo m_regionInfo;
182 protected ulong crossingFromRegion; 194 protected ulong crossingFromRegion;
183 195
184 private readonly Vector3[] Dir_Vectors = new Vector3[9]; 196 private readonly Vector3[] Dir_Vectors = new Vector3[11];
197 private bool m_isNudging = false;
185 198
186 // Position of agent's camera in world (region cordinates) 199 // Position of agent's camera in world (region cordinates)
187 protected Vector3 m_CameraCenter; 200 protected Vector3 m_CameraCenter;
@@ -206,17 +219,25 @@ namespace OpenSim.Region.Framework.Scenes
206 private bool m_autopilotMoving; 219 private bool m_autopilotMoving;
207 private Vector3 m_autoPilotTarget; 220 private Vector3 m_autoPilotTarget;
208 private bool m_sitAtAutoTarget; 221 private bool m_sitAtAutoTarget;
222 private Vector3 m_initialSitTarget = Vector3.Zero; //KF: First estimate of where to sit
209 223
210 private string m_nextSitAnimation = String.Empty; 224 private string m_nextSitAnimation = String.Empty;
211 225
212 //PauPaw:Proper PID Controler for autopilot************ 226 //PauPaw:Proper PID Controler for autopilot************
213 private bool m_moveToPositionInProgress; 227 private bool m_moveToPositionInProgress;
214 private Vector3 m_moveToPositionTarget; 228 private Vector3 m_moveToPositionTarget;
229 private Quaternion m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
215 230
216 private bool m_followCamAuto; 231 private bool m_followCamAuto;
217 232
218 private int m_movementUpdateCount; 233 private int m_movementUpdateCount;
234 private int m_lastColCount = -1; //KF: Look for Collision chnages
235 private int m_updateCount = 0; //KF: Update Anims for a while
236 private static readonly int UPDATE_COUNT = 10; // how many frames to update for
219 private const int NumMovementsBetweenRayCast = 5; 237 private const int NumMovementsBetweenRayCast = 5;
238 private List<uint> m_lastColliders = new List<uint>();
239
240 private object m_syncRoot = new Object();
220 241
221 private bool CameraConstraintActive; 242 private bool CameraConstraintActive;
222 //private int m_moveToPositionStateStatus; 243 //private int m_moveToPositionStateStatus;
@@ -243,7 +264,9 @@ namespace OpenSim.Region.Framework.Scenes
243 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS, 264 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
244 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG, 265 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
245 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS, 266 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS,
246 DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, 267 DIR_CONTROL_FLAG_BACK_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG,
268 DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS,
269 DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG,
247 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG 270 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
248 } 271 }
249 272
@@ -450,7 +473,8 @@ namespace OpenSim.Region.Framework.Scenes
450 get 473 get
451 { 474 {
452 PhysicsActor actor = m_physicsActor; 475 PhysicsActor actor = m_physicsActor;
453 if (actor != null) 476// if (actor != null)
477 if ((actor != null) && (m_parentID == 0)) // KF Do NOT update m_pos here if Av is sitting!
454 m_pos = actor.Position; 478 m_pos = actor.Position;
455 else 479 else
456 { 480 {
@@ -472,7 +496,7 @@ namespace OpenSim.Region.Framework.Scenes
472 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID); 496 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID);
473 if (part != null) 497 if (part != null)
474 { 498 {
475 return m_parentPosition + (m_pos * part.GetWorldRotation()); 499 return part.AbsolutePosition + (m_pos * part.GetWorldRotation());
476 } 500 }
477 else 501 else
478 { 502 {
@@ -499,7 +523,8 @@ namespace OpenSim.Region.Framework.Scenes
499 } 523 }
500 } 524 }
501 525
502 m_pos = value; 526 if (m_parentID == 0) // KF Do NOT update m_pos here if Av is sitting!
527 m_pos = value;
503 m_parentPosition = Vector3.Zero; 528 m_parentPosition = Vector3.Zero;
504 } 529 }
505 } 530 }
@@ -543,10 +568,39 @@ namespace OpenSim.Region.Framework.Scenes
543 } 568 }
544 } 569 }
545 570
571 public Quaternion OffsetRotation
572 {
573 get { return m_offsetRotation; }
574 set { m_offsetRotation = value; }
575 }
576
546 public Quaternion Rotation 577 public Quaternion Rotation
547 { 578 {
548 get { return m_bodyRot; } 579 get {
549 set { m_bodyRot = value; } 580 if (m_parentID != 0)
581 {
582 if (m_offsetRotation != null)
583 {
584 return m_offsetRotation;
585 }
586 else
587 {
588 return new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
589 }
590
591 }
592 else
593 {
594 return m_bodyRot;
595 }
596 }
597 set {
598 m_bodyRot = value;
599 if (m_parentID != 0)
600 {
601 m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
602 }
603 }
550 } 604 }
551 605
552 public Quaternion PreviousRotation 606 public Quaternion PreviousRotation
@@ -571,11 +625,21 @@ namespace OpenSim.Region.Framework.Scenes
571 625
572 private uint m_parentID; 626 private uint m_parentID;
573 627
628
629 private UUID m_linkedPrim;
630
574 public uint ParentID 631 public uint ParentID
575 { 632 {
576 get { return m_parentID; } 633 get { return m_parentID; }
577 set { m_parentID = value; } 634 set { m_parentID = value; }
578 } 635 }
636
637 public UUID LinkedPrim
638 {
639 get { return m_linkedPrim; }
640 set { m_linkedPrim = value; }
641 }
642
579 public float Health 643 public float Health
580 { 644 {
581 get { return m_health; } 645 get { return m_health; }
@@ -697,7 +761,7 @@ namespace OpenSim.Region.Framework.Scenes
697 CreateSceneViewer(); 761 CreateSceneViewer();
698 m_animator = new ScenePresenceAnimator(this); 762 m_animator = new ScenePresenceAnimator(this);
699 } 763 }
700 764
701 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this() 765 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) : this()
702 { 766 {
703 m_DrawDistance = world.DefaultDrawDistance; 767 m_DrawDistance = world.DefaultDrawDistance;
@@ -712,6 +776,7 @@ namespace OpenSim.Region.Framework.Scenes
712 m_localId = m_scene.AllocateLocalId(); 776 m_localId = m_scene.AllocateLocalId();
713 777
714 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); 778 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid);
779 m_userFlags = account.UserFlags;
715 780
716 if (account != null) 781 if (account != null)
717 m_userLevel = account.UserLevel; 782 m_userLevel = account.UserLevel;
@@ -730,10 +795,7 @@ namespace OpenSim.Region.Framework.Scenes
730 m_reprioritization_timer.AutoReset = false; 795 m_reprioritization_timer.AutoReset = false;
731 796
732 AdjustKnownSeeds(); 797 AdjustKnownSeeds();
733
734 // TODO: I think, this won't send anything, as we are still a child here...
735 Animator.TrySetMovementAnimation("STAND"); 798 Animator.TrySetMovementAnimation("STAND");
736
737 // we created a new ScenePresence (a new child agent) in a fresh region. 799 // we created a new ScenePresence (a new child agent) in a fresh region.
738 // Request info about all the (root) agents in this region 800 // Request info about all the (root) agents in this region
739 // Note: This won't send data *to* other clients in that region (children don't send) 801 // Note: This won't send data *to* other clients in that region (children don't send)
@@ -784,25 +846,47 @@ namespace OpenSim.Region.Framework.Scenes
784 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT 846 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT
785 Dir_Vectors[4] = Vector3.UnitZ; //UP 847 Dir_Vectors[4] = Vector3.UnitZ; //UP
786 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN 848 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN
787 Dir_Vectors[8] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge 849 Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE
788 Dir_Vectors[6] = Vector3.UnitX*2; //FORWARD 850 Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE
789 Dir_Vectors[7] = -Vector3.UnitX; //BACK 851 Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE
852 Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE
853 Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge
790 } 854 }
791 855
792 private Vector3[] GetWalkDirectionVectors() 856 private Vector3[] GetWalkDirectionVectors()
793 { 857 {
794 Vector3[] vector = new Vector3[9]; 858 Vector3[] vector = new Vector3[11];
795 vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD 859 vector[0] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD
796 vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK 860 vector[1] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK
797 vector[2] = Vector3.UnitY; //LEFT 861 vector[2] = Vector3.UnitY; //LEFT
798 vector[3] = -Vector3.UnitY; //RIGHT 862 vector[3] = -Vector3.UnitY; //RIGHT
799 vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP 863 vector[4] = new Vector3(m_CameraAtAxis.Z, 0f, m_CameraUpAxis.Z); //UP
800 vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN 864 vector[5] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN
801 vector[8] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_Nudge 865 vector[6] = new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z); //FORWARD_NUDGE
802 vector[6] = (new Vector3(m_CameraUpAxis.Z, 0f, -m_CameraAtAxis.Z) * 2); //FORWARD Nudge 866 vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK_NUDGE
803 vector[7] = new Vector3(-m_CameraUpAxis.Z, 0f, m_CameraAtAxis.Z); //BACK Nudge 867 vector[8] = Vector3.UnitY; //LEFT_NUDGE
868 vector[9] = -Vector3.UnitY; //RIGHT_NUDGE
869 vector[10] = new Vector3(-m_CameraAtAxis.Z, 0f, -m_CameraUpAxis.Z); //DOWN_NUDGE
804 return vector; 870 return vector;
805 } 871 }
872
873 private bool[] GetDirectionIsNudge()
874 {
875 bool[] isNudge = new bool[11];
876 isNudge[0] = false; //FORWARD
877 isNudge[1] = false; //BACK
878 isNudge[2] = false; //LEFT
879 isNudge[3] = false; //RIGHT
880 isNudge[4] = false; //UP
881 isNudge[5] = false; //DOWN
882 isNudge[6] = true; //FORWARD_NUDGE
883 isNudge[7] = true; //BACK_NUDGE
884 isNudge[8] = true; //LEFT_NUDGE
885 isNudge[9] = true; //RIGHT_NUDGE
886 isNudge[10] = true; //DOWN_Nudge
887 return isNudge;
888 }
889
806 890
807 #endregion 891 #endregion
808 892
@@ -864,6 +948,62 @@ namespace OpenSim.Region.Framework.Scenes
864 pos.Y = crossedBorder.BorderLine.Z - 1; 948 pos.Y = crossedBorder.BorderLine.Z - 1;
865 } 949 }
866 950
951 ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
952 if (land != null)
953 {
954 // If we come in via login, landmark or map, we want to
955 // honor landing points. If we come in via Lure, we want
956 // to ignore them.
957 if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) ||
958 (m_teleportFlags & TeleportFlags.ViaLandmark) != 0 ||
959 (m_teleportFlags & TeleportFlags.ViaLocation) != 0)
960 {
961 // Don't restrict gods, estate managers, or land owners to
962 // the TP point. This behaviour mimics agni.
963 if (land.LandData.LandingType == (byte)LandingType.LandingPoint &&
964 land.LandData.UserLocation != Vector3.Zero &&
965 GodLevel < 200 &&
966 ((land.LandData.OwnerID != m_uuid &&
967 (!m_scene.Permissions.IsGod(m_uuid)) &&
968 (!m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid))) || (m_teleportFlags & TeleportFlags.ViaLocation) != 0))
969 {
970 pos = land.LandData.UserLocation;
971 }
972 }
973
974 land.SendLandUpdateToClient(ControllingClient);
975 }
976
977 if (pos.X < 0 || pos.Y < 0 || pos.Z < 0)
978 {
979 Vector3 emergencyPos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 128);
980
981 if (pos.X < 0)
982 {
983 emergencyPos.X = (int)Constants.RegionSize + pos.X;
984 if (!(pos.Y < 0))
985 emergencyPos.Y = pos.Y;
986 if (!(pos.Z < 0))
987 emergencyPos.Z = pos.Z;
988 }
989 if (pos.Y < 0)
990 {
991 emergencyPos.Y = (int)Constants.RegionSize + pos.Y;
992 if (!(pos.X < 0))
993 emergencyPos.X = pos.X;
994 if (!(pos.Z < 0))
995 emergencyPos.Z = pos.Z;
996 }
997 if (pos.Z < 0)
998 {
999 emergencyPos.Z = 128;
1000 if (!(pos.Y < 0))
1001 emergencyPos.Y = pos.Y;
1002 if (!(pos.X < 0))
1003 emergencyPos.X = pos.X;
1004 }
1005 }
1006
867 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) 1007 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
868 { 1008 {
869 m_log.WarnFormat( 1009 m_log.WarnFormat(
@@ -988,16 +1128,21 @@ namespace OpenSim.Region.Framework.Scenes
988 /// <summary> 1128 /// <summary>
989 /// Removes physics plugin scene representation of this agent if it exists. 1129 /// Removes physics plugin scene representation of this agent if it exists.
990 /// </summary> 1130 /// </summary>
991 private void RemoveFromPhysicalScene() 1131 public void RemoveFromPhysicalScene()
992 { 1132 {
993 if (PhysicsActor != null) 1133 if (PhysicsActor != null)
994 { 1134 {
995 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; 1135 try
996 m_physicsActor.OnOutOfBounds -= OutOfBoundsCall; 1136 {
997 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); 1137 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
998 m_physicsActor.UnSubscribeEvents(); 1138 m_physicsActor.OnOutOfBounds -= OutOfBoundsCall;
999 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; 1139 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
1000 PhysicsActor = null; 1140 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
1141 m_physicsActor.UnSubscribeEvents();
1142 PhysicsActor = null;
1143 }
1144 catch
1145 { }
1001 } 1146 }
1002 } 1147 }
1003 1148
@@ -1008,11 +1153,13 @@ namespace OpenSim.Region.Framework.Scenes
1008 public void Teleport(Vector3 pos) 1153 public void Teleport(Vector3 pos)
1009 { 1154 {
1010 bool isFlying = false; 1155 bool isFlying = false;
1156
1011 if (m_physicsActor != null) 1157 if (m_physicsActor != null)
1012 isFlying = m_physicsActor.Flying; 1158 isFlying = m_physicsActor.Flying;
1013 1159
1014 RemoveFromPhysicalScene(); 1160 RemoveFromPhysicalScene();
1015 Velocity = Vector3.Zero; 1161 Velocity = Vector3.Zero;
1162 CheckLandingPoint(ref pos);
1016 AbsolutePosition = pos; 1163 AbsolutePosition = pos;
1017 AddToPhysicalScene(isFlying); 1164 AddToPhysicalScene(isFlying);
1018 if (m_appearance != null) 1165 if (m_appearance != null)
@@ -1022,6 +1169,7 @@ namespace OpenSim.Region.Framework.Scenes
1022 } 1169 }
1023 1170
1024 SendTerseUpdateToAllClients(); 1171 SendTerseUpdateToAllClients();
1172
1025 } 1173 }
1026 1174
1027 public void TeleportWithMomentum(Vector3 pos) 1175 public void TeleportWithMomentum(Vector3 pos)
@@ -1031,6 +1179,7 @@ namespace OpenSim.Region.Framework.Scenes
1031 isFlying = m_physicsActor.Flying; 1179 isFlying = m_physicsActor.Flying;
1032 1180
1033 RemoveFromPhysicalScene(); 1181 RemoveFromPhysicalScene();
1182 CheckLandingPoint(ref pos);
1034 AbsolutePosition = pos; 1183 AbsolutePosition = pos;
1035 AddToPhysicalScene(isFlying); 1184 AddToPhysicalScene(isFlying);
1036 if (m_appearance != null) 1185 if (m_appearance != null)
@@ -1242,6 +1391,7 @@ namespace OpenSim.Region.Framework.Scenes
1242 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); 1391 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902");
1243 1392
1244 m_pos = m_LastFinitePos; 1393 m_pos = m_LastFinitePos;
1394
1245 if (!m_pos.IsFinite()) 1395 if (!m_pos.IsFinite())
1246 { 1396 {
1247 m_pos.X = 127f; 1397 m_pos.X = 127f;
@@ -1312,7 +1462,6 @@ namespace OpenSim.Region.Framework.Scenes
1312 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback); 1462 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(m_CameraCenter - posAdjusted), Vector3.Distance(m_CameraCenter, posAdjusted) + 0.3f, RayCastCameraCallback);
1313 } 1463 }
1314 } 1464 }
1315
1316 lock (scriptedcontrols) 1465 lock (scriptedcontrols)
1317 { 1466 {
1318 if (scriptedcontrols.Count > 0) 1467 if (scriptedcontrols.Count > 0)
@@ -1327,6 +1476,9 @@ namespace OpenSim.Region.Framework.Scenes
1327 1476
1328 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) 1477 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0)
1329 { 1478 {
1479 m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.
1480 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
1481
1330 // TODO: This doesn't prevent the user from walking yet. 1482 // TODO: This doesn't prevent the user from walking yet.
1331 // Setting parent ID would fix this, if we knew what value 1483 // Setting parent ID would fix this, if we knew what value
1332 // to use. Or we could add a m_isSitting variable. 1484 // to use. Or we could add a m_isSitting variable.
@@ -1375,12 +1527,20 @@ namespace OpenSim.Region.Framework.Scenes
1375 if (actor.Flying != oldflying) 1527 if (actor.Flying != oldflying)
1376 update_movementflag = true; 1528 update_movementflag = true;
1377 1529
1530 if (m_animator.m_jumping) // add for jumping
1531 update_movementflag = true;
1532
1378 if (q != m_bodyRot) 1533 if (q != m_bodyRot)
1379 { 1534 {
1380 m_bodyRot = q; 1535 m_bodyRot = q;
1381 update_rotation = true; 1536 update_rotation = true;
1382 } 1537 }
1383 1538
1539 //guilty until proven innocent..
1540 bool Nudging = true;
1541 //Basically, if there is at least one non-nudge control then we don't need
1542 //to worry about stopping the avatar
1543
1384 if (m_parentID == 0) 1544 if (m_parentID == 0)
1385 { 1545 {
1386 bool bAllowUpdateMoveToPosition = false; 1546 bool bAllowUpdateMoveToPosition = false;
@@ -1395,9 +1555,12 @@ namespace OpenSim.Region.Framework.Scenes
1395 else 1555 else
1396 dirVectors = Dir_Vectors; 1556 dirVectors = Dir_Vectors;
1397 1557
1398 // The fact that m_movementflag is a byte needs to be fixed 1558 bool[] isNudge = GetDirectionIsNudge();
1399 // it really should be a uint 1559
1400 uint nudgehack = 250; 1560
1561
1562
1563
1401 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) 1564 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS)
1402 { 1565 {
1403 if (((uint)flags & (uint)DCF) != 0) 1566 if (((uint)flags & (uint)DCF) != 0)
@@ -1407,40 +1570,28 @@ namespace OpenSim.Region.Framework.Scenes
1407 try 1570 try
1408 { 1571 {
1409 agent_control_v3 += dirVectors[i]; 1572 agent_control_v3 += dirVectors[i];
1410 //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); 1573 if (isNudge[i] == false)
1574 {
1575 Nudging = false;
1576 }
1411 } 1577 }
1412 catch (IndexOutOfRangeException) 1578 catch (IndexOutOfRangeException)
1413 { 1579 {
1414 // Why did I get this? 1580 // Why did I get this?
1415 } 1581 }
1416 1582
1417 if ((m_movementflag & (byte)(uint)DCF) == 0) 1583 if ((m_movementflag & (uint)DCF) == 0)
1418 { 1584 {
1419 if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1420 {
1421 m_movementflag |= (byte)nudgehack;
1422 }
1423 m_movementflag += (byte)(uint)DCF; 1585 m_movementflag += (byte)(uint)DCF;
1424 update_movementflag = true; 1586 update_movementflag = true;
1425 } 1587 }
1426 } 1588 }
1427 else 1589 else
1428 { 1590 {
1429 if ((m_movementflag & (byte)(uint)DCF) != 0 || 1591 if ((m_movementflag & (uint)DCF) != 0)
1430 ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1431 && ((m_movementflag & (byte)nudgehack) == nudgehack))
1432 ) // This or is for Nudge forward
1433 { 1592 {
1434 m_movementflag -= ((byte)(uint)DCF); 1593 m_movementflag -= (byte)(uint)DCF;
1435
1436 update_movementflag = true; 1594 update_movementflag = true;
1437 /*
1438 if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
1439 && ((m_movementflag & (byte)nudgehack) == nudgehack))
1440 {
1441 m_log.Debug("Removed Hack flag");
1442 }
1443 */
1444 } 1595 }
1445 else 1596 else
1446 { 1597 {
@@ -1449,7 +1600,6 @@ namespace OpenSim.Region.Framework.Scenes
1449 } 1600 }
1450 i++; 1601 i++;
1451 } 1602 }
1452
1453 //Paupaw:Do Proper PID for Autopilot here 1603 //Paupaw:Do Proper PID for Autopilot here
1454 if (bResetMoveToPosition) 1604 if (bResetMoveToPosition)
1455 { 1605 {
@@ -1461,8 +1611,41 @@ namespace OpenSim.Region.Framework.Scenes
1461 1611
1462 if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving)) 1612 if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving))
1463 { 1613 {
1614/*
1615 bool twoD = false;
1616 bool there = false;
1617 if (Animator != null)
1618 {
1619 switch (Animator.CurrentMovementAnimation)
1620 {
1621 case "STAND":
1622 case "WALK":
1623 case "RUN":
1624 case "CROUCH":
1625 case "CROUCHWALK":
1626 {
1627 twoD = true;
1628 }
1629 break;
1630 }
1631 }
1632
1633 if (twoD)
1634 {
1635*/
1636 Vector3 abspos = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, 0.0f);
1637 Vector3 tgt = new Vector3(m_moveToPositionTarget.X, m_moveToPositionTarget.Y, 0.0f);
1638/* if (Util.GetDistanceTo(abspos, tgt) <= 0.5f) there = true;
1639 }
1640 else
1641 {
1642 if (Util.GetDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 0.5f) there = true;
1643 }
1644*/
1464 //Check the error term of the current position in relation to the target position 1645 //Check the error term of the current position in relation to the target position
1465 if (Util.GetDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 0.5f) 1646// if (Util.GetDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 0.5f)
1647// if (there)
1648 if (Util.GetDistanceTo(abspos, tgt) <= 0.5f)
1466 { 1649 {
1467 // we are close enough to the target 1650 // we are close enough to the target
1468 m_moveToPositionTarget = Vector3.Zero; 1651 m_moveToPositionTarget = Vector3.Zero;
@@ -1479,11 +1662,15 @@ namespace OpenSim.Region.Framework.Scenes
1479 // unknown forces are acting on the avatar and we need to adaptively respond 1662 // unknown forces are acting on the avatar and we need to adaptively respond
1480 // to such forces, but the following simple approach seems to works fine. 1663 // to such forces, but the following simple approach seems to works fine.
1481 Vector3 LocalVectorToTarget3D = 1664 Vector3 LocalVectorToTarget3D =
1482 (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords 1665// (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords
1666 (tgt - abspos)
1483 * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords 1667 * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords
1484 // Ignore z component of vector 1668 // Ignore z component of vector
1485 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); 1669 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f);
1486 LocalVectorToTarget2D.Normalize(); 1670 LocalVectorToTarget2D.Normalize();
1671
1672 //We're not nudging
1673 Nudging = false;
1487 agent_control_v3 += LocalVectorToTarget2D; 1674 agent_control_v3 += LocalVectorToTarget2D;
1488 1675
1489 // update avatar movement flags. the avatar coordinate system is as follows: 1676 // update avatar movement flags. the avatar coordinate system is as follows:
@@ -1574,13 +1761,13 @@ namespace OpenSim.Region.Framework.Scenes
1574 // m_log.DebugFormat( 1761 // m_log.DebugFormat(
1575 // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3); 1762 // "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3);
1576 1763
1577 AddNewMovement(agent_control_v3, q); 1764 AddNewMovement(agent_control_v3, q, Nudging);
1578 1765
1579 1766
1580 } 1767 }
1581 } 1768 }
1582 1769
1583 if (update_movementflag && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) == 0) && (m_parentID == 0) && !SitGround) 1770 if (update_movementflag && !SitGround)
1584 Animator.UpdateMovementAnimations(); 1771 Animator.UpdateMovementAnimations();
1585 1772
1586 m_scene.EventManager.TriggerOnClientMovement(this); 1773 m_scene.EventManager.TriggerOnClientMovement(this);
@@ -1595,7 +1782,6 @@ namespace OpenSim.Region.Framework.Scenes
1595 m_sitAtAutoTarget = false; 1782 m_sitAtAutoTarget = false;
1596 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; 1783 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default;
1597 //proxy.PCode = (byte)PCode.ParticleSystem; 1784 //proxy.PCode = (byte)PCode.ParticleSystem;
1598
1599 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy); 1785 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy);
1600 proxyObjectGroup.AttachToScene(m_scene); 1786 proxyObjectGroup.AttachToScene(m_scene);
1601 1787
@@ -1614,8 +1800,15 @@ namespace OpenSim.Region.Framework.Scenes
1614// } 1800// }
1615 } 1801 }
1616 1802
1803 public void StopMoveToPosition()
1804 {
1805 m_moveToPositionTarget = Vector3.Zero;
1806 m_moveToPositionInProgress = false;
1807 }
1808
1617 public void DoMoveToPosition(Object sender, string method, List<String> args) 1809 public void DoMoveToPosition(Object sender, string method, List<String> args)
1618 { 1810 {
1811//Console.WriteLine("SP:DoMoveToPosition");
1619 try 1812 try
1620 { 1813 {
1621 float locx = 0f; 1814 float locx = 0f;
@@ -1637,7 +1830,7 @@ namespace OpenSim.Region.Framework.Scenes
1637 } 1830 }
1638 m_moveToPositionInProgress = true; 1831 m_moveToPositionInProgress = true;
1639 m_moveToPositionTarget = new Vector3(locx, locy, locz); 1832 m_moveToPositionTarget = new Vector3(locx, locy, locz);
1640 } 1833 }
1641 catch (Exception ex) 1834 catch (Exception ex)
1642 { 1835 {
1643 //Why did I get this error? 1836 //Why did I get this error?
@@ -1659,7 +1852,7 @@ namespace OpenSim.Region.Framework.Scenes
1659 Velocity = Vector3.Zero; 1852 Velocity = Vector3.Zero;
1660 SendAvatarDataToAllAgents(); 1853 SendAvatarDataToAllAgents();
1661 1854
1662 //HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); 1855 HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); //KF ??
1663 } 1856 }
1664 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false); 1857 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false);
1665 m_requestedSitTargetUUID = UUID.Zero; 1858 m_requestedSitTargetUUID = UUID.Zero;
@@ -1696,25 +1889,22 @@ namespace OpenSim.Region.Framework.Scenes
1696 1889
1697 if (m_parentID != 0) 1890 if (m_parentID != 0)
1698 { 1891 {
1699 m_log.Debug("StandupCode Executed"); 1892 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
1700 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID);
1701 if (part != null) 1893 if (part != null)
1702 { 1894 {
1895 part.TaskInventory.LockItemsForRead(true);
1703 TaskInventoryDictionary taskIDict = part.TaskInventory; 1896 TaskInventoryDictionary taskIDict = part.TaskInventory;
1704 if (taskIDict != null) 1897 if (taskIDict != null)
1705 { 1898 {
1706 lock (taskIDict) 1899 foreach (UUID taskID in taskIDict.Keys)
1707 { 1900 {
1708 foreach (UUID taskID in taskIDict.Keys) 1901 UnRegisterControlEventsToScript(LocalId, taskID);
1709 { 1902 taskIDict[taskID].PermsMask &= ~(
1710 UnRegisterControlEventsToScript(LocalId, taskID); 1903 2048 | //PERMISSION_CONTROL_CAMERA
1711 taskIDict[taskID].PermsMask &= ~( 1904 4); // PERMISSION_TAKE_CONTROLS
1712 2048 | //PERMISSION_CONTROL_CAMERA
1713 4); // PERMISSION_TAKE_CONTROLS
1714 }
1715 } 1905 }
1716
1717 } 1906 }
1907 part.TaskInventory.LockItemsForRead(false);
1718 // Reset sit target. 1908 // Reset sit target.
1719 if (part.GetAvatarOnSitTarget() == UUID) 1909 if (part.GetAvatarOnSitTarget() == UUID)
1720 part.SitTargetAvatar = UUID.Zero; 1910 part.SitTargetAvatar = UUID.Zero;
@@ -1723,16 +1913,55 @@ namespace OpenSim.Region.Framework.Scenes
1723 m_parentPosition = part.GetWorldPosition(); 1913 m_parentPosition = part.GetWorldPosition();
1724 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 1914 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
1725 } 1915 }
1916 // part.GetWorldRotation() is the rotation of the object being sat on
1917 // Rotation is the sittiing Av's rotation
1918
1919 Quaternion partRot;
1920// if (part.LinkNum == 1)
1921// { // Root prim of linkset
1922// partRot = part.ParentGroup.RootPart.RotationOffset;
1923// }
1924// else
1925// { // single or child prim
1926
1927// }
1928 if (part == null) //CW: Part may be gone. llDie() for example.
1929 {
1930 partRot = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
1931 }
1932 else
1933 {
1934 partRot = part.GetWorldRotation();
1935 }
1936
1937 Quaternion partIRot = Quaternion.Inverse(partRot);
1726 1938
1939 Quaternion avatarRot = Quaternion.Inverse(Quaternion.Inverse(Rotation) * partIRot); // world or. of the av
1940 Vector3 avStandUp = new Vector3(0.3f, 0f, 0f) * avatarRot; // 0.3M infront of av
1941
1942
1727 if (m_physicsActor == null) 1943 if (m_physicsActor == null)
1728 { 1944 {
1729 AddToPhysicalScene(false); 1945 AddToPhysicalScene(false);
1730 } 1946 }
1731 1947 //CW: If the part isn't null then we can set the current position
1732 m_pos += m_parentPosition + new Vector3(0.0f, 0.0f, 2.0f*m_sitAvatarHeight); 1948 if (part != null)
1733 m_parentPosition = Vector3.Zero; 1949 {
1734 1950 Vector3 avWorldStandUp = avStandUp + part.GetWorldPosition() + ((m_pos - part.OffsetPosition) * partRot); // + av sit offset!
1735 m_parentID = 0; 1951 AbsolutePosition = avWorldStandUp; //KF: Fix stand up.
1952 part.IsOccupied = false;
1953 part.ParentGroup.DeleteAvatar(ControllingClient.AgentId);
1954 }
1955 else
1956 {
1957 //CW: Since the part doesn't exist, a coarse standup position isn't an issue
1958 AbsolutePosition = m_lastWorldPosition;
1959 }
1960
1961 m_parentPosition = Vector3.Zero;
1962 m_parentID = 0;
1963 m_linkedPrim = UUID.Zero;
1964 m_offsetRotation = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
1736 SendAvatarDataToAllAgents(); 1965 SendAvatarDataToAllAgents();
1737 m_requestedSitTargetID = 0; 1966 m_requestedSitTargetID = 0;
1738 if (m_physicsActor != null && m_appearance != null) 1967 if (m_physicsActor != null && m_appearance != null)
@@ -1741,7 +1970,6 @@ namespace OpenSim.Region.Framework.Scenes
1741 SetHeight(m_appearance.AvatarHeight); 1970 SetHeight(m_appearance.AvatarHeight);
1742 } 1971 }
1743 } 1972 }
1744
1745 Animator.TrySetMovementAnimation("STAND"); 1973 Animator.TrySetMovementAnimation("STAND");
1746 } 1974 }
1747 1975
@@ -1772,13 +2000,9 @@ namespace OpenSim.Region.Framework.Scenes
1772 Vector3 avSitOffSet = part.SitTargetPosition; 2000 Vector3 avSitOffSet = part.SitTargetPosition;
1773 Quaternion avSitOrientation = part.SitTargetOrientation; 2001 Quaternion avSitOrientation = part.SitTargetOrientation;
1774 UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); 2002 UUID avOnTargetAlready = part.GetAvatarOnSitTarget();
1775 2003 bool SitTargetOccupied = (avOnTargetAlready != UUID.Zero);
1776 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); 2004 bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored.
1777 bool SitTargetisSet = 2005 if (SitTargetisSet && !SitTargetOccupied)
1778 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && avSitOrientation.W == 1f &&
1779 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f));
1780
1781 if (SitTargetisSet && SitTargetUnOccupied)
1782 { 2006 {
1783 //switch the target to this prim 2007 //switch the target to this prim
1784 return part; 2008 return part;
@@ -1792,85 +2016,168 @@ namespace OpenSim.Region.Framework.Scenes
1792 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation) 2016 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation)
1793 { 2017 {
1794 bool autopilot = true; 2018 bool autopilot = true;
2019 Vector3 autopilotTarget = new Vector3();
2020 Quaternion sitOrientation = Quaternion.Identity;
1795 Vector3 pos = new Vector3(); 2021 Vector3 pos = new Vector3();
1796 Quaternion sitOrientation = pSitOrientation;
1797 Vector3 cameraEyeOffset = Vector3.Zero; 2022 Vector3 cameraEyeOffset = Vector3.Zero;
1798 Vector3 cameraAtOffset = Vector3.Zero; 2023 Vector3 cameraAtOffset = Vector3.Zero;
1799 bool forceMouselook = false; 2024 bool forceMouselook = false;
1800 2025
1801 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID); 2026 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
1802 SceneObjectPart part = FindNextAvailableSitTarget(targetID); 2027 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
1803 if (part != null) 2028 if (part == null) return;
1804 { 2029
1805 // TODO: determine position to sit at based on scene geometry; don't trust offset from client 2030 // TODO: determine position to sit at based on scene geometry; don't trust offset from client
1806 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it 2031 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
1807 2032
1808 // Is a sit target available? 2033 // part is the prim to sit on
1809 Vector3 avSitOffSet = part.SitTargetPosition; 2034 // offset is the world-ref vector distance from that prim center to the click-spot
1810 Quaternion avSitOrientation = part.SitTargetOrientation; 2035 // UUID is the UUID of the Avatar doing the clicking
1811 UUID avOnTargetAlready = part.GetAvatarOnSitTarget(); 2036
1812 2037 m_avInitialPos = AbsolutePosition; // saved to calculate unscripted sit rotation
1813 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); 2038
1814 bool SitTargetisSet = 2039 // Is a sit target available?
1815 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && 2040 Vector3 avSitOffSet = part.SitTargetPosition;
1816 ( 2041 Quaternion avSitOrientation = part.SitTargetOrientation;
1817 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 1f // Valid Zero Rotation quaternion 2042
1818 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point 2043 bool SitTargetisSet = (Vector3.Zero != avSitOffSet); //NB Latest SL Spec shows Sit Rotation setting is ignored.
1819 || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion 2044 // Quaternion partIRot = Quaternion.Inverse(part.GetWorldRotation());
1820 ) 2045 Quaternion partRot;
1821 )); 2046// if (part.LinkNum == 1)
1822 2047// { // Root prim of linkset
1823 if (SitTargetisSet && SitTargetUnOccupied) 2048// partRot = part.ParentGroup.RootPart.RotationOffset;
1824 { 2049// }
1825 part.SitTargetAvatar = UUID; 2050// else
1826 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); 2051// { // single or child prim
1827 sitOrientation = avSitOrientation; 2052 partRot = part.GetWorldRotation();
1828 autopilot = false; 2053// }
1829 } 2054 Quaternion partIRot = Quaternion.Inverse(partRot);
1830 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); 2055//Console.WriteLine("SendSitResponse offset=" + offset + " Occup=" + part.IsOccupied + " TargSet=" + SitTargetisSet);
1831 2056 // Sit analysis rewritten by KF 091125
1832 pos = part.AbsolutePosition + offset; 2057 if (SitTargetisSet) // scipted sit
1833 //if (Math.Abs(part.AbsolutePosition.Z - AbsolutePosition.Z) > 1) 2058 {
1834 //{ 2059 if (!part.IsOccupied)
1835 // offset = pos; 2060 {
1836 //autopilot = false; 2061//Console.WriteLine("Scripted, unoccupied");
1837 //} 2062 part.SitTargetAvatar = UUID; // set that Av will be on it
1838 if (m_physicsActor != null) 2063 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); // change ofset to the scripted one
1839 { 2064
1840 // If we're not using the client autopilot, we're immediately warping the avatar to the location 2065 Quaternion nrot = avSitOrientation;
1841 // We can remove the physicsActor until they stand up. 2066 if (!part.IsRoot)
1842 m_sitAvatarHeight = m_physicsActor.Size.Z;
1843
1844 if (autopilot)
1845 { 2067 {
1846 if (Util.GetDistanceTo(AbsolutePosition, pos) < 4.5) 2068 nrot = part.RotationOffset * avSitOrientation;
1847 {
1848 autopilot = false;
1849
1850 RemoveFromPhysicalScene();
1851 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
1852 }
1853 } 2069 }
1854 else 2070 sitOrientation = nrot; // Change rotatione to the scripted one
2071 OffsetRotation = nrot;
2072 autopilot = false; // Jump direct to scripted llSitPos()
2073 }
2074 else
2075 {
2076//Console.WriteLine("Scripted, occupied");
2077 return;
2078 }
2079 }
2080 else // Not Scripted
2081 {
2082 if ( (Math.Abs(offset.X) > 0.1f) || (Math.Abs(offset.Y) > 0.1f) ) // Changed 0.5M to 0.1M as they want to be able to sit close together
2083 {
2084 // large prim & offset, ignore if other Avs sitting
2085// offset.Z -= 0.05f;
2086 m_avUnscriptedSitPos = offset * partIRot; // (non-zero) sit where clicked
2087 autopilotTarget = part.AbsolutePosition + offset; // World location of clicked point
2088
2089//Console.WriteLine(" offset ={0}", offset);
2090//Console.WriteLine(" UnscriptedSitPos={0}", m_avUnscriptedSitPos);
2091//Console.WriteLine(" autopilotTarget={0}", autopilotTarget);
2092
2093 }
2094 else // small offset
2095 {
2096//Console.WriteLine("Small offset");
2097 if (!part.IsOccupied)
2098 {
2099 m_avUnscriptedSitPos = Vector3.Zero; // Zero = Sit on prim center
2100 autopilotTarget = part.AbsolutePosition;
2101//Console.WriteLine("UsSmall autopilotTarget={0}", autopilotTarget);
2102 }
2103 else return; // occupied small
2104 } // end large/small
2105 } // end Scripted/not
2106
2107 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2108
2109 cameraAtOffset = part.GetCameraAtOffset();
2110 cameraEyeOffset = part.GetCameraEyeOffset();
2111 forceMouselook = part.GetForceMouselook();
2112 if(cameraAtOffset == Vector3.Zero) cameraAtOffset = new Vector3(0f, 0f, 0.1f); //
2113 if(cameraEyeOffset == Vector3.Zero) cameraEyeOffset = new Vector3(0f, 0f, 0.1f); //
2114
2115 if (m_physicsActor != null)
2116 {
2117 // If we're not using the client autopilot, we're immediately warping the avatar to the location
2118 // We can remove the physicsActor until they stand up.
2119 m_sitAvatarHeight = m_physicsActor.Size.Z;
2120 if (autopilot)
2121 { // its not a scripted sit
2122// if (Util.GetDistanceTo(AbsolutePosition, autopilotTarget) < 4.5)
2123 if( (Math.Abs(AbsolutePosition.X - autopilotTarget.X) < 256.0f) && (Math.Abs(AbsolutePosition.Y - autopilotTarget.Y) < 256.0f) )
1855 { 2124 {
2125 autopilot = false; // close enough
2126 m_lastWorldPosition = m_pos; /* CW - This give us a position to return the avatar to if the part is killed before standup.
2127 Not using the part's position because returning the AV to the last known standing
2128 position is likely to be more friendly, isn't it? */
1856 RemoveFromPhysicalScene(); 2129 RemoveFromPhysicalScene();
1857 } 2130 Velocity = Vector3.Zero;
2131 AbsolutePosition = autopilotTarget + new Vector3(0.0f, 0.0f, (m_sitAvatarHeight / 2.0f)); // Warp av to over sit target
2132 } // else the autopilot will get us close
2133 }
2134 else
2135 { // its a scripted sit
2136 m_lastWorldPosition = part.AbsolutePosition; /* CW - This give us a position to return the avatar to if the part is killed before standup.
2137 I *am* using the part's position this time because we have no real idea how far away
2138 the avatar is from the sit target. */
2139 RemoveFromPhysicalScene();
2140 Velocity = Vector3.Zero;
1858 } 2141 }
1859
1860 cameraAtOffset = part.GetCameraAtOffset();
1861 cameraEyeOffset = part.GetCameraEyeOffset();
1862 forceMouselook = part.GetForceMouselook();
1863 } 2142 }
1864 2143 else return; // physactor is null!
1865 ControllingClient.SendSitResponse(targetID, offset, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook); 2144
1866 m_requestedSitTargetUUID = targetID; 2145 Vector3 offsetr; // = offset * partIRot;
2146 // KF: In a linkset, offsetr needs to be relative to the group root! 091208
2147 // offsetr = (part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) + (offset * partIRot);
2148 // if (part.LinkNum < 2) 091216 All this was necessary because of the GetWorldRotation error.
2149 // { // Single, or Root prim of linkset, target is ClickOffset * RootRot
2150 //offsetr = offset * partIRot;
2151//
2152 // }
2153 // else
2154 // { // Child prim, offset is (ChildOffset * RootRot) + (ClickOffset * ChildRot)
2155 // offsetr = //(part.OffsetPosition * Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset)) +
2156 // (offset * partRot);
2157 // }
2158
2159//Console.WriteLine(" ");
2160//Console.WriteLine("link number ={0}", part.LinkNum);
2161//Console.WriteLine("Prim offset ={0}", part.OffsetPosition );
2162//Console.WriteLine("Root Rotate ={0}", part.ParentGroup.RootPart.RotationOffset);
2163//Console.WriteLine("Click offst ={0}", offset);
2164//Console.WriteLine("Prim Rotate ={0}", part.GetWorldRotation());
2165//Console.WriteLine("offsetr ={0}", offsetr);
2166//Console.WriteLine("Camera At ={0}", cameraAtOffset);
2167//Console.WriteLine("Camera Eye ={0}", cameraEyeOffset);
2168
2169 //NOTE: SendSitResponse should be relative to the GROUP *NOT* THE PRIM if we're sitting on a child
2170 ControllingClient.SendSitResponse(part.ParentGroup.UUID, ((offset * part.RotationOffset) + part.OffsetPosition), sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook);
2171
2172 m_requestedSitTargetUUID = part.UUID; //KF: Correct autopilot target
1867 // This calls HandleAgentSit twice, once from here, and the client calls 2173 // This calls HandleAgentSit twice, once from here, and the client calls
1868 // HandleAgentSit itself after it gets to the location 2174 // HandleAgentSit itself after it gets to the location
1869 // It doesn't get to the location until we've moved them there though 2175 // It doesn't get to the location until we've moved them there though
1870 // which happens in HandleAgentSit :P 2176 // which happens in HandleAgentSit :P
1871 m_autopilotMoving = autopilot; 2177 m_autopilotMoving = autopilot;
1872 m_autoPilotTarget = pos; 2178 m_autoPilotTarget = autopilotTarget;
1873 m_sitAtAutoTarget = autopilot; 2179 m_sitAtAutoTarget = autopilot;
2180 m_initialSitTarget = autopilotTarget;
1874 if (!autopilot) 2181 if (!autopilot)
1875 HandleAgentSit(remoteClient, UUID); 2182 HandleAgentSit(remoteClient, UUID);
1876 } 2183 }
@@ -2165,47 +2472,130 @@ namespace OpenSim.Region.Framework.Scenes
2165 { 2472 {
2166 if (part != null) 2473 if (part != null)
2167 { 2474 {
2475//Console.WriteLine("Link #{0}, Rot {1}", part.LinkNum, part.GetWorldRotation());
2168 if (part.GetAvatarOnSitTarget() == UUID) 2476 if (part.GetAvatarOnSitTarget() == UUID)
2169 { 2477 {
2478//Console.WriteLine("Scripted Sit");
2479 // Scripted sit
2170 Vector3 sitTargetPos = part.SitTargetPosition; 2480 Vector3 sitTargetPos = part.SitTargetPosition;
2171 Quaternion sitTargetOrient = part.SitTargetOrientation; 2481 Quaternion sitTargetOrient = part.SitTargetOrientation;
2172
2173 //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0);
2174 //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w);
2175
2176 //Quaternion result = (sitTargetOrient * vq) * nq;
2177
2178 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z); 2482 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z);
2179 m_pos += SIT_TARGET_ADJUSTMENT; 2483 m_pos += SIT_TARGET_ADJUSTMENT;
2484 if (!part.IsRoot)
2485 {
2486 m_pos *= part.RotationOffset;
2487 }
2180 m_bodyRot = sitTargetOrient; 2488 m_bodyRot = sitTargetOrient;
2181 //Rotation = sitTargetOrient;
2182 m_parentPosition = part.AbsolutePosition; 2489 m_parentPosition = part.AbsolutePosition;
2183 2490 part.IsOccupied = true;
2184 //SendTerseUpdateToAllClients(); 2491 part.ParentGroup.AddAvatar(agentID);
2185 } 2492 }
2186 else 2493 else
2187 { 2494 {
2188 m_pos -= part.AbsolutePosition; 2495 // if m_avUnscriptedSitPos is zero then Av sits above center
2496 // Else Av sits at m_avUnscriptedSitPos
2497
2498 // Non-scripted sit by Kitto Flora 21Nov09
2499 // Calculate angle of line from prim to Av
2500 Quaternion partIRot;
2501// if (part.LinkNum == 1)
2502// { // Root prim of linkset
2503// partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset);
2504// }
2505// else
2506// { // single or child prim
2507 partIRot = Quaternion.Inverse(part.GetWorldRotation());
2508// }
2509 Vector3 sitTargetPos= part.AbsolutePosition + m_avUnscriptedSitPos;
2510 float y_diff = (m_avInitialPos.Y - sitTargetPos.Y);
2511 float x_diff = ( m_avInitialPos.X - sitTargetPos.X);
2512 if(Math.Abs(x_diff) < 0.001f) x_diff = 0.001f; // avoid div by 0
2513 if(Math.Abs(y_diff) < 0.001f) y_diff = 0.001f; // avoid pol flip at 0
2514 float sit_angle = (float)Math.Atan2( (double)y_diff, (double)x_diff);
2515 // NOTE: when sitting m_ pos and m_bodyRot are *relative* to the prim location/rotation, not 'World'.
2516 // Av sits at world euler <0,0, z>, translated by part rotation
2517 m_bodyRot = partIRot * Quaternion.CreateFromEulers(0f, 0f, sit_angle); // sit at 0,0,inv-click
2518
2189 m_parentPosition = part.AbsolutePosition; 2519 m_parentPosition = part.AbsolutePosition;
2190 } 2520 part.IsOccupied = true;
2521 part.ParentGroup.AddAvatar(agentID);
2522 m_pos = new Vector3(0f, 0f, 0.05f) + // corrections to get Sit Animation
2523 (new Vector3(0.0f, 0f, 0.61f) * partIRot) + // located on center
2524 (new Vector3(0.34f, 0f, 0.0f) * m_bodyRot) +
2525 m_avUnscriptedSitPos; // adds click offset, if any
2526 //Set up raytrace to find top surface of prim
2527 Vector3 size = part.Scale;
2528 float mag = 2.0f; // 0.1f + (float)Math.Sqrt((size.X * size.X) + (size.Y * size.Y) + (size.Z * size.Z));
2529 Vector3 start = part.AbsolutePosition + new Vector3(0f, 0f, mag);
2530 Vector3 down = new Vector3(0f, 0f, -1f);
2531//Console.WriteLine("st={0} do={1} ma={2}", start, down, mag);
2532 m_scene.PhysicsScene.RaycastWorld(
2533 start, // Vector3 position,
2534 down, // Vector3 direction,
2535 mag, // float length,
2536 SitAltitudeCallback); // retMethod
2537 } // end scripted/not
2191 } 2538 }
2192 else 2539 else // no Av
2193 { 2540 {
2194 return; 2541 return;
2195 } 2542 }
2196 } 2543 }
2197 m_parentID = m_requestedSitTargetID;
2198 2544
2545 //We want our offsets to reference the root prim, not the child we may have sat on
2546 if (!part.IsRoot)
2547 {
2548 m_parentID = part.ParentGroup.RootPart.LocalId;
2549 m_pos += part.OffsetPosition;
2550 }
2551 else
2552 {
2553 m_parentID = m_requestedSitTargetID;
2554 }
2555
2556 m_linkedPrim = part.UUID;
2557 if (part.GetAvatarOnSitTarget() != UUID)
2558 {
2559 m_offsetRotation = m_offsetRotation / part.RotationOffset;
2560 }
2199 Velocity = Vector3.Zero; 2561 Velocity = Vector3.Zero;
2200 RemoveFromPhysicalScene(); 2562 RemoveFromPhysicalScene();
2201
2202 Animator.TrySetMovementAnimation(sitAnimation); 2563 Animator.TrySetMovementAnimation(sitAnimation);
2203 SendAvatarDataToAllAgents(); 2564 SendAvatarDataToAllAgents();
2204 // This may seem stupid, but Our Full updates don't send avatar rotation :P
2205 // So we're also sending a terse update (which has avatar rotation)
2206 // [Update] We do now.
2207 //SendTerseUpdateToAllClients(); 2565 //SendTerseUpdateToAllClients();
2208 } 2566 }
2567
2568 public void SitAltitudeCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal)
2569 {
2570 // KF: 091202 There appears to be a bug in Prim Edit Size - the process sometimes make a prim that RayTrace no longer
2571 // sees. Take/re-rez, or sim restart corrects the condition. Result of bug is incorrect sit height.
2572 if(hitYN)
2573 {
2574 // m_pos = Av offset from prim center to make look like on center
2575 // m_parentPosition = Actual center pos of prim
2576 // collisionPoint = spot on prim where we want to sit
2577 // collisionPoint.Z = global sit surface height
2578 SceneObjectPart part = m_scene.GetSceneObjectPart(localid);
2579 Quaternion partIRot;
2580// if (part.LinkNum == 1)
2581/// { // Root prim of linkset
2582// partIRot = Quaternion.Inverse(part.ParentGroup.RootPart.RotationOffset);
2583// }
2584// else
2585// { // single or child prim
2586 partIRot = Quaternion.Inverse(part.GetWorldRotation());
2587// }
2588 if (m_initialSitTarget != null)
2589 {
2590 float offZ = collisionPoint.Z - m_initialSitTarget.Z;
2591 Vector3 offset = new Vector3(0.0f, 0.0f, offZ) * partIRot; // Altitude correction
2592 //Console.WriteLine("sitPoint={0}, offset={1}", sitPoint, offset);
2593 m_pos += offset;
2594 // ControllingClient.SendClearFollowCamProperties(part.UUID);
2595 }
2596
2597 }
2598 } // End SitAltitudeCallback KF.
2209 2599
2210 /// <summary> 2600 /// <summary>
2211 /// Event handler for the 'Always run' setting on the client 2601 /// Event handler for the 'Always run' setting on the client
@@ -2235,12 +2625,13 @@ namespace OpenSim.Region.Framework.Scenes
2235 /// </summary> 2625 /// </summary>
2236 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> 2626 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
2237 /// <param name="rotation">The direction in which this avatar should now face. 2627 /// <param name="rotation">The direction in which this avatar should now face.
2238 public void AddNewMovement(Vector3 vec, Quaternion rotation) 2628 public void AddNewMovement(Vector3 vec, Quaternion rotation, bool Nudging)
2239 { 2629 {
2240 if (m_isChildAgent) 2630 if (m_isChildAgent)
2241 { 2631 {
2242 // WHAT??? 2632 // WHAT???
2243 m_log.Debug("[SCENEPRESENCE]: AddNewMovement() called on child agent, making root agent!"); 2633 m_log.Debug("[SCENEPRESENCE]: AddNewMovement() called on child agent");
2634
2244 return; 2635 return;
2245 } 2636 }
2246 2637
@@ -2249,15 +2640,26 @@ namespace OpenSim.Region.Framework.Scenes
2249 Rotation = rotation; 2640 Rotation = rotation;
2250 Vector3 direc = vec * rotation; 2641 Vector3 direc = vec * rotation;
2251 direc.Normalize(); 2642 direc.Normalize();
2643 PhysicsActor actor = m_physicsActor;
2644
2645 if (actor.Flying != m_flyingOld) // add for fly velocity control
2646 {
2647 m_flyingOld = actor.Flying; // add for fly velocity control
2648 if (!actor.Flying) m_wasFlying = true; // add for fly velocity control
2649 }
2650
2651 if (m_physicsActor.IsColliding == true) m_wasFlying = false; // add for fly velocity control
2652
2653 if ((vec.Z == 0f) && !actor.Flying) direc.Z = 0f; // Prevent camera WASD up.
2252 2654
2253 direc *= 0.03f * 128f * m_speedModifier; 2655 direc *= 0.03f * 128f * m_speedModifier;
2254 2656
2255 PhysicsActor actor = m_physicsActor;
2256 if (actor != null) 2657 if (actor != null)
2257 { 2658 {
2258 if (actor.Flying) 2659 if (actor.Flying)
2259 { 2660 {
2260 direc *= 4.0f; 2661// rm speed mod direc *= 4.0f;
2662 direc *= 5.2f; // for speed mod
2261 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); 2663 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
2262 //bool colliding = (m_physicsActor.IsColliding==true); 2664 //bool colliding = (m_physicsActor.IsColliding==true);
2263 //if (controlland) 2665 //if (controlland)
@@ -2270,22 +2672,34 @@ namespace OpenSim.Region.Framework.Scenes
2270 // m_log.Info("[AGENT]: Stop FLying"); 2672 // m_log.Info("[AGENT]: Stop FLying");
2271 //} 2673 //}
2272 } 2674 }
2675 if (Animator.m_falling && m_wasFlying) // if falling from flying, disable motion add
2676 {
2677 direc *= 0.0f;
2678 }
2679 /* This jumping section removed to SPA
2273 else if (!actor.Flying && actor.IsColliding) 2680 else if (!actor.Flying && actor.IsColliding)
2274 { 2681 {
2275 if (direc.Z > 2.0f) 2682 if (direc.Z > 2.0f)
2276 { 2683 {
2277 direc.Z *= 3.0f; 2684 if(m_animator.m_animTickJump == -1)
2278 2685 {
2279 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. 2686 direc.Z *= 3.0f; // jump
2280 Animator.TrySetMovementAnimation("PREJUMP"); 2687 }
2281 Animator.TrySetMovementAnimation("JUMP"); 2688 else
2689 {
2690 direc.Z *= 0.1f; // prejump
2691 }
2692 / * Animations are controlled via GetMovementAnimation() in ScenePresenceAnimator.cs
2693 Animator.TrySetMovementAnimation("PREJUMP");
2694 Animator.TrySetMovementAnimation("JUMP");
2695 * /
2282 } 2696 }
2283 } 2697 } */
2284 } 2698 }
2285 2699
2286 // TODO: Add the force instead of only setting it to support multiple forces per frame? 2700 // TODO: Add the force instead of only setting it to support multiple forces per frame?
2287 m_forceToApply = direc; 2701 m_forceToApply = direc;
2288 2702 m_isNudging = Nudging;
2289 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2703 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
2290 } 2704 }
2291 2705
@@ -2334,6 +2748,9 @@ namespace OpenSim.Region.Framework.Scenes
2334 2748
2335 CheckForSignificantMovement(); // sends update to the modules. 2749 CheckForSignificantMovement(); // sends update to the modules.
2336 } 2750 }
2751
2752 //Sending prim updates AFTER the avatar terse updates are sent
2753 SendPrimUpdates();
2337 } 2754 }
2338 2755
2339 #endregion 2756 #endregion
@@ -3143,6 +3560,7 @@ namespace OpenSim.Region.Framework.Scenes
3143 m_callbackURI = cAgent.CallbackURI; 3560 m_callbackURI = cAgent.CallbackURI;
3144 3561
3145 m_pos = cAgent.Position; 3562 m_pos = cAgent.Position;
3563
3146 m_velocity = cAgent.Velocity; 3564 m_velocity = cAgent.Velocity;
3147 m_CameraCenter = cAgent.Center; 3565 m_CameraCenter = cAgent.Center;
3148 m_CameraAtAxis = cAgent.AtAxis; 3566 m_CameraAtAxis = cAgent.AtAxis;
@@ -3265,20 +3683,45 @@ namespace OpenSim.Region.Framework.Scenes
3265 /// </summary> 3683 /// </summary>
3266 public override void UpdateMovement() 3684 public override void UpdateMovement()
3267 { 3685 {
3268 if (m_forceToApply.HasValue) 3686 if (Animator!=null) // add for jumping
3269 { 3687 { // add for jumping
3270 Vector3 force = m_forceToApply.Value; 3688 // if (!m_animator.m_jumping) // add for jumping
3689 // { // add for jumping
3271 3690
3272 m_updateflag = true; 3691 if (m_forceToApply.HasValue) // this section realigned
3273 3692 {
3274 // The magic constant 0.95f seems to make walking feel less jerky,
3275 // probably because it hackishly accounts for the overall latency of
3276 // these Velocity updates -- Diva
3277 Velocity = force * .95F;
3278 3693
3279 m_forceToApply = null; 3694 Vector3 force = m_forceToApply.Value;
3280 } 3695 m_updateflag = true;
3281 } 3696if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3697 Velocity = force;
3698//Console.WriteLine("UM1 {0}", Velocity);
3699 m_forceToApply = null;
3700 }
3701 else
3702 {
3703 if (m_isNudging)
3704 {
3705 Vector3 force = Vector3.Zero;
3706
3707 m_updateflag = true;
3708if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3709 Velocity = force;
3710//Console.WriteLine("UM2 {0}", Velocity);
3711 m_isNudging = false;
3712 m_updateCount = UPDATE_COUNT; //KF: Update anims to pickup "STAND"
3713 }
3714 else // add for jumping
3715 { // add for jumping
3716 Vector3 force = Vector3.Zero; // add for jumping
3717if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for jumping
3718//Console.WriteLine("UM3 {0}", Velocity);
3719 Velocity = force; // add for jumping
3720 }
3721 }
3722 // } // end realign
3723 } // add for jumping
3724 } // add for jumping
3282 3725
3283 /// <summary> 3726 /// <summary>
3284 /// Adds a physical representation of the avatar to the Physics plugin 3727 /// Adds a physical representation of the avatar to the Physics plugin
@@ -3292,10 +3735,8 @@ namespace OpenSim.Region.Framework.Scenes
3292 3735
3293 Vector3 pVec = AbsolutePosition; 3736 Vector3 pVec = AbsolutePosition;
3294 3737
3295 // Old bug where the height was in centimeters instead of meters
3296 m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec, 3738 m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec,
3297 new Vector3(0f, 0f, m_appearance.AvatarHeight), isFlying); 3739 new Vector3(0f, 0f, m_appearance.AvatarHeight), isFlying);
3298
3299 scene.AddPhysicsActorTaint(m_physicsActor); 3740 scene.AddPhysicsActorTaint(m_physicsActor);
3300 //m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; 3741 //m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients;
3301 m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; 3742 m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate;
@@ -3319,18 +3760,29 @@ namespace OpenSim.Region.Framework.Scenes
3319 { 3760 {
3320 if (e == null) 3761 if (e == null)
3321 return; 3762 return;
3322 3763
3323 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) 3764 // The Physics Scene will send (spam!) updates every 500 ms grep: m_physicsActor.SubscribeEvents(
3324 // The Physics Scene will send updates every 500 ms grep: m_physicsActor.SubscribeEvents(
3325 // as of this comment the interval is set in AddToPhysicalScene 3765 // as of this comment the interval is set in AddToPhysicalScene
3326 if (Animator!=null) 3766 if (Animator!=null)
3327 Animator.UpdateMovementAnimations(); 3767 {
3768 if (m_updateCount > 0) //KF: DO NOT call UpdateMovementAnimations outside of the m_updateCount wrapper,
3769 { // else its will lock out other animation changes, like ground sit.
3770 Animator.UpdateMovementAnimations();
3771 m_updateCount--;
3772 }
3773 }
3328 3774
3329 CollisionEventUpdate collisionData = (CollisionEventUpdate)e; 3775 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3330 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; 3776 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3331 3777
3332 CollisionPlane = Vector4.UnitW; 3778 CollisionPlane = Vector4.UnitW;
3333 3779
3780 if (m_lastColCount != coldata.Count)
3781 {
3782 m_updateCount = UPDATE_COUNT;
3783 m_lastColCount = coldata.Count;
3784 }
3785
3334 if (coldata.Count != 0 && Animator != null) 3786 if (coldata.Count != 0 && Animator != null)
3335 { 3787 {
3336 switch (Animator.CurrentMovementAnimation) 3788 switch (Animator.CurrentMovementAnimation)
@@ -3360,6 +3812,148 @@ namespace OpenSim.Region.Framework.Scenes
3360 } 3812 }
3361 } 3813 }
3362 3814
3815 List<uint> thisHitColliders = new List<uint>();
3816 List<uint> endedColliders = new List<uint>();
3817 List<uint> startedColliders = new List<uint>();
3818
3819 foreach (uint localid in coldata.Keys)
3820 {
3821 thisHitColliders.Add(localid);
3822 if (!m_lastColliders.Contains(localid))
3823 {
3824 startedColliders.Add(localid);
3825 }
3826 //m_log.Debug("[SCENE PRESENCE]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
3827 }
3828
3829 // calculate things that ended colliding
3830 foreach (uint localID in m_lastColliders)
3831 {
3832 if (!thisHitColliders.Contains(localID))
3833 {
3834 endedColliders.Add(localID);
3835 }
3836 }
3837 //add the items that started colliding this time to the last colliders list.
3838 foreach (uint localID in startedColliders)
3839 {
3840 m_lastColliders.Add(localID);
3841 }
3842 // remove things that ended colliding from the last colliders list
3843 foreach (uint localID in endedColliders)
3844 {
3845 m_lastColliders.Remove(localID);
3846 }
3847
3848 // do event notification
3849 if (startedColliders.Count > 0)
3850 {
3851 ColliderArgs StartCollidingMessage = new ColliderArgs();
3852 List<DetectedObject> colliding = new List<DetectedObject>();
3853 foreach (uint localId in startedColliders)
3854 {
3855 if (localId == 0)
3856 continue;
3857
3858 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3859 string data = "";
3860 if (obj != null)
3861 {
3862 DetectedObject detobj = new DetectedObject();
3863 detobj.keyUUID = obj.UUID;
3864 detobj.nameStr = obj.Name;
3865 detobj.ownerUUID = obj.OwnerID;
3866 detobj.posVector = obj.AbsolutePosition;
3867 detobj.rotQuat = obj.GetWorldRotation();
3868 detobj.velVector = obj.Velocity;
3869 detobj.colliderType = 0;
3870 detobj.groupUUID = obj.GroupID;
3871 colliding.Add(detobj);
3872 }
3873 }
3874
3875 if (colliding.Count > 0)
3876 {
3877 StartCollidingMessage.Colliders = colliding;
3878
3879 foreach (SceneObjectGroup att in Attachments)
3880 Scene.EventManager.TriggerScriptCollidingStart(att.LocalId, StartCollidingMessage);
3881 }
3882 }
3883
3884 if (endedColliders.Count > 0)
3885 {
3886 ColliderArgs EndCollidingMessage = new ColliderArgs();
3887 List<DetectedObject> colliding = new List<DetectedObject>();
3888 foreach (uint localId in endedColliders)
3889 {
3890 if (localId == 0)
3891 continue;
3892
3893 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3894 string data = "";
3895 if (obj != null)
3896 {
3897 DetectedObject detobj = new DetectedObject();
3898 detobj.keyUUID = obj.UUID;
3899 detobj.nameStr = obj.Name;
3900 detobj.ownerUUID = obj.OwnerID;
3901 detobj.posVector = obj.AbsolutePosition;
3902 detobj.rotQuat = obj.GetWorldRotation();
3903 detobj.velVector = obj.Velocity;
3904 detobj.colliderType = 0;
3905 detobj.groupUUID = obj.GroupID;
3906 colliding.Add(detobj);
3907 }
3908 }
3909
3910 if (colliding.Count > 0)
3911 {
3912 EndCollidingMessage.Colliders = colliding;
3913
3914 foreach (SceneObjectGroup att in Attachments)
3915 Scene.EventManager.TriggerScriptCollidingEnd(att.LocalId, EndCollidingMessage);
3916 }
3917 }
3918
3919 if (thisHitColliders.Count > 0)
3920 {
3921 ColliderArgs CollidingMessage = new ColliderArgs();
3922 List<DetectedObject> colliding = new List<DetectedObject>();
3923 foreach (uint localId in thisHitColliders)
3924 {
3925 if (localId == 0)
3926 continue;
3927
3928 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
3929 string data = "";
3930 if (obj != null)
3931 {
3932 DetectedObject detobj = new DetectedObject();
3933 detobj.keyUUID = obj.UUID;
3934 detobj.nameStr = obj.Name;
3935 detobj.ownerUUID = obj.OwnerID;
3936 detobj.posVector = obj.AbsolutePosition;
3937 detobj.rotQuat = obj.GetWorldRotation();
3938 detobj.velVector = obj.Velocity;
3939 detobj.colliderType = 0;
3940 detobj.groupUUID = obj.GroupID;
3941 colliding.Add(detobj);
3942 }
3943 }
3944
3945 if (colliding.Count > 0)
3946 {
3947 CollidingMessage.Colliders = colliding;
3948
3949 lock (m_attachments)
3950 {
3951 foreach (SceneObjectGroup att in m_attachments)
3952 Scene.EventManager.TriggerScriptColliding(att.LocalId, CollidingMessage);
3953 }
3954 }
3955 }
3956
3363 if (m_invulnerable) 3957 if (m_invulnerable)
3364 return; 3958 return;
3365 3959
@@ -3785,6 +4379,39 @@ namespace OpenSim.Region.Framework.Scenes
3785 return; 4379 return;
3786 } 4380 }
3787 4381
4382 XmlDocument doc = new XmlDocument();
4383 string stateData = String.Empty;
4384
4385 IAttachmentsService attServ = m_scene.RequestModuleInterface<IAttachmentsService>();
4386 if (attServ != null)
4387 {
4388 m_log.DebugFormat("[ATTACHMENT]: Loading attachment data from attachment service");
4389 stateData = attServ.Get(ControllingClient.AgentId.ToString());
4390 if (stateData != String.Empty)
4391 {
4392 try
4393 {
4394 doc.LoadXml(stateData);
4395 }
4396 catch { }
4397 }
4398 }
4399
4400 Dictionary<UUID, string> itemData = new Dictionary<UUID, string>();
4401
4402 XmlNodeList nodes = doc.GetElementsByTagName("Attachment");
4403 if (nodes.Count > 0)
4404 {
4405 foreach (XmlNode n in nodes)
4406 {
4407 XmlElement elem = (XmlElement)n;
4408 string itemID = elem.GetAttribute("ItemID");
4409 string xml = elem.InnerXml;
4410
4411 itemData[new UUID(itemID)] = xml;
4412 }
4413 }
4414
3788 List<AvatarAttachment> attachments = m_appearance.GetAttachments(); 4415 List<AvatarAttachment> attachments = m_appearance.GetAttachments();
3789 foreach (AvatarAttachment attach in attachments) 4416 foreach (AvatarAttachment attach in attachments)
3790 { 4417 {
@@ -3805,7 +4432,30 @@ namespace OpenSim.Region.Framework.Scenes
3805 4432
3806 try 4433 try
3807 { 4434 {
3808 m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p); 4435 string xmlData;
4436 XmlDocument d = new XmlDocument();
4437 UUID asset;
4438 if (itemData.TryGetValue(itemID, out xmlData))
4439 {
4440 d.LoadXml(xmlData);
4441 m_log.InfoFormat("[ATTACHMENT]: Found saved state for item {0}, loading it", itemID);
4442
4443 // Rez from inventory
4444 asset
4445 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p, true, d);
4446
4447 }
4448 else
4449 {
4450 // Rez from inventory (with a null doc to let
4451 // CHANGED_OWNER happen)
4452 asset
4453 = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p, true, null);
4454 }
4455
4456 m_log.InfoFormat(
4457 "[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2}",
4458 p, itemID, asset);
3809 } 4459 }
3810 catch (Exception e) 4460 catch (Exception e)
3811 { 4461 {
@@ -3838,6 +4488,15 @@ namespace OpenSim.Region.Framework.Scenes
3838 m_reprioritization_called = false; 4488 m_reprioritization_called = false;
3839 } 4489 }
3840 } 4490 }
4491
4492 private Vector3 Quat2Euler(Quaternion rot){
4493 float x = Utils.RAD_TO_DEG * (float)Math.Atan2((double)((2.0f * rot.X * rot.W) - (2.0f * rot.Y * rot.Z)) ,
4494 (double)(1 - (2.0f * rot.X * rot.X) - (2.0f * rot.Z * rot.Z)));
4495 float y = Utils.RAD_TO_DEG * (float)Math.Asin ((double)((2.0f * rot.X * rot.Y) + (2.0f * rot.Z * rot.W)));
4496 float z = Utils.RAD_TO_DEG * (float)Math.Atan2(((double)(2.0f * rot.Y * rot.W) - (2.0f * rot.X * rot.Z)) ,
4497 (double)(1 - (2.0f * rot.Y * rot.Y) - (2.0f * rot.Z * rot.Z)));
4498 return(new Vector3(x,y,z));
4499 }
3841 4500
3842 public void SaveChangedAttachments() 4501 public void SaveChangedAttachments()
3843 { 4502 {
@@ -3861,5 +4520,30 @@ namespace OpenSim.Region.Framework.Scenes
3861 } 4520 }
3862 } 4521 }
3863 } 4522 }
4523
4524 private void CheckLandingPoint(ref Vector3 pos)
4525 {
4526 // Never constrain lures
4527 if ((TeleportFlags & TeleportFlags.ViaLure) != 0)
4528 return;
4529
4530 if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport)
4531 return;
4532
4533 ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
4534
4535 if (land.LandData.LandingType == (byte)LandingType.LandingPoint &&
4536 land.LandData.UserLocation != Vector3.Zero &&
4537 land.LandData.OwnerID != m_uuid &&
4538 (!m_scene.Permissions.IsGod(m_uuid)) &&
4539 (!m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid)))
4540 {
4541 float curr = Vector3.Distance(AbsolutePosition, pos);
4542 if (Vector3.Distance(land.LandData.UserLocation, pos) < curr)
4543 pos = land.LandData.UserLocation;
4544 else
4545 ControllingClient.SendAlertMessage("Can't teleport closer to destination");
4546 }
4547 }
3864 } 4548 }
3865} 4549}
diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs
index 7c067ca..1f4ec96 100644
--- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs
@@ -106,7 +106,7 @@ namespace OpenSim.Region.Framework.Scenes
106 g.ScheduleFullUpdateToAvatar(m_presence); 106 g.ScheduleFullUpdateToAvatar(m_presence);
107 } 107 }
108 108
109 while (m_partsUpdateQueue.Count > 0) 109 while (m_partsUpdateQueue.Count != null && m_partsUpdateQueue.Count > 0)
110 { 110 {
111 SceneObjectPart part = m_partsUpdateQueue.Dequeue(); 111 SceneObjectPart part = m_partsUpdateQueue.Dequeue();
112 112
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 57ae4fd..b2b3ad9 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -102,7 +102,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
102 sceneObject.AddPart(part); 102 sceneObject.AddPart(part);
103 part.LinkNum = linkNum; 103 part.LinkNum = linkNum;
104 part.TrimPermissions(); 104 part.TrimPermissions();
105 part.StoreUndoState(); 105 part.StoreUndoState(UndoType.STATE_ALL);
106 reader.Close(); 106 reader.Close();
107 sr.Close(); 107 sr.Close();
108 } 108 }
@@ -220,7 +220,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
220 if (originalLinkNum != 0) 220 if (originalLinkNum != 0)
221 part.LinkNum = originalLinkNum; 221 part.LinkNum = originalLinkNum;
222 222
223 part.StoreUndoState(); 223 part.StoreUndoState(UndoType.STATE_ALL);
224 reader.Close(); 224 reader.Close();
225 sr.Close(); 225 sr.Close();
226 } 226 }
@@ -1441,12 +1441,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1441 { 1441 {
1442 TaskInventoryDictionary tinv = new TaskInventoryDictionary(); 1442 TaskInventoryDictionary tinv = new TaskInventoryDictionary();
1443 1443
1444 if (reader.IsEmptyElement)
1445 {
1446 reader.Read();
1447 return tinv;
1448 }
1449
1450 reader.ReadStartElement(name, String.Empty); 1444 reader.ReadStartElement(name, String.Empty);
1451 1445
1452 while (reader.Name == "TaskInventoryItem") 1446 while (reader.Name == "TaskInventoryItem")
@@ -1480,12 +1474,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1480 { 1474 {
1481 PrimitiveBaseShape shape = new PrimitiveBaseShape(); 1475 PrimitiveBaseShape shape = new PrimitiveBaseShape();
1482 1476
1483 if (reader.IsEmptyElement)
1484 {
1485 reader.Read();
1486 return shape;
1487 }
1488
1489 reader.ReadStartElement(name, String.Empty); // Shape 1477 reader.ReadStartElement(name, String.Empty); // Shape
1490 1478
1491 string nodeName = string.Empty; 1479 string nodeName = string.Empty;
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/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index 83906d7..3978a7d 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -86,10 +86,6 @@ namespace OpenSim.Region.Framework.Scenes
86 /// <param name="assetUuids">The assets gathered</param> 86 /// <param name="assetUuids">The assets gathered</param>
87 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids) 87 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids)
88 { 88 {
89 // avoid infinite loops
90 if (assetUuids.ContainsKey(assetUuid))
91 return;
92
93 try 89 try
94 { 90 {
95 assetUuids[assetUuid] = assetType; 91 assetUuids[assetUuid] = assetType;
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 821cd4b..627b58f 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;
@@ -883,6 +884,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
883 884
884 public void Close() 885 public void Close()
885 { 886 {
887 Close(true);
888 }
889
890 public void Close(bool sendStop)
891 {
886 Disconnect(); 892 Disconnect();
887 } 893 }
888 894
@@ -937,7 +943,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
937 943
938 } 944 }
939 945
940 public void SendKillObject(ulong regionHandle, uint localID) 946 public void SendKillObject(ulong regionHandle, List<uint> localID)
941 { 947 {
942 948
943 } 949 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 7909d8a..0e679a9 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -558,7 +558,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
558 558
559 public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request) 559 public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request)
560 { 560 {
561 m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called"); 561// m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called");
562 562
563 Hashtable response = new Hashtable(); 563 Hashtable response = new Hashtable();
564 response["content_type"] = "text/xml"; 564 response["content_type"] = "text/xml";
@@ -664,7 +664,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
664 664
665 public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request) 665 public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request)
666 { 666 {
667 m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called"); 667 //m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called");
668// string requestbody = (string)request["body"]; 668// string requestbody = (string)request["body"];
669// string uri = (string)request["uri"]; 669// string uri = (string)request["uri"];
670// string contenttype = (string)request["content-type"]; 670// string contenttype = (string)request["content-type"];
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index 534bf92..ae902eb 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -190,7 +190,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
190 break; 190 break;
191 } 191 }
192 192
193 m_vivoxVoiceAccountApi = String.Format("http://{0}/api2", m_vivoxServer); 193 m_vivoxVoiceAccountApi = String.Format("https://{0}/api2", m_vivoxServer);
194 194
195 // Admin interface required values 195 // Admin interface required values
196 if (String.IsNullOrEmpty(m_vivoxServer) || 196 if (String.IsNullOrEmpty(m_vivoxServer) ||
@@ -749,7 +749,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
749 } 749 }
750 750
751 751
752 private static readonly string m_vivoxLoginPath = "http://{0}/api2/viv_signin.php?userid={1}&pwd={2}"; 752 private static readonly string m_vivoxLoginPath = "https://{0}/api2/viv_signin.php?userid={1}&pwd={2}";
753 753
754 /// <summary> 754 /// <summary>
755 /// Perform administrative login for Vivox. 755 /// Perform administrative login for Vivox.
@@ -762,7 +762,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
762 } 762 }
763 763
764 764
765 private static readonly string m_vivoxLogoutPath = "http://{0}/api2/viv_signout.php?auth_token={1}"; 765 private static readonly string m_vivoxLogoutPath = "https://{0}/api2/viv_signout.php?auth_token={1}";
766 766
767 /// <summary> 767 /// <summary>
768 /// Perform administrative logout for Vivox. 768 /// Perform administrative logout for Vivox.
@@ -774,7 +774,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
774 } 774 }
775 775
776 776
777 private static readonly string m_vivoxGetAccountPath = "http://{0}/api2/viv_get_acct.php?auth_token={1}&user_name={2}"; 777 private static readonly string m_vivoxGetAccountPath = "https://{0}/api2/viv_get_acct.php?auth_token={1}&user_name={2}";
778 778
779 /// <summary> 779 /// <summary>
780 /// Retrieve account information for the specified user. 780 /// Retrieve account information for the specified user.
@@ -787,7 +787,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
787 } 787 }
788 788
789 789
790 private static readonly string m_vivoxNewAccountPath = "http://{0}/api2/viv_adm_acct_new.php?username={1}&pwd={2}&auth_token={3}"; 790 private static readonly string m_vivoxNewAccountPath = "https://{0}/api2/viv_adm_acct_new.php?username={1}&pwd={2}&auth_token={3}";
791 791
792 /// <summary> 792 /// <summary>
793 /// Creates a new account. 793 /// Creates a new account.
@@ -802,7 +802,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
802 } 802 }
803 803
804 804
805 private static readonly string m_vivoxPasswordPath = "http://{0}/api2/viv_adm_password.php?user_name={1}&new_pwd={2}&auth_token={3}"; 805 private static readonly string m_vivoxPasswordPath = "https://{0}/api2/viv_adm_password.php?user_name={1}&new_pwd={2}&auth_token={3}";
806 806
807 /// <summary> 807 /// <summary>
808 /// Change the user's password. 808 /// Change the user's password.
@@ -814,7 +814,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
814 } 814 }
815 815
816 816
817 private static readonly string m_vivoxChannelPath = "http://{0}/api2/viv_chan_mod.php?mode={1}&chan_name={2}&auth_token={3}"; 817 private static readonly string m_vivoxChannelPath = "https://{0}/api2/viv_chan_mod.php?mode={1}&chan_name={2}&auth_token={3}";
818 818
819 /// <summary> 819 /// <summary>
820 /// Create a channel. 820 /// Create a channel.
@@ -888,7 +888,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
888 return false; 888 return false;
889 } 889 }
890 890
891 private static readonly string m_vivoxChannelSearchPath = "http://{0}/api2/viv_chan_search.php?cond_channame={1}&auth_token={2}"; 891 private static readonly string m_vivoxChannelSearchPath = "https://{0}/api2/viv_chan_search.php?cond_channame={1}&auth_token={2}";
892 892
893 /// <summary> 893 /// <summary>
894 /// Retrieve a channel. 894 /// Retrieve a channel.
@@ -1032,7 +1032,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1032 return false; 1032 return false;
1033 } 1033 }
1034 1034
1035 // private static readonly string m_vivoxChannelById = "http://{0}/api2/viv_chan_mod.php?mode={1}&chan_id={2}&auth_token={3}"; 1035 // private static readonly string m_vivoxChannelById = "https://{0}/api2/viv_chan_mod.php?mode={1}&chan_id={2}&auth_token={3}";
1036 1036
1037 // private XmlElement VivoxGetChannelById(string parent, string channelid) 1037 // private XmlElement VivoxGetChannelById(string parent, string channelid)
1038 // { 1038 // {
@@ -1056,7 +1056,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1056 /// In this case the call handles parent and description as optional values. 1056 /// In this case the call handles parent and description as optional values.
1057 /// </summary> 1057 /// </summary>
1058 1058
1059 private static readonly string m_vivoxChannelDel = "http://{0}/api2/viv_chan_mod.php?mode={1}&chan_id={2}&auth_token={3}"; 1059 private static readonly string m_vivoxChannelDel = "https://{0}/api2/viv_chan_mod.php?mode={1}&chan_id={2}&auth_token={3}";
1060 1060
1061 private XmlElement VivoxDeleteChannel(string parent, string channelid) 1061 private XmlElement VivoxDeleteChannel(string parent, string channelid)
1062 { 1062 {
@@ -1072,7 +1072,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1072 /// Return information on channels in the given directory 1072 /// Return information on channels in the given directory
1073 /// </summary> 1073 /// </summary>
1074 1074
1075 private static readonly string m_vivoxChannelSearch = "http://{0}/api2/viv_chan_search.php?&cond_chanparent={1}&auth_token={2}"; 1075 private static readonly string m_vivoxChannelSearch = "https://{0}/api2/viv_chan_search.php?&cond_chanparent={1}&auth_token={2}";
1076 1076
1077 private XmlElement VivoxListChildren(string channelid) 1077 private XmlElement VivoxListChildren(string channelid)
1078 { 1078 {
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/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
index b84a34d..d469548 100644
--- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
+++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs
@@ -838,6 +838,10 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule
838 if (module != null) 838 if (module != null)
839 module.BuyObject(remoteClient, categoryID, localID, saleType, salePrice); 839 module.BuyObject(remoteClient, categoryID, localID, saleType, salePrice);
840 } 840 }
841
842 public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text)
843 {
844 }
841 } 845 }
842 846
843 public enum TransactionType : int 847 public enum TransactionType : int
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 96760a2..227450d 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
@@ -846,6 +846,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
846 846
847 public void Close() 847 public void Close()
848 { 848 {
849 Close(true);
850 }
851
852 public void Close(bool sendStop)
853 {
849 } 854 }
850 855
851 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..1bce760
--- /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 m_taintPosition = _position; // update the stale taint position
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;
597//Console.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..7cd2dd1
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -0,0 +1,3873 @@
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 private float m_APIDdamper = 1.0f;
89
90 // These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
91 // do not confuse with VEHICLE HOVER
92
93 private float m_PIDHoverHeight;
94 private float m_PIDHoverTau;
95 private bool m_useHoverPID;
96 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
97 private float m_targetHoverHeight;
98 private float m_groundHeight;
99 private float m_waterHeight;
100 private float m_buoyancy; //m_buoyancy set by llSetBuoyancy()
101
102 // private float m_tensor = 5f;
103 private int body_autodisable_frames = 20;
104
105
106 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
107 | CollisionCategories.Space
108 | CollisionCategories.Body
109 | CollisionCategories.Character
110 );
111 private bool m_taintshape;
112 private bool m_taintPhysics;
113 private bool m_collidesLand = true;
114 private bool m_collidesWater;
115 public bool m_returnCollisions;
116
117 // Default we're a Geometry
118 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
119
120 // Default, Collide with Other Geometries, spaces and Bodies
121 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
122
123 public bool m_taintremove;
124 public bool m_taintdisable;
125 public bool m_disabled;
126 public bool m_taintadd;
127 public bool m_taintselected;
128 public bool m_taintCollidesWater;
129
130 public uint m_localID;
131
132 //public GCHandle gc;
133 private CollisionLocker ode;
134
135 private bool m_meshfailed = false;
136 private bool m_taintforce = false;
137 private bool m_taintaddangularforce = false;
138 private Vector3 m_force;
139 private List<Vector3> m_forcelist = new List<Vector3>();
140 private List<Vector3> m_angularforcelist = new List<Vector3>();
141
142 private IMesh _mesh;
143 private PrimitiveBaseShape _pbs;
144 private OdeScene _parent_scene;
145 public IntPtr m_targetSpace = IntPtr.Zero;
146 public IntPtr prim_geom;
147// public IntPtr prev_geom;
148 public IntPtr _triMeshData;
149
150 private IntPtr _linkJointGroup = IntPtr.Zero;
151 private PhysicsActor _parent;
152 private PhysicsActor m_taintparent;
153
154 private List<OdePrim> childrenPrim = new List<OdePrim>();
155
156 private bool iscolliding;
157 private bool m_isphysical;
158 private bool m_isSelected;
159
160 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
161
162 private bool m_throttleUpdates;
163 private int throttleCounter;
164 public int m_interpenetrationcount;
165 public float m_collisionscore;
166 public int m_roundsUnderMotionThreshold;
167 private int m_crossingfailures;
168
169 public bool outofBounds;
170 private float m_density = 10.000006836f; // Aluminum g/cm3;
171
172 public bool _zeroFlag; // if body has been stopped
173 private bool m_lastUpdateSent;
174
175 public IntPtr Body = IntPtr.Zero;
176 public String m_primName;
177 private Vector3 _target_velocity;
178 public d.Mass pMass;
179
180 public int m_eventsubscription;
181 private CollisionEventUpdate CollisionEventsThisFrame;
182
183 private IntPtr m_linkJoint = IntPtr.Zero;
184
185 public volatile bool childPrim;
186
187 internal int m_material = (int)Material.Wood;
188
189 private int frcount = 0; // Used to limit dynamics debug output to
190 private int revcount = 0; // Reverse motion while > 0
191
192 private IntPtr m_body = IntPtr.Zero;
193
194 // Vehicle properties ============================================================================================
195 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
196 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
197 private VehicleFlag m_flags = (VehicleFlag) 0; // Bit settings:
198 // HOVER_TERRAIN_ONLY
199 // HOVER_GLOBAL_HEIGHT
200 // NO_DEFLECTION_UP
201 // HOVER_WATER_ONLY
202 // HOVER_UP_ONLY
203 // LIMIT_MOTOR_UP
204 // LIMIT_ROLL_ONLY
205
206 // Linear properties
207 private Vector3 m_linearMotorDirection = Vector3.Zero; // (was m_linearMotorDirectionLASTSET) the (local) Velocity
208 //requested by LSL
209 private float m_linearMotorTimescale = 0; // Motor Attack rate set by LSL
210 private float m_linearMotorDecayTimescale = 0; // Motor Decay rate set by LSL
211 private Vector3 m_linearFrictionTimescale = Vector3.Zero; // General Friction set by LSL
212
213 private Vector3 m_lLinMotorDVel = Vector3.Zero; // decayed motor
214 private Vector3 m_lLinObjectVel = Vector3.Zero; // local frame object velocity
215 private Vector3 m_wLinObjectVel = Vector3.Zero; // world frame object velocity
216
217 //Angular properties
218 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
219
220 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
221 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
222 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
223
224 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
225// private Vector3 m_angObjectVel = Vector3.Zero; // current body angular velocity
226 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
227
228 //Deflection properties
229 // private float m_angularDeflectionEfficiency = 0;
230 // private float m_angularDeflectionTimescale = 0;
231 // private float m_linearDeflectionEfficiency = 0;
232 // private float m_linearDeflectionTimescale = 0;
233
234 //Banking properties
235 // private float m_bankingEfficiency = 0;
236 // private float m_bankingMix = 0;
237 // private float m_bankingTimescale = 0;
238
239 //Hover and Buoyancy properties
240 private float m_VhoverHeight = 0f;
241// private float m_VhoverEfficiency = 0f;
242 private float m_VhoverTimescale = 0f;
243 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
244 private float m_VehicleBuoyancy = 0f; // Set by VEHICLE_BUOYANCY, for a vehicle.
245 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
246 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
247 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
248
249 //Attractor properties
250 private float m_verticalAttractionEfficiency = 1.0f; // damped
251 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
252
253
254
255
256
257
258 public OdePrim(String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
259 Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical, CollisionLocker dode)
260 {
261 ode = dode;
262 if (!pos.IsFinite())
263 {
264 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
265 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
266 m_log.Warn("[PHYSICS]: Got nonFinite Object create Position");
267 }
268
269 _position = pos;
270 m_taintposition = pos;
271 PID_D = parent_scene.bodyPIDD;
272 PID_G = parent_scene.bodyPIDG;
273 m_density = parent_scene.geomDefaultDensity;
274 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
275 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
276
277
278 prim_geom = IntPtr.Zero;
279// prev_geom = IntPtr.Zero;
280
281 if (!pos.IsFinite())
282 {
283 size = new Vector3(0.5f, 0.5f, 0.5f);
284 m_log.Warn("[PHYSICS]: Got nonFinite Object create Size");
285 }
286
287 if (size.X <= 0) size.X = 0.01f;
288 if (size.Y <= 0) size.Y = 0.01f;
289 if (size.Z <= 0) size.Z = 0.01f;
290
291 _size = size;
292 m_taintsize = _size;
293
294 if (!QuaternionIsFinite(rotation))
295 {
296 rotation = Quaternion.Identity;
297 m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation");
298 }
299
300 _orientation = rotation;
301 m_taintrot = _orientation;
302 _mesh = mesh;
303 _pbs = pbs;
304
305 _parent_scene = parent_scene;
306 m_targetSpace = (IntPtr)0;
307
308// if (pos.Z < 0)
309 if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y))
310 m_isphysical = false;
311 else
312 {
313 m_isphysical = pisPhysical;
314 // If we're physical, we need to be in the master space for now.
315 // linksets *should* be in a space together.. but are not currently
316 if (m_isphysical)
317 m_targetSpace = _parent_scene.space;
318 }
319 m_primName = primName;
320 m_taintadd = true;
321 _parent_scene.AddPhysicsActorTaint(this);
322 // don't do .add() here; old geoms get recycled with the same hash
323 }
324
325 public override int PhysicsActorType
326 {
327 get { return (int) ActorTypes.Prim; }
328 set { return; }
329 }
330
331 public override bool SetAlwaysRun
332 {
333 get { return false; }
334 set { return; }
335 }
336
337 public override uint LocalID
338 {
339 set {
340 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
341 m_localID = value; }
342 }
343
344 public override bool Grabbed
345 {
346 set { return; }
347 }
348
349 public override bool Selected
350 {
351 set {
352
353//Console.WriteLine("Sel {0} {1} {2}", m_primName, value, m_isphysical);
354 // This only makes the object not collidable if the object
355 // is physical or the object is modified somehow *IN THE FUTURE*
356 // without this, if an avatar selects prim, they can walk right
357 // through it while it's selected
358 m_collisionscore = 0;
359 if ((m_isphysical && !_zeroFlag) || !value)
360 {
361 m_taintselected = value;
362 _parent_scene.AddPhysicsActorTaint(this);
363 }
364 else
365 {
366 m_taintselected = value;
367 m_isSelected = value;
368 }
369 if(m_isSelected) disableBodySoft();
370 }
371 }
372
373 public override bool IsPhysical
374 {
375 get { return m_isphysical; }
376 set
377 {
378 m_isphysical = value;
379 if (!m_isphysical)
380 { // Zero the remembered last velocity
381 m_lastVelocity = Vector3.Zero;
382 if (m_type != Vehicle.TYPE_NONE) Halt();
383 }
384 }
385 }
386
387 public void setPrimForRemoval()
388 {
389 m_taintremove = true;
390 }
391
392 public override bool Flying
393 {
394 // no flying prims for you
395 get { return false; }
396 set { }
397 }
398
399 public override bool IsColliding
400 {
401 get { return iscolliding; }
402 set { iscolliding = value; }
403 }
404
405 public override bool CollidingGround
406 {
407 get { return false; }
408 set { return; }
409 }
410
411 public override bool CollidingObj
412 {
413 get { return false; }
414 set { return; }
415 }
416
417 public override bool ThrottleUpdates
418 {
419 get { return m_throttleUpdates; }
420 set { m_throttleUpdates = value; }
421 }
422
423 public override bool Stopped
424 {
425 get { return _zeroFlag; }
426 }
427
428 public override Vector3 Position
429 {
430 get { return _position; }
431
432 set { _position = value;
433 //m_log.Info("[PHYSICS]: " + _position.ToString());
434 }
435 }
436
437 public override Vector3 Size
438 {
439 get { return _size; }
440 set
441 {
442 if (value.IsFinite())
443 {
444 _size = value;
445 }
446 else
447 {
448 m_log.Warn("[PHYSICS]: Got NaN Size on object");
449 }
450 }
451 }
452
453 public override float Mass
454 {
455 get { return CalculateMass(); }
456 }
457
458 public override Vector3 Force
459 {
460 //get { return Vector3.Zero; }
461 get { return m_force; }
462 set
463 {
464 if (value.IsFinite())
465 {
466 m_force = value;
467 }
468 else
469 {
470 m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object");
471 }
472 }
473 }
474
475 public override int VehicleType
476 {
477 get { return (int)m_type; }
478 set { ProcessTypeChange((Vehicle)value); }
479 }
480
481 public override void VehicleFloatParam(int param, float value)
482 {
483 ProcessFloatVehicleParam((Vehicle) param, value);
484 }
485
486 public override void VehicleVectorParam(int param, Vector3 value)
487 {
488 ProcessVectorVehicleParam((Vehicle) param, value);
489 }
490
491 public override void VehicleRotationParam(int param, Quaternion rotation)
492 {
493 ProcessRotationVehicleParam((Vehicle) param, rotation);
494 }
495
496 public override void VehicleFlags(int param, bool remove)
497 {
498 ProcessVehicleFlags(param, remove);
499 }
500
501 public override void SetVolumeDetect(int param)
502 {
503 lock (_parent_scene.OdeLock)
504 {
505 m_isVolumeDetect = (param!=0);
506 }
507 }
508
509 public override Vector3 CenterOfMass
510 {
511 get { return Vector3.Zero; }
512 }
513
514 public override Vector3 GeometricCenter
515 {
516 get { return Vector3.Zero; }
517 }
518
519 public override PrimitiveBaseShape Shape
520 {
521 set
522 {
523 _pbs = value;
524 m_taintshape = true;
525 }
526 }
527
528 public override Vector3 Velocity
529 {
530 get
531 {
532 // Averate previous velocity with the new one so
533 // client object interpolation works a 'little' better
534 if (_zeroFlag)
535 return Vector3.Zero;
536
537 Vector3 returnVelocity = Vector3.Zero;
538 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2;
539 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2;
540 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2;
541 return returnVelocity;
542 }
543 set
544 {
545 if (value.IsFinite())
546 {
547 _velocity = value;
548 if (_velocity.ApproxEquals(Vector3.Zero,0.001f))
549 _acceleration = Vector3.Zero;
550
551 m_taintVelocity = value;
552 _parent_scene.AddPhysicsActorTaint(this);
553 }
554 else
555 {
556 m_log.Warn("[PHYSICS]: Got NaN Velocity in Object");
557 }
558
559 }
560 }
561
562 public override Vector3 Torque
563 {
564 get
565 {
566 if (!m_isphysical || Body == IntPtr.Zero)
567 return Vector3.Zero;
568
569 return _torque;
570 }
571
572 set
573 {
574 if (value.IsFinite())
575 {
576 m_taintTorque = value;
577 _parent_scene.AddPhysicsActorTaint(this);
578 }
579 else
580 {
581 m_log.Warn("[PHYSICS]: Got NaN Torque in Object");
582 }
583 }
584 }
585
586 public override float CollisionScore
587 {
588 get { return m_collisionscore; }
589 set { m_collisionscore = value; }
590 }
591
592 public override bool Kinematic
593 {
594 get { return false; }
595 set { }
596 }
597
598 public override Quaternion Orientation
599 {
600 get { return _orientation; }
601 set
602 {
603 if (QuaternionIsFinite(value))
604 {
605 _orientation = value;
606 }
607 else
608 m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object");
609
610 }
611 }
612
613
614 public override bool FloatOnWater
615 {
616 set {
617 m_taintCollidesWater = value;
618 _parent_scene.AddPhysicsActorTaint(this);
619 }
620 }
621
622 public override void SetMomentum(Vector3 momentum)
623 {
624 }
625
626 public override Vector3 PIDTarget
627 {
628 set
629 {
630 if (value.IsFinite())
631 {
632 m_PIDTarget = value;
633 }
634 else
635 m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object");
636 }
637 }
638 public override bool PIDActive { set { m_usePID = value; } }
639 public override float PIDTau { set { m_PIDTau = value; } }
640
641 // For RotLookAt
642 public override Quaternion APIDTarget { set { m_APIDTarget = value; } }
643 public override bool APIDActive { set { m_useAPID = value; } }
644 public override float APIDStrength { set { m_APIDStrength = value; } }
645 public override float APIDDamping { set { m_APIDDamping = value; } }
646
647 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
648 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
649 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
650 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
651
652 internal static bool QuaternionIsFinite(Quaternion q)
653 {
654 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
655 return false;
656 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
657 return false;
658 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
659 return false;
660 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
661 return false;
662 return true;
663 }
664
665 public override Vector3 Acceleration // client updates read data via here
666 {
667 get
668 {
669 if (_zeroFlag)
670 {
671 return Vector3.Zero;
672 }
673 return _acceleration;
674 }
675 }
676
677
678 public void SetAcceleration(Vector3 accel) // No one calls this, and it would not do anything.
679 {
680 _acceleration = accel;
681 }
682
683 public override void AddForce(Vector3 force, bool pushforce)
684 {
685 if (force.IsFinite())
686 {
687 lock (m_forcelist)
688 m_forcelist.Add(force);
689
690 m_taintforce = true;
691 }
692 else
693 {
694 m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object");
695 }
696 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
697 }
698
699 public override void AddAngularForce(Vector3 force, bool pushforce)
700 {
701 if (force.IsFinite())
702 {
703 m_angularforcelist.Add(force);
704 m_taintaddangularforce = true;
705 }
706 else
707 {
708 m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object");
709 }
710 }
711
712 public override Vector3 RotationalVelocity
713 {
714 get
715 {
716 return m_rotationalVelocity;
717 }
718 set
719 {
720 if (value.IsFinite())
721 {
722 m_rotationalVelocity = value;
723 }
724 else
725 {
726 m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object");
727 }
728 }
729 }
730
731 public override void CrossingFailure()
732 {
733 m_crossingfailures++;
734 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
735 {
736 base.RaiseOutOfBounds(_position);
737 return;
738 }
739 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
740 {
741 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName);
742 }
743 }
744
745 public override float Buoyancy
746 {
747 get { return m_buoyancy; }
748 set { m_buoyancy = value; }
749 }
750
751 public override void link(PhysicsActor obj)
752 {
753 m_taintparent = obj;
754 }
755
756 public override void delink()
757 {
758 m_taintparent = null;
759 }
760
761 public override void LockAngularMotion(Vector3 axis)
762 {
763 // This is actually ROTATION ENABLE, not a lock.
764 // default is <1,1,1> which is all enabled.
765 // The lock value is updated inside Move(), no point in using the taint system.
766 // OS 'm_taintAngularLock' etc change to m_rotateEnable.
767 if (axis.IsFinite())
768 {
769 axis.X = (axis.X > 0) ? 1f : 0f;
770 axis.Y = (axis.Y > 0) ? 1f : 0f;
771 axis.Z = (axis.Z > 0) ? 1f : 0f;
772 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
773 m_rotateEnableRequest = axis;
774 m_rotateEnableUpdate = true;
775 }
776 else
777 {
778 m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object");
779 }
780 }
781
782
783 public void SetGeom(IntPtr geom)
784 {
785 if(prim_geom != IntPtr.Zero)
786 {
787 // Remove any old entries
788//string tPA;
789//_parent_scene.geom_name_map.TryGetValue(prim_geom, out tPA);
790//Console.WriteLine("**** Remove {0}", tPA);
791 if(_parent_scene.geom_name_map.ContainsKey(prim_geom)) _parent_scene.geom_name_map.Remove(prim_geom);
792 if(_parent_scene.actor_name_map.ContainsKey(prim_geom)) _parent_scene.actor_name_map.Remove(prim_geom);
793 d.GeomDestroy(prim_geom);
794 }
795
796 prim_geom = geom;
797//Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName);
798 if (prim_geom != IntPtr.Zero)
799 {
800 _parent_scene.geom_name_map[prim_geom] = this.m_primName;
801 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
802 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
803 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
804//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, this.m_primName);
805 }
806
807 if (childPrim)
808 {
809 if (_parent != null && _parent is OdePrim)
810 {
811 OdePrim parent = (OdePrim)_parent;
812//Console.WriteLine("SetGeom calls ChildSetGeom");
813 parent.ChildSetGeom(this);
814 }
815 }
816 //m_log.Warn("Setting Geom to: " + prim_geom);
817 }
818
819 public void enableBodySoft()
820 {
821 if (!childPrim)
822 {
823 if (m_isphysical && Body != IntPtr.Zero)
824 {
825 d.BodyEnable(Body);
826 if (m_type != Vehicle.TYPE_NONE)
827 Enable(Body, _parent_scene);
828 }
829
830 m_disabled = false;
831 }
832 }
833
834 public void disableBodySoft()
835 {
836 m_disabled = true;
837
838 if (m_isphysical && Body != IntPtr.Zero)
839 {
840 d.BodyDisable(Body);
841 Halt();
842 }
843 }
844
845 public void enableBody()
846 {
847 // Don't enable this body if we're a child prim
848 // this should be taken care of in the parent function not here
849 if (!childPrim)
850 {
851 // Sets the geom to a body
852 Body = d.BodyCreate(_parent_scene.world);
853
854 setMass();
855 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
856 d.Quaternion myrot = new d.Quaternion();
857 myrot.X = _orientation.X;
858 myrot.Y = _orientation.Y;
859 myrot.Z = _orientation.Z;
860 myrot.W = _orientation.W;
861 d.BodySetQuaternion(Body, ref myrot);
862 d.GeomSetBody(prim_geom, Body);
863 m_collisionCategories |= CollisionCategories.Body;
864 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
865
866 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
867 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
868
869 d.BodySetAutoDisableFlag(Body, true);
870 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
871
872 // disconnect from world gravity so we can apply buoyancy
873 d.BodySetGravityMode (Body, false);
874
875 m_interpenetrationcount = 0;
876 m_collisionscore = 0;
877 m_disabled = false;
878
879 if (m_type != Vehicle.TYPE_NONE)
880 {
881 Enable(Body, _parent_scene);
882 }
883
884 _parent_scene.addActivePrim(this);
885 }
886 }
887
888 #region Mass Calculation
889
890 private float CalculateMass()
891 {
892 float volume = _size.X * _size.Y * _size.Z; // default
893 float tmp;
894
895 float returnMass = 0;
896 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
897 float hollowVolume = hollowAmount * hollowAmount;
898
899 switch (_pbs.ProfileShape)
900 {
901 case ProfileShape.Square:
902 // default box
903
904 if (_pbs.PathCurve == (byte)Extrusion.Straight)
905 {
906 if (hollowAmount > 0.0)
907 {
908 switch (_pbs.HollowShape)
909 {
910 case HollowShape.Square:
911 case HollowShape.Same:
912 break;
913
914 case HollowShape.Circle:
915
916 hollowVolume *= 0.78539816339f;
917 break;
918
919 case HollowShape.Triangle:
920
921 hollowVolume *= (0.5f * .5f);
922 break;
923
924 default:
925 hollowVolume = 0;
926 break;
927 }
928 volume *= (1.0f - hollowVolume);
929 }
930 }
931
932 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
933 {
934 //a tube
935
936 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
937 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
938 volume -= volume*tmp*tmp;
939
940 if (hollowAmount > 0.0)
941 {
942 hollowVolume *= hollowAmount;
943
944 switch (_pbs.HollowShape)
945 {
946 case HollowShape.Square:
947 case HollowShape.Same:
948 break;
949
950 case HollowShape.Circle:
951 hollowVolume *= 0.78539816339f;;
952 break;
953
954 case HollowShape.Triangle:
955 hollowVolume *= 0.5f * 0.5f;
956 break;
957 default:
958 hollowVolume = 0;
959 break;
960 }
961 volume *= (1.0f - hollowVolume);
962 }
963 }
964
965 break;
966
967 case ProfileShape.Circle:
968
969 if (_pbs.PathCurve == (byte)Extrusion.Straight)
970 {
971 volume *= 0.78539816339f; // elipse base
972
973 if (hollowAmount > 0.0)
974 {
975 switch (_pbs.HollowShape)
976 {
977 case HollowShape.Same:
978 case HollowShape.Circle:
979 break;
980
981 case HollowShape.Square:
982 hollowVolume *= 0.5f * 2.5984480504799f;
983 break;
984
985 case HollowShape.Triangle:
986 hollowVolume *= .5f * 1.27323954473516f;
987 break;
988
989 default:
990 hollowVolume = 0;
991 break;
992 }
993 volume *= (1.0f - hollowVolume);
994 }
995 }
996
997 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
998 {
999 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
1000 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1001 volume *= (1.0f - tmp * tmp);
1002
1003 if (hollowAmount > 0.0)
1004 {
1005
1006 // calculate the hollow volume by it's shape compared to the prim shape
1007 hollowVolume *= hollowAmount;
1008
1009 switch (_pbs.HollowShape)
1010 {
1011 case HollowShape.Same:
1012 case HollowShape.Circle:
1013 break;
1014
1015 case HollowShape.Square:
1016 hollowVolume *= 0.5f * 2.5984480504799f;
1017 break;
1018
1019 case HollowShape.Triangle:
1020 hollowVolume *= .5f * 1.27323954473516f;
1021 break;
1022
1023 default:
1024 hollowVolume = 0;
1025 break;
1026 }
1027 volume *= (1.0f - hollowVolume);
1028 }
1029 }
1030 break;
1031
1032 case ProfileShape.HalfCircle:
1033 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1034 {
1035 volume *= 0.52359877559829887307710723054658f;
1036 }
1037 break;
1038
1039 case ProfileShape.EquilateralTriangle:
1040
1041 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1042 {
1043 volume *= 0.32475953f;
1044
1045 if (hollowAmount > 0.0)
1046 {
1047
1048 // calculate the hollow volume by it's shape compared to the prim shape
1049 switch (_pbs.HollowShape)
1050 {
1051 case HollowShape.Same:
1052 case HollowShape.Triangle:
1053 hollowVolume *= .25f;
1054 break;
1055
1056 case HollowShape.Square:
1057 hollowVolume *= 0.499849f * 3.07920140172638f;
1058 break;
1059
1060 case HollowShape.Circle:
1061 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1062 // Cyllinder hollow volume calculation
1063
1064 hollowVolume *= 0.1963495f * 3.07920140172638f;
1065 break;
1066
1067 default:
1068 hollowVolume = 0;
1069 break;
1070 }
1071 volume *= (1.0f - hollowVolume);
1072 }
1073 }
1074 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1075 {
1076 volume *= 0.32475953f;
1077 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
1078 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1079 volume *= (1.0f - tmp * tmp);
1080
1081 if (hollowAmount > 0.0)
1082 {
1083
1084 hollowVolume *= hollowAmount;
1085
1086 switch (_pbs.HollowShape)
1087 {
1088 case HollowShape.Same:
1089 case HollowShape.Triangle:
1090 hollowVolume *= .25f;
1091 break;
1092
1093 case HollowShape.Square:
1094 hollowVolume *= 0.499849f * 3.07920140172638f;
1095 break;
1096
1097 case HollowShape.Circle:
1098
1099 hollowVolume *= 0.1963495f * 3.07920140172638f;
1100 break;
1101
1102 default:
1103 hollowVolume = 0;
1104 break;
1105 }
1106 volume *= (1.0f - hollowVolume);
1107 }
1108 }
1109 break;
1110
1111 default:
1112 break;
1113 }
1114
1115
1116
1117 float taperX1;
1118 float taperY1;
1119 float taperX;
1120 float taperY;
1121 float pathBegin;
1122 float pathEnd;
1123 float profileBegin;
1124 float profileEnd;
1125
1126 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
1127 {
1128 taperX1 = _pbs.PathScaleX * 0.01f;
1129 if (taperX1 > 1.0f)
1130 taperX1 = 2.0f - taperX1;
1131 taperX = 1.0f - taperX1;
1132
1133 taperY1 = _pbs.PathScaleY * 0.01f;
1134 if (taperY1 > 1.0f)
1135 taperY1 = 2.0f - taperY1;
1136 taperY = 1.0f - taperY1;
1137 }
1138 else
1139 {
1140 taperX = _pbs.PathTaperX * 0.01f;
1141 if (taperX < 0.0f)
1142 taperX = -taperX;
1143 taperX1 = 1.0f - taperX;
1144
1145 taperY = _pbs.PathTaperY * 0.01f;
1146 if (taperY < 0.0f)
1147 taperY = -taperY;
1148 taperY1 = 1.0f - taperY;
1149
1150 }
1151
1152
1153 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1154
1155 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
1156 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
1157 volume *= (pathEnd - pathBegin);
1158
1159// this is crude aproximation
1160 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
1161 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
1162 volume *= (profileEnd - profileBegin);
1163
1164 returnMass = m_density * volume;
1165
1166 if (returnMass <= 0)
1167 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1168// else if (returnMass > _parent_scene.maximumMassObject)
1169// returnMass = _parent_scene.maximumMassObject;
1170
1171
1172
1173
1174 // Recursively calculate mass
1175 bool HasChildPrim = false;
1176 lock (childrenPrim)
1177 {
1178 if (childrenPrim.Count > 0)
1179 {
1180 HasChildPrim = true;
1181 }
1182
1183 }
1184 if (HasChildPrim)
1185 {
1186 OdePrim[] childPrimArr = new OdePrim[0];
1187
1188 lock (childrenPrim)
1189 childPrimArr = childrenPrim.ToArray();
1190
1191 for (int i = 0; i < childPrimArr.Length; i++)
1192 {
1193 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
1194 returnMass += childPrimArr[i].CalculateMass();
1195 // failsafe, this shouldn't happen but with OpenSim, you never know :)
1196 if (i > 256)
1197 break;
1198 }
1199 }
1200 if (returnMass > _parent_scene.maximumMassObject)
1201 returnMass = _parent_scene.maximumMassObject;
1202 return returnMass;
1203 }// end CalculateMass
1204
1205 #endregion
1206
1207 public void setMass()
1208 {
1209 if (Body != (IntPtr) 0)
1210 {
1211 float newmass = CalculateMass();
1212
1213 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
1214
1215 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
1216 d.BodySetMass(Body, ref pMass);
1217 }
1218 }
1219
1220 public void disableBody()
1221 {
1222 //this kills the body so things like 'mesh' can re-create it.
1223 lock (this)
1224 {
1225 if (!childPrim)
1226 {
1227 if (Body != IntPtr.Zero)
1228 {
1229 _parent_scene.remActivePrim(this);
1230 m_collisionCategories &= ~CollisionCategories.Body;
1231 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1232
1233 if (prim_geom != IntPtr.Zero)
1234 {
1235 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1236 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1237 }
1238
1239
1240 d.BodyDestroy(Body);
1241 lock (childrenPrim)
1242 {
1243 if (childrenPrim.Count > 0)
1244 {
1245 foreach (OdePrim prm in childrenPrim)
1246 {
1247 _parent_scene.remActivePrim(prm);
1248 prm.Body = IntPtr.Zero;
1249 }
1250 }
1251 }
1252 Body = IntPtr.Zero;
1253 }
1254 }
1255 else
1256 {
1257 _parent_scene.remActivePrim(this);
1258
1259 m_collisionCategories &= ~CollisionCategories.Body;
1260 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1261
1262 if (prim_geom != IntPtr.Zero)
1263 {
1264 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1265 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1266 }
1267
1268
1269 Body = IntPtr.Zero;
1270 }
1271 }
1272 m_disabled = true;
1273 m_collisionscore = 0;
1274 }
1275
1276 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
1277
1278 public void setMesh(OdeScene parent_scene, IMesh mesh)
1279 {
1280 // This sleeper is there to moderate how long it takes between
1281 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
1282
1283 //Thread.Sleep(10);
1284
1285 //Kill Body so that mesh can re-make the geom
1286 if (IsPhysical && Body != IntPtr.Zero)
1287 {
1288 if (childPrim)
1289 {
1290 if (_parent != null)
1291 {
1292 OdePrim parent = (OdePrim)_parent;
1293 parent.ChildDelink(this);
1294 }
1295 }
1296 else
1297 {
1298 disableBody();
1299 }
1300 }
1301 IntPtr vertices, indices;
1302 int vertexCount, indexCount;
1303 int vertexStride, triStride;
1304 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1305 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1306
1307 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
1308 if (m_MeshToTriMeshMap.ContainsKey(mesh))
1309 {
1310 _triMeshData = m_MeshToTriMeshMap[mesh];
1311 }
1312 else
1313 {
1314 _triMeshData = d.GeomTriMeshDataCreate();
1315
1316 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1317 d.GeomTriMeshDataPreprocess(_triMeshData);
1318 m_MeshToTriMeshMap[mesh] = _triMeshData;
1319 }
1320
1321 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1322 try
1323 {
1324 // if (prim_geom == IntPtr.Zero) // setGeom takes care of phys engine recreate and prim_geom pointer
1325 // {
1326 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
1327 // }
1328 }
1329 catch (AccessViolationException)
1330 {
1331 m_log.Error("[PHYSICS]: MESH LOCKED");
1332 return;
1333 }
1334
1335
1336 // if (IsPhysical && Body == (IntPtr) 0)
1337 // {
1338 // Recreate the body
1339 // m_interpenetrationcount = 0;
1340 // m_collisionscore = 0;
1341
1342 // enableBody();
1343 // }
1344 }
1345
1346 public void ProcessTaints(float timestep) //=============================================================================
1347 {
1348 if (m_taintadd)
1349 {
1350 changeadd(timestep);
1351 }
1352
1353 if (prim_geom != IntPtr.Zero)
1354 {
1355 if (!_position.ApproxEquals(m_taintposition, 0f))
1356 {
1357 changemove(timestep);
1358 }
1359 if (m_taintrot != _orientation)
1360 {
1361 if(childPrim && IsPhysical) // For physical child prim...
1362 {
1363 rotate(timestep);
1364 // KF: ODE will also rotate the parent prim!
1365 // so rotate the root back to where it was
1366 OdePrim parent = (OdePrim)_parent;
1367 parent.rotate(timestep);
1368 }
1369 else
1370 {
1371 //Just rotate the prim
1372 rotate(timestep);
1373 }
1374 }
1375 //
1376
1377 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
1378 {
1379 changePhysicsStatus(timestep);
1380 }//
1381
1382 if (!_size.ApproxEquals(m_taintsize,0f))
1383 changesize(timestep);
1384 //
1385
1386 if (m_taintshape)
1387 changeshape(timestep);
1388 //
1389
1390 if (m_taintforce)
1391 changeAddForce(timestep);
1392
1393 if (m_taintaddangularforce)
1394 changeAddAngularForce(timestep);
1395
1396 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
1397 changeSetTorque(timestep);
1398
1399 if (m_taintdisable)
1400 changedisable(timestep);
1401
1402 if (m_taintselected != m_isSelected)
1403 changeSelectedStatus(timestep);
1404
1405 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
1406 changevelocity(timestep);
1407
1408 if (m_taintparent != _parent)
1409 changelink(timestep);
1410
1411 if (m_taintCollidesWater != m_collidesWater)
1412 changefloatonwater(timestep);
1413/* obsolete
1414 if (!m_angularLock.ApproxEquals(m_taintAngularLock,0f))
1415 changeAngularLock(timestep);
1416 */
1417 }
1418 else
1419 {
1420 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.)");
1421 }
1422 }
1423
1424/* obsolete
1425 private void changeAngularLock(float timestep)
1426 {
1427 if (_parent == null)
1428 {
1429 m_angularLock = m_taintAngularLock;
1430 m_angularLockSet = true;
1431 }
1432 }
1433 */
1434 private void changelink(float timestep)
1435 {
1436 // If the newly set parent is not null
1437 // create link
1438 if (_parent == null && m_taintparent != null)
1439 {
1440 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1441 {
1442 OdePrim obj = (OdePrim)m_taintparent;
1443 //obj.disableBody();
1444 obj.ParentPrim(this);
1445
1446 /*
1447 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1448 {
1449 _linkJointGroup = d.JointGroupCreate(0);
1450 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1451 d.JointAttach(m_linkJoint, obj.Body, Body);
1452 d.JointSetFixed(m_linkJoint);
1453 }
1454 */
1455 }
1456 }
1457 // If the newly set parent is null
1458 // destroy link
1459 else if (_parent != null && m_taintparent == null)
1460 {
1461 if (_parent is OdePrim)
1462 {
1463 OdePrim obj = (OdePrim)_parent;
1464 obj.ChildDelink(this);
1465 childPrim = false;
1466 //_parent = null;
1467 }
1468
1469 /*
1470 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1471 d.JointGroupDestroy(_linkJointGroup);
1472
1473 _linkJointGroup = (IntPtr)0;
1474 m_linkJoint = (IntPtr)0;
1475 */
1476 }
1477
1478 _parent = m_taintparent;
1479 m_taintPhysics = m_isphysical;
1480 }
1481
1482 // I'm the parent
1483 // prim is the child
1484 public void ParentPrim(OdePrim prim)
1485 {
1486 if (this.m_localID != prim.m_localID)
1487 {
1488 if (Body == IntPtr.Zero)
1489 {
1490 Body = d.BodyCreate(_parent_scene.world);
1491 // disconnect from world gravity so we can apply buoyancy
1492 d.BodySetGravityMode (Body, false);
1493
1494 setMass();
1495 }
1496 if (Body != IntPtr.Zero)
1497 {
1498 lock (childrenPrim)
1499 {
1500 if (!childrenPrim.Contains(prim))
1501 {
1502 childrenPrim.Add(prim);
1503
1504 foreach (OdePrim prm in childrenPrim)
1505 {
1506 d.Mass m2;
1507 d.MassSetZero(out m2);
1508 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1509
1510
1511 d.Quaternion quat = new d.Quaternion();
1512 quat.W = prm._orientation.W;
1513 quat.X = prm._orientation.X;
1514 quat.Y = prm._orientation.Y;
1515 quat.Z = prm._orientation.Z;
1516
1517 d.Matrix3 mat = new d.Matrix3();
1518 d.RfromQ(out mat, ref quat);
1519 d.MassRotate(ref m2, ref mat);
1520 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1521 d.MassAdd(ref pMass, ref m2);
1522 }
1523 foreach (OdePrim prm in childrenPrim)
1524 {
1525
1526 prm.m_collisionCategories |= CollisionCategories.Body;
1527 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1528
1529 if (prm.prim_geom == IntPtr.Zero)
1530 {
1531 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet");
1532 continue;
1533 }
1534 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1535 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1536
1537
1538 d.Quaternion quat = new d.Quaternion();
1539 quat.W = prm._orientation.W;
1540 quat.X = prm._orientation.X;
1541 quat.Y = prm._orientation.Y;
1542 quat.Z = prm._orientation.Z;
1543
1544 d.Matrix3 mat = new d.Matrix3();
1545 d.RfromQ(out mat, ref quat);
1546 if (Body != IntPtr.Zero)
1547 {
1548 d.GeomSetBody(prm.prim_geom, Body);
1549 prm.childPrim = true;
1550 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1551 //d.GeomSetOffsetPosition(prim.prim_geom,
1552 // (Position.X - prm.Position.X) - pMass.c.X,
1553 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1554 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1555 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1556 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1557 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1558 d.BodySetMass(Body, ref pMass);
1559 }
1560 else
1561 {
1562 m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body");
1563 }
1564
1565
1566 prm.m_interpenetrationcount = 0;
1567 prm.m_collisionscore = 0;
1568 prm.m_disabled = false;
1569
1570 prm.Body = Body;
1571 _parent_scene.addActivePrim(prm);
1572 }
1573 m_collisionCategories |= CollisionCategories.Body;
1574 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1575
1576 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1577 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1578
1579
1580 d.Quaternion quat2 = new d.Quaternion();
1581 quat2.W = _orientation.W;
1582 quat2.X = _orientation.X;
1583 quat2.Y = _orientation.Y;
1584 quat2.Z = _orientation.Z;
1585
1586 d.Matrix3 mat2 = new d.Matrix3();
1587 d.RfromQ(out mat2, ref quat2);
1588 d.GeomSetBody(prim_geom, Body);
1589 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1590 //d.GeomSetOffsetPosition(prim.prim_geom,
1591 // (Position.X - prm.Position.X) - pMass.c.X,
1592 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1593 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1594 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1595 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1596 d.BodySetMass(Body, ref pMass);
1597
1598 d.BodySetAutoDisableFlag(Body, true);
1599 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1600
1601
1602 m_interpenetrationcount = 0;
1603 m_collisionscore = 0;
1604 m_disabled = false;
1605
1606 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1607 if (m_type != Vehicle.TYPE_NONE) Enable(Body, _parent_scene);
1608 _parent_scene.addActivePrim(this);
1609 }
1610 }
1611 }
1612 }
1613
1614 }
1615
1616 private void ChildSetGeom(OdePrim odePrim)
1617 {
1618 //if (m_isphysical && Body != IntPtr.Zero)
1619 lock (childrenPrim)
1620 {
1621 foreach (OdePrim prm in childrenPrim)
1622 {
1623 //prm.childPrim = true;
1624 prm.disableBody();
1625 //prm.m_taintparent = null;
1626 //prm._parent = null;
1627 //prm.m_taintPhysics = false;
1628 //prm.m_disabled = true;
1629 //prm.childPrim = false;
1630 }
1631 }
1632 disableBody();
1633
1634
1635 if (Body != IntPtr.Zero)
1636 {
1637 _parent_scene.remActivePrim(this);
1638 }
1639
1640 lock (childrenPrim)
1641 {
1642 foreach (OdePrim prm in childrenPrim)
1643 {
1644 ParentPrim(prm);
1645 }
1646 }
1647
1648 }
1649
1650 private void ChildDelink(OdePrim odePrim)
1651 {
1652 // Okay, we have a delinked child.. need to rebuild the body.
1653 lock (childrenPrim)
1654 {
1655 foreach (OdePrim prm in childrenPrim)
1656 {
1657 prm.childPrim = true;
1658 prm.disableBody();
1659 //prm.m_taintparent = null;
1660 //prm._parent = null;
1661 //prm.m_taintPhysics = false;
1662 //prm.m_disabled = true;
1663 //prm.childPrim = false;
1664 }
1665 }
1666 disableBody();
1667
1668 lock (childrenPrim)
1669 {
1670 childrenPrim.Remove(odePrim);
1671 }
1672
1673 if (Body != IntPtr.Zero)
1674 {
1675 _parent_scene.remActivePrim(this);
1676 }
1677
1678 lock (childrenPrim)
1679 {
1680 foreach (OdePrim prm in childrenPrim)
1681 {
1682 ParentPrim(prm);
1683 }
1684 }
1685 }
1686
1687 private void changeSelectedStatus(float timestep)
1688 {
1689 if (m_taintselected)
1690 {
1691 m_collisionCategories = CollisionCategories.Selected;
1692 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1693
1694 // We do the body disable soft twice because 'in theory' a collision could have happened
1695 // in between the disabling and the collision properties setting
1696 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1697 // through the ground.
1698
1699 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1700 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1701 // so that causes the selected part to wake up and continue moving.
1702
1703 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1704 // assembly will stop simulating during the selection, because of the lack of atomicity
1705 // of select operations (their processing could be interrupted by a thread switch, causing
1706 // simulation to continue before all of the selected object notifications trickle down to
1707 // the physics engine).
1708
1709 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1710 // selected and disabled. then, due to a thread switch, the selection processing is
1711 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1712 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1713 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1714 // up, start simulating again, which in turn wakes up the last 50.
1715
1716 if (m_isphysical)
1717 {
1718 disableBodySoft();
1719 }
1720
1721 if (prim_geom != IntPtr.Zero)
1722 {
1723 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1724 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1725 }
1726
1727 if (m_isphysical)
1728 {
1729 disableBodySoft();
1730 }
1731 if (Body != IntPtr.Zero)
1732 {
1733 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1734 d.BodySetForce(Body, 0f, 0f, 0f);
1735 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
1736 d.BodySetTorque (Body, 0.0f, 0.0f, 0.0f);
1737 }
1738
1739 }
1740 else
1741 {
1742 m_collisionCategories = CollisionCategories.Geom;
1743
1744 if (m_isphysical)
1745 m_collisionCategories |= CollisionCategories.Body;
1746
1747 m_collisionFlags = m_default_collisionFlags;
1748
1749 if (m_collidesLand)
1750 m_collisionFlags |= CollisionCategories.Land;
1751 if (m_collidesWater)
1752 m_collisionFlags |= CollisionCategories.Water;
1753
1754 if (prim_geom != IntPtr.Zero)
1755 {
1756 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1757 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1758 }
1759 if (Body != IntPtr.Zero)
1760 {
1761 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1762 d.BodySetForce(Body, 0f, 0f, 0f);
1763 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
1764 d.BodySetTorque (Body, 0.0f, 0.0f, 0.0f);
1765 }
1766
1767 if (m_isphysical)
1768 {
1769 if (Body != IntPtr.Zero)
1770 {
1771 enableBodySoft();
1772 }
1773 }
1774 }
1775
1776 resetCollisionAccounting();
1777 m_isSelected = m_taintselected;
1778 }//end changeSelectedStatus
1779
1780 public void ResetTaints()
1781 {
1782 m_taintposition = _position;
1783 m_taintrot = _orientation;
1784 m_taintPhysics = m_isphysical;
1785 m_taintselected = m_isSelected;
1786 m_taintsize = _size;
1787 m_taintshape = false;
1788 m_taintforce = false;
1789 m_taintdisable = false;
1790 m_taintVelocity = Vector3.Zero;
1791 }
1792
1793 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh)
1794 {
1795 if (_mesh != null) // Special - make mesh
1796 {
1797 setMesh(_parent_scene, _mesh);
1798 }
1799 else // not a mesh
1800 {
1801 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) // special profile??
1802 {
1803 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // Equi-size
1804 {
1805 if (((_size.X / 2f) > 0f)) // Has size
1806 {
1807 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1808 try
1809 {
1810 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1811 }
1812 catch (AccessViolationException)
1813 {
1814 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1815 ode.dunlock(_parent_scene.world);
1816 return;
1817 }
1818 }
1819 else
1820 {
1821 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1822 try
1823 {
1824 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1825 }
1826 catch (AccessViolationException)
1827 {
1828 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1829 ode.dunlock(_parent_scene.world);
1830 return;
1831 }
1832 }
1833 }
1834 else // not equi-size
1835 {
1836 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1837 try
1838 {
1839 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1840 }
1841 catch (AccessViolationException)
1842 {
1843 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1844 ode.dunlock(_parent_scene.world);
1845 return;
1846 }
1847 }
1848 }
1849
1850 else // not special profile
1851 {
1852 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1853 try
1854 {
1855 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1856 }
1857 catch (AccessViolationException)
1858 {
1859 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1860 ode.dunlock(_parent_scene.world);
1861 return;
1862 }
1863 }
1864 }
1865 }
1866
1867 public void changeadd(float timestep)
1868 {
1869 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1870 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1871
1872 if (targetspace == IntPtr.Zero)
1873 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1874
1875 m_targetSpace = targetspace;
1876
1877 if (_mesh == null && m_meshfailed == false)
1878 {
1879 if (_parent_scene.needsMeshing(_pbs))
1880 {
1881 // Don't need to re-enable body.. it's done in SetMesh
1882 try
1883 {
1884 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1885 }
1886 catch
1887 {
1888 //Don't continuously try to mesh prims when meshing has failed
1889 m_meshfailed = true;
1890 }
1891 // createmesh returns null when it's a shape that isn't a cube.
1892 // m_log.Debug(m_localID);
1893 }
1894 }
1895
1896
1897 lock (_parent_scene.OdeLock)
1898 {
1899 CreateGeom(m_targetSpace, _mesh);
1900
1901 if (prim_geom != IntPtr.Zero)
1902 {
1903 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1904 d.Quaternion myrot = new d.Quaternion();
1905 myrot.X = _orientation.X;
1906 myrot.Y = _orientation.Y;
1907 myrot.Z = _orientation.Z;
1908 myrot.W = _orientation.W;
1909 d.GeomSetQuaternion(prim_geom, ref myrot);
1910 }
1911
1912 if (m_isphysical && Body == IntPtr.Zero)
1913 {
1914 enableBody();
1915 }
1916 }
1917
1918 changeSelectedStatus(timestep);
1919
1920 m_taintadd = false;
1921 }
1922
1923 public void changemove(float timestep)
1924 {
1925 if (m_isphysical)
1926 {
1927// if (!m_disabled && !m_taintremove && !childPrim) After one edit m_disabled is sometimes set, disabling further edits!
1928 if (!m_taintremove && !childPrim)
1929 {
1930 if (Body == IntPtr.Zero)
1931 enableBody();
1932 //Prim auto disable after 20 frames,
1933 //if you move it, re-enable the prim manually.
1934 if (_parent != null)
1935 {
1936 if (m_linkJoint != IntPtr.Zero)
1937 {
1938 d.JointDestroy(m_linkJoint);
1939 m_linkJoint = IntPtr.Zero;
1940 }
1941 }
1942 if (Body != IntPtr.Zero)
1943 {
1944 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1945
1946 if (_parent != null)
1947 {
1948 OdePrim odParent = (OdePrim)_parent;
1949 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1950 {
1951// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1952Console.WriteLine("ODEPrim JointCreateFixed !!!");
1953 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1954 d.JointAttach(m_linkJoint, Body, odParent.Body);
1955 d.JointSetFixed(m_linkJoint);
1956 }
1957 }
1958 d.BodyEnable(Body);
1959 if (m_type != Vehicle.TYPE_NONE)
1960 {
1961 Enable(Body, _parent_scene);
1962 }
1963 }
1964 else
1965 {
1966 m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario.");
1967 }
1968 }
1969 //else
1970 // {
1971 //m_log.Debug("[BUG]: race!");
1972 //}
1973 }
1974 else
1975 {
1976 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1977 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1978 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1979
1980 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1981 m_targetSpace = tempspace;
1982
1983 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1984 if (prim_geom != IntPtr.Zero)
1985 {
1986 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1987
1988 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1989 d.SpaceAdd(m_targetSpace, prim_geom);
1990 }
1991 }
1992
1993 changeSelectedStatus(timestep);
1994
1995 resetCollisionAccounting();
1996 m_taintposition = _position;
1997 }
1998
1999
2000
2001 public void rotate(float timestep)
2002 {
2003 d.Quaternion myrot = new d.Quaternion();
2004 myrot.X = _orientation.X;
2005 myrot.Y = _orientation.Y;
2006 myrot.Z = _orientation.Z;
2007 myrot.W = _orientation.W;
2008 if (Body != IntPtr.Zero)
2009 {
2010 // KF: If this is a root prim do BodySet
2011 d.BodySetQuaternion(Body, ref myrot);
2012 }
2013 else
2014 {
2015 // daughter prim, do Geom set
2016 d.GeomSetQuaternion(prim_geom, ref myrot);
2017 }
2018
2019 resetCollisionAccounting();
2020 m_taintrot = _orientation;
2021 }
2022
2023 private void resetCollisionAccounting()
2024 {
2025 m_collisionscore = 0;
2026 m_interpenetrationcount = 0;
2027 m_disabled = false;
2028 }
2029
2030 public void changedisable(float timestep)
2031 {
2032 m_disabled = true;
2033 if (Body != IntPtr.Zero)
2034 {
2035 d.BodyDisable(Body);
2036 Body = IntPtr.Zero;
2037 }
2038
2039 m_taintdisable = false;
2040 }
2041
2042 public void changePhysicsStatus(float timestep)
2043 {
2044 if (m_isphysical == true)
2045 {
2046 if (Body == IntPtr.Zero)
2047 {
2048 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2049 {
2050 changeshape(2f);
2051 }
2052 else
2053 {
2054 enableBody();
2055 }
2056 }
2057 }
2058 else
2059 {
2060 if (Body != IntPtr.Zero)
2061 {
2062 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2063 {
2064 _mesh = null;
2065 changeadd(2f);
2066 }
2067 if (childPrim)
2068 {
2069 if (_parent != null)
2070 {
2071 OdePrim parent = (OdePrim)_parent;
2072 parent.ChildDelink(this);
2073 }
2074 }
2075 else
2076 {
2077 disableBody();
2078 }
2079 }
2080 }
2081
2082 changeSelectedStatus(timestep);
2083
2084 resetCollisionAccounting();
2085 m_taintPhysics = m_isphysical;
2086 }
2087
2088 public void changesize(float timestamp)
2089 {
2090
2091 string oldname = _parent_scene.geom_name_map[prim_geom];
2092
2093 if (_size.X <= 0) _size.X = 0.01f;
2094 if (_size.Y <= 0) _size.Y = 0.01f;
2095 if (_size.Z <= 0) _size.Z = 0.01f;
2096
2097 // Cleanup of old prim geometry
2098 if (_mesh != null)
2099 {
2100 // Cleanup meshing here
2101 }
2102 //kill body to rebuild
2103 if (IsPhysical && Body != IntPtr.Zero)
2104 {
2105 if (childPrim)
2106 {
2107 if (_parent != null)
2108 {
2109 OdePrim parent = (OdePrim)_parent;
2110 parent.ChildDelink(this);
2111 }
2112 }
2113 else
2114 {
2115 disableBody();
2116 }
2117 }
2118 if (d.SpaceQuery(m_targetSpace, prim_geom))
2119 {
2120 _parent_scene.waitForSpaceUnlock(m_targetSpace);
2121 d.SpaceRemove(m_targetSpace, prim_geom);
2122 }
2123 // we don't need to do space calculation because the client sends a position update also.
2124
2125 // Construction of new prim
2126 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2127 {
2128 float meshlod = _parent_scene.meshSculptLOD;
2129
2130 if (IsPhysical)
2131 meshlod = _parent_scene.MeshSculptphysicalLOD;
2132 // Don't need to re-enable body.. it's done in SetMesh
2133
2134 IMesh mesh = null;
2135
2136 try
2137 {
2138 if (_parent_scene.needsMeshing(_pbs))
2139 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2140 }
2141 catch
2142 {
2143 m_meshfailed = true;
2144 }
2145
2146 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2147 CreateGeom(m_targetSpace, mesh);
2148
2149
2150 }
2151 else
2152 {
2153 _mesh = null;
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 CreateGeom(m_targetSpace, null);
2259 }
2260
2261 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2262 d.Quaternion myrot = new d.Quaternion();
2263 //myrot.W = _orientation.w;
2264 myrot.W = _orientation.W;
2265 myrot.X = _orientation.X;
2266 myrot.Y = _orientation.Y;
2267 myrot.Z = _orientation.Z;
2268 d.GeomSetQuaternion(prim_geom, ref myrot);
2269
2270 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2271 if (IsPhysical && Body == IntPtr.Zero)
2272 {
2273 // Re creates body on size.
2274 // EnableBody also does setMass()
2275 enableBody();
2276 if (Body != IntPtr.Zero)
2277 {
2278 d.BodyEnable(Body);
2279 }
2280 }
2281 _parent_scene.geom_name_map[prim_geom] = oldname;
2282
2283 changeSelectedStatus(timestamp);
2284 if (childPrim)
2285 {
2286 if (_parent is OdePrim)
2287 {
2288 OdePrim parent = (OdePrim)_parent;
2289 parent.ChildSetGeom(this);
2290 }
2291 }
2292 resetCollisionAccounting();
2293 m_taintshape = false;
2294 }
2295
2296 public void changeAddForce(float timestamp)
2297 {
2298 if (!m_isSelected)
2299 {
2300 lock (m_forcelist)
2301 {
2302 //m_log.Info("[PHYSICS]: dequeing forcelist");
2303 if (IsPhysical)
2304 {
2305 Vector3 iforce = Vector3.Zero;
2306 int i = 0;
2307 try
2308 {
2309 for (i = 0; i < m_forcelist.Count; i++)
2310 {
2311
2312 iforce = iforce + (m_forcelist[i] * 100);
2313 }
2314 }
2315 catch (IndexOutOfRangeException)
2316 {
2317 m_forcelist = new List<Vector3>();
2318 m_collisionscore = 0;
2319 m_interpenetrationcount = 0;
2320 m_taintforce = false;
2321 return;
2322 }
2323 catch (ArgumentOutOfRangeException)
2324 {
2325 m_forcelist = new List<Vector3>();
2326 m_collisionscore = 0;
2327 m_interpenetrationcount = 0;
2328 m_taintforce = false;
2329 return;
2330 }
2331 d.BodyEnable(Body);
2332
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 float fence = _parent_scene.geomRegionFence;
3005
3006 frcount++; // used to limit debug comment output
3007 if (frcount > 50)
3008 frcount = 0;
3009
3010 if(revcount > 0) revcount--;
3011
3012 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // Only move root prims.
3013 {
3014 // Old public void UpdatePositionAndVelocity(), more accuratley calculated here
3015 bool lastZeroFlag = _zeroFlag; // was it stopped
3016
3017 d.Vector3 vec = d.BodyGetPosition(Body);
3018 Vector3 l_position = Vector3.Zero;
3019 l_position.X = vec.X;
3020 l_position.Y = vec.Y;
3021 l_position.Z = vec.Z;
3022 m_lastposition = _position;
3023 _position = l_position;
3024
3025 d.Quaternion ori = d.BodyGetQuaternion(Body);
3026 // Quaternion l_orientation = Quaternion.Identity;
3027 _orientation.X = ori.X;
3028 _orientation.Y = ori.Y;
3029 _orientation.Z = ori.Z;
3030 _orientation.W = ori.W;
3031 m_lastorientation = _orientation;
3032
3033 d.Vector3 vel = d.BodyGetLinearVel(Body);
3034 m_lastVelocity = _velocity;
3035 _velocity.X = vel.X;
3036 _velocity.Y = vel.Y;
3037 _velocity.Z = vel.Z;
3038 _acceleration = ((_velocity - m_lastVelocity) / timestep);
3039
3040 d.Vector3 torque = d.BodyGetTorque(Body);
3041 _torque = new Vector3(torque.X, torque.Y, torque.Z);
3042
3043 base.RequestPhysicsterseUpdate();
3044
3045//Console.WriteLine("Move {0} at {1}", m_primName, l_position);
3046
3047 // Check if outside region
3048 // In Scene.cs/CrossPrimGroupIntoNewRegion the object is checked for 0.1M from border!
3049 if (l_position.X > ((float)_parent_scene.WorldExtents.X - fence))
3050 {
3051 l_position.X = ((float)_parent_scene.WorldExtents.X - fence);
3052 outside = 1;
3053 }
3054
3055 if (l_position.X < fence)
3056 {
3057 l_position.X = fence;
3058 outside = 2;
3059 }
3060 if (l_position.Y > ((float)_parent_scene.WorldExtents.Y - fence))
3061 {
3062 l_position.Y = ((float)_parent_scene.WorldExtents.Y - fence);
3063 outside = 3;
3064 }
3065
3066 if (l_position.Y < fence)
3067 {
3068 l_position.Y = fence;
3069 outside = 4;
3070 }
3071
3072 if (outside > 0)
3073 {
3074
3075//Console.WriteLine("Border {0} fence={1}", l_position, fence);
3076 if (fence > 0.0f) // bounce object off boundary
3077 {
3078 if (revcount == 0)
3079 {
3080 if (outside < 3)
3081 {
3082 _velocity.X = -_velocity.X;
3083 }
3084 else
3085 {
3086 _velocity.Y = -_velocity.Y;
3087 }
3088 if (m_type != Vehicle.TYPE_NONE) Halt();
3089 _position = l_position;
3090 m_taintposition = _position;
3091 m_lastVelocity = _velocity;
3092 _acceleration = Vector3.Zero;
3093 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
3094 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
3095 base.RequestPhysicsterseUpdate();
3096
3097 revcount = 25; // wait for object to move away from border
3098 }
3099 } // else old crossing mode
3100 else if (m_crossingfailures < failureLimit)
3101 { // keep trying to cross?
3102 _position = l_position;
3103 //_parent_scene.remActivePrim(this);
3104 if (_parent == null) base.RequestPhysicsterseUpdate();
3105 return; // Dont process any other motion?
3106 }
3107 else
3108 { // Too many tries
3109 if (_parent == null) base.RaiseOutOfBounds(l_position);
3110 return; // Dont process any other motion?
3111 } // end various methods
3112 } // end outside region horizontally
3113
3114
3115 if (l_position.Z < 0)
3116 {
3117 // This is so prim that get lost underground don't fall forever and suck up
3118 //
3119 // Sim resources and memory.
3120 // Disables the prim's movement physics....
3121 // It's a hack and will generate a console message if it fails.
3122
3123 //IsPhysical = false;
3124 if (_parent == null) base.RaiseOutOfBounds(_position);
3125
3126
3127 _acceleration.X = 0; // This stuff may stop client display but it has no
3128 _acceleration.Y = 0; // effect on the object in phys engine!
3129 _acceleration.Z = 0;
3130
3131 _velocity.X = 0;
3132 _velocity.Y = 0;
3133 _velocity.Z = 0;
3134 m_lastVelocity = Vector3.Zero;
3135 m_rotationalVelocity.X = 0;
3136 m_rotationalVelocity.Y = 0;
3137 m_rotationalVelocity.Z = 0;
3138
3139 if (_parent == null) base.RequestPhysicsterseUpdate();
3140
3141 m_throttleUpdates = false;
3142 throttleCounter = 0;
3143 _zeroFlag = true;
3144 //outofBounds = true;
3145 } // end neg Z check
3146
3147 // Is it moving?
3148 /* if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
3149 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
3150 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) */
3151 if ( (Vector3.Mag(_velocity) < 0.01) && // moving very slowly
3152 (Vector3.Mag(_velocity) < Vector3.Mag(m_lastVelocity)) && // decelerating
3153 (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, _orientation)) < 0.0001) ) // spinning very slowly
3154 {
3155 _zeroFlag = true;
3156 m_throttleUpdates = false;
3157 }
3158 else
3159 {
3160 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3161 _zeroFlag = false;
3162 m_lastUpdateSent = false;
3163 //m_throttleUpdates = false;
3164 }
3165
3166 if (_zeroFlag)
3167 { // Its stopped
3168 _velocity.X = 0.0f;
3169 _velocity.Y = 0.0f;
3170 // _velocity.Z = 0.0f;
3171
3172 _acceleration.X = 0;
3173 _acceleration.Y = 0;
3174 // _acceleration.Z = 0;
3175
3176 m_rotationalVelocity.X = 0;
3177 m_rotationalVelocity.Y = 0;
3178 m_rotationalVelocity.Z = 0;
3179 // Stop it in the phys engine
3180 d.BodySetLinearVel(Body, 0.0f, 0.0f, _velocity.Z);
3181 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3182 d.BodySetForce(Body, 0f, 0f, 0f);
3183
3184 if (!m_lastUpdateSent)
3185 {
3186 m_throttleUpdates = false;
3187 throttleCounter = 0;
3188 if (_parent == null)
3189 {
3190 base.RequestPhysicsterseUpdate();
3191 }
3192
3193 m_lastUpdateSent = true;
3194 }
3195 }
3196 else
3197 { // Its moving
3198 if (lastZeroFlag != _zeroFlag)
3199 {
3200 if (_parent == null)
3201 {
3202 base.RequestPhysicsterseUpdate();
3203 }
3204 }
3205 m_lastUpdateSent = false;
3206 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3207 {
3208 if (_parent == null)
3209 {
3210 base.RequestPhysicsterseUpdate();
3211 }
3212 }
3213 else
3214 {
3215 throttleCounter++;
3216 }
3217 }
3218 m_lastposition = l_position;
3219
3220 /// End UpdatePositionAndVelocity insert
3221
3222
3223 // Rotation lock =====================================
3224 if(m_rotateEnableUpdate)
3225 {
3226 // Snapshot current angles, set up Amotor(s)
3227 m_rotateEnableUpdate = false;
3228 m_rotateEnable = m_rotateEnableRequest;
3229//Console.WriteLine("RotEnable {0} = {1}",m_primName, m_rotateEnable);
3230
3231 if (Amotor != IntPtr.Zero)
3232 {
3233 d.JointDestroy(Amotor);
3234 Amotor = IntPtr.Zero;
3235//Console.WriteLine("Old Amotor Destroyed");
3236 }
3237
3238 if (!m_rotateEnable.ApproxEquals(Vector3.One, 0.003f))
3239 { // not all are enabled
3240 d.Quaternion r = d.BodyGetQuaternion(Body);
3241 Quaternion locrot = new Quaternion(r.X, r.Y, r.Z, r.W);
3242 // extract the axes vectors
3243 Vector3 vX = new Vector3(1f,0f,0f);
3244 Vector3 vY = new Vector3(0f,1f,0f);
3245 Vector3 vZ = new Vector3(0f,0f,1f);
3246 vX = vX * locrot;
3247 vY = vY * locrot;
3248 vZ = vZ * locrot;
3249 // snapshot the current angle vectors
3250 m_lockX = vX;
3251 m_lockY = vY;
3252 m_lockZ = vZ;
3253 // m_lockRot = locrot;
3254 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3255 d.JointAttach(Amotor, Body, IntPtr.Zero);
3256 d.JointSetAMotorMode(Amotor, 0); // User mode??
3257//Console.WriteLine("New Amotor Created for {0}", m_primName);
3258
3259 float axisnum = 3; // how many to lock
3260 axisnum = (axisnum - (m_rotateEnable.X + m_rotateEnable.Y + m_rotateEnable.Z));
3261 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3262//Console.WriteLine("AxisNum={0}",(int)axisnum);
3263
3264 int i = 0;
3265
3266 if (m_rotateEnable.X == 0)
3267 {
3268 d.JointSetAMotorAxis(Amotor, i, 0, m_lockX.X, m_lockX.Y, m_lockX.Z);
3269//Console.WriteLine("AxisX {0} set to {1}", i, m_lockX);
3270 i++;
3271 }
3272
3273 if (m_rotateEnable.Y == 0)
3274 {
3275 d.JointSetAMotorAxis(Amotor, i, 0, m_lockY.X, m_lockY.Y, m_lockY.Z);
3276//Console.WriteLine("AxisY {0} set to {1}", i, m_lockY);
3277 i++;
3278 }
3279
3280 if (m_rotateEnable.Z == 0)
3281 {
3282 d.JointSetAMotorAxis(Amotor, i, 0, m_lockZ.X, m_lockZ.Y, m_lockZ.Z);
3283//Console.WriteLine("AxisZ {0} set to {1}", i, m_lockZ);
3284 i++;
3285 }
3286
3287 // These lowstops and high stops are effectively (no wiggle room)
3288 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0f);
3289 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
3290 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0f);
3291 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3292 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3293 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3294 d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 0f);
3295 d.JointSetAMotorParam(Amotor, (int) dParam.Vel3, 0f);
3296 d.JointSetAMotorParam(Amotor, (int) dParam.Vel2, 0f);
3297 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f);
3298 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
3299 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
3300 } // else none are locked
3301 } // end Rotation Update
3302
3303
3304 // VEHICLE processing ==========================================
3305 if (m_type != Vehicle.TYPE_NONE)
3306 {
3307 // get body attitude
3308 d.Quaternion rot = d.BodyGetQuaternion(Body);
3309 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
3310 Quaternion irotq = Quaternion.Inverse(rotq);
3311
3312 // VEHICLE Linear Motion
3313 d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame
3314 Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z);
3315 m_lLinObjectVel = vel_now * irotq;
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("Vel={0} Force={1}",linvel , 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 if ((m_usePID) && (m_PIDTau > 0.0f)) // Dynamics llMoveToTarget.
3616 {
3617 fz = 0; // llMoveToTarget ignores gravity.
3618 // it also ignores mass of object, and any physical resting on it.
3619 // Vector3 m_PIDTarget is where we are going
3620 // float m_PIDTau is time to get there
3621 fx = 0;
3622 fy = 0;
3623 d.Vector3 pos = d.BodyGetPosition(Body);
3624 Vector3 error = new Vector3(
3625 (m_PIDTarget.X - pos.X),
3626 (m_PIDTarget.Y - pos.Y),
3627 (m_PIDTarget.Z - pos.Z));
3628 if (error.ApproxEquals(Vector3.Zero,0.01f))
3629 { // Very close, Jump there and quit move
3630
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 d.BodySetForce(Body, 0f, 0f, 0f);
3635 }
3636 else
3637 {
3638 float scale = 50.0f * timestep / m_PIDTau;
3639 if ((error.ApproxEquals(Vector3.Zero,0.5f)) && (_target_velocity != Vector3.Zero))
3640 {
3641 // Nearby, quit update of velocity
3642 }
3643 else
3644 { // Far, calc damped velocity
3645 _target_velocity = error * scale;
3646 }
3647 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3648 }
3649 } // end PID MoveToTarget
3650
3651
3652 /// Dynamics Hover ===================================================================================
3653 // Hover PID Controller can only run if the PIDcontroller is not in use.
3654 if (m_useHoverPID && !m_usePID)
3655 {
3656//Console.WriteLine("Hover " + m_primName);
3657
3658 // If we're using the PID controller, then we have no gravity
3659 fz = (-1 * _parent_scene.gravityz) * m_mass;
3660
3661 // no lock; for now it's only called from within Simulate()
3662
3663 // If the PID Controller isn't active then we set our force
3664 // calculating base velocity to the current position
3665
3666 if ((m_PIDTau < 1))
3667 {
3668 PID_G = PID_G / m_PIDTau;
3669 }
3670
3671 if ((PID_G - m_PIDTau) <= 0)
3672 {
3673 PID_G = m_PIDTau + 1;
3674 }
3675
3676
3677 // Where are we, and where are we headed?
3678 d.Vector3 pos = d.BodyGetPosition(Body);
3679// d.Vector3 vel = d.BodyGetLinearVel(Body);
3680
3681
3682 // Non-Vehicles have a limited set of Hover options.
3683 // determine what our target height really is based on HoverType
3684 switch (m_PIDHoverType)
3685 {
3686 case PIDHoverType.Ground:
3687 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3688 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3689 break;
3690 case PIDHoverType.GroundAndWater:
3691 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3692 m_waterHeight = _parent_scene.GetWaterLevel();
3693 if (m_groundHeight > m_waterHeight)
3694 {
3695 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3696 }
3697 else
3698 {
3699 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3700 }
3701 break;
3702
3703 } // end switch (m_PIDHoverType)
3704
3705
3706 _target_velocity =
3707 new Vector3(0.0f, 0.0f,
3708 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3709 );
3710
3711 // if velocity is zero, use position control; otherwise, velocity control
3712
3713 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3714 {
3715 // keep track of where we stopped. No more slippin' & slidin'
3716
3717 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3718 // react to the physics scene by moving it's position.
3719 // Avatar to Avatar collisions
3720 // Prim to avatar collisions
3721 d.Vector3 dlinvel = vel;
3722 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3723 d.BodySetLinearVel(Body, dlinvel.X, dlinvel.Y, dlinvel.Z);
3724 d.BodyAddForce(Body, 0, 0, fz);
3725 //KF this prevents furthur motions return;
3726 }
3727 else
3728 {
3729 _zeroFlag = false;
3730
3731 // We're flying and colliding with something
3732 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3733 }
3734 } // end m_useHoverPID && !m_usePID
3735
3736
3737 /// Dynamics Apply Forces ===================================================================================
3738 fx *= m_mass;
3739 fy *= m_mass;
3740 //fz *= m_mass;
3741 fx += m_force.X;
3742 fy += m_force.Y;
3743 fz += m_force.Z;
3744
3745 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3746 if (fx != 0 || fy != 0 || fz != 0)
3747 {
3748 //m_taintdisable = true;
3749 //base.RaiseOutOfBounds(Position);
3750 //d.BodySetLinearVel(Body, fx, fy, 0f);
3751 if (!d.BodyIsEnabled(Body))
3752 {
3753 // A physical body at rest on a surface will auto-disable after a while,
3754 // this appears to re-enable it incase the surface it is upon vanishes,
3755 // and the body should fall again.
3756 d.BodySetLinearVel(Body, 0f, 0f, 0f);
3757 d.BodySetForce(Body, 0f, 0f, 0f);
3758 enableBodySoft();
3759 }
3760
3761 // 35x10 = 350n times the mass per second applied maximum.
3762 float nmax = 35f * m_mass;
3763 float nmin = -35f * m_mass;
3764
3765
3766 if (fx > nmax)
3767 fx = nmax;
3768 if (fx < nmin)
3769 fx = nmin;
3770 if (fy > nmax)
3771 fy = nmax;
3772 if (fy < nmin)
3773 fy = nmin;
3774 d.BodyAddForce(Body, fx, fy, fz);
3775 } // end apply forces
3776 } // end Vehicle/Dynamics
3777
3778 /// RotLookAt / LookAt =================================================================================
3779 if (m_useAPID)
3780 {
3781 // RotLookAt, apparently overrides all other rotation sources. Inputs:
3782 // Quaternion m_APIDTarget
3783 // float m_APIDStrength // From SL experiments, this is the time to get there
3784 // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly
3785 // Also in SL the mass of the object has no effect on time to get there.
3786 // Factors:
3787 // get present body rotation
3788 float limit = 1.0f;
3789 float rscaler = 50f; // adjusts rotation damping time
3790 float lscaler = 10f; // adjusts linear damping time in llLookAt
3791 float RLAservo = 0f;
3792 Vector3 diff_axis;
3793 float diff_angle;
3794 d.Quaternion rot = d.BodyGetQuaternion(Body); // prim present rotation
3795 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
3796 Quaternion rtarget = new Quaternion();
3797
3798 if(m_APIDTarget.W == -99.9f)
3799 {
3800 // this is really a llLookAt(), x,y,z is the target vector
3801 Vector3 target = new Vector3(m_APIDTarget.X, m_APIDTarget.Y, m_APIDTarget.Z);
3802 Vector3 ospin = new Vector3(1.0f, 0.0f, 0.0f) * rotq;
3803 Vector3 error = new Vector3(0.0f, 0.0f, 0.0f);
3804 float twopi = 2.0f * (float)Math.PI;
3805 Vector3 dir = target - _position;
3806 dir.Normalize();
3807 float tzrot = (float)Math.Atan2(dir.Y, dir.X);
3808 float txy = (float)Math.Sqrt((dir.X * dir.X) + (dir.Y * dir.Y));
3809 float terot = (float)Math.Atan2(dir.Z, txy);
3810 float ozrot = (float)Math.Atan2(ospin.Y, ospin.X);
3811 float oxy = (float)Math.Sqrt((ospin.X * ospin.X) + (ospin.Y * ospin.Y));
3812 float oerot = (float)Math.Atan2(ospin.Z, oxy);
3813 float ra = 2.0f * ((rotq.W * rotq.X) + (rotq.Y * rotq.Z));
3814 float rb = 1.0f - 2.0f * ((rotq.Y * rotq.Y)+(rotq.X * rotq.X));
3815 float roll = (float)Math.Atan2(ra, rb);
3816 float errorz = tzrot - ozrot;
3817 if(errorz > (float)Math.PI) errorz -= twopi;
3818 else if(errorz < -(float)Math.PI) errorz += twopi;
3819 float errory = oerot - terot;
3820 if(errory > (float)Math.PI) errory -= twopi;
3821 else if(errory < -(float)Math.PI) errory += twopi;
3822 diff_angle = Math.Abs(errorz) + Math.Abs(errory) + Math.Abs(roll);
3823 if(diff_angle > 0.01f * m_APIDdamper)
3824 {
3825 m_APIDdamper = 1.0f;
3826 RLAservo = timestep / m_APIDStrength * rscaler;
3827 errorz *= RLAservo;
3828 errory *= RLAservo;
3829 error.X = -roll * 8.0f;
3830 error.Y = errory;
3831 error.Z = errorz;
3832 error *= rotq;
3833 d.BodySetAngularVel (Body, error.X, error.Y, error.Z);
3834 }
3835 else
3836 {
3837 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3838 m_APIDdamper = 2.0f;
3839 }
3840 }
3841 else
3842 {
3843 // this is a llRotLookAt()
3844 rtarget = m_APIDTarget;
3845
3846 Quaternion rot_diff = Quaternion.Inverse(rotq) * rtarget; // difference to desired rot
3847 rot_diff.GetAxisAngle(out diff_axis, out diff_angle); // convert to axis to point at & error angle
3848//if(frcount == 0) Console.WriteLine("axis {0} angle {1}",diff_axis * 57.3f, diff_angle);
3849
3850 // diff_axis.Normalize(); it already is!
3851 if(diff_angle > 0.01f * m_APIDdamper) // diff_angle is always +ve // if there is enough error
3852 {
3853 m_APIDdamper = 1.0f;
3854 Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z);
3855 rotforce = rotforce * rotq;
3856 if(diff_angle > limit) diff_angle = limit; // cap the rotate rate
3857 RLAservo = timestep / m_APIDStrength * lscaler;
3858 rotforce = rotforce * RLAservo * diff_angle ;
3859 d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z);
3860//Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo);
3861 }
3862 else
3863 { // close enough
3864 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3865 m_APIDdamper = 2.0f;
3866 }
3867 } // end llLookAt/llRotLookAt
3868//if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle);
3869 } // end m_useAPID
3870 } // end root prims
3871 } // end Move()
3872 } // end class
3873}
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..88f9658
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
@@ -0,0 +1,3846 @@
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 float geomRegionFence = 0.0f;
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 ContactCopy; // local copy that can be modified
268 private d.Contact TerrainContact;
269 private d.Contact AvatarStaticprimContact; // was 'contact'
270 private d.Contact AvatarMovementprimContact;
271 private d.Contact AvatarMovementTerrainContact;
272 private d.Contact WaterContact;
273 private d.Contact[,] m_materialContacts;
274
275//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
276//Ckrinke private int m_randomizeWater = 200;
277 private int m_physicsiterations = 10;
278 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
279 private readonly PhysicsActor PANull = new NullPhysicsActor();
280 private float step_time = 0.0f;
281//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
282//Ckrinke private int ms = 0;
283 public IntPtr world;
284 //private bool returncollisions = false;
285 // private uint obj1LocalID = 0;
286 private uint obj2LocalID = 0;
287 //private int ctype = 0;
288 private OdeCharacter cc1;
289 private OdePrim cp1;
290 private OdeCharacter cc2;
291 private OdePrim cp2;
292 //private int cStartStop = 0;
293 //private string cDictKey = "";
294
295 public IntPtr space;
296
297 //private IntPtr tmpSpace;
298 // split static geometry collision handling into spaces of 30 meters
299 public IntPtr[,] staticPrimspace;
300
301 public Object OdeLock;
302
303 public IMesher mesher;
304
305 private IConfigSource m_config;
306
307 public bool physics_logging = false;
308 public int physics_logging_interval = 0;
309 public bool physics_logging_append_existing_logfile = false;
310
311 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
312 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
313
314 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
315 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
316 // TODO: unused: private uint heightmapWidthSamples;
317 // TODO: unused: private uint heightmapHeightSamples;
318
319 private volatile int m_global_contactcount = 0;
320
321 private Vector3 m_worldOffset = Vector3.Zero;
322 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
323 private PhysicsScene m_parentScene = null;
324
325 private ODERayCastRequestManager m_rayCastManager;
326
327 /// <summary>
328 /// Initiailizes the scene
329 /// Sets many properties that ODE requires to be stable
330 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
331 /// </summary>
332 public OdeScene(CollisionLocker dode, string sceneIdentifier)
333 {
334 m_log
335 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + sceneIdentifier);
336
337 OdeLock = new Object();
338 ode = dode;
339 nearCallback = near;
340 triCallback = TriCallback;
341 triArrayCallback = TriArrayCallback;
342 m_rayCastManager = new ODERayCastRequestManager(this);
343 lock (OdeLock)
344 {
345 // Create the world and the first space
346 world = d.WorldCreate();
347 space = d.HashSpaceCreate(IntPtr.Zero);
348
349
350 contactgroup = d.JointGroupCreate(0);
351 //contactgroup
352
353 d.WorldSetAutoDisableFlag(world, false);
354 #if USE_DRAWSTUFF
355
356 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
357 viewthread.Start();
358 #endif
359 }
360
361
362 _watermap = new float[258 * 258];
363
364 // Zero out the prim spaces array (we split our space into smaller spaces so
365 // we can hit test less.
366 }
367
368#if USE_DRAWSTUFF
369 public void startvisualization(object o)
370 {
371 ds.Functions fn;
372 fn.version = ds.VERSION;
373 fn.start = new ds.CallbackFunction(start);
374 fn.step = new ds.CallbackFunction(step);
375 fn.command = new ds.CallbackFunction(command);
376 fn.stop = null;
377 fn.path_to_textures = "./textures";
378 string[] args = new string[0];
379 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
380 }
381#endif
382
383 // Initialize the mesh plugin
384 public override void Initialise(IMesher meshmerizer, IConfigSource config)
385 {
386 mesher = meshmerizer;
387 m_config = config;
388 // Defaults
389
390 if (Environment.OSVersion.Platform == PlatformID.Unix)
391 {
392 avPIDD = 3200.0f;
393 avPIDP = 1400.0f;
394 avStandupTensor = 2000000f;
395 }
396 else
397 {
398 avPIDD = 2200.0f;
399 avPIDP = 900.0f;
400 avStandupTensor = 550000f;
401 }
402
403 int contactsPerCollision = 80;
404
405 if (m_config != null)
406 {
407 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
408 if (physicsconfig != null)
409 {
410 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
411 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
412 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
413
414 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
415 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
416
417 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
418 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
419 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
420
421 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
422
423 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
424 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
425 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
426
427 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
428 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
429 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
430
431 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
432 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
433
434 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
435 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
436
437 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", 0.020f);
438 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
439
440 avDensity = physicsconfig.GetFloat("av_density", 80f);
441 avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
442 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
443 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
444 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
445 avCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
446
447 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
448
449 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 3);
450 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
451 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
452 geomRegionFence = physicsconfig.GetFloat("region_border_fence", 0.0f);
453
454 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
455 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
456
457 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
458 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
459
460 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
461 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
462 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
463 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
464 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
465
466 if (Environment.OSVersion.Platform == PlatformID.Unix)
467 {
468 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
469 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
470 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
471 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
472 }
473 else
474 {
475 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
476 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
477 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
478 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
479 }
480
481 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
482 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
483 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
484
485 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
486 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
487 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
488 }
489 }
490
491 contacts = new d.ContactGeom[contactsPerCollision];
492
493 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
494
495 // Avatar static on a Prim parameters
496 AvatarStaticprimContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
497 AvatarStaticprimContact.surface.mu = 255.0f;
498 AvatarStaticprimContact.surface.bounce = 0.0f;
499 AvatarStaticprimContact.surface.soft_cfm = 0.0f;
500 AvatarStaticprimContact.surface.soft_erp = 0.30f; // If this is too small static Av will fall through a sloping prim. 1.0 prevents fall-thru
501
502 // Avatar moving on a Prim parameters
503 AvatarMovementprimContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
504 AvatarMovementprimContact.surface.mu = 255.0f;
505 AvatarMovementprimContact.surface.bounce = 0.0f;
506 AvatarMovementprimContact.surface.soft_cfm = 0.0f; // if this is 0.01 then prims become phantom to Avs!
507 AvatarMovementprimContact.surface.soft_erp = 0.3f;
508
509 // Static Avatar on Terrain parameters
510 // Keeps Avatar in place better
511 TerrainContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
512 TerrainContact.surface.mu = 255.0f;
513 TerrainContact.surface.bounce = 0.0f;
514 TerrainContact.surface.soft_cfm = 0.0f;
515 TerrainContact.surface.soft_erp = 0.05f;
516
517 // Moving Avatar on Terrain parameters
518 AvatarMovementTerrainContact.surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
519 AvatarMovementTerrainContact.surface.mu = 75f;
520 AvatarMovementTerrainContact.surface.bounce = 0.0f;
521 AvatarMovementTerrainContact.surface.soft_cfm = 0.0f;
522 AvatarMovementTerrainContact.surface.soft_erp = 0.05f;
523
524 // Avatar or prim the the water, this may not be used, possibly water is same as air?
525 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
526 WaterContact.surface.mu = 0.0f; // No friction
527 WaterContact.surface.bounce = 0.0f; // No bounce
528 WaterContact.surface.soft_cfm = 0.010f;
529 WaterContact.surface.soft_erp = 0.010f;
530
531
532 // Prim static or moving on a prim, depends on material type
533 m_materialContacts = new d.Contact[7,2];
534 // V 1 = Sliding; 0 = static or fell onto
535 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
536 m_materialContacts[(int)Material.Stone, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
537 m_materialContacts[(int)Material.Stone, 0].surface.mu = 60f; // friction, 1 = slippery, 255 = no slip
538 m_materialContacts[(int)Material.Stone, 0].surface.bounce = 0.0f;
539 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.0f;
540 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.50f; // erp also changes friction, more erp=less friction
541
542 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
543 m_materialContacts[(int)Material.Stone, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
544 m_materialContacts[(int)Material.Stone, 1].surface.mu = 40f;
545 m_materialContacts[(int)Material.Stone, 1].surface.bounce = 0.0f;
546 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.0f;
547 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.50f;
548
549 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
550 m_materialContacts[(int)Material.Metal, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
551 m_materialContacts[(int)Material.Metal, 0].surface.mu = 15f;
552 m_materialContacts[(int)Material.Metal, 0].surface.bounce = 0.2f;
553 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.0f;
554 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.50f;
555
556 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
557 m_materialContacts[(int)Material.Metal, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
558 m_materialContacts[(int)Material.Metal, 1].surface.mu = 10f;
559 m_materialContacts[(int)Material.Metal, 1].surface.bounce = 0.2f;
560 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.0f;
561 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.50f;
562
563 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
564 m_materialContacts[(int)Material.Glass, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
565 m_materialContacts[(int)Material.Glass, 0].surface.mu = 7.5f;
566 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.0f;
567 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.0f;
568 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.50f;
569
570 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
571 m_materialContacts[(int)Material.Glass, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
572 m_materialContacts[(int)Material.Glass, 1].surface.mu = 5f;
573 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.0f;
574 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.0f;
575 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.50f;
576
577 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
578 m_materialContacts[(int)Material.Wood, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
579 m_materialContacts[(int)Material.Wood, 0].surface.mu = 45f;
580 m_materialContacts[(int)Material.Wood, 0].surface.bounce = 0.1f;
581 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.0f;
582 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.50f;
583
584 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
585 m_materialContacts[(int)Material.Wood, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
586 m_materialContacts[(int)Material.Wood, 1].surface.mu = 30f;
587 m_materialContacts[(int)Material.Wood, 1].surface.bounce = 0.1f;
588 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.0f;
589 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.50f;
590
591 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
592 m_materialContacts[(int)Material.Flesh, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
593 m_materialContacts[(int)Material.Flesh, 0].surface.mu = 150f;
594 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = 0.0f;
595 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.0f;
596 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.50f;
597
598 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
599 m_materialContacts[(int)Material.Flesh, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
600 m_materialContacts[(int)Material.Flesh, 1].surface.mu = 100f;
601 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = 0.0f;
602 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.0f;
603 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.50f;
604
605 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
606 m_materialContacts[(int)Material.Plastic, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
607 m_materialContacts[(int)Material.Plastic, 0].surface.mu = 30f;
608 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = 0.2f;
609 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.0f;
610 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.50f;
611
612 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
613 m_materialContacts[(int)Material.Plastic, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
614 m_materialContacts[(int)Material.Plastic, 1].surface.mu = 20f;
615 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = 0.2f;
616 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.0f;
617 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.50f;
618
619 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
620 m_materialContacts[(int)Material.Rubber, 0].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
621 m_materialContacts[(int)Material.Rubber, 0].surface.mu = 150f;
622 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = 0.7f;
623 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.0f;
624 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.50f;
625
626 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
627 m_materialContacts[(int)Material.Rubber, 1].surface.mode = d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP | d.ContactFlags.Bounce;
628 m_materialContacts[(int)Material.Rubber, 1].surface.mu = 100f;
629 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = 0.7f;
630 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.0f;
631 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.50f;
632
633 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
634
635 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
636
637 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
638 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
639
640
641 d.WorldSetLinearDampingThreshold(world, 256f);
642 d.WorldSetLinearDamping(world, 256f);
643// d.WorldSetLinearDampingThreshold(world, 0.01f);
644// d.WorldSetLinearDamping(world, 0.1f);
645 d.WorldSetAngularDampingThreshold(world, 256f);
646 d.WorldSetAngularDamping(world, 256f);
647 d.WorldSetMaxAngularSpeed(world, 256f);
648
649 // Set how many steps we go without running collision testing
650 // This is in addition to the step size.
651 // Essentially Steps * m_physicsiterations
652 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
653 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
654
655
656
657 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
658 {
659 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
660 {
661 staticPrimspace[i, j] = IntPtr.Zero;
662 }
663 }
664 }
665
666 internal void waitForSpaceUnlock(IntPtr space)
667 {
668 //if (space != IntPtr.Zero)
669 //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
670 }
671
672 /// <summary>
673 /// Debug space message for printing the space that a prim/avatar is in.
674 /// </summary>
675 /// <param name="pos"></param>
676 /// <returns>Returns which split up space the given position is in.</returns>
677 public string whichspaceamIin(Vector3 pos)
678 {
679 return calculateSpaceForGeom(pos).ToString();
680 }
681
682 #region Collision Detection
683
684 /// <summary>
685 /// This is our near callback. A geometry is near a body
686 /// </summary>
687 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
688 /// <param name="g1">a geometry or space</param>
689 /// <param name="g2">another geometry or space</param>
690 private void near(IntPtr space, IntPtr g1, IntPtr g2)
691 {
692 // no lock here! It's invoked from within Simulate(), which is thread-locked
693
694 // Test if we're colliding a geom with a space.
695 // If so we have to drill down into the space recursively
696//Console.WriteLine("near -----------"); //##
697 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
698 {
699 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
700 return;
701
702 // Separating static prim geometry spaces.
703 // We'll be calling near recursivly if one
704 // of them is a space to find all of the
705 // contact points in the space
706 try
707 {
708 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
709 }
710 catch (AccessViolationException)
711 {
712 m_log.Warn("[PHYSICS]: Unable to collide test a space");
713 return;
714 }
715 //Colliding a space or a geom with a space or a geom. so drill down
716
717 //Collide all geoms in each space..
718 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
719 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
720 return;
721 }
722
723 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
724 return;
725
726 IntPtr b1 = d.GeomGetBody(g1);
727 IntPtr b2 = d.GeomGetBody(g2);
728
729 // d.GeomClassID id = d.GeomGetClass(g1);
730
731 String name1 = null;
732 String name2 = null;
733
734 if (!geom_name_map.TryGetValue(g1, out name1))
735 {
736 name1 = "null";
737 }
738 if (!geom_name_map.TryGetValue(g2, out name2))
739 {
740 name2 = "null";
741 }
742
743 //if (id == d.GeomClassId.TriMeshClass)
744 //{
745 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
746 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
747 //}
748
749 // Figure out how many contact points we have
750 int count = 0;
751 try
752 {
753 // Colliding Geom To Geom
754 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
755
756 if (g1 == g2)
757 return; // Can't collide with yourself
758
759 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
760 return;
761
762 lock (contacts)
763 {
764 count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
765 if (count > contacts.Length)
766 m_log.Error("[PHYSICS]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
767 }
768 }
769 catch (SEHException)
770 {
771 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.");
772 ode.drelease(world);
773 base.TriggerPhysicsBasedRestart();
774 }
775 catch (Exception e)
776 {
777 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
778 return;
779 }
780
781 PhysicsActor p1;
782 PhysicsActor p2;
783
784 if (!actor_name_map.TryGetValue(g1, out p1))
785 {
786 p1 = PANull;
787 }
788
789 if (!actor_name_map.TryGetValue(g2, out p2))
790 {
791 p2 = PANull;
792 }
793
794 ContactPoint maxDepthContact = new ContactPoint();
795 if (p1.CollisionScore + count >= float.MaxValue)
796 p1.CollisionScore = 0;
797 p1.CollisionScore += count;
798
799 if (p2.CollisionScore + count >= float.MaxValue)
800 p2.CollisionScore = 0;
801 p2.CollisionScore += count;
802 for (int i = 0; i < count; i++)
803 {
804 d.ContactGeom curContact = contacts[i];
805
806 if (curContact.depth > maxDepthContact.PenetrationDepth)
807 {
808 maxDepthContact = new ContactPoint(
809 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
810 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
811 curContact.depth
812 );
813 }
814
815 //m_log.Warn("[CCOUNT]: " + count);
816 IntPtr joint;
817 // If we're colliding with terrain, use 'TerrainContact' instead of AvatarStaticprimContact.
818 // allows us to have different settings
819
820 // We only need to test p2 for 'jump crouch purposes'
821 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
822 {
823 // Testing if the collision is at the feet of the avatar
824
825 //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));
826//#@ if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
827//#@ p2.IsColliding = true;
828 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f)){ //##
829 p2.IsColliding = true; //##
830 }else{
831
832 } //##
833 }
834 else
835 {
836 p2.IsColliding = true;
837 }
838
839 //if ((framecount % m_returncollisions) == 0)
840
841 switch (p1.PhysicsActorType)
842 {
843 case (int)ActorTypes.Agent:
844 p2.CollidingObj = true;
845 break;
846 case (int)ActorTypes.Prim:
847 if (p2.Velocity.LengthSquared() > 0.0f)
848 p2.CollidingObj = true;
849 break;
850 case (int)ActorTypes.Unknown:
851 p2.CollidingGround = true;
852 break;
853 default:
854 p2.CollidingGround = true;
855 break;
856 }
857
858 // we don't want prim or avatar to explode
859
860 #region InterPenetration Handling - Unintended physics explosions
861# region disabled code1
862
863 if (curContact.depth >= 0.08f)
864 {
865 //This is disabled at the moment only because it needs more tweaking
866 //It will eventually be uncommented
867 /*
868 if (AvatarStaticprimContact.depth >= 1.00f)
869 {
870 //m_log.Debug("[PHYSICS]: " + AvatarStaticprimContact.depth.ToString());
871 }
872
873 //If you interpenetrate a prim with an agent
874 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
875 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
876 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
877 p2.PhysicsActorType == (int) ActorTypes.Prim))
878 {
879
880 //AvatarStaticprimContact.depth = AvatarStaticprimContact.depth * 4.15f;
881 /*
882 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
883 {
884 p2.CollidingObj = true;
885 AvatarStaticprimContact.depth = 0.003f;
886 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
887 OdeCharacter character = (OdeCharacter) p2;
888 character.SetPidStatus(true);
889 AvatarStaticprimContact.pos = new d.Vector3(AvatarStaticprimContact.pos.X + (p1.Size.X / 2), AvatarStaticprimContact.pos.Y + (p1.Size.Y / 2), AvatarStaticprimContact.pos.Z + (p1.Size.Z / 2));
890
891 }
892 else
893 {
894
895 //AvatarStaticprimContact.depth = 0.0000000f;
896 }
897 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
898 {
899
900 p1.CollidingObj = true;
901 AvatarStaticprimContact.depth = 0.003f;
902 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
903 AvatarStaticprimContact.pos = new d.Vector3(AvatarStaticprimContact.pos.X + (p2.Size.X / 2), AvatarStaticprimContact.pos.Y + (p2.Size.Y / 2), AvatarStaticprimContact.pos.Z + (p2.Size.Z / 2));
904 OdeCharacter character = (OdeCharacter)p1;
905 character.SetPidStatus(true);
906 }
907 else
908 {
909
910 //AvatarStaticprimContact.depth = 0.0000000f;
911 }
912
913
914
915 }
916*/
917 // If you interpenetrate a prim with another prim
918 /*
919 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
920 {
921 #region disabledcode2
922 //OdePrim op1 = (OdePrim)p1;
923 //OdePrim op2 = (OdePrim)p2;
924 //op1.m_collisionscore++;
925 //op2.m_collisionscore++;
926
927 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
928 //{
929 //op1.m_taintdisable = true;
930 //AddPhysicsActorTaint(p1);
931 //op2.m_taintdisable = true;
932 //AddPhysicsActorTaint(p2);
933 //}
934
935 //if (AvatarStaticprimContact.depth >= 0.25f)
936 //{
937 // Don't collide, one or both prim will expld.
938
939 //op1.m_interpenetrationcount++;
940 //op2.m_interpenetrationcount++;
941 //interpenetrations_before_disable = 200;
942 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
943 //{
944 //op1.m_taintdisable = true;
945 //AddPhysicsActorTaint(p1);
946 //}
947 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
948 //{
949 // op2.m_taintdisable = true;
950 //AddPhysicsActorTaint(p2);
951 //}
952
953 //AvatarStaticprimContact.depth = AvatarStaticprimContact.depth / 8f;
954 //AvatarStaticprimContact.normal = new d.Vector3(0, 0, 1);
955 //}
956 //if (op1.m_disabled || op2.m_disabled)
957 //{
958 //Manually disabled objects stay disabled
959 //AvatarStaticprimContact.depth = 0f;
960 //}
961 #endregion
962 }
963 */
964#endregion
965 if (curContact.depth >= 1.00f)
966 {
967 //m_log.Info("[P]: " + AvatarStaticprimContact.depth.ToString());
968 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
969 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
970 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
971 p2.PhysicsActorType == (int) ActorTypes.Unknown))
972 {
973 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
974 {
975 if (p2 is OdeCharacter)
976 {
977 OdeCharacter character = (OdeCharacter) p2;
978
979 //p2.CollidingObj = true;
980 curContact.depth = 0.00000003f;
981 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
982 curContact.pos =
983 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
984 curContact.pos.Y + (p1.Size.Y/2),
985 curContact.pos.Z + (p1.Size.Z/2));
986 character.SetPidStatus(true);
987 }
988 }
989
990
991 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
992 {
993 if (p1 is OdeCharacter)
994 {
995 OdeCharacter character = (OdeCharacter) p1;
996
997 //p2.CollidingObj = true;
998 curContact.depth = 0.00000003f;
999 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1000 curContact.pos =
1001 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1002 curContact.pos.Y + (p1.Size.Y/2),
1003 curContact.pos.Z + (p1.Size.Z/2));
1004 character.SetPidStatus(true);
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011 #endregion
1012
1013 // Logic for collision handling
1014 // Note, that if *all* contacts are skipped (VolumeDetect)
1015 // The prim still detects (and forwards) collision events but
1016 // appears to be phantom for the world
1017 Boolean skipThisContact = false;
1018
1019 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1020 skipThisContact = true; // No collision on volume detect prims
1021
1022 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1023 skipThisContact = true; // No collision on volume detect prims
1024
1025 if (!skipThisContact && curContact.depth < 0f)
1026 skipThisContact = true;
1027
1028 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1029 skipThisContact = true;
1030
1031 const int maxContactsbeforedeath = 4000;
1032 joint = IntPtr.Zero;
1033
1034 if (!skipThisContact)
1035 {
1036 // Add contact joints with materials params----------------------------------
1037 // p1 is what is being hit, p2 is the physical object doing the hitting
1038 int material = (int) Material.Wood;
1039 int movintYN = 0; // 1 = Sliding; 0 = static or fell onto
1040 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f) movintYN = 1;
1041
1042 // If we're colliding against terrain
1043 if (name1 == "Terrain" || name2 == "Terrain")
1044 {
1045 // If we're moving
1046 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && (movintYN == 1))
1047 {
1048 //$ Av walk/run on terrain (not falling) Use the Avatar movement terrain contact
1049 AvatarMovementTerrainContact.geom = curContact;
1050 _perloopContact.Add(curContact);
1051 if (m_global_contactcount < maxContactsbeforedeath)
1052 {
1053 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1054 m_global_contactcount++;
1055 }
1056 }
1057 else
1058 {
1059 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1060 {
1061 //$ Av standing on terrain, Use the non moving Avata terrain contact
1062 TerrainContact.geom = curContact;
1063 _perloopContact.Add(curContact);
1064 if (m_global_contactcount < maxContactsbeforedeath)
1065 {
1066 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1067 m_global_contactcount++;
1068 }
1069 }
1070 else
1071 {
1072 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1073 {
1074 //& THIS NEVER HAPPENS? prim prim contact In terrain contact?
1075 // int pj294950 = 0;
1076 // prim terrain contact
1077
1078 if (p2 is OdePrim)
1079 material = ((OdePrim)p2).m_material;
1080 //m_log.DebugFormat("Material: {0}", material);
1081 m_materialContacts[material, movintYN].geom = curContact;
1082 _perloopContact.Add(curContact);
1083
1084 if (m_global_contactcount < maxContactsbeforedeath)
1085 {
1086 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1087 m_global_contactcount++;
1088
1089 }
1090
1091 }
1092 else
1093 {
1094 //$ prim on terrain contact
1095 if (p2 is OdePrim)
1096 material = ((OdePrim)p2).m_material;
1097 //m_log.DebugFormat("Material: {0}", material);
1098 m_materialContacts[material, movintYN].geom = curContact;
1099 _perloopContact.Add(curContact);
1100
1101 ContactCopy = m_materialContacts[material, movintYN];
1102 if(movintYN == 1)
1103 {
1104 // prevent excessive slide on terrain
1105 ContactCopy.surface.mu = m_materialContacts[material, movintYN].surface.mu * 30.0f;
1106 }
1107
1108 if (m_global_contactcount < maxContactsbeforedeath)
1109 {
1110 joint = d.JointCreateContact(world, contactgroup, ref ContactCopy);
1111 m_global_contactcount++;
1112 }
1113 }
1114 }
1115 }
1116 }
1117 else if (name1 == "Water" || name2 == "Water")
1118 {
1119 //$ This never happens! Perhaps water is treated like air?
1120 /*
1121 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1122 {
1123 }
1124 else
1125 {
1126 }
1127 */
1128 //WaterContact.surface.soft_cfm = 0.0000f;
1129 //WaterContact.surface.soft_erp = 0.00000f;
1130 if (curContact.depth > 0.1f)
1131 {
1132 curContact.depth *= 52;
1133 //AvatarStaticprimContact.normal = new d.Vector3(0, 0, 1);
1134 //AvatarStaticprimContact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1135 }
1136 WaterContact.geom = curContact;
1137 _perloopContact.Add(curContact);
1138 if (m_global_contactcount < maxContactsbeforedeath)
1139 {
1140 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1141 m_global_contactcount++;
1142 }
1143 //m_log.Info("[PHYSICS]: Prim Water Contact" + AvatarStaticprimContact.depth);
1144 }
1145 else
1146 {
1147
1148 // no terrain and no water, we're colliding with prim or avatar
1149 // check if we're moving
1150 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1151 {
1152 //$ Avatar on Prim or other Avatar
1153 if (movintYN == 1)
1154 {
1155 // Use the AV Movement / prim contact
1156 AvatarMovementprimContact.geom = curContact;
1157 _perloopContact.Add(curContact);
1158 if (m_global_contactcount < maxContactsbeforedeath)
1159 {
1160 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1161 m_global_contactcount++;
1162 }
1163 }
1164 else
1165 {
1166 // Use the Av non movement / prim contact
1167 AvatarStaticprimContact.geom = curContact;
1168 _perloopContact.Add(curContact);
1169 ContactCopy = AvatarStaticprimContact; // local copy so we can change locally
1170
1171 if (m_global_contactcount < maxContactsbeforedeath)
1172 {
1173 if (curContact.depth > 0.2)
1174 { // embedded, eject slowly
1175 ContactCopy.surface.soft_erp = 0.1f;
1176 ContactCopy.surface.soft_cfm = 0.1f;
1177 }
1178 else
1179 { // keep on the surface
1180 ContactCopy.surface.soft_erp = 0.3f;
1181 ContactCopy.surface.soft_cfm = 0.0f;
1182 }
1183 joint = d.JointCreateContact(world, contactgroup, ref ContactCopy);
1184 m_global_contactcount++;
1185 }
1186 }
1187 }
1188 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1189 {
1190 //$ Prim on Prim
1191 //p1.PhysicsActorType
1192
1193 if (p2 is OdePrim) material = ((OdePrim)p2).m_material;
1194 //m_log.DebugFormat("Material: {0}", material);
1195
1196 m_materialContacts[material, movintYN].geom = curContact;
1197 _perloopContact.Add(curContact);
1198
1199 if (m_global_contactcount < maxContactsbeforedeath)
1200 {
1201 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1202 m_global_contactcount++;
1203 }
1204 }
1205 }
1206
1207 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1208 {
1209 d.JointAttach(joint, b1, b2);
1210 m_global_contactcount++;
1211 }
1212
1213 }
1214 collision_accounting_events(p1, p2, maxDepthContact);
1215 if (count > geomContactPointsStartthrottle)
1216 {
1217 // If there are more then 3 contact points, it's likely
1218 // that we've got a pile of objects, so ...
1219 // We don't want to send out hundreds of terse updates over and over again
1220 // so lets throttle them and send them again after it's somewhat sorted out.
1221 p2.ThrottleUpdates = true;
1222 }
1223 //m_log.Debug(count.ToString());
1224 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1225 } // end for i.. loop
1226 } // end near
1227
1228 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1229 {
1230 bool result = false;
1231 //return result;
1232 if (!m_filterCollisions)
1233 return false;
1234
1235 ActorTypes at = (ActorTypes)atype;
1236 lock (_perloopContact)
1237 {
1238 foreach (d.ContactGeom contact in _perloopContact)
1239 {
1240 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1241 //{
1242 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1243 if (at == ActorTypes.Agent)
1244 {
1245 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)
1246 {
1247
1248 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1249 {
1250 //contactGeom.depth *= .00005f;
1251 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1252 // 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));
1253 result = true;
1254 break;
1255 }
1256 else
1257 {
1258 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1259 }
1260 }
1261 else
1262 {
1263 //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));
1264 //int i = 0;
1265 }
1266 }
1267 else if (at == ActorTypes.Prim)
1268 {
1269 //d.AABB aabb1 = new d.AABB();
1270 //d.AABB aabb2 = new d.AABB();
1271
1272 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1273 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1274 //aabb1.
1275 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)
1276 {
1277 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1278 {
1279 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1280 {
1281 result = true;
1282 break;
1283 }
1284 }
1285 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
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 }
1288
1289 }
1290
1291 //}
1292
1293 }
1294 }
1295 return result;
1296 }
1297
1298 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1299 {
1300 // obj1LocalID = 0;
1301 //returncollisions = false;
1302 obj2LocalID = 0;
1303 //ctype = 0;
1304 //cStartStop = 0;
1305 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1306 return;
1307
1308 switch ((ActorTypes)p2.PhysicsActorType)
1309 {
1310 case ActorTypes.Agent:
1311 cc2 = (OdeCharacter)p2;
1312
1313 // obj1LocalID = cc2.m_localID;
1314 switch ((ActorTypes)p1.PhysicsActorType)
1315 {
1316 case ActorTypes.Agent:
1317 cc1 = (OdeCharacter)p1;
1318 obj2LocalID = cc1.m_localID;
1319 cc1.AddCollisionEvent(cc2.m_localID, contact);
1320 //ctype = (int)CollisionCategories.Character;
1321
1322 //if (cc1.CollidingObj)
1323 //cStartStop = (int)StatusIndicators.Generic;
1324 //else
1325 //cStartStop = (int)StatusIndicators.Start;
1326
1327 //returncollisions = true;
1328 break;
1329 case ActorTypes.Prim:
1330 if (p1 is OdePrim)
1331 {
1332 cp1 = (OdePrim) p1;
1333 obj2LocalID = cp1.m_localID;
1334 cp1.AddCollisionEvent(cc2.m_localID, contact);
1335 }
1336 //ctype = (int)CollisionCategories.Geom;
1337
1338 //if (cp1.CollidingObj)
1339 //cStartStop = (int)StatusIndicators.Generic;
1340 //else
1341 //cStartStop = (int)StatusIndicators.Start;
1342
1343 //returncollisions = true;
1344 break;
1345
1346 case ActorTypes.Ground:
1347 case ActorTypes.Unknown:
1348 obj2LocalID = 0;
1349 //ctype = (int)CollisionCategories.Land;
1350 //returncollisions = true;
1351 break;
1352 }
1353
1354 cc2.AddCollisionEvent(obj2LocalID, contact);
1355 break;
1356 case ActorTypes.Prim:
1357
1358 if (p2 is OdePrim)
1359 {
1360 cp2 = (OdePrim) p2;
1361
1362 // obj1LocalID = cp2.m_localID;
1363 switch ((ActorTypes) p1.PhysicsActorType)
1364 {
1365 case ActorTypes.Agent:
1366 if (p1 is OdeCharacter)
1367 {
1368 cc1 = (OdeCharacter) p1;
1369 obj2LocalID = cc1.m_localID;
1370 cc1.AddCollisionEvent(cp2.m_localID, contact);
1371 //ctype = (int)CollisionCategories.Character;
1372
1373 //if (cc1.CollidingObj)
1374 //cStartStop = (int)StatusIndicators.Generic;
1375 //else
1376 //cStartStop = (int)StatusIndicators.Start;
1377 //returncollisions = true;
1378 }
1379 break;
1380 case ActorTypes.Prim:
1381
1382 if (p1 is OdePrim)
1383 {
1384 cp1 = (OdePrim) p1;
1385 obj2LocalID = cp1.m_localID;
1386 cp1.AddCollisionEvent(cp2.m_localID, contact);
1387 //ctype = (int)CollisionCategories.Geom;
1388
1389 //if (cp1.CollidingObj)
1390 //cStartStop = (int)StatusIndicators.Generic;
1391 //else
1392 //cStartStop = (int)StatusIndicators.Start;
1393
1394 //returncollisions = true;
1395 }
1396 break;
1397
1398 case ActorTypes.Ground:
1399 case ActorTypes.Unknown:
1400 obj2LocalID = 0;
1401 //ctype = (int)CollisionCategories.Land;
1402
1403 //returncollisions = true;
1404 break;
1405 }
1406
1407 cp2.AddCollisionEvent(obj2LocalID, contact);
1408 }
1409 break;
1410 }
1411 //if (returncollisions)
1412 //{
1413
1414 //lock (m_storedCollisions)
1415 //{
1416 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1417 //if (m_storedCollisions.ContainsKey(cDictKey))
1418 //{
1419 //sCollisionData objd = m_storedCollisions[cDictKey];
1420 //objd.NumberOfCollisions += 1;
1421 //objd.lastframe = framecount;
1422 //m_storedCollisions[cDictKey] = objd;
1423 //}
1424 //else
1425 //{
1426 //sCollisionData objd = new sCollisionData();
1427 //objd.ColliderLocalId = obj1LocalID;
1428 //objd.CollidedWithLocalId = obj2LocalID;
1429 //objd.CollisionType = ctype;
1430 //objd.NumberOfCollisions = 1;
1431 //objd.lastframe = framecount;
1432 //objd.StatusIndicator = cStartStop;
1433 //m_storedCollisions.Add(cDictKey, objd);
1434 //}
1435 //}
1436 // }
1437 }
1438
1439 public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1440 {
1441 /* String name1 = null;
1442 String name2 = null;
1443
1444 if (!geom_name_map.TryGetValue(trimesh, out name1))
1445 {
1446 name1 = "null";
1447 }
1448 if (!geom_name_map.TryGetValue(refObject, out name2))
1449 {
1450 name2 = "null";
1451 }
1452
1453 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1454 */
1455 return 1;
1456 }
1457
1458 public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1459 {
1460 String name1 = null;
1461 String name2 = null;
1462
1463 if (!geom_name_map.TryGetValue(trimesh, out name1))
1464 {
1465 name1 = "null";
1466 }
1467
1468 if (!geom_name_map.TryGetValue(refObject, out name2))
1469 {
1470 name2 = "null";
1471 }
1472
1473 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1474
1475 d.Vector3 v0 = new d.Vector3();
1476 d.Vector3 v1 = new d.Vector3();
1477 d.Vector3 v2 = new d.Vector3();
1478
1479 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1480 // 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);
1481
1482 return 1;
1483 }
1484
1485 /// <summary>
1486 /// This is our collision testing routine in ODE
1487 /// </summary>
1488 /// <param name="timeStep"></param>
1489 private void collision_optimized(float timeStep)
1490 {
1491 _perloopContact.Clear();
1492
1493 lock (_characters)
1494 {
1495 foreach (OdeCharacter chr in _characters)
1496 {
1497 // Reset the collision values to false
1498 // since we don't know if we're colliding yet
1499
1500 // For some reason this can happen. Don't ask...
1501 //
1502 if (chr == null)
1503 continue;
1504
1505 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1506 continue;
1507
1508 chr.IsColliding = false;
1509 chr.CollidingGround = false;
1510 chr.CollidingObj = false;
1511
1512 // test the avatar's geometry for collision with the space
1513 // This will return near and the space that they are the closest to
1514 // And we'll run this again against the avatar and the space segment
1515 // This will return with a bunch of possible objects in the space segment
1516 // and we'll run it again on all of them.
1517 try
1518 {
1519 d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
1520 }
1521 catch (AccessViolationException)
1522 {
1523 m_log.Warn("[PHYSICS]: Unable to space collide");
1524 }
1525 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1526 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1527 //{
1528 //chr.Position.Z = terrainheight + 10.0f;
1529 //forcedZ = true;
1530 //}
1531 }
1532 }
1533
1534 lock (_activeprims)
1535 {
1536 List<OdePrim> removeprims = null;
1537 foreach (OdePrim chr in _activeprims)
1538 {
1539 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1540 {
1541 try
1542 {
1543 lock (chr)
1544 {
1545 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1546 {
1547 d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
1548 }
1549 else
1550 {
1551 if (removeprims == null)
1552 {
1553 removeprims = new List<OdePrim>();
1554 }
1555 removeprims.Add(chr);
1556 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!");
1557 }
1558 }
1559 }
1560 catch (AccessViolationException)
1561 {
1562 m_log.Warn("[PHYSICS]: Unable to space collide");
1563 }
1564 }
1565 }
1566 if (removeprims != null)
1567 {
1568 foreach (OdePrim chr in removeprims)
1569 {
1570 _activeprims.Remove(chr);
1571 }
1572 }
1573 }
1574
1575 _perloopContact.Clear();
1576 }
1577
1578 #endregion
1579
1580 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1581 {
1582 m_worldOffset = offset;
1583 WorldExtents = new Vector2(extents.X, extents.Y);
1584 m_parentScene = pScene;
1585
1586 }
1587
1588 // Recovered for use by fly height. Kitto Flora
1589 public float GetTerrainHeightAtXY(float x, float y)
1590 {
1591
1592 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1593 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1594
1595 IntPtr heightFieldGeom = IntPtr.Zero;
1596
1597 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1598 {
1599 if (heightFieldGeom != IntPtr.Zero)
1600 {
1601 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1602 {
1603
1604 int index;
1605
1606
1607 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1608 (int)x < 0.001f || (int)y < 0.001f)
1609 return 0;
1610
1611 x = x - offsetX;
1612 y = y - offsetY;
1613
1614 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1615
1616 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1617 {
1618 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1619 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1620 }
1621
1622 else
1623 return 0f;
1624 }
1625 else
1626 {
1627 return 0f;
1628 }
1629
1630 }
1631 else
1632 {
1633 return 0f;
1634 }
1635
1636 }
1637 else
1638 {
1639 return 0f;
1640 }
1641
1642
1643 }
1644// End recovered. Kitto Flora
1645
1646 public void addCollisionEventReporting(PhysicsActor obj)
1647 {
1648 lock (_collisionEventPrim)
1649 {
1650 if (!_collisionEventPrim.Contains(obj))
1651 _collisionEventPrim.Add(obj);
1652 }
1653 }
1654
1655 public void remCollisionEventReporting(PhysicsActor obj)
1656 {
1657 lock (_collisionEventPrim)
1658 {
1659 if (!_collisionEventPrim.Contains(obj))
1660 _collisionEventPrim.Remove(obj);
1661 }
1662 }
1663
1664 #region Add/Remove Entities
1665
1666 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1667 {
1668 Vector3 pos;
1669 pos.X = position.X;
1670 pos.Y = position.Y;
1671 pos.Z = position.Z;
1672 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1673 newAv.Flying = isFlying;
1674 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1675
1676 return newAv;
1677 }
1678
1679 public void AddCharacter(OdeCharacter chr)
1680 {
1681 lock (_characters)
1682 {
1683 if (!_characters.Contains(chr))
1684 {
1685 _characters.Add(chr);
1686 if (chr.bad)
1687 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1688 }
1689 }
1690 }
1691
1692 public void RemoveCharacter(OdeCharacter chr)
1693 {
1694 lock (_characters)
1695 {
1696 if (_characters.Contains(chr))
1697 {
1698 _characters.Remove(chr);
1699 }
1700 }
1701 }
1702 public void BadCharacter(OdeCharacter chr)
1703 {
1704 lock (_badCharacter)
1705 {
1706 if (!_badCharacter.Contains(chr))
1707 _badCharacter.Add(chr);
1708 }
1709 }
1710
1711 public override void RemoveAvatar(PhysicsActor actor)
1712 {
1713 //m_log.Debug("[PHYSICS]:ODELOCK");
1714 ((OdeCharacter) actor).Destroy();
1715
1716 }
1717
1718 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1719 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
1720 {
1721
1722 Vector3 pos = position;
1723 Vector3 siz = size;
1724 Quaternion rot = rotation;
1725
1726 OdePrim newPrim;
1727 lock (OdeLock)
1728 {
1729 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
1730
1731 lock (_prims)
1732 _prims.Add(newPrim);
1733 }
1734
1735 return newPrim;
1736 }
1737
1738 public void addActivePrim(OdePrim activatePrim)
1739 {
1740 // adds active prim.. (ones that should be iterated over in collisions_optimized
1741 lock (_activeprims)
1742 {
1743 if (!_activeprims.Contains(activatePrim))
1744 _activeprims.Add(activatePrim);
1745 //else
1746 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1747 }
1748 }
1749
1750 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1751 Vector3 size, Quaternion rotation) //To be removed
1752 {
1753 return AddPrimShape(primName, pbs, position, size, rotation, false);
1754 }
1755
1756 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1757 Vector3 size, Quaternion rotation, bool isPhysical)
1758 {
1759 PhysicsActor result;
1760 IMesh mesh = null;
1761
1762 if (needsMeshing(pbs))
1763 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1764
1765 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
1766
1767 return result;
1768 }
1769
1770 public override float TimeDilation
1771 {
1772 get { return m_timeDilation; }
1773 }
1774
1775 public override bool SupportsNINJAJoints
1776 {
1777 get { return m_NINJA_physics_joints_enabled; }
1778 }
1779
1780 // internal utility function: must be called within a lock (OdeLock)
1781 private void InternalAddActiveJoint(PhysicsJoint joint)
1782 {
1783 activeJoints.Add(joint);
1784 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1785 }
1786
1787 // internal utility function: must be called within a lock (OdeLock)
1788 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1789 {
1790 pendingJoints.Add(joint);
1791 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1792 }
1793
1794 // internal utility function: must be called within a lock (OdeLock)
1795 private void InternalRemovePendingJoint(PhysicsJoint joint)
1796 {
1797 pendingJoints.Remove(joint);
1798 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1799 }
1800
1801 // internal utility function: must be called within a lock (OdeLock)
1802 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1803 {
1804 activeJoints.Remove(joint);
1805 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1806 }
1807
1808 public override void DumpJointInfo()
1809 {
1810 string hdr = "[NINJA] JOINTINFO: ";
1811 foreach (PhysicsJoint j in pendingJoints)
1812 {
1813 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1814 }
1815 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1816 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1817 {
1818 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1819 }
1820 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1821 foreach (PhysicsJoint j in activeJoints)
1822 {
1823 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1824 }
1825 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1826 foreach (string jointName in SOPName_to_activeJoint.Keys)
1827 {
1828 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1829 }
1830 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1831
1832 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1833 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1834 foreach (string actorName in joints_connecting_actor.Keys)
1835 {
1836 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1837 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1838 {
1839 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1840 }
1841 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1842 }
1843 }
1844
1845 public override void RequestJointDeletion(string ObjectNameInScene)
1846 {
1847 lock (externalJointRequestsLock)
1848 {
1849 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1850 {
1851 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1852 }
1853 }
1854 }
1855
1856 private void DeleteRequestedJoints()
1857 {
1858 List<string> myRequestedJointsToBeDeleted;
1859 lock (externalJointRequestsLock)
1860 {
1861 // make a local copy of the shared list for processing (threading issues)
1862 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1863 }
1864
1865 foreach (string jointName in myRequestedJointsToBeDeleted)
1866 {
1867 lock (OdeLock)
1868 {
1869 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1870 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1871 {
1872 OdePhysicsJoint joint = null;
1873 if (SOPName_to_activeJoint.ContainsKey(jointName))
1874 {
1875 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1876 InternalRemoveActiveJoint(joint);
1877 }
1878 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1879 {
1880 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1881 InternalRemovePendingJoint(joint);
1882 }
1883
1884 if (joint != null)
1885 {
1886 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1887 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1888 {
1889 string bodyName = joint.BodyNames[iBodyName];
1890 if (bodyName != "NULL")
1891 {
1892 joints_connecting_actor[bodyName].Remove(joint);
1893 if (joints_connecting_actor[bodyName].Count == 0)
1894 {
1895 joints_connecting_actor.Remove(bodyName);
1896 }
1897 }
1898 }
1899
1900 DoJointDeactivated(joint);
1901 if (joint.jointID != IntPtr.Zero)
1902 {
1903 d.JointDestroy(joint.jointID);
1904 joint.jointID = IntPtr.Zero;
1905 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1906 }
1907 else
1908 {
1909 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1910 }
1911 }
1912 else
1913 {
1914 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1915 }
1916 }
1917 else
1918 {
1919 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1920 }
1921 }
1922 }
1923
1924 // remove processed joints from the shared list
1925 lock (externalJointRequestsLock)
1926 {
1927 foreach (string jointName in myRequestedJointsToBeDeleted)
1928 {
1929 requestedJointsToBeDeleted.Remove(jointName);
1930 }
1931 }
1932 }
1933
1934 // for pending joints we don't know if their associated bodies exist yet or not.
1935 // the joint is actually created during processing of the taints
1936 private void CreateRequestedJoints()
1937 {
1938 List<PhysicsJoint> myRequestedJointsToBeCreated;
1939 lock (externalJointRequestsLock)
1940 {
1941 // make a local copy of the shared list for processing (threading issues)
1942 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1943 }
1944
1945 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1946 {
1947 lock (OdeLock)
1948 {
1949 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1950 {
1951 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);
1952 continue;
1953 }
1954 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1955 {
1956 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);
1957 continue;
1958 }
1959
1960 InternalAddPendingJoint(joint as OdePhysicsJoint);
1961
1962 if (joint.BodyNames.Count >= 2)
1963 {
1964 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1965 {
1966 string bodyName = joint.BodyNames[iBodyName];
1967 if (bodyName != "NULL")
1968 {
1969 if (!joints_connecting_actor.ContainsKey(bodyName))
1970 {
1971 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1972 }
1973 joints_connecting_actor[bodyName].Add(joint);
1974 }
1975 }
1976 }
1977 }
1978 }
1979
1980 // remove processed joints from shared list
1981 lock (externalJointRequestsLock)
1982 {
1983 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1984 {
1985 requestedJointsToBeCreated.Remove(joint);
1986 }
1987 }
1988
1989 }
1990
1991 // public function to add an request for joint creation
1992 // this joint will just be added to a waiting list that is NOT processed during the main
1993 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
1994
1995 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
1996 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
1997
1998 {
1999
2000 OdePhysicsJoint joint = new OdePhysicsJoint();
2001 joint.ObjectNameInScene = objectNameInScene;
2002 joint.Type = jointType;
2003 joint.Position = position;
2004 joint.Rotation = rotation;
2005 joint.RawParams = parms;
2006 joint.BodyNames = new List<string>(bodyNames);
2007 joint.TrackedBodyName = trackedBodyName;
2008 joint.LocalRotation = localRotation;
2009 joint.jointID = IntPtr.Zero;
2010 joint.ErrorMessageCount = 0;
2011
2012 lock (externalJointRequestsLock)
2013 {
2014 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2015 {
2016 requestedJointsToBeCreated.Add(joint);
2017 }
2018 }
2019 return joint;
2020 }
2021
2022 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2023 {
2024 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2025 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2026 {
2027
2028 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2029 //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)
2030 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2031 {
2032 jointsToRemove.Add(j);
2033 }
2034 foreach (PhysicsJoint j in jointsToRemove)
2035 {
2036 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2037 RequestJointDeletion(j.ObjectNameInScene);
2038 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2039 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)
2040 }
2041 }
2042 }
2043
2044 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2045 {
2046 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2047 lock (OdeLock)
2048 {
2049 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2050 RemoveAllJointsConnectedToActor(actor);
2051 }
2052 }
2053
2054 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2055 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2056 {
2057 Debug.Assert(joint.IsInPhysicsEngine);
2058 d.Vector3 pos = new d.Vector3();
2059
2060 if (!(joint is OdePhysicsJoint))
2061 {
2062 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2063 }
2064 else
2065 {
2066 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2067 switch (odeJoint.Type)
2068 {
2069 case PhysicsJointType.Ball:
2070 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2071 break;
2072 case PhysicsJointType.Hinge:
2073 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2074 break;
2075 }
2076 }
2077 return new Vector3(pos.X, pos.Y, pos.Z);
2078 }
2079
2080 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2081 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2082 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2083 // keeping track of the joint's original orientation relative to one of the involved bodies.
2084 public override Vector3 GetJointAxis(PhysicsJoint joint)
2085 {
2086 Debug.Assert(joint.IsInPhysicsEngine);
2087 d.Vector3 axis = new d.Vector3();
2088
2089 if (!(joint is OdePhysicsJoint))
2090 {
2091 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2092 }
2093 else
2094 {
2095 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2096 switch (odeJoint.Type)
2097 {
2098 case PhysicsJointType.Ball:
2099 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2100 break;
2101 case PhysicsJointType.Hinge:
2102 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2103 break;
2104 }
2105 }
2106 return new Vector3(axis.X, axis.Y, axis.Z);
2107 }
2108
2109
2110 public void remActivePrim(OdePrim deactivatePrim)
2111 {
2112 lock (_activeprims)
2113 {
2114 _activeprims.Remove(deactivatePrim);
2115 }
2116 }
2117
2118 public override void RemovePrim(PhysicsActor prim)
2119 {
2120 if (prim is OdePrim)
2121 {
2122 lock (OdeLock)
2123 {
2124 OdePrim p = (OdePrim) prim;
2125
2126 p.setPrimForRemoval();
2127 AddPhysicsActorTaint(prim);
2128 //RemovePrimThreadLocked(p);
2129 }
2130 }
2131 }
2132
2133 /// <summary>
2134 /// This is called from within simulate but outside the locked portion
2135 /// We need to do our own locking here
2136 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2137 ///
2138 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2139 /// that the space was using.
2140 /// </summary>
2141 /// <param name="prim"></param>
2142 public void RemovePrimThreadLocked(OdePrim prim)
2143 {
2144//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2145 lock (prim)
2146 {
2147 remCollisionEventReporting(prim);
2148 lock (ode)
2149 {
2150 if (prim.prim_geom != IntPtr.Zero)
2151 {
2152 prim.ResetTaints();
2153
2154 if (prim.IsPhysical)
2155 {
2156 prim.disableBody();
2157 if (prim.childPrim)
2158 {
2159 prim.childPrim = false;
2160 prim.Body = IntPtr.Zero;
2161 prim.m_disabled = true;
2162 prim.IsPhysical = false;
2163 }
2164
2165
2166 }
2167 // we don't want to remove the main space
2168
2169 // If the geometry is in the targetspace, remove it from the target space
2170 //m_log.Warn(prim.m_targetSpace);
2171
2172 //if (prim.m_targetSpace != IntPtr.Zero)
2173 //{
2174 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2175 //{
2176
2177 //if (d.GeomIsSpace(prim.m_targetSpace))
2178 //{
2179 //waitForSpaceUnlock(prim.m_targetSpace);
2180 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2181 prim.m_targetSpace = IntPtr.Zero;
2182 //}
2183 //else
2184 //{
2185 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2186 //((OdePrim)prim).m_targetSpace.ToString());
2187 //}
2188
2189 //}
2190 //}
2191 //m_log.Warn(prim.prim_geom);
2192 try
2193 {
2194 if (prim.prim_geom != IntPtr.Zero)
2195 {
2196
2197//string tPA;
2198//geom_name_map.TryGetValue(prim.prim_geom, out tPA);
2199//Console.WriteLine("**** Remove {0}", tPA);
2200 if(geom_name_map.ContainsKey(prim.prim_geom)) geom_name_map.Remove(prim.prim_geom);
2201 if(actor_name_map.ContainsKey(prim.prim_geom)) actor_name_map.Remove(prim.prim_geom);
2202 d.GeomDestroy(prim.prim_geom);
2203 prim.prim_geom = IntPtr.Zero;
2204 }
2205 else
2206 {
2207 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2208 }
2209 }
2210 catch (AccessViolationException)
2211 {
2212 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2213 }
2214 lock (_prims)
2215 _prims.Remove(prim);
2216
2217 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2218 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2219 //{
2220 //if (prim.m_targetSpace != null)
2221 //{
2222 //if (d.GeomIsSpace(prim.m_targetSpace))
2223 //{
2224 //waitForSpaceUnlock(prim.m_targetSpace);
2225 //d.SpaceRemove(space, prim.m_targetSpace);
2226 // free up memory used by the space.
2227 //d.SpaceDestroy(prim.m_targetSpace);
2228 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2229 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2230 //}
2231 //else
2232 //{
2233 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2234 //((OdePrim) prim).m_targetSpace.ToString());
2235 //}
2236 //}
2237 //}
2238
2239 if (SupportsNINJAJoints)
2240 {
2241 RemoveAllJointsConnectedToActorThreadLocked(prim);
2242 }
2243 }
2244 }
2245 }
2246 }
2247
2248 #endregion
2249
2250 #region Space Separation Calculation
2251
2252 /// <summary>
2253 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2254 /// </summary>
2255 /// <param name="pSpace"></param>
2256 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2257 {
2258 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2259 {
2260 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2261 {
2262 if (staticPrimspace[x, y] == pSpace)
2263 staticPrimspace[x, y] = IntPtr.Zero;
2264 }
2265 }
2266 }
2267
2268 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2269 {
2270 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2271 }
2272
2273 /// <summary>
2274 /// Called when a static prim moves. Allocates a space for the prim based on its position
2275 /// </summary>
2276 /// <param name="geom">the pointer to the geom that moved</param>
2277 /// <param name="pos">the position that the geom moved to</param>
2278 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2279 /// <returns>a pointer to the new space it's in</returns>
2280 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2281 {
2282 // Called from setting the Position and Size of an ODEPrim so
2283 // it's already in locked space.
2284
2285 // we don't want to remove the main space
2286 // we don't need to test physical here because this function should
2287 // never be called if the prim is physical(active)
2288
2289 // All physical prim end up in the root space
2290 //Thread.Sleep(20);
2291 if (currentspace != space)
2292 {
2293 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2294 //if (currentspace == IntPtr.Zero)
2295 //{
2296 //int adfadf = 0;
2297 //}
2298 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2299 {
2300 if (d.GeomIsSpace(currentspace))
2301 {
2302 waitForSpaceUnlock(currentspace);
2303 d.SpaceRemove(currentspace, geom);
2304 }
2305 else
2306 {
2307 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2308 " Geom:" + geom);
2309 }
2310 }
2311 else
2312 {
2313 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2314 if (sGeomIsIn != IntPtr.Zero)
2315 {
2316 if (d.GeomIsSpace(currentspace))
2317 {
2318 waitForSpaceUnlock(sGeomIsIn);
2319 d.SpaceRemove(sGeomIsIn, geom);
2320 }
2321 else
2322 {
2323 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2324 sGeomIsIn + " Geom:" + geom);
2325 }
2326 }
2327 }
2328
2329 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2330 if (d.SpaceGetNumGeoms(currentspace) == 0)
2331 {
2332 if (currentspace != IntPtr.Zero)
2333 {
2334 if (d.GeomIsSpace(currentspace))
2335 {
2336 waitForSpaceUnlock(currentspace);
2337 waitForSpaceUnlock(space);
2338 d.SpaceRemove(space, currentspace);
2339 // free up memory used by the space.
2340
2341 //d.SpaceDestroy(currentspace);
2342 resetSpaceArrayItemToZero(currentspace);
2343 }
2344 else
2345 {
2346 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2347 currentspace + " Geom:" + geom);
2348 }
2349 }
2350 }
2351 }
2352 else
2353 {
2354 // this is a physical object that got disabled. ;.;
2355 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2356 {
2357 if (d.SpaceQuery(currentspace, geom))
2358 {
2359 if (d.GeomIsSpace(currentspace))
2360 {
2361 waitForSpaceUnlock(currentspace);
2362 d.SpaceRemove(currentspace, geom);
2363 }
2364 else
2365 {
2366 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2367 currentspace + " Geom:" + geom);
2368 }
2369 }
2370 else
2371 {
2372 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2373 if (sGeomIsIn != IntPtr.Zero)
2374 {
2375 if (d.GeomIsSpace(sGeomIsIn))
2376 {
2377 waitForSpaceUnlock(sGeomIsIn);
2378 d.SpaceRemove(sGeomIsIn, geom);
2379 }
2380 else
2381 {
2382 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2383 sGeomIsIn + " Geom:" + geom);
2384 }
2385 }
2386 }
2387 }
2388 }
2389
2390 // The routines in the Position and Size sections do the 'inserting' into the space,
2391 // so all we have to do is make sure that the space that we're putting the prim into
2392 // is in the 'main' space.
2393 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2394 IntPtr newspace = calculateSpaceForGeom(pos);
2395
2396 if (newspace == IntPtr.Zero)
2397 {
2398 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2399 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2400 }
2401
2402 return newspace;
2403 }
2404
2405 /// <summary>
2406 /// Creates a new space at X Y
2407 /// </summary>
2408 /// <param name="iprimspaceArrItemX"></param>
2409 /// <param name="iprimspaceArrItemY"></param>
2410 /// <returns>A pointer to the created space</returns>
2411 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2412 {
2413 // creating a new space for prim and inserting it into main space.
2414 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2415 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2416 waitForSpaceUnlock(space);
2417 d.SpaceSetSublevel(space, 1);
2418 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2419 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2420 }
2421
2422 /// <summary>
2423 /// Calculates the space the prim should be in by its position
2424 /// </summary>
2425 /// <param name="pos"></param>
2426 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2427 public IntPtr calculateSpaceForGeom(Vector3 pos)
2428 {
2429 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2430 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2431 return staticPrimspace[xyspace[0], xyspace[1]];
2432 }
2433
2434 /// <summary>
2435 /// Holds the space allocation logic
2436 /// </summary>
2437 /// <param name="pos"></param>
2438 /// <returns>an array item based on the position</returns>
2439 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2440 {
2441 int[] returnint = new int[2];
2442
2443 returnint[0] = (int) (pos.X/metersInSpace);
2444
2445 if (returnint[0] > ((int) (259f/metersInSpace)))
2446 returnint[0] = ((int) (259f/metersInSpace));
2447 if (returnint[0] < 0)
2448 returnint[0] = 0;
2449
2450 returnint[1] = (int) (pos.Y/metersInSpace);
2451 if (returnint[1] > ((int) (259f/metersInSpace)))
2452 returnint[1] = ((int) (259f/metersInSpace));
2453 if (returnint[1] < 0)
2454 returnint[1] = 0;
2455
2456 return returnint;
2457 }
2458
2459 #endregion
2460
2461 /// <summary>
2462 /// Routine to figure out if we need to mesh this prim with our mesher
2463 /// </summary>
2464 /// <param name="pbs"></param>
2465 /// <returns></returns>
2466 public bool needsMeshing(PrimitiveBaseShape pbs)
2467 {
2468 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2469 // but we still need to check for sculptie meshing being enabled so this is the most
2470 // convenient place to do it for now...
2471
2472 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2473 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2474 int iPropertiesNotSupportedDefault = 0;
2475
2476 if (pbs.SculptEntry && !meshSculptedPrim)
2477 {
2478#if SPAM
2479 m_log.Warn("NonMesh");
2480#endif
2481 return false;
2482 }
2483
2484 // 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
2485 if (!forceSimplePrimMeshing)
2486 {
2487 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2488 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2489 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2490 {
2491
2492 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2493 && pbs.ProfileHollow == 0
2494 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2495 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2496 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2497 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2498 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2499 {
2500#if SPAM
2501 m_log.Warn("NonMesh");
2502#endif
2503 return false;
2504 }
2505 }
2506 }
2507
2508 if (pbs.ProfileHollow != 0)
2509 iPropertiesNotSupportedDefault++;
2510
2511 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2512 iPropertiesNotSupportedDefault++;
2513
2514 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2515 iPropertiesNotSupportedDefault++;
2516
2517 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2518 iPropertiesNotSupportedDefault++;
2519
2520 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2521 iPropertiesNotSupportedDefault++;
2522
2523 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2524 iPropertiesNotSupportedDefault++;
2525
2526 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))
2527 iPropertiesNotSupportedDefault++;
2528
2529 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2530 iPropertiesNotSupportedDefault++;
2531
2532 // test for torus
2533 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2534 {
2535 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2536 {
2537 iPropertiesNotSupportedDefault++;
2538 }
2539 }
2540 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2541 {
2542 if (pbs.PathCurve == (byte)Extrusion.Straight)
2543 {
2544 iPropertiesNotSupportedDefault++;
2545 }
2546
2547 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2548 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2549 {
2550 iPropertiesNotSupportedDefault++;
2551 }
2552 }
2553 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2554 {
2555 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2556 {
2557 iPropertiesNotSupportedDefault++;
2558 }
2559 }
2560 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2561 {
2562 if (pbs.PathCurve == (byte)Extrusion.Straight)
2563 {
2564 iPropertiesNotSupportedDefault++;
2565 }
2566 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2567 {
2568 iPropertiesNotSupportedDefault++;
2569 }
2570 }
2571
2572
2573 if (iPropertiesNotSupportedDefault == 0)
2574 {
2575#if SPAM
2576 m_log.Warn("NonMesh");
2577#endif
2578 return false;
2579 }
2580#if SPAM
2581 m_log.Debug("Mesh");
2582#endif
2583 return true;
2584 }
2585
2586 /// <summary>
2587 /// Called after our prim properties are set Scale, position etc.
2588 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2589 /// This assures us that we have no race conditions
2590 /// </summary>
2591 /// <param name="prim"></param>
2592 public override void AddPhysicsActorTaint(PhysicsActor prim)
2593 {
2594
2595 if (prim is OdePrim)
2596 {
2597 OdePrim taintedprim = ((OdePrim) prim);
2598 lock (_taintedPrimLock)
2599 {
2600 if (!(_taintedPrimH.Contains(taintedprim)))
2601 {
2602//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2603 _taintedPrimH.Add(taintedprim); // HashSet for searching
2604 _taintedPrimL.Add(taintedprim); // List for ordered readout
2605 }
2606 }
2607 return;
2608 }
2609 else if (prim is OdeCharacter)
2610 {
2611 OdeCharacter taintedchar = ((OdeCharacter)prim);
2612 lock (_taintedActors)
2613 {
2614 if (!(_taintedActors.Contains(taintedchar)))
2615 {
2616 _taintedActors.Add(taintedchar);
2617 if (taintedchar.bad)
2618 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2619 }
2620 }
2621 }
2622 }
2623
2624 /// <summary>
2625 /// This is our main simulate loop
2626 /// It's thread locked by a Mutex in the scene.
2627 /// It holds Collisions, it instructs ODE to step through the physical reactions
2628 /// It moves the objects around in memory
2629 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2630 /// </summary>
2631 /// <param name="timeStep"></param>
2632 /// <returns></returns>
2633 public override float Simulate(float timeStep)
2634 {
2635 if (framecount >= int.MaxValue)
2636 framecount = 0;
2637 //if (m_worldOffset != Vector3.Zero)
2638 // return 0;
2639
2640 framecount++;
2641
2642 DateTime now = DateTime.UtcNow;
2643 TimeSpan SinceLastFrame = now - m_lastframe;
2644 m_lastframe = now;
2645 float realtime = (float)SinceLastFrame.TotalSeconds;
2646// Console.WriteLine("ts={0} rt={1}", timeStep, realtime);
2647 timeStep = realtime;
2648
2649 // float fps = 1.0f / realtime;
2650 float fps = 0.0f; // number of ODE steps in this Simulate step
2651 //m_log.Info(timeStep.ToString());
2652 step_time += timeStep;
2653
2654 // If We're loaded down by something else,
2655 // or debugging with the Visual Studio project on pause
2656 // skip a few frames to catch up gracefully.
2657 // without shooting the physicsactors all over the place
2658
2659 if (step_time >= m_SkipFramesAtms)
2660 {
2661 // Instead of trying to catch up, it'll do 5 physics frames only
2662 step_time = ODE_STEPSIZE;
2663 m_physicsiterations = 5;
2664 }
2665 else
2666 {
2667 m_physicsiterations = 10;
2668 }
2669
2670 if (SupportsNINJAJoints)
2671 {
2672 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2673 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2674 }
2675
2676 lock (OdeLock)
2677 {
2678 // Process 10 frames if the sim is running normal..
2679 // process 5 frames if the sim is running slow
2680 //try
2681 //{
2682 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2683 //}
2684 //catch (StackOverflowException)
2685 //{
2686 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2687 // ode.drelease(world);
2688 //base.TriggerPhysicsBasedRestart();
2689 //}
2690
2691 int i = 0;
2692
2693 // Figure out the Frames Per Second we're going at.
2694 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2695
2696 // fps = (step_time / ODE_STEPSIZE) * 1000;
2697 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2698 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2699
2700 // step_time = 0.09375f;
2701
2702 while (step_time > 0.0f)
2703 {
2704 //lock (ode)
2705 //{
2706 //if (!ode.lockquery())
2707 //{
2708 // ode.dlock(world);
2709 try
2710 {
2711 // Insert, remove Characters
2712 bool processedtaints = false;
2713
2714 lock (_taintedActors)
2715 {
2716 if (_taintedActors.Count > 0)
2717 {
2718 foreach (OdeCharacter character in _taintedActors)
2719 {
2720
2721 character.ProcessTaints(ODE_STEPSIZE);
2722
2723 processedtaints = true;
2724 //character.m_collisionscore = 0;
2725 }
2726
2727 if (processedtaints)
2728 _taintedActors.Clear();
2729 }
2730 } // end lock _taintedActors
2731
2732 // Modify other objects in the scene.
2733 processedtaints = false;
2734
2735 lock (_taintedPrimLock)
2736 {
2737 foreach (OdePrim prim in _taintedPrimL)
2738 {
2739 if (prim.m_taintremove)
2740 {
2741 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2742 RemovePrimThreadLocked(prim);
2743 }
2744 else
2745 {
2746 //Console.WriteLine("Simulate calls ProcessTaints");
2747 prim.ProcessTaints(ODE_STEPSIZE);
2748 }
2749 processedtaints = true;
2750 prim.m_collisionscore = 0;
2751
2752 // This loop can block up the Heartbeat for a very long time on large regions.
2753 // We need to let the Watchdog know that the Heartbeat is not dead
2754 // NOTE: This is currently commented out, but if things like OAR loading are
2755 // timing the heartbeat out we will need to uncomment it
2756 //Watchdog.UpdateThread();
2757 }
2758
2759 if (SupportsNINJAJoints)
2760 {
2761 // Create pending joints, if possible
2762
2763 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2764 // a joint requires specifying the body id of both involved bodies
2765 if (pendingJoints.Count > 0)
2766 {
2767 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2768 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2769 foreach (PhysicsJoint joint in pendingJoints)
2770 {
2771 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2772 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(),
2773 System.StringSplitOptions.RemoveEmptyEntries);
2774 List<IntPtr> jointBodies = new List<IntPtr>();
2775 bool allJointBodiesAreReady = true;
2776 foreach (string jointParam in jointParams)
2777 {
2778 if (jointParam == "NULL")
2779 {
2780 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2781 jointBodies.Add(IntPtr.Zero);
2782 }
2783 else
2784 {
2785 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2786 bool foundPrim = false;
2787 lock (_prims)
2788 {
2789 foreach (OdePrim prim in _prims) // FIXME: inefficient
2790 {
2791 if (prim.SOPName == jointParam)
2792 {
2793 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2794 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2795 {
2796 jointBodies.Add(prim.Body);
2797 foundPrim = true;
2798 break;
2799 }
2800 else
2801 {
2802 DoJointErrorMessage(joint, "prim name " + jointParam +
2803 " exists but is not (yet) physical; deferring joint creation. " +
2804 "IsPhysical property is " + prim.IsPhysical +
2805 " and body is " + prim.Body);
2806 foundPrim = false;
2807 break;
2808 }
2809 }
2810 }
2811 }
2812 if (foundPrim)
2813 {
2814 // all is fine
2815 }
2816 else
2817 {
2818 allJointBodiesAreReady = false;
2819 break;
2820 }
2821 }
2822 }
2823 if (allJointBodiesAreReady)
2824 {
2825 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2826 if (jointBodies[0] == jointBodies[1])
2827 {
2828 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2829 }
2830 else
2831 {
2832 switch (joint.Type)
2833 {
2834 case PhysicsJointType.Ball:
2835 {
2836 IntPtr odeJoint;
2837 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2838 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2839 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2840 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2841 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2842 d.JointSetBallAnchor(odeJoint,
2843 joint.Position.X,
2844 joint.Position.Y,
2845 joint.Position.Z);
2846 //DoJointErrorMessage(joint, "ODE joint setting OK");
2847 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2848 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2849 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2850 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2851
2852 if (joint is OdePhysicsJoint)
2853 {
2854 ((OdePhysicsJoint)joint).jointID = odeJoint;
2855 }
2856 else
2857 {
2858 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2859 }
2860 }
2861 break;
2862 case PhysicsJointType.Hinge:
2863 {
2864 IntPtr odeJoint;
2865 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2866 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2867 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2868 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2869 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2870 d.JointSetHingeAnchor(odeJoint,
2871 joint.Position.X,
2872 joint.Position.Y,
2873 joint.Position.Z);
2874 // We use the orientation of the x-axis of the joint's coordinate frame
2875 // as the axis for the hinge.
2876
2877 // Therefore, we must get the joint's coordinate frame based on the
2878 // joint.Rotation field, which originates from the orientation of the
2879 // joint's proxy object in the scene.
2880
2881 // The joint's coordinate frame is defined as the transformation matrix
2882 // that converts a vector from joint-local coordinates into world coordinates.
2883 // World coordinates are defined as the XYZ coordinate system of the sim,
2884 // as shown in the top status-bar of the viewer.
2885
2886 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2887 // and use that as the hinge axis.
2888
2889 //joint.Rotation.Normalize();
2890 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2891
2892 // Now extract the X axis of the joint's coordinate frame.
2893
2894 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2895 // tar pit of transposed, inverted, and generally messed-up orientations.
2896 // (In other words, Matrix4.AtAxis() is borked.)
2897 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2898
2899 // Instead, compute the X axis of the coordinate frame by transforming
2900 // the (1,0,0) vector. At least that works.
2901
2902 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2903 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2904 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2905 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2906 d.JointSetHingeAxis(odeJoint,
2907 jointAxis.X,
2908 jointAxis.Y,
2909 jointAxis.Z);
2910 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2911 if (joint is OdePhysicsJoint)
2912 {
2913 ((OdePhysicsJoint)joint).jointID = odeJoint;
2914 }
2915 else
2916 {
2917 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2918 }
2919 }
2920 break;
2921 }
2922 successfullyProcessedPendingJoints.Add(joint);
2923 }
2924 }
2925 else
2926 {
2927 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2928 }
2929 }
2930 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2931 {
2932 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2933 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2934 InternalRemovePendingJoint(successfullyProcessedJoint);
2935 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2936 InternalAddActiveJoint(successfullyProcessedJoint);
2937 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2938 }
2939 }
2940 } // end SupportsNINJAJoints
2941
2942 if (processedtaints)
2943//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2944 _taintedPrimH.Clear(); // ??? if this only ???
2945 _taintedPrimL.Clear();
2946 } // end lock _taintedPrimLock
2947
2948 // Move characters
2949 lock (_characters)
2950 {
2951 List<OdeCharacter> defects = new List<OdeCharacter>();
2952 foreach (OdeCharacter actor in _characters)
2953 {
2954 if (actor != null)
2955 actor.Move(ODE_STEPSIZE, defects);
2956 }
2957 if (0 != defects.Count)
2958 {
2959 foreach (OdeCharacter defect in defects)
2960 {
2961 RemoveCharacter(defect);
2962 }
2963 }
2964 } // end lock _characters
2965
2966 // Move other active objects
2967 lock (_activeprims)
2968 {
2969 foreach (OdePrim prim in _activeprims)
2970 {
2971 prim.m_collisionscore = 0;
2972 prim.Move(ODE_STEPSIZE);
2973 }
2974 } // end lock _activeprims
2975
2976 //if ((framecount % m_randomizeWater) == 0)
2977 // randomizeWater(waterlevel);
2978
2979 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2980 m_rayCastManager.ProcessQueuedRequests();
2981
2982 collision_optimized(ODE_STEPSIZE);
2983
2984 lock (_collisionEventPrim)
2985 {
2986 foreach (PhysicsActor obj in _collisionEventPrim)
2987 {
2988 if (obj == null)
2989 continue;
2990
2991 switch ((ActorTypes)obj.PhysicsActorType)
2992 {
2993 case ActorTypes.Agent:
2994 OdeCharacter cobj = (OdeCharacter)obj;
2995 cobj.AddCollisionFrameTime(100);
2996 cobj.SendCollisions();
2997 break;
2998 case ActorTypes.Prim:
2999 OdePrim pobj = (OdePrim)obj;
3000 pobj.SendCollisions();
3001 break;
3002 }
3003 }
3004 } // end lock _collisionEventPrim
3005
3006 //if (m_global_contactcount > 5)
3007 //{
3008 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3009 //}
3010
3011 m_global_contactcount = 0;
3012
3013 d.WorldQuickStep(world, ODE_STEPSIZE);
3014 d.JointGroupEmpty(contactgroup);
3015 fps++;
3016 //ode.dunlock(world);
3017 } // end try
3018 catch (Exception e)
3019 {
3020 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3021 ode.dunlock(world);
3022 }
3023
3024 step_time -= ODE_STEPSIZE;
3025 i++;
3026 //}
3027 //else
3028 //{
3029 //fps = 0;
3030 //}
3031 //}
3032 } // end while (step_time > 0.0f)
3033
3034 lock (_characters)
3035 {
3036 foreach (OdeCharacter actor in _characters)
3037 {
3038 if (actor != null)
3039 {
3040 if (actor.bad)
3041 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3042 actor.UpdatePositionAndVelocity();
3043 }
3044 }
3045 }
3046
3047 lock (_badCharacter)
3048 {
3049 if (_badCharacter.Count > 0)
3050 {
3051 foreach (OdeCharacter chr in _badCharacter)
3052 {
3053 RemoveCharacter(chr);
3054 }
3055 _badCharacter.Clear();
3056 }
3057 }
3058
3059 lock (_activeprims)
3060 {
3061 //if (timeStep < 0.2f)
3062 {
3063 foreach (OdePrim actor in _activeprims)
3064 {
3065 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3066 {
3067 actor.UpdatePositionAndVelocity();
3068
3069 if (SupportsNINJAJoints)
3070 {
3071 // If an actor moved, move its joint proxy objects as well.
3072 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3073 // for this purpose but it is never called! So we just do the joint
3074 // movement code here.
3075
3076 if (actor.SOPName != null &&
3077 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3078 joints_connecting_actor[actor.SOPName] != null &&
3079 joints_connecting_actor[actor.SOPName].Count > 0)
3080 {
3081 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3082 {
3083 if (affectedJoint.IsInPhysicsEngine)
3084 {
3085 DoJointMoved(affectedJoint);
3086 }
3087 else
3088 {
3089 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);
3090 }
3091 }
3092 }
3093 }
3094 }
3095 }
3096 }
3097 } // end lock _activeprims
3098
3099 //DumpJointInfo();
3100
3101 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3102 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3103 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3104 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3105 {
3106 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3107 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3108
3109 if (physics_logging_append_existing_logfile)
3110 {
3111 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3112 TextWriter fwriter = File.AppendText(fname);
3113 fwriter.WriteLine(header);
3114 fwriter.Close();
3115 }
3116 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3117 }
3118 } // end lock OdeLock
3119
3120 return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter!
3121 } // end Simulate
3122
3123 public override void GetResults()
3124 {
3125 }
3126
3127 public override bool IsThreaded
3128 {
3129 // for now we won't be multithreaded
3130 get { return (false); }
3131 }
3132
3133 #region ODE Specific Terrain Fixes
3134 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3135 {
3136 float[] returnarr = new float[262144];
3137 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3138
3139 // Filling out the array into its multi-dimensional components
3140 for (int y = 0; y < WorldExtents.Y; y++)
3141 {
3142 for (int x = 0; x < WorldExtents.X; x++)
3143 {
3144 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3145 }
3146 }
3147
3148 // Resize using Nearest Neighbour
3149
3150 // This particular way is quick but it only works on a multiple of the original
3151
3152 // The idea behind this method can be described with the following diagrams
3153 // second pass and third pass happen in the same loop really.. just separated
3154 // them to show what this does.
3155
3156 // First Pass
3157 // ResultArr:
3158 // 1,1,1,1,1,1
3159 // 1,1,1,1,1,1
3160 // 1,1,1,1,1,1
3161 // 1,1,1,1,1,1
3162 // 1,1,1,1,1,1
3163 // 1,1,1,1,1,1
3164
3165 // Second Pass
3166 // ResultArr2:
3167 // 1,,1,,1,,1,,1,,1,
3168 // ,,,,,,,,,,
3169 // 1,,1,,1,,1,,1,,1,
3170 // ,,,,,,,,,,
3171 // 1,,1,,1,,1,,1,,1,
3172 // ,,,,,,,,,,
3173 // 1,,1,,1,,1,,1,,1,
3174 // ,,,,,,,,,,
3175 // 1,,1,,1,,1,,1,,1,
3176 // ,,,,,,,,,,
3177 // 1,,1,,1,,1,,1,,1,
3178
3179 // Third pass fills in the blanks
3180 // ResultArr2:
3181 // 1,1,1,1,1,1,1,1,1,1,1,1
3182 // 1,1,1,1,1,1,1,1,1,1,1,1
3183 // 1,1,1,1,1,1,1,1,1,1,1,1
3184 // 1,1,1,1,1,1,1,1,1,1,1,1
3185 // 1,1,1,1,1,1,1,1,1,1,1,1
3186 // 1,1,1,1,1,1,1,1,1,1,1,1
3187 // 1,1,1,1,1,1,1,1,1,1,1,1
3188 // 1,1,1,1,1,1,1,1,1,1,1,1
3189 // 1,1,1,1,1,1,1,1,1,1,1,1
3190 // 1,1,1,1,1,1,1,1,1,1,1,1
3191 // 1,1,1,1,1,1,1,1,1,1,1,1
3192
3193 // X,Y = .
3194 // X+1,y = ^
3195 // X,Y+1 = *
3196 // X+1,Y+1 = #
3197
3198 // Filling in like this;
3199 // .*
3200 // ^#
3201 // 1st .
3202 // 2nd *
3203 // 3rd ^
3204 // 4th #
3205 // on single loop.
3206
3207 float[,] resultarr2 = new float[512, 512];
3208 for (int y = 0; y < WorldExtents.Y; y++)
3209 {
3210 for (int x = 0; x < WorldExtents.X; x++)
3211 {
3212 resultarr2[y * 2, x * 2] = resultarr[y, x];
3213
3214 if (y < WorldExtents.Y)
3215 {
3216 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3217 }
3218 if (x < WorldExtents.X)
3219 {
3220 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3221 }
3222 if (x < WorldExtents.X && y < WorldExtents.Y)
3223 {
3224 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3225 }
3226 }
3227 }
3228
3229 //Flatten out the array
3230 int i = 0;
3231 for (int y = 0; y < 512; y++)
3232 {
3233 for (int x = 0; x < 512; x++)
3234 {
3235 if (resultarr2[y, x] <= 0)
3236 returnarr[i] = 0.0000001f;
3237 else
3238 returnarr[i] = resultarr2[y, x];
3239
3240 i++;
3241 }
3242 }
3243
3244 return returnarr;
3245 }
3246
3247 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3248 {
3249 float[] returnarr = new float[262144];
3250 float[,] resultarr = new float[512,512];
3251
3252 // Filling out the array into its multi-dimensional components
3253 for (int y = 0; y < 256; y++)
3254 {
3255 for (int x = 0; x < 256; x++)
3256 {
3257 resultarr[y, x] = heightMap[y * 256 + x];
3258 }
3259 }
3260
3261 // Resize using interpolation
3262
3263 // This particular way is quick but it only works on a multiple of the original
3264
3265 // The idea behind this method can be described with the following diagrams
3266 // second pass and third pass happen in the same loop really.. just separated
3267 // them to show what this does.
3268
3269 // First Pass
3270 // ResultArr:
3271 // 1,1,1,1,1,1
3272 // 1,1,1,1,1,1
3273 // 1,1,1,1,1,1
3274 // 1,1,1,1,1,1
3275 // 1,1,1,1,1,1
3276 // 1,1,1,1,1,1
3277
3278 // Second Pass
3279 // ResultArr2:
3280 // 1,,1,,1,,1,,1,,1,
3281 // ,,,,,,,,,,
3282 // 1,,1,,1,,1,,1,,1,
3283 // ,,,,,,,,,,
3284 // 1,,1,,1,,1,,1,,1,
3285 // ,,,,,,,,,,
3286 // 1,,1,,1,,1,,1,,1,
3287 // ,,,,,,,,,,
3288 // 1,,1,,1,,1,,1,,1,
3289 // ,,,,,,,,,,
3290 // 1,,1,,1,,1,,1,,1,
3291
3292 // Third pass fills in the blanks
3293 // ResultArr2:
3294 // 1,1,1,1,1,1,1,1,1,1,1,1
3295 // 1,1,1,1,1,1,1,1,1,1,1,1
3296 // 1,1,1,1,1,1,1,1,1,1,1,1
3297 // 1,1,1,1,1,1,1,1,1,1,1,1
3298 // 1,1,1,1,1,1,1,1,1,1,1,1
3299 // 1,1,1,1,1,1,1,1,1,1,1,1
3300 // 1,1,1,1,1,1,1,1,1,1,1,1
3301 // 1,1,1,1,1,1,1,1,1,1,1,1
3302 // 1,1,1,1,1,1,1,1,1,1,1,1
3303 // 1,1,1,1,1,1,1,1,1,1,1,1
3304 // 1,1,1,1,1,1,1,1,1,1,1,1
3305
3306 // X,Y = .
3307 // X+1,y = ^
3308 // X,Y+1 = *
3309 // X+1,Y+1 = #
3310
3311 // Filling in like this;
3312 // .*
3313 // ^#
3314 // 1st .
3315 // 2nd *
3316 // 3rd ^
3317 // 4th #
3318 // on single loop.
3319
3320 float[,] resultarr2 = new float[512,512];
3321 for (int y = 0; y < (int)Constants.RegionSize; y++)
3322 {
3323 for (int x = 0; x < (int)Constants.RegionSize; x++)
3324 {
3325 resultarr2[y*2, x*2] = resultarr[y, x];
3326
3327 if (y < (int)Constants.RegionSize)
3328 {
3329 if (y + 1 < (int)Constants.RegionSize)
3330 {
3331 if (x + 1 < (int)Constants.RegionSize)
3332 {
3333 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3334 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3335 }
3336 else
3337 {
3338 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3339 }
3340 }
3341 else
3342 {
3343 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3344 }
3345 }
3346 if (x < (int)Constants.RegionSize)
3347 {
3348 if (x + 1 < (int)Constants.RegionSize)
3349 {
3350 if (y + 1 < (int)Constants.RegionSize)
3351 {
3352 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3353 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3354 }
3355 else
3356 {
3357 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3358 }
3359 }
3360 else
3361 {
3362 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3363 }
3364 }
3365 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3366 {
3367 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3368 {
3369 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3370 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3371 }
3372 else
3373 {
3374 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3375 }
3376 }
3377 }
3378 }
3379 //Flatten out the array
3380 int i = 0;
3381 for (int y = 0; y < 512; y++)
3382 {
3383 for (int x = 0; x < 512; x++)
3384 {
3385 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3386 {
3387 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3388 resultarr2[y, x] = 0;
3389 }
3390 returnarr[i] = resultarr2[y, x];
3391 i++;
3392 }
3393 }
3394
3395 return returnarr;
3396 }
3397
3398 #endregion
3399
3400 public override void SetTerrain(float[] heightMap)
3401 {
3402 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3403 {
3404 if (m_parentScene is OdeScene)
3405 {
3406 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3407 }
3408 }
3409 else
3410 {
3411 SetTerrain(heightMap, m_worldOffset);
3412 }
3413 }
3414
3415 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3416 {
3417
3418 uint regionsize = (uint) Constants.RegionSize; // visible region size eg. 256(M)
3419
3420 uint heightmapWidth = regionsize + 1; // ODE map size 257 x 257 (Meters) (1 extra
3421 uint heightmapHeight = regionsize + 1;
3422
3423 uint heightmapWidthSamples = (uint)regionsize + 2; // Sample file size, 258 x 258 samples
3424 uint heightmapHeightSamples = (uint)regionsize + 2;
3425
3426 // Array of height samples for ODE
3427 float[] _heightmap;
3428 _heightmap = new float[(heightmapWidthSamples * heightmapHeightSamples)]; // loaded samples 258 x 258
3429
3430 // Other ODE parameters
3431 const float scale = 1.0f;
3432 const float offset = 0.0f;
3433 const float thickness = 2.0f; // Was 0.2f, Larger appears to prevent Av fall-through
3434 const int wrap = 0;
3435
3436 float hfmin = 2000f;
3437 float hfmax = -2000f;
3438 float minele = 0.0f; // Dont allow -ve heights
3439
3440 uint x = 0;
3441 uint y = 0;
3442 uint xx = 0;
3443 uint yy = 0;
3444
3445 // load the height samples array from the heightMap
3446 for ( x = 0; x < heightmapWidthSamples; x++) // 0 to 257
3447 {
3448 for ( y = 0; y < heightmapHeightSamples; y++) // 0 to 257
3449 {
3450 xx = x - 1;
3451 if (xx < 0) xx = 0;
3452 if (xx > (regionsize - 1)) xx = regionsize - 1;
3453
3454 yy = y - 1;
3455 if (yy < 0) yy = 0;
3456 if (yy > (regionsize - 1)) yy = regionsize - 1;
3457 // Input xx = 0 0 1 2 ..... 254 255 255 256 total in
3458 // Output x = 0 1 2 3 ..... 255 256 257 258 total out
3459 float val= heightMap[(yy * regionsize) + xx]; // input from heightMap, <0-255 * 256> <0-255>
3460 if (val < minele) val = minele;
3461 _heightmap[x * (regionsize + 2) + y] = val; // samples output to _heightmap, <0-257 * 258> <0-257>
3462 hfmin = (val < hfmin) ? val : hfmin;
3463 hfmax = (val > hfmax) ? val : hfmax;
3464 }
3465 }
3466
3467 lock (OdeLock)
3468 {
3469 IntPtr GroundGeom = IntPtr.Zero;
3470 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3471 {
3472 RegionTerrain.Remove(pOffset);
3473 if (GroundGeom != IntPtr.Zero)
3474 {
3475 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3476 {
3477 TerrainHeightFieldHeights.Remove(GroundGeom);
3478 }
3479 d.SpaceRemove(space, GroundGeom);
3480 d.GeomDestroy(GroundGeom);
3481 }
3482 }
3483 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3484 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3485 heightmapWidth, heightmapHeight, (int)heightmapWidthSamples,
3486 (int)heightmapHeightSamples, scale, offset, thickness, wrap);
3487 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3488 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3489 if (GroundGeom != IntPtr.Zero)
3490 {
3491 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3492 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3493 }
3494 geom_name_map[GroundGeom] = "Terrain";
3495
3496 d.Matrix3 R = new d.Matrix3();
3497
3498 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3499 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3500 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3501
3502 q1 = q1 * q2;
3503 //q1 = q1 * q3;
3504 Vector3 v3;
3505 float angle;
3506 q1.GetAxisAngle(out v3, out angle);
3507
3508 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3509 d.GeomSetRotation(GroundGeom, ref R);
3510 d.GeomSetPosition(GroundGeom, (pOffset.X + (regionsize * 0.5f)) - 0.5f, (pOffset.Y + (regionsize * 0.5f)) - 0.5f, 0);
3511 IntPtr testGround = IntPtr.Zero;
3512 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3513 {
3514 RegionTerrain.Remove(pOffset);
3515 }
3516 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3517 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3518 }
3519 }
3520
3521 public override void DeleteTerrain()
3522 {
3523 }
3524
3525 public float GetWaterLevel()
3526 {
3527 return waterlevel;
3528 }
3529
3530 public override bool SupportsCombining()
3531 {
3532 return true;
3533 }
3534
3535 public override void UnCombine(PhysicsScene pScene)
3536 {
3537 IntPtr localGround = IntPtr.Zero;
3538// float[] localHeightfield;
3539 bool proceed = false;
3540 List<IntPtr> geomDestroyList = new List<IntPtr>();
3541
3542 lock (OdeLock)
3543 {
3544 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3545 {
3546 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3547 {
3548 if (geom == localGround)
3549 {
3550// localHeightfield = TerrainHeightFieldHeights[geom];
3551 proceed = true;
3552 }
3553 else
3554 {
3555 geomDestroyList.Add(geom);
3556 }
3557 }
3558
3559 if (proceed)
3560 {
3561 m_worldOffset = Vector3.Zero;
3562 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3563 m_parentScene = null;
3564
3565 foreach (IntPtr g in geomDestroyList)
3566 {
3567 // removingHeightField needs to be done or the garbage collector will
3568 // collect the terrain data before we tell ODE to destroy it causing
3569 // memory corruption
3570 if (TerrainHeightFieldHeights.ContainsKey(g))
3571 {
3572// float[] removingHeightField = TerrainHeightFieldHeights[g];
3573 TerrainHeightFieldHeights.Remove(g);
3574
3575 if (RegionTerrain.ContainsKey(g))
3576 {
3577 RegionTerrain.Remove(g);
3578 }
3579
3580 d.GeomDestroy(g);
3581 //removingHeightField = new float[0];
3582 }
3583 }
3584
3585 }
3586 else
3587 {
3588 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3589
3590 }
3591 }
3592 }
3593 }
3594
3595 public override void SetWaterLevel(float baseheight)
3596 {
3597 waterlevel = baseheight;
3598 randomizeWater(waterlevel);
3599 }
3600
3601 public void randomizeWater(float baseheight)
3602 {
3603 const uint heightmapWidth = m_regionWidth + 2;
3604 const uint heightmapHeight = m_regionHeight + 2;
3605 const uint heightmapWidthSamples = m_regionWidth + 2;
3606 const uint heightmapHeightSamples = m_regionHeight + 2;
3607 const float scale = 1.0f;
3608 const float offset = 0.0f;
3609 const float thickness = 2.9f;
3610 const int wrap = 0;
3611
3612 for (int i = 0; i < (258 * 258); i++)
3613 {
3614 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3615 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3616 }
3617
3618 lock (OdeLock)
3619 {
3620 if (WaterGeom != IntPtr.Zero)
3621 {
3622 d.SpaceRemove(space, WaterGeom);
3623 }
3624 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3625 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3626 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3627 offset, thickness, wrap);
3628 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3629 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3630 if (WaterGeom != IntPtr.Zero)
3631 {
3632 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3633 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3634
3635 }
3636 geom_name_map[WaterGeom] = "Water";
3637
3638 d.Matrix3 R = new d.Matrix3();
3639
3640 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3641 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3642 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3643
3644 q1 = q1 * q2;
3645 //q1 = q1 * q3;
3646 Vector3 v3;
3647 float angle;
3648 q1.GetAxisAngle(out v3, out angle);
3649
3650 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3651 d.GeomSetRotation(WaterGeom, ref R);
3652 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3653
3654 }
3655
3656 }
3657
3658 public override void Dispose()
3659 {
3660 m_rayCastManager.Dispose();
3661 m_rayCastManager = null;
3662
3663 lock (OdeLock)
3664 {
3665 lock (_prims)
3666 {
3667 foreach (OdePrim prm in _prims)
3668 {
3669 RemovePrim(prm);
3670 }
3671 }
3672
3673 //foreach (OdeCharacter act in _characters)
3674 //{
3675 //RemoveAvatar(act);
3676 //}
3677 d.WorldDestroy(world);
3678 //d.CloseODE();
3679 }
3680 }
3681 public override Dictionary<uint, float> GetTopColliders()
3682 {
3683 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3684 int cnt = 0;
3685 lock (_prims)
3686 {
3687 foreach (OdePrim prm in _prims)
3688 {
3689 if (prm.CollisionScore > 0)
3690 {
3691 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3692 cnt++;
3693 prm.CollisionScore = 0f;
3694 if (cnt > 25)
3695 {
3696 break;
3697 }
3698 }
3699 }
3700 }
3701 return returncolliders;
3702 }
3703
3704 public override bool SupportsRayCast()
3705 {
3706 return true;
3707 }
3708
3709 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3710 {
3711 if (retMethod != null)
3712 {
3713 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3714 }
3715 }
3716
3717#if USE_DRAWSTUFF
3718 // Keyboard callback
3719 public void command(int cmd)
3720 {
3721 IntPtr geom;
3722 d.Mass mass;
3723 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3724
3725
3726
3727 Char ch = Char.ToLower((Char)cmd);
3728 switch ((Char)ch)
3729 {
3730 case 'w':
3731 try
3732 {
3733 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));
3734
3735 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3736 ds.SetViewpoint(ref xyz, ref hpr);
3737 }
3738 catch (ArgumentException)
3739 { hpr.X = 0; }
3740 break;
3741
3742 case 'a':
3743 hpr.X++;
3744 ds.SetViewpoint(ref xyz, ref hpr);
3745 break;
3746
3747 case 's':
3748 try
3749 {
3750 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));
3751
3752 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3753 ds.SetViewpoint(ref xyz, ref hpr);
3754 }
3755 catch (ArgumentException)
3756 { hpr.X = 0; }
3757 break;
3758 case 'd':
3759 hpr.X--;
3760 ds.SetViewpoint(ref xyz, ref hpr);
3761 break;
3762 case 'r':
3763 xyz.Z++;
3764 ds.SetViewpoint(ref xyz, ref hpr);
3765 break;
3766 case 'f':
3767 xyz.Z--;
3768 ds.SetViewpoint(ref xyz, ref hpr);
3769 break;
3770 case 'e':
3771 xyz.Y++;
3772 ds.SetViewpoint(ref xyz, ref hpr);
3773 break;
3774 case 'q':
3775 xyz.Y--;
3776 ds.SetViewpoint(ref xyz, ref hpr);
3777 break;
3778 }
3779 }
3780
3781 public void step(int pause)
3782 {
3783
3784 ds.SetColor(1.0f, 1.0f, 0.0f);
3785 ds.SetTexture(ds.Texture.Wood);
3786 lock (_prims)
3787 {
3788 foreach (OdePrim prm in _prims)
3789 {
3790 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3791 if (prm.prim_geom != IntPtr.Zero)
3792 {
3793 d.Vector3 pos;
3794 d.GeomCopyPosition(prm.prim_geom, out pos);
3795 //d.BodyCopyPosition(body, out pos);
3796
3797 d.Matrix3 R;
3798 d.GeomCopyRotation(prm.prim_geom, out R);
3799 //d.BodyCopyRotation(body, out R);
3800
3801
3802 d.Vector3 sides = new d.Vector3();
3803 sides.X = prm.Size.X;
3804 sides.Y = prm.Size.Y;
3805 sides.Z = prm.Size.Z;
3806
3807 ds.DrawBox(ref pos, ref R, ref sides);
3808 }
3809 }
3810 }
3811 ds.SetColor(1.0f, 0.0f, 0.0f);
3812 lock (_characters)
3813 {
3814 foreach (OdeCharacter chr in _characters)
3815 {
3816 if (chr.Shell != IntPtr.Zero)
3817 {
3818 IntPtr body = d.GeomGetBody(chr.Shell);
3819
3820 d.Vector3 pos;
3821 d.GeomCopyPosition(chr.Shell, out pos);
3822 //d.BodyCopyPosition(body, out pos);
3823
3824 d.Matrix3 R;
3825 d.GeomCopyRotation(chr.Shell, out R);
3826 //d.BodyCopyRotation(body, out R);
3827
3828 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3829 d.Vector3 sides = new d.Vector3();
3830 sides.X = 0.5f;
3831 sides.Y = 0.5f;
3832 sides.Z = 0.5f;
3833
3834 ds.DrawBox(ref pos, ref R, ref sides);
3835 }
3836 }
3837 }
3838 }
3839
3840 public void start(int unused)
3841 {
3842 ds.SetViewpoint(ref xyz, ref hpr);
3843 }
3844#endif
3845 }
3846}
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 6b74e74..0e7dd81 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
@@ -1215,7 +1215,6 @@ namespace OpenSim.Region.Physics.OdePlugin
1215 1215
1216 public override float APIDDamping{ set { return; } } 1216 public override float APIDDamping{ set { return; } }
1217 1217
1218
1219 public override void SubscribeEvents(int ms) 1218 public override void SubscribeEvents(int ms)
1220 { 1219 {
1221 m_requestedUpdateFrequency = ms; 1220 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 4a24c7d..3edc3a2 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/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs
new file mode 100644
index 0000000..489c1c6
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs
@@ -0,0 +1,118 @@
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.Reflection;
30using System.Collections;
31using System.Collections.Generic;
32using System.Runtime.Remoting.Lifetime;
33using OpenMetaverse;
34using Nini.Config;
35using OpenSim;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.World.LightShare;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.ScriptEngine.Shared;
41using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
42using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
43using OpenSim.Region.ScriptEngine.Interfaces;
44using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
45using OpenSim.Services.Interfaces;
46
47using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
48using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
49using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
50using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
51using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
52using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
53using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
54
55namespace OpenSim.Region.ScriptEngine.Shared.Api
56{
57 [Serializable]
58 public class CM_Api : MarshalByRefObject, ICM_Api, IScriptApi
59 {
60 internal IScriptEngine m_ScriptEngine;
61 internal SceneObjectPart m_host;
62 internal uint m_localID;
63 internal UUID m_itemID;
64 internal bool m_CMFunctionsEnabled = false;
65
66 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
67 {
68 m_ScriptEngine = ScriptEngine;
69 m_host = host;
70 m_localID = localID;
71 m_itemID = itemID;
72
73 if (m_ScriptEngine.Config.GetBoolean("AllowCareminsterFunctions", false))
74 m_CMFunctionsEnabled = true;
75 }
76
77 public override Object InitializeLifetimeService()
78 {
79 ILease lease = (ILease)base.InitializeLifetimeService();
80
81 if (lease.CurrentState == LeaseState.Initial)
82 {
83 lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
84 // lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
85 // lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
86 }
87 return lease;
88 }
89
90 public Scene World
91 {
92 get { return m_ScriptEngine.World; }
93 }
94
95 public string cmDetectedCountry(int number)
96 {
97 m_host.AddScriptLPS(1);
98 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number);
99 if (detectedParams == null)
100 return String.Empty;
101 return detectedParams.Country;
102 }
103
104 public string cmGetAgentCountry(LSL_Key key)
105 {
106 if (!World.Permissions.IsGod(m_host.OwnerID))
107 return String.Empty;
108
109 UUID uuid;
110
111 if (!UUID.TryParse(key, out uuid))
112 return String.Empty;
113
114 UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
115 return account.UserCountry;
116 }
117 }
118}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index c16a985..8ceb814 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);
801 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
802 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
803 double angle = Math.Acos(dotProduct / magProduct);
804 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
805 double s = Math.Sin(angle / 2);
806
807 double x = axis.x * s;
808 double y = axis.y * s;
809 double z = axis.z * s;
810 double w = Math.Cos(angle / 2);
811
812 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
813 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
814
815 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
816 */
817
818 // This method mimics the 180 errors found in SL
819 // See www.euclideanspace.com... angleBetween
820 LSL_Vector vec_a = a;
821 LSL_Vector vec_b = b;
822
823 // Eliminate zero length
824 LSL_Float vec_a_mag = LSL_Vector.Mag(vec_a);
825 LSL_Float vec_b_mag = LSL_Vector.Mag(vec_b);
826 if (vec_a_mag < 0.00001 ||
827 vec_b_mag < 0.00001)
709 { 828 {
710 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 829 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
711 } 830 }
712 else 831
832 // Normalize
833 vec_a = llVecNorm(vec_a);
834 vec_b = llVecNorm(vec_b);
835
836 // Calculate axis and rotation angle
837 LSL_Vector axis = vec_a % vec_b;
838 LSL_Float cos_theta = vec_a * vec_b;
839
840 // Check if parallel
841 if (cos_theta > 0.99999)
713 { 842 {
714 a = LSL_Vector.Norm(a); 843 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
715 b = LSL_Vector.Norm(b); 844 }
716 double dotProduct = LSL_Vector.Dot(a, b); 845
717 // There are two degenerate cases possible. These are for vectors 180 or 846 // Check if anti-parallel
718 // 0 degrees apart. These have to be detected and handled individually. 847 else if (cos_theta < -0.99999)
719 // 848 {
720 // Check for vectors 180 degrees apart. 849 LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (vec_a.x / (vec_a * vec_a) * vec_a);
721 // A dot product of -1 would mean the angle between vectors is 180 degrees. 850 if (LSL_Vector.Mag(orthog_axis) < 0.000001) orthog_axis = new LSL_Vector(0.0, 0.0, 1.0);
722 if (dotProduct < -0.9999999f) 851 return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0);
723 { 852 }
724 // First assume X axis is orthogonal to the vectors. 853 else // other rotation
725 LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f); 854 {
726 orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a)); 855 LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f;
727 // Check for near zero vector. A very small non-zero number here will create 856 axis = llVecNorm(axis);
728 // a rotation in an undesired direction. 857 double x, y, z, s, t;
729 if (LSL_Vector.Mag(orthoVector) > 0.0001) 858 s = Math.Cos(theta);
730 { 859 t = Math.Sin(theta);
731 rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f); 860 x = axis.x * t;
732 } 861 y = axis.y * t;
733 // If the magnitude of the vector was near zero, then assume the X axis is not 862 z = axis.z * t;
734 // orthogonal and use the Z axis instead. 863 return new LSL_Rotation(x,y,z,s);
735 else
736 {
737 // Set 180 z rotation.
738 rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f);
739 }
740 }
741 // Check for parallel vectors.
742 // A dot product of 1 would mean the angle between vectors is 0 degrees.
743 else if (dotProduct > 0.9999999f)
744 {
745 // Set zero rotation.
746 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
747 }
748 else
749 {
750 // All special checks have been performed so get the axis of rotation.
751 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
752 // Quarternion s value is the length of the unit vector + dot product.
753 double qs = 1.0 + dotProduct;
754 rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs);
755 // Normalize the rotation.
756 double mag = LSL_Rotation.Mag(rotBetween);
757 // We shouldn't have to worry about a divide by zero here. The qs value will be
758 // non-zero because we already know if we're here, then the dotProduct is not -1 so
759 // qs will not be zero. Also, we've already handled the input vectors being zero so the
760 // crossProduct vector should also not be zero.
761 rotBetween.x = rotBetween.x / mag;
762 rotBetween.y = rotBetween.y / mag;
763 rotBetween.z = rotBetween.z / mag;
764 rotBetween.s = rotBetween.s / mag;
765 // Check for undefined values and set zero rotation if any found. This code might not actually be required
766 // any longer since zero vectors are checked for at the top.
767 if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s))
768 {
769 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
770 }
771 }
772 } 864 }
773 return rotBetween;
774 } 865 }
775 866
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 textureID = InventoryKey(texture, (int)AssetType.Texture); 1925 textureID = InventoryKey(texture, (int)AssetType.Texture);
@@ -1792,6 +1964,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1792 1964
1793 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) 1965 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1794 { 1966 {
1967 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1968 return;
1969
1795 Primitive.TextureEntry tex = part.Shape.Textures; 1970 Primitive.TextureEntry tex = part.Shape.Textures;
1796 if (face >= 0 && face < GetNumberOfSides(part)) 1971 if (face >= 0 && face < GetNumberOfSides(part))
1797 { 1972 {
@@ -1828,6 +2003,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1828 2003
1829 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) 2004 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1830 { 2005 {
2006 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2007 return;
2008
1831 Primitive.TextureEntry tex = part.Shape.Textures; 2009 Primitive.TextureEntry tex = part.Shape.Textures;
1832 if (face >= 0 && face < GetNumberOfSides(part)) 2010 if (face >= 0 && face < GetNumberOfSides(part))
1833 { 2011 {
@@ -1864,6 +2042,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1864 2042
1865 protected void RotateTexture(SceneObjectPart part, double rotation, int face) 2043 protected void RotateTexture(SceneObjectPart part, double rotation, int face)
1866 { 2044 {
2045 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2046 return;
2047
1867 Primitive.TextureEntry tex = part.Shape.Textures; 2048 Primitive.TextureEntry tex = part.Shape.Textures;
1868 if (face >= 0 && face < GetNumberOfSides(part)) 2049 if (face >= 0 && face < GetNumberOfSides(part))
1869 { 2050 {
@@ -1932,10 +2113,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1932 return end; 2113 return end;
1933 } 2114 }
1934 2115
1935 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) 2116 protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos)
1936 { 2117 {
2118 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2119 return fromPos;
2120
1937 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) 2121 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
1938 LSL_Vector currentPos = GetPartLocalPos(part); 2122
1939 2123
1940 float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y); 2124 float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
1941 bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true); 2125 bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
@@ -1944,14 +2128,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1944 { 2128 {
1945 if ((targetPos.z < ground) && disable_underground_movement && m_host.AttachmentPoint == 0) 2129 if ((targetPos.z < ground) && disable_underground_movement && m_host.AttachmentPoint == 0)
1946 targetPos.z = ground; 2130 targetPos.z = ground;
2131 }
2132 LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos);
2133
2134 return real_vec;
2135 }
2136
2137 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos)
2138 {
2139 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2140 return;
2141
2142 LSL_Vector currentPos = GetPartLocalPos(part);
2143 LSL_Vector toPos = GetSetPosTarget(part, targetPos, currentPos);
2144
2145 if (part.ParentGroup.RootPart == part)
2146 {
1947 SceneObjectGroup parent = part.ParentGroup; 2147 SceneObjectGroup parent = part.ParentGroup;
1948 LSL_Vector real_vec = SetPosAdjust(currentPos, targetPos); 2148 parent.UpdateGroupPosition(new Vector3((float)toPos.x, (float)toPos.y, (float)toPos.z));
1949 parent.UpdateGroupPosition(new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z));
1950 } 2149 }
1951 else 2150 else
1952 { 2151 {
1953 LSL_Vector rel_vec = SetPosAdjust(currentPos, targetPos); 2152 part.OffsetPosition = new Vector3((float)toPos.x, (float)toPos.y, (float)toPos.z);
1954 part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z);
1955 SceneObjectGroup parent = part.ParentGroup; 2153 SceneObjectGroup parent = part.ParentGroup;
1956 parent.HasGroupChanged = true; 2154 parent.HasGroupChanged = true;
1957 parent.ScheduleGroupForTerseUpdate(); 2155 parent.ScheduleGroupForTerseUpdate();
@@ -2002,9 +2200,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2002 m_host.AddScriptLPS(1); 2200 m_host.AddScriptLPS(1);
2003 2201
2004 // try to let this work as in SL... 2202 // try to let this work as in SL...
2005 if (m_host.ParentID == 0) 2203 if (m_host.LinkNum < 2)
2006 { 2204 {
2007 // special case: If we are root, rotate complete SOG to new rotation 2205 // Special case: If we are root, rotate complete SOG to new
2206 // rotation.
2207 // We are root if the link number is 0 (single prim) or 1
2208 // (root prim). ParentID may be nonzero in attachments and
2209 // using it would cause attachments and HUDs to rotate
2210 // to the wrong positions.
2008 SetRot(m_host, Rot2Quaternion(rot)); 2211 SetRot(m_host, Rot2Quaternion(rot));
2009 } 2212 }
2010 else 2213 else
@@ -2033,6 +2236,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2033 2236
2034 protected void SetRot(SceneObjectPart part, Quaternion rot) 2237 protected void SetRot(SceneObjectPart part, Quaternion rot)
2035 { 2238 {
2239 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2240 return;
2241
2036 part.UpdateRotation(rot); 2242 part.UpdateRotation(rot);
2037 // Update rotation does not move the object in the physics scene if it's a linkset. 2243 // Update rotation does not move the object in the physics scene if it's a linkset.
2038 2244
@@ -2652,12 +2858,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2652 2858
2653 m_host.AddScriptLPS(1); 2859 m_host.AddScriptLPS(1);
2654 2860
2861 m_host.TaskInventory.LockItemsForRead(true);
2655 TaskInventoryItem item = m_host.TaskInventory[invItemID]; 2862 TaskInventoryItem item = m_host.TaskInventory[invItemID];
2656 2863 m_host.TaskInventory.LockItemsForRead(false);
2657 lock (m_host.TaskInventory)
2658 {
2659 item = m_host.TaskInventory[invItemID];
2660 }
2661 2864
2662 if (item.PermsGranter == UUID.Zero) 2865 if (item.PermsGranter == UUID.Zero)
2663 return 0; 2866 return 0;
@@ -2732,6 +2935,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2732 if (dist > m_ScriptDistanceFactor * 10.0f) 2935 if (dist > m_ScriptDistanceFactor * 10.0f)
2733 return; 2936 return;
2734 2937
2938 //Clone is thread-safe
2735 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 2939 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
2736 2940
2737 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory) 2941 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory)
@@ -2794,6 +2998,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2794 2998
2795 public void llLookAt(LSL_Vector target, double strength, double damping) 2999 public void llLookAt(LSL_Vector target, double strength, double damping)
2796 { 3000 {
3001 /*
2797 m_host.AddScriptLPS(1); 3002 m_host.AddScriptLPS(1);
2798 // Determine where we are looking from 3003 // Determine where we are looking from
2799 LSL_Vector from = llGetPos(); 3004 LSL_Vector from = llGetPos();
@@ -2813,10 +3018,54 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2813 // the angles of rotation in radians into rotation value 3018 // the angles of rotation in radians into rotation value
2814 3019
2815 LSL_Types.Quaternion rot = llEuler2Rot(angle); 3020 LSL_Types.Quaternion rot = llEuler2Rot(angle);
2816 Quaternion rotation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s); 3021
2817 m_host.startLookAt(rotation, (float)damping, (float)strength); 3022 // This would only work if your physics system contains an APID controller:
3023 // Quaternion rotation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
3024 // m_host.startLookAt(rotation, (float)damping, (float)strength);
3025
2818 // Orient the object to the angle calculated 3026 // Orient the object to the angle calculated
2819 //llSetRot(rot); 3027 llSetRot(rot);
3028 */
3029
3030 //The above code, while nice, doesn't replicate the behaviour of SL and tends to "roll" the object.
3031 //There's probably a smarter way of doing this, my rotation math-fu is weak.
3032 // http://bugs.meta7.com/view.php?id=28
3033 // - Tom
3034
3035 /* And the following does not do the job either. It has to be performed inside the ODE glue-code. -.- .._.
3036 LSL_Rotation newrot = llGetRot() * llRotBetween(new LSL_Vector(1.0d, 0.0d, 0.0d) * llGetRot(), new LSL_Vector(0.0d, 0.0d, -1.0d));
3037 llSetRot(newrot * llRotBetween(new LSL_Vector(0.0d,0.0d,1.0d) * newrot, target - llGetPos()));
3038 */
3039 if (m_host.PhysActor != null && !m_host.PhysActor.IsPhysical)
3040 {
3041 // Part is non-phys, convert this to a llSetRot()
3042 Vector3 tgt = new Vector3((float)target.x, (float)target.y, (float)target.z);
3043 Vector3 dir = tgt - m_host.GroupPosition;
3044 dir.Normalize();
3045 float tzrot = (float)Math.Atan2(dir.Y, dir.X);
3046 float txy = (float)Math.Sqrt((dir.X * dir.X) + (dir.Y * dir.Y));
3047 float terot = (float)Math.Atan2(-dir.Z, txy);
3048 LSL_Vector az = new LSL_Vector(0.0f, 0.0f, tzrot);
3049 LSL_Vector ae = new LSL_Vector(0.0f, terot, 0.0f);
3050 LSL_Types.Quaternion spin = llEuler2Rot(az);
3051 LSL_Types.Quaternion rot = llEuler2Rot(ae) * spin;
3052 llSetRot(rot);
3053 }
3054 else
3055 {
3056 // Physical, send the target vector to RotLookAt method inside a 'rotation', the .w -99.9 value indicates it is really a LookAt.
3057 Quaternion q = new Quaternion((float)target.x, (float)target.y, (float)target.z, -99.9f);
3058 m_host.RotLookAt(q, (float)strength, (float)damping);
3059 }
3060
3061 }
3062
3063 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3064 {
3065 m_host.AddScriptLPS(1);
3066// NotImplemented("llRotLookAt");
3067 m_host.RotLookAt(Rot2Quaternion(target), (float)strength, (float)damping);
3068
2820 } 3069 }
2821 3070
2822 public void llStopLookAt() 3071 public void llStopLookAt()
@@ -2865,13 +3114,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2865 { 3114 {
2866 TaskInventoryItem item; 3115 TaskInventoryItem item;
2867 3116
2868 lock (m_host.TaskInventory) 3117 m_host.TaskInventory.LockItemsForRead(true);
3118 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2869 { 3119 {
2870 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3120 m_host.TaskInventory.LockItemsForRead(false);
2871 return; 3121 return;
2872 else 3122 }
2873 item = m_host.TaskInventory[InventorySelf()]; 3123 else
3124 {
3125 item = m_host.TaskInventory[InventorySelf()];
2874 } 3126 }
3127 m_host.TaskInventory.LockItemsForRead(false);
2875 3128
2876 if (item.PermsGranter != UUID.Zero) 3129 if (item.PermsGranter != UUID.Zero)
2877 { 3130 {
@@ -2893,13 +3146,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2893 { 3146 {
2894 TaskInventoryItem item; 3147 TaskInventoryItem item;
2895 3148
3149 m_host.TaskInventory.LockItemsForRead(true);
2896 lock (m_host.TaskInventory) 3150 lock (m_host.TaskInventory)
2897 { 3151 {
3152
2898 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3153 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3154 {
3155 m_host.TaskInventory.LockItemsForRead(false);
2899 return; 3156 return;
3157 }
2900 else 3158 else
3159 {
2901 item = m_host.TaskInventory[InventorySelf()]; 3160 item = m_host.TaskInventory[InventorySelf()];
3161 }
2902 } 3162 }
3163 m_host.TaskInventory.LockItemsForRead(false);
2903 3164
2904 m_host.AddScriptLPS(1); 3165 m_host.AddScriptLPS(1);
2905 3166
@@ -2931,18 +3192,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2931 { 3192 {
2932 m_host.AddScriptLPS(1); 3193 m_host.AddScriptLPS(1);
2933 3194
2934 if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
2935 return;
2936
2937 TaskInventoryItem item; 3195 TaskInventoryItem item;
2938 3196
2939 lock (m_host.TaskInventory) 3197 m_host.TaskInventory.LockItemsForRead(true);
3198
3199 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2940 { 3200 {
2941 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3201 m_host.TaskInventory.LockItemsForRead(false);
2942 return; 3202 return;
2943 else
2944 item = m_host.TaskInventory[InventorySelf()];
2945 } 3203 }
3204 else
3205 {
3206 item = m_host.TaskInventory[InventorySelf()];
3207 }
3208
3209 m_host.TaskInventory.LockItemsForRead(false);
2946 3210
2947 if (item.PermsGranter != m_host.OwnerID) 3211 if (item.PermsGranter != m_host.OwnerID)
2948 return; 3212 return;
@@ -2953,10 +3217,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2953 3217
2954 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 3218 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
2955 3219
2956 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; 3220 grp.AttachToAgent(m_host.OwnerID, (uint)attachment, Vector3.Zero, false);
2957 if (attachmentsModule != null)
2958 attachmentsModule.AttachObject(presence.ControllingClient,
2959 grp, (uint)attachment, false);
2960 } 3221 }
2961 } 3222 }
2962 3223
@@ -2969,13 +3230,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2969 3230
2970 TaskInventoryItem item; 3231 TaskInventoryItem item;
2971 3232
2972 lock (m_host.TaskInventory) 3233 m_host.TaskInventory.LockItemsForRead(true);
3234
3235 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2973 { 3236 {
2974 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3237 m_host.TaskInventory.LockItemsForRead(false);
2975 return; 3238 return;
2976 else
2977 item = m_host.TaskInventory[InventorySelf()];
2978 } 3239 }
3240 else
3241 {
3242 item = m_host.TaskInventory[InventorySelf()];
3243 }
3244 m_host.TaskInventory.LockItemsForRead(false);
3245
2979 3246
2980 if (item.PermsGranter != m_host.OwnerID) 3247 if (item.PermsGranter != m_host.OwnerID)
2981 return; 3248 return;
@@ -3022,6 +3289,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3022 3289
3023 public void llInstantMessage(string user, string message) 3290 public void llInstantMessage(string user, string message)
3024 { 3291 {
3292 UUID result;
3293 if (!UUID.TryParse(user, out result))
3294 {
3295 ShoutError("An invalid key was passed to llInstantMessage");
3296 ScriptSleep(2000);
3297 return;
3298 }
3299
3300
3025 m_host.AddScriptLPS(1); 3301 m_host.AddScriptLPS(1);
3026 3302
3027 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance. 3303 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
@@ -3036,14 +3312,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3036 UUID friendTransactionID = UUID.Random(); 3312 UUID friendTransactionID = UUID.Random();
3037 3313
3038 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); 3314 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
3039 3315
3040 GridInstantMessage msg = new GridInstantMessage(); 3316 GridInstantMessage msg = new GridInstantMessage();
3041 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; 3317 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
3042 msg.toAgentID = new Guid(user); // toAgentID.Guid; 3318 msg.toAgentID = new Guid(user); // toAgentID.Guid;
3043 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here 3319 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
3044// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message); 3320// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
3045// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString()); 3321// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
3046 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp; 3322// DateTime dt = DateTime.UtcNow;
3323//
3324// // Ticks from UtcNow, but make it look like local. Evil, huh?
3325// dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
3326//
3327// try
3328// {
3329// // Convert that to the PST timezone
3330// TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
3331// dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
3332// }
3333// catch
3334// {
3335// // No logging here, as it could be VERY spammy
3336// }
3337//
3338// // And make it look local again to fool the unix time util
3339// dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
3340
3341 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
3342
3047 //if (client != null) 3343 //if (client != null)
3048 //{ 3344 //{
3049 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName; 3345 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
@@ -3057,12 +3353,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3057 msg.message = message.Substring(0, 1024); 3353 msg.message = message.Substring(0, 1024);
3058 else 3354 else
3059 msg.message = message; 3355 msg.message = message;
3060 msg.dialog = (byte)19; // messgage from script ??? // dialog; 3356 msg.dialog = (byte)19; // MessageFromObject
3061 msg.fromGroup = false;// fromGroup; 3357 msg.fromGroup = false;// fromGroup;
3062 msg.offline = (byte)0; //offline; 3358 msg.offline = (byte)0; //offline;
3063 msg.ParentEstateID = 0; //ParentEstateID; 3359 msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID;
3064 msg.Position = new Vector3(m_host.AbsolutePosition); 3360 msg.Position = new Vector3(m_host.AbsolutePosition);
3065 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; 3361 msg.RegionID = World.RegionInfo.RegionID.Guid;
3066 msg.binaryBucket 3362 msg.binaryBucket
3067 = Util.StringToBytes256( 3363 = Util.StringToBytes256(
3068 "{0}/{1}/{2}/{3}", 3364 "{0}/{1}/{2}/{3}",
@@ -3090,7 +3386,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3090 } 3386 }
3091 3387
3092 emailModule.SendEmail(m_host.UUID, address, subject, message); 3388 emailModule.SendEmail(m_host.UUID, address, subject, message);
3093 ScriptSleep(20000); 3389 ScriptSleep(15000);
3094 } 3390 }
3095 3391
3096 public void llGetNextEmail(string address, string subject) 3392 public void llGetNextEmail(string address, string subject)
@@ -3192,13 +3488,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3192 m_host.AddScriptLPS(1); 3488 m_host.AddScriptLPS(1);
3193 } 3489 }
3194 3490
3195 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3196 {
3197 m_host.AddScriptLPS(1);
3198 Quaternion rot = new Quaternion((float)target.x, (float)target.y, (float)target.z, (float)target.s);
3199 m_host.RotLookAt(rot, (float)strength, (float)damping);
3200 }
3201
3202 public LSL_Integer llStringLength(string str) 3491 public LSL_Integer llStringLength(string str)
3203 { 3492 {
3204 m_host.AddScriptLPS(1); 3493 m_host.AddScriptLPS(1);
@@ -3222,14 +3511,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3222 3511
3223 TaskInventoryItem item; 3512 TaskInventoryItem item;
3224 3513
3225 lock (m_host.TaskInventory) 3514 m_host.TaskInventory.LockItemsForRead(true);
3515 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3226 { 3516 {
3227 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3517 m_host.TaskInventory.LockItemsForRead(false);
3228 return; 3518 return;
3229 else
3230 item = m_host.TaskInventory[InventorySelf()];
3231 } 3519 }
3232 3520 else
3521 {
3522 item = m_host.TaskInventory[InventorySelf()];
3523 }
3524 m_host.TaskInventory.LockItemsForRead(false);
3233 if (item.PermsGranter == UUID.Zero) 3525 if (item.PermsGranter == UUID.Zero)
3234 return; 3526 return;
3235 3527
@@ -3259,13 +3551,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3259 3551
3260 TaskInventoryItem item; 3552 TaskInventoryItem item;
3261 3553
3262 lock (m_host.TaskInventory) 3554 m_host.TaskInventory.LockItemsForRead(true);
3555 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3263 { 3556 {
3264 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3557 m_host.TaskInventory.LockItemsForRead(false);
3265 return; 3558 return;
3266 else 3559 }
3267 item = m_host.TaskInventory[InventorySelf()]; 3560 else
3561 {
3562 item = m_host.TaskInventory[InventorySelf()];
3268 } 3563 }
3564 m_host.TaskInventory.LockItemsForRead(false);
3565
3269 3566
3270 if (item.PermsGranter == UUID.Zero) 3567 if (item.PermsGranter == UUID.Zero)
3271 return; 3568 return;
@@ -3336,10 +3633,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3336 3633
3337 TaskInventoryItem item; 3634 TaskInventoryItem item;
3338 3635
3339 lock (m_host.TaskInventory) 3636
3637 m_host.TaskInventory.LockItemsForRead(true);
3638 if (!m_host.TaskInventory.ContainsKey(invItemID))
3639 {
3640 m_host.TaskInventory.LockItemsForRead(false);
3641 return;
3642 }
3643 else
3340 { 3644 {
3341 item = m_host.TaskInventory[invItemID]; 3645 item = m_host.TaskInventory[invItemID];
3342 } 3646 }
3647 m_host.TaskInventory.LockItemsForRead(false);
3343 3648
3344 if (agentID == UUID.Zero || perm == 0) // Releasing permissions 3649 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
3345 { 3650 {
@@ -3371,11 +3676,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3371 3676
3372 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3677 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3373 { 3678 {
3374 lock (m_host.TaskInventory) 3679 m_host.TaskInventory.LockItemsForWrite(true);
3375 { 3680 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3376 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3681 m_host.TaskInventory[invItemID].PermsMask = perm;
3377 m_host.TaskInventory[invItemID].PermsMask = perm; 3682 m_host.TaskInventory.LockItemsForWrite(false);
3378 }
3379 3683
3380 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3684 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3381 "run_time_permissions", new Object[] { 3685 "run_time_permissions", new Object[] {
@@ -3395,11 +3699,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3395 3699
3396 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3700 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3397 { 3701 {
3398 lock (m_host.TaskInventory) 3702 m_host.TaskInventory.LockItemsForWrite(true);
3399 { 3703 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3400 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3704 m_host.TaskInventory[invItemID].PermsMask = perm;
3401 m_host.TaskInventory[invItemID].PermsMask = perm; 3705 m_host.TaskInventory.LockItemsForWrite(false);
3402 }
3403 3706
3404 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3707 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3405 "run_time_permissions", new Object[] { 3708 "run_time_permissions", new Object[] {
@@ -3420,11 +3723,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3420 3723
3421 if (!m_waitingForScriptAnswer) 3724 if (!m_waitingForScriptAnswer)
3422 { 3725 {
3423 lock (m_host.TaskInventory) 3726 m_host.TaskInventory.LockItemsForWrite(true);
3424 { 3727 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3425 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3728 m_host.TaskInventory[invItemID].PermsMask = 0;
3426 m_host.TaskInventory[invItemID].PermsMask = 0; 3729 m_host.TaskInventory.LockItemsForWrite(false);
3427 }
3428 3730
3429 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; 3731 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
3430 m_waitingForScriptAnswer=true; 3732 m_waitingForScriptAnswer=true;
@@ -3459,10 +3761,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3459 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) 3761 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3460 llReleaseControls(); 3762 llReleaseControls();
3461 3763
3462 lock (m_host.TaskInventory) 3764
3463 { 3765 m_host.TaskInventory.LockItemsForWrite(true);
3464 m_host.TaskInventory[invItemID].PermsMask = answer; 3766 m_host.TaskInventory[invItemID].PermsMask = answer;
3465 } 3767 m_host.TaskInventory.LockItemsForWrite(false);
3768
3466 3769
3467 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3770 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3468 "run_time_permissions", new Object[] { 3771 "run_time_permissions", new Object[] {
@@ -3474,16 +3777,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3474 { 3777 {
3475 m_host.AddScriptLPS(1); 3778 m_host.AddScriptLPS(1);
3476 3779
3477 lock (m_host.TaskInventory) 3780 m_host.TaskInventory.LockItemsForRead(true);
3781
3782 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3478 { 3783 {
3479 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3784 if (item.Type == 10 && item.ItemID == m_itemID)
3480 { 3785 {
3481 if (item.Type == 10 && item.ItemID == m_itemID) 3786 m_host.TaskInventory.LockItemsForRead(false);
3482 { 3787 return item.PermsGranter.ToString();
3483 return item.PermsGranter.ToString();
3484 }
3485 } 3788 }
3486 } 3789 }
3790 m_host.TaskInventory.LockItemsForRead(false);
3487 3791
3488 return UUID.Zero.ToString(); 3792 return UUID.Zero.ToString();
3489 } 3793 }
@@ -3492,19 +3796,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3492 { 3796 {
3493 m_host.AddScriptLPS(1); 3797 m_host.AddScriptLPS(1);
3494 3798
3495 lock (m_host.TaskInventory) 3799 m_host.TaskInventory.LockItemsForRead(true);
3800
3801 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3496 { 3802 {
3497 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3803 if (item.Type == 10 && item.ItemID == m_itemID)
3498 { 3804 {
3499 if (item.Type == 10 && item.ItemID == m_itemID) 3805 int perms = item.PermsMask;
3500 { 3806 if (m_automaticLinkPermission)
3501 int perms = item.PermsMask; 3807 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
3502 if (m_automaticLinkPermission) 3808 m_host.TaskInventory.LockItemsForRead(false);
3503 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; 3809 return perms;
3504 return perms;
3505 }
3506 } 3810 }
3507 } 3811 }
3812 m_host.TaskInventory.LockItemsForRead(false);
3508 3813
3509 return 0; 3814 return 0;
3510 } 3815 }
@@ -3526,9 +3831,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3526 public void llSetLinkColor(int linknumber, LSL_Vector color, int face) 3831 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
3527 { 3832 {
3528 List<SceneObjectPart> parts = GetLinkParts(linknumber); 3833 List<SceneObjectPart> parts = GetLinkParts(linknumber);
3529 3834 if (parts.Count > 0)
3530 foreach (SceneObjectPart part in parts) 3835 {
3531 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 3836 try
3837 {
3838 parts[0].ParentGroup.areUpdatesSuspended = true;
3839 foreach (SceneObjectPart part in parts)
3840 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face);
3841 }
3842 finally
3843 {
3844 parts[0].ParentGroup.areUpdatesSuspended = false;
3845 }
3846 }
3532 } 3847 }
3533 3848
3534 public void llCreateLink(string target, int parent) 3849 public void llCreateLink(string target, int parent)
@@ -3541,11 +3856,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3541 return; 3856 return;
3542 3857
3543 TaskInventoryItem item; 3858 TaskInventoryItem item;
3544 lock (m_host.TaskInventory) 3859 m_host.TaskInventory.LockItemsForRead(true);
3545 { 3860 item = m_host.TaskInventory[invItemID];
3546 item = m_host.TaskInventory[invItemID]; 3861 m_host.TaskInventory.LockItemsForRead(false);
3547 } 3862
3548
3549 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3863 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3550 && !m_automaticLinkPermission) 3864 && !m_automaticLinkPermission)
3551 { 3865 {
@@ -3566,7 +3880,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3566 3880
3567 if (targetPart != null) 3881 if (targetPart != null)
3568 { 3882 {
3569 if (parent != 0) { 3883 if (parent != 0)
3884 {
3570 parentPrim = m_host.ParentGroup; 3885 parentPrim = m_host.ParentGroup;
3571 childPrim = targetPart.ParentGroup; 3886 childPrim = targetPart.ParentGroup;
3572 } 3887 }
@@ -3598,16 +3913,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3598 m_host.AddScriptLPS(1); 3913 m_host.AddScriptLPS(1);
3599 UUID invItemID = InventorySelf(); 3914 UUID invItemID = InventorySelf();
3600 3915
3601 lock (m_host.TaskInventory) 3916 m_host.TaskInventory.LockItemsForRead(true);
3602 {
3603 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3917 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3604 && !m_automaticLinkPermission) 3918 && !m_automaticLinkPermission)
3605 { 3919 {
3606 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); 3920 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
3921 m_host.TaskInventory.LockItemsForRead(false);
3607 return; 3922 return;
3608 } 3923 }
3609 } 3924 m_host.TaskInventory.LockItemsForRead(false);
3610 3925
3611 if (linknum < ScriptBaseClass.LINK_THIS) 3926 if (linknum < ScriptBaseClass.LINK_THIS)
3612 return; 3927 return;
3613 3928
@@ -3646,10 +3961,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3646 // Restructuring Multiple Prims. 3961 // Restructuring Multiple Prims.
3647 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts); 3962 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3648 parts.Remove(parentPrim.RootPart); 3963 parts.Remove(parentPrim.RootPart);
3649 foreach (SceneObjectPart part in parts) 3964 if (parts.Count > 0)
3650 { 3965 {
3651 parentPrim.DelinkFromGroup(part.LocalId, true); 3966 try
3967 {
3968 parts[0].ParentGroup.areUpdatesSuspended = true;
3969 foreach (SceneObjectPart part in parts)
3970 {
3971 parentPrim.DelinkFromGroup(part.LocalId, true);
3972 }
3973 }
3974 finally
3975 {
3976 parts[0].ParentGroup.areUpdatesSuspended = false;
3977 }
3652 } 3978 }
3979
3653 parentPrim.HasGroupChanged = true; 3980 parentPrim.HasGroupChanged = true;
3654 parentPrim.ScheduleGroupForFullUpdate(); 3981 parentPrim.ScheduleGroupForFullUpdate();
3655 parentPrim.TriggerScriptChangedEvent(Changed.LINK); 3982 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
@@ -3658,11 +3985,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3658 { 3985 {
3659 SceneObjectPart newRoot = parts[0]; 3986 SceneObjectPart newRoot = parts[0];
3660 parts.Remove(newRoot); 3987 parts.Remove(newRoot);
3661 foreach (SceneObjectPart part in parts) 3988
3989 try
3662 { 3990 {
3663 part.UpdateFlag = 0; 3991 parts[0].ParentGroup.areUpdatesSuspended = true;
3664 newRoot.ParentGroup.LinkToGroup(part.ParentGroup); 3992 foreach (SceneObjectPart part in parts)
3993 {
3994 part.UpdateFlag = 0;
3995 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
3996 }
3665 } 3997 }
3998 finally
3999 {
4000 parts[0].ParentGroup.areUpdatesSuspended = false;
4001 }
4002
4003
3666 newRoot.ParentGroup.HasGroupChanged = true; 4004 newRoot.ParentGroup.HasGroupChanged = true;
3667 newRoot.ParentGroup.ScheduleGroupForFullUpdate(); 4005 newRoot.ParentGroup.ScheduleGroupForFullUpdate();
3668 } 4006 }
@@ -3708,6 +4046,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3708 } 4046 }
3709 else 4047 else
3710 { 4048 {
4049 if (linknum > m_host.ParentGroup.PrimCount || (linknum == 1 && m_host.ParentGroup.PrimCount == 1))
4050 {
4051 linknum -= (m_host.ParentGroup.PrimCount) + 1;
4052
4053 if (linknum < 0)
4054 return UUID.Zero.ToString();
4055
4056 List<ScenePresence> avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET);
4057 if (avatars.Count > linknum)
4058 {
4059 return avatars[linknum].UUID.ToString();
4060 }
4061 }
3711 return UUID.Zero.ToString(); 4062 return UUID.Zero.ToString();
3712 } 4063 }
3713 } 4064 }
@@ -3784,17 +4135,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3784 m_host.AddScriptLPS(1); 4135 m_host.AddScriptLPS(1);
3785 int count = 0; 4136 int count = 0;
3786 4137
3787 lock (m_host.TaskInventory) 4138 m_host.TaskInventory.LockItemsForRead(true);
4139 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3788 { 4140 {
3789 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4141 if (inv.Value.Type == type || type == -1)
3790 { 4142 {
3791 if (inv.Value.Type == type || type == -1) 4143 count = count + 1;
3792 {
3793 count = count + 1;
3794 }
3795 } 4144 }
3796 } 4145 }
3797 4146
4147 m_host.TaskInventory.LockItemsForRead(false);
3798 return count; 4148 return count;
3799 } 4149 }
3800 4150
@@ -3803,16 +4153,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3803 m_host.AddScriptLPS(1); 4153 m_host.AddScriptLPS(1);
3804 ArrayList keys = new ArrayList(); 4154 ArrayList keys = new ArrayList();
3805 4155
3806 lock (m_host.TaskInventory) 4156 m_host.TaskInventory.LockItemsForRead(true);
4157 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3807 { 4158 {
3808 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4159 if (inv.Value.Type == type || type == -1)
3809 { 4160 {
3810 if (inv.Value.Type == type || type == -1) 4161 keys.Add(inv.Value.Name);
3811 {
3812 keys.Add(inv.Value.Name);
3813 }
3814 } 4162 }
3815 } 4163 }
4164 m_host.TaskInventory.LockItemsForRead(false);
3816 4165
3817 if (keys.Count == 0) 4166 if (keys.Count == 0)
3818 { 4167 {
@@ -3849,30 +4198,51 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3849 } 4198 }
3850 4199
3851 // move the first object found with this inventory name 4200 // move the first object found with this inventory name
3852 lock (m_host.TaskInventory) 4201 m_host.TaskInventory.LockItemsForRead(true);
4202 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3853 { 4203 {
3854 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4204 if (inv.Value.Name == inventory)
3855 { 4205 {
3856 if (inv.Value.Name == inventory) 4206 found = true;
3857 { 4207 objId = inv.Key;
3858 found = true; 4208 assetType = inv.Value.Type;
3859 objId = inv.Key; 4209 objName = inv.Value.Name;
3860 assetType = inv.Value.Type; 4210 break;
3861 objName = inv.Value.Name;
3862 break;
3863 }
3864 } 4211 }
3865 } 4212 }
4213 m_host.TaskInventory.LockItemsForRead(false);
3866 4214
3867 if (!found) 4215 if (!found)
3868 { 4216 {
3869 llSay(0, String.Format("Could not find object '{0}'", inventory)); 4217 llSay(0, String.Format("Could not find object '{0}'", inventory));
3870 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); 4218 return;
4219// throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3871 } 4220 }
3872 4221
3873 // check if destination is an avatar 4222 // check if destination is an object
3874 if (World.GetScenePresence(destId) != null) 4223 if (World.GetSceneObjectPart(destId) != null)
4224 {
4225 // destination is an object
4226 World.MoveTaskInventoryItem(destId, m_host, objId);
4227 }
4228 else
3875 { 4229 {
4230 ScenePresence presence = World.GetScenePresence(destId);
4231
4232 if (presence == null)
4233 {
4234 UserAccount account =
4235 World.UserAccountService.GetUserAccount(
4236 World.RegionInfo.ScopeID,
4237 destId);
4238
4239 if (account == null)
4240 {
4241 llSay(0, "Can't find destination "+destId.ToString());
4242 return;
4243 }
4244 }
4245
3876 // destination is an avatar 4246 // destination is an avatar
3877 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId); 4247 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
3878 4248
@@ -3896,31 +4266,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3896 4266
3897 if (m_TransferModule != null) 4267 if (m_TransferModule != null)
3898 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 4268 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
4269
4270 //This delay should only occur when giving inventory to avatars.
4271 ScriptSleep(3000);
3899 } 4272 }
3900 else
3901 {
3902 // destination is an object
3903 World.MoveTaskInventoryItem(destId, m_host, objId);
3904 }
3905 ScriptSleep(3000);
3906 } 4273 }
3907 4274
4275 [DebuggerNonUserCode]
3908 public void llRemoveInventory(string name) 4276 public void llRemoveInventory(string name)
3909 { 4277 {
3910 m_host.AddScriptLPS(1); 4278 m_host.AddScriptLPS(1);
3911 4279
3912 lock (m_host.TaskInventory) 4280 List<TaskInventoryItem> inv;
4281 try
3913 { 4282 {
3914 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4283 m_host.TaskInventory.LockItemsForRead(true);
4284 inv = new List<TaskInventoryItem>(m_host.TaskInventory.Values);
4285 }
4286 finally
4287 {
4288 m_host.TaskInventory.LockItemsForRead(false);
4289 }
4290 foreach (TaskInventoryItem item in inv)
4291 {
4292 if (item.Name == name)
3915 { 4293 {
3916 if (item.Name == name) 4294 if (item.ItemID == m_itemID)
3917 { 4295 throw new ScriptDeleteException();
3918 if (item.ItemID == m_itemID) 4296 else
3919 throw new ScriptDeleteException(); 4297 m_host.Inventory.RemoveInventoryItem(item.ItemID);
3920 else 4298 return;
3921 m_host.Inventory.RemoveInventoryItem(item.ItemID);
3922 return;
3923 }
3924 } 4299 }
3925 } 4300 }
3926 } 4301 }
@@ -3955,112 +4330,122 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3955 { 4330 {
3956 m_host.AddScriptLPS(1); 4331 m_host.AddScriptLPS(1);
3957 4332
3958 UUID uuid = (UUID)id; 4333 UUID uuid;
3959 PresenceInfo pinfo = null; 4334 if (UUID.TryParse(id, out uuid))
3960 UserAccount account;
3961
3962 UserInfoCacheEntry ce;
3963 if (!m_userInfoCache.TryGetValue(uuid, out ce))
3964 { 4335 {
3965 account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid); 4336 PresenceInfo pinfo = null;
3966 if (account == null) 4337 UserAccount account;
4338
4339 UserInfoCacheEntry ce;
4340 if (!m_userInfoCache.TryGetValue(uuid, out ce))
3967 { 4341 {
3968 m_userInfoCache[uuid] = null; // Cache negative 4342 account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
3969 return UUID.Zero.ToString(); 4343 if (account == null)
3970 } 4344 {
4345 m_userInfoCache[uuid] = null; // Cache negative
4346 return UUID.Zero.ToString();
4347 }
3971 4348
3972 4349
3973 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); 4350 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
3974 if (pinfos != null && pinfos.Length > 0) 4351 if (pinfos != null && pinfos.Length > 0)
3975 {
3976 foreach (PresenceInfo p in pinfos)
3977 { 4352 {
3978 if (p.RegionID != UUID.Zero) 4353 foreach (PresenceInfo p in pinfos)
3979 { 4354 {
3980 pinfo = p; 4355 if (p.RegionID != UUID.Zero)
4356 {
4357 pinfo = p;
4358 }
3981 } 4359 }
3982 } 4360 }
3983 }
3984 4361
3985 ce = new UserInfoCacheEntry(); 4362 ce = new UserInfoCacheEntry();
3986 ce.time = Util.EnvironmentTickCount(); 4363 ce.time = Util.EnvironmentTickCount();
3987 ce.account = account; 4364 ce.account = account;
3988 ce.pinfo = pinfo; 4365 ce.pinfo = pinfo;
3989 } 4366 m_userInfoCache[uuid] = ce;
3990 else 4367 }
3991 { 4368 else
3992 if (ce == null) 4369 {
3993 return UUID.Zero.ToString(); 4370 if (ce == null)
4371 return UUID.Zero.ToString();
3994 4372
3995 account = ce.account; 4373 account = ce.account;
3996 pinfo = ce.pinfo; 4374 pinfo = ce.pinfo;
3997 } 4375 }
3998 4376
3999 if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000) 4377 if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000)
4000 {
4001 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4002 if (pinfos != null && pinfos.Length > 0)
4003 { 4378 {
4004 foreach (PresenceInfo p in pinfos) 4379 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4380 if (pinfos != null && pinfos.Length > 0)
4005 { 4381 {
4006 if (p.RegionID != UUID.Zero) 4382 foreach (PresenceInfo p in pinfos)
4007 { 4383 {
4008 pinfo = p; 4384 if (p.RegionID != UUID.Zero)
4385 {
4386 pinfo = p;
4387 }
4009 } 4388 }
4010 } 4389 }
4011 } 4390 else
4012 else 4391 pinfo = null;
4013 pinfo = null;
4014 4392
4015 ce.time = Util.EnvironmentTickCount(); 4393 ce.time = Util.EnvironmentTickCount();
4016 ce.pinfo = pinfo; 4394 ce.pinfo = pinfo;
4017 } 4395 }
4018 4396
4019 string reply = String.Empty; 4397 string reply = String.Empty;
4020 4398
4021 switch (data) 4399 switch (data)
4022 { 4400 {
4023 case 1: // DATA_ONLINE (0|1) 4401 case 1: // DATA_ONLINE (0|1)
4024 if (pinfo != null && pinfo.RegionID != UUID.Zero) 4402 if (pinfo != null && pinfo.RegionID != UUID.Zero)
4025 reply = "1"; 4403 reply = "1";
4026 else 4404 else
4027 reply = "0"; 4405 reply = "0";
4028 break; 4406 break;
4029 case 2: // DATA_NAME (First Last) 4407 case 2: // DATA_NAME (First Last)
4030 reply = account.FirstName + " " + account.LastName; 4408 reply = account.FirstName + " " + account.LastName;
4031 break; 4409 break;
4032 case 3: // DATA_BORN (YYYY-MM-DD) 4410 case 3: // DATA_BORN (YYYY-MM-DD)
4033 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0); 4411 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
4034 born = born.AddSeconds(account.Created); 4412 born = born.AddSeconds(account.Created);
4035 reply = born.ToString("yyyy-MM-dd"); 4413 reply = born.ToString("yyyy-MM-dd");
4036 break; 4414 break;
4037 case 4: // DATA_RATING (0,0,0,0,0,0) 4415 case 4: // DATA_RATING (0,0,0,0,0,0)
4038 reply = "0,0,0,0,0,0"; 4416 reply = "0,0,0,0,0,0";
4039 break; 4417 break;
4040 case 8: // DATA_PAYINFO (0|1|2|3) 4418 case 8: // DATA_PAYINFO (0|1|2|3)
4041 reply = "0"; 4419 reply = "0";
4042 break; 4420 break;
4043 default: 4421 default:
4044 return UUID.Zero.ToString(); // Raise no event 4422 return UUID.Zero.ToString(); // Raise no event
4045 } 4423 }
4046 4424
4047 UUID rq = UUID.Random(); 4425 UUID rq = UUID.Random();
4048 4426
4049 UUID tid = AsyncCommands. 4427 UUID tid = AsyncCommands.
4050 DataserverPlugin.RegisterRequest(m_localID, 4428 DataserverPlugin.RegisterRequest(m_localID,
4051 m_itemID, rq.ToString()); 4429 m_itemID, rq.ToString());
4052 4430
4053 AsyncCommands. 4431 AsyncCommands.
4054 DataserverPlugin.DataserverReply(rq.ToString(), reply); 4432 DataserverPlugin.DataserverReply(rq.ToString(), reply);
4055 4433
4056 ScriptSleep(100); 4434 ScriptSleep(100);
4057 return tid.ToString(); 4435 return tid.ToString();
4436 }
4437 else
4438 {
4439 ShoutError("Invalid UUID passed to llRequestAgentData.");
4440 }
4441 return "";
4058 } 4442 }
4059 4443
4060 public LSL_String llRequestInventoryData(string name) 4444 public LSL_String llRequestInventoryData(string name)
4061 { 4445 {
4062 m_host.AddScriptLPS(1); 4446 m_host.AddScriptLPS(1);
4063 4447
4448 //Clone is thread safe
4064 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 4449 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
4065 4450
4066 foreach (TaskInventoryItem item in itemDictionary.Values) 4451 foreach (TaskInventoryItem item in itemDictionary.Values)
@@ -4114,6 +4499,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4114 ScenePresence presence = World.GetScenePresence(agentId); 4499 ScenePresence presence = World.GetScenePresence(agentId);
4115 if (presence != null) 4500 if (presence != null)
4116 { 4501 {
4502 // agent must not be a god
4503 if (presence.UserLevel >= 200) return;
4504
4117 // agent must be over the owners land 4505 // agent must be over the owners land
4118 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4506 if (m_host.OwnerID == World.LandChannel.GetLandObject(
4119 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) 4507 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
@@ -4136,7 +4524,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4136 UUID av = new UUID(); 4524 UUID av = new UUID();
4137 if (!UUID.TryParse(agent,out av)) 4525 if (!UUID.TryParse(agent,out av))
4138 { 4526 {
4139 LSLError("First parameter to llDialog needs to be a key"); 4527 //LSLError("First parameter to llDialog needs to be a key");
4140 return; 4528 return;
4141 } 4529 }
4142 4530
@@ -4173,17 +4561,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4173 UUID soundId = UUID.Zero; 4561 UUID soundId = UUID.Zero;
4174 if (!UUID.TryParse(impact_sound, out soundId)) 4562 if (!UUID.TryParse(impact_sound, out soundId))
4175 { 4563 {
4176 lock (m_host.TaskInventory) 4564 m_host.TaskInventory.LockItemsForRead(true);
4565 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4177 { 4566 {
4178 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4567 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound)
4179 { 4568 {
4180 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) 4569 soundId = item.AssetID;
4181 { 4570 break;
4182 soundId = item.AssetID;
4183 break;
4184 }
4185 } 4571 }
4186 } 4572 }
4573 m_host.TaskInventory.LockItemsForRead(false);
4187 } 4574 }
4188 m_host.CollisionSound = soundId; 4575 m_host.CollisionSound = soundId;
4189 m_host.CollisionSoundVolume = (float)impact_volume; 4576 m_host.CollisionSoundVolume = (float)impact_volume;
@@ -4229,6 +4616,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4229 UUID partItemID; 4616 UUID partItemID;
4230 foreach (SceneObjectPart part in parts) 4617 foreach (SceneObjectPart part in parts)
4231 { 4618 {
4619 //Clone is thread safe
4232 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); 4620 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
4233 4621
4234 foreach (TaskInventoryItem item in itemsDictionary.Values) 4622 foreach (TaskInventoryItem item in itemsDictionary.Values)
@@ -4443,17 +4831,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4443 4831
4444 m_host.AddScriptLPS(1); 4832 m_host.AddScriptLPS(1);
4445 4833
4446 lock (m_host.TaskInventory) 4834 m_host.TaskInventory.LockItemsForRead(true);
4835 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4447 { 4836 {
4448 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4837 if (item.Type == 10 && item.ItemID == m_itemID)
4449 { 4838 {
4450 if (item.Type == 10 && item.ItemID == m_itemID) 4839 result = item.Name!=null?item.Name:String.Empty;
4451 { 4840 break;
4452 result = item.Name != null ? item.Name : String.Empty;
4453 break;
4454 }
4455 } 4841 }
4456 } 4842 }
4843 m_host.TaskInventory.LockItemsForRead(false);
4457 4844
4458 return result; 4845 return result;
4459 } 4846 }
@@ -4606,23 +4993,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4606 { 4993 {
4607 m_host.AddScriptLPS(1); 4994 m_host.AddScriptLPS(1);
4608 4995
4609 lock (m_host.TaskInventory) 4996 m_host.TaskInventory.LockItemsForRead(true);
4997 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4610 { 4998 {
4611 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4999 if (inv.Value.Name == name)
4612 { 5000 {
4613 if (inv.Value.Name == name) 5001 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4614 { 5002 {
4615 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) 5003 m_host.TaskInventory.LockItemsForRead(false);
4616 { 5004 return inv.Value.AssetID.ToString();
4617 return inv.Value.AssetID.ToString(); 5005 }
4618 } 5006 else
4619 else 5007 {
4620 { 5008 m_host.TaskInventory.LockItemsForRead(false);
4621 return UUID.Zero.ToString(); 5009 return UUID.Zero.ToString();
4622 }
4623 } 5010 }
4624 } 5011 }
4625 } 5012 }
5013 m_host.TaskInventory.LockItemsForRead(false);
4626 5014
4627 return UUID.Zero.ToString(); 5015 return UUID.Zero.ToString();
4628 } 5016 }
@@ -4775,14 +5163,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4775 { 5163 {
4776 m_host.AddScriptLPS(1); 5164 m_host.AddScriptLPS(1);
4777 5165
4778 if (src == null) 5166 return src.Length;
4779 {
4780 return 0;
4781 }
4782 else
4783 {
4784 return src.Length;
4785 }
4786 } 5167 }
4787 5168
4788 public LSL_Integer llList2Integer(LSL_List src, int index) 5169 public LSL_Integer llList2Integer(LSL_List src, int index)
@@ -4828,7 +5209,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4828 else if (src.Data[index] is LSL_Float) 5209 else if (src.Data[index] is LSL_Float)
4829 return Convert.ToDouble(((LSL_Float) src.Data[index]).value); 5210 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
4830 else if (src.Data[index] is LSL_String) 5211 else if (src.Data[index] is LSL_String)
4831 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string); 5212 {
5213 string str = ((LSL_String) src.Data[index]).m_string;
5214 Match m = Regex.Match(str, "^\\s*(-?\\+?[,0-9]+\\.?[0-9]*)");
5215 if (m != Match.Empty)
5216 {
5217 str = m.Value;
5218 double d = 0.0;
5219 if (!Double.TryParse(str, out d))
5220 return 0.0;
5221
5222 return d;
5223 }
5224 return 0.0;
5225 }
4832 return Convert.ToDouble(src.Data[index]); 5226 return Convert.ToDouble(src.Data[index]);
4833 } 5227 }
4834 catch (FormatException) 5228 catch (FormatException)
@@ -5101,7 +5495,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5101 } 5495 }
5102 } 5496 }
5103 } 5497 }
5104 else { 5498 else
5499 {
5105 object[] array = new object[src.Length]; 5500 object[] array = new object[src.Length];
5106 Array.Copy(src.Data, 0, array, 0, src.Length); 5501 Array.Copy(src.Data, 0, array, 0, src.Length);
5107 result = new LSL_List(array); 5502 result = new LSL_List(array);
@@ -5513,7 +5908,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5513 public void llSetSoundQueueing(int queue) 5908 public void llSetSoundQueueing(int queue)
5514 { 5909 {
5515 m_host.AddScriptLPS(1); 5910 m_host.AddScriptLPS(1);
5516 NotImplemented("llSetSoundQueueing");
5517 } 5911 }
5518 5912
5519 public void llSetSoundRadius(double radius) 5913 public void llSetSoundRadius(double radius)
@@ -5558,10 +5952,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5558 m_host.AddScriptLPS(1); 5952 m_host.AddScriptLPS(1);
5559 5953
5560 List<SceneObjectPart> parts = GetLinkParts(linknumber); 5954 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5561 5955 if (parts.Count > 0)
5562 foreach (var part in parts)
5563 { 5956 {
5564 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate); 5957 try
5958 {
5959 parts[0].ParentGroup.areUpdatesSuspended = true;
5960 foreach (var part in parts)
5961 {
5962 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
5963 }
5964 }
5965 finally
5966 {
5967 parts[0].ParentGroup.areUpdatesSuspended = false;
5968 }
5565 } 5969 }
5566 } 5970 }
5567 5971
@@ -5615,6 +6019,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5615 ScriptSleep(5000); 6019 ScriptSleep(5000);
5616 } 6020 }
5617 6021
6022 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers)
6023 {
6024 return ParseString2List(str, separators, in_spacers, false);
6025 }
6026
5618 public LSL_Integer llOverMyLand(string id) 6027 public LSL_Integer llOverMyLand(string id)
5619 { 6028 {
5620 m_host.AddScriptLPS(1); 6029 m_host.AddScriptLPS(1);
@@ -5815,7 +6224,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5815 return m_host.ParentGroup.RootPart.AttachmentPoint; 6224 return m_host.ParentGroup.RootPart.AttachmentPoint;
5816 } 6225 }
5817 6226
5818 public LSL_Integer llGetFreeMemory() 6227 public virtual LSL_Integer llGetFreeMemory()
5819 { 6228 {
5820 m_host.AddScriptLPS(1); 6229 m_host.AddScriptLPS(1);
5821 // Make scripts designed for LSO happy 6230 // Make scripts designed for LSO happy
@@ -5932,7 +6341,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5932 SetParticleSystem(m_host, rules); 6341 SetParticleSystem(m_host, rules);
5933 } 6342 }
5934 6343
5935 private void SetParticleSystem(SceneObjectPart part, LSL_List rules) { 6344 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6345 {
5936 6346
5937 6347
5938 if (rules.Length == 0) 6348 if (rules.Length == 0)
@@ -6126,14 +6536,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6126 6536
6127 protected UUID GetTaskInventoryItem(string name) 6537 protected UUID GetTaskInventoryItem(string name)
6128 { 6538 {
6129 lock (m_host.TaskInventory) 6539 m_host.TaskInventory.LockItemsForRead(true);
6540 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6130 { 6541 {
6131 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6542 if (inv.Value.Name == name)
6132 { 6543 {
6133 if (inv.Value.Name == name) 6544 m_host.TaskInventory.LockItemsForRead(false);
6134 return inv.Key; 6545 return inv.Key;
6135 } 6546 }
6136 } 6547 }
6548 m_host.TaskInventory.LockItemsForRead(false);
6137 6549
6138 return UUID.Zero; 6550 return UUID.Zero;
6139 } 6551 }
@@ -6383,13 +6795,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6383 UUID av = new UUID(); 6795 UUID av = new UUID();
6384 if (!UUID.TryParse(avatar,out av)) 6796 if (!UUID.TryParse(avatar,out av))
6385 { 6797 {
6386 LSLError("First parameter to llDialog needs to be a key"); 6798 //LSLError("First parameter to llDialog needs to be a key");
6387 return; 6799 return;
6388 } 6800 }
6389 if (buttons.Length < 1) 6801 if (buttons.Length < 1)
6390 { 6802 {
6391 LSLError("No less than 1 button can be shown"); 6803 buttons.Add("OK");
6392 return;
6393 } 6804 }
6394 if (buttons.Length > 12) 6805 if (buttons.Length > 12)
6395 { 6806 {
@@ -6406,7 +6817,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6406 } 6817 }
6407 if (buttons.Data[i].ToString().Length > 24) 6818 if (buttons.Data[i].ToString().Length > 24)
6408 { 6819 {
6409 LSLError("button label cannot be longer than 24 characters"); 6820 llWhisper(ScriptBaseClass.DEBUG_CHANNEL, "button label cannot be longer than 24 characters");
6410 return; 6821 return;
6411 } 6822 }
6412 buts[i] = buttons.Data[i].ToString(); 6823 buts[i] = buttons.Data[i].ToString();
@@ -6470,22 +6881,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6470 } 6881 }
6471 6882
6472 // copy the first script found with this inventory name 6883 // copy the first script found with this inventory name
6473 lock (m_host.TaskInventory) 6884 TaskInventoryItem scriptItem = null;
6885 m_host.TaskInventory.LockItemsForRead(true);
6886 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6474 { 6887 {
6475 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6888 if (inv.Value.Name == name)
6476 { 6889 {
6477 if (inv.Value.Name == name) 6890 // make sure the object is a script
6891 if (10 == inv.Value.Type)
6478 { 6892 {
6479 // make sure the object is a script 6893 found = true;
6480 if (10 == inv.Value.Type) 6894 srcId = inv.Key;
6481 { 6895 scriptItem = inv.Value;
6482 found = true; 6896 break;
6483 srcId = inv.Key;
6484 break;
6485 }
6486 } 6897 }
6487 } 6898 }
6488 } 6899 }
6900 m_host.TaskInventory.LockItemsForRead(false);
6489 6901
6490 if (!found) 6902 if (!found)
6491 { 6903 {
@@ -6493,8 +6905,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6493 return; 6905 return;
6494 } 6906 }
6495 6907
6496 // the rest of the permission checks are done in RezScript, so check the pin there as well 6908 SceneObjectPart dest = World.GetSceneObjectPart(destId);
6497 World.RezScript(srcId, m_host, destId, pin, running, start_param); 6909 if (dest != null)
6910 {
6911 if ((scriptItem.BasePermissions & (uint)PermissionMask.Transfer) != 0 || dest.ParentGroup.RootPart.OwnerID == m_host.ParentGroup.RootPart.OwnerID)
6912 {
6913 // the rest of the permission checks are done in RezScript, so check the pin there as well
6914 World.RezScript(srcId, m_host, destId, pin, running, start_param);
6915
6916 if ((scriptItem.BasePermissions & (uint)PermissionMask.Copy) == 0)
6917 m_host.Inventory.RemoveInventoryItem(srcId);
6918 }
6919 }
6498 // this will cause the delay even if the script pin or permissions were wrong - seems ok 6920 // this will cause the delay even if the script pin or permissions were wrong - seems ok
6499 ScriptSleep(3000); 6921 ScriptSleep(3000);
6500 } 6922 }
@@ -6557,18 +6979,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6557 public LSL_String llMD5String(string src, int nonce) 6979 public LSL_String llMD5String(string src, int nonce)
6558 { 6980 {
6559 m_host.AddScriptLPS(1); 6981 m_host.AddScriptLPS(1);
6560 return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString())); 6982 return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()), Encoding.UTF8);
6561 } 6983 }
6562 6984
6563 public LSL_String llSHA1String(string src) 6985 public LSL_String llSHA1String(string src)
6564 { 6986 {
6565 m_host.AddScriptLPS(1); 6987 m_host.AddScriptLPS(1);
6566 return Util.SHA1Hash(src).ToLower(); 6988 return Util.SHA1Hash(src, Encoding.UTF8).ToLower();
6567 } 6989 }
6568 6990
6569 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist) 6991 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist)
6570 { 6992 {
6571 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 6993 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6994 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
6995 return shapeBlock;
6572 6996
6573 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && 6997 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
6574 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && 6998 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
@@ -6644,6 +7068,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6644 7068
6645 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge) 7069 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge)
6646 { 7070 {
7071 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7072 return;
7073
6647 ObjectShapePacket.ObjectDataBlock shapeBlock; 7074 ObjectShapePacket.ObjectDataBlock shapeBlock;
6648 7075
6649 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7076 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6693,6 +7120,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6693 7120
6694 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge) 7121 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge)
6695 { 7122 {
7123 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7124 return;
7125
6696 ObjectShapePacket.ObjectDataBlock shapeBlock; 7126 ObjectShapePacket.ObjectDataBlock shapeBlock;
6697 7127
6698 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7128 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6735,6 +7165,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6735 7165
6736 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) 7166 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)
6737 { 7167 {
7168 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7169 return;
7170
6738 ObjectShapePacket.ObjectDataBlock shapeBlock; 7171 ObjectShapePacket.ObjectDataBlock shapeBlock;
6739 7172
6740 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist); 7173 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
@@ -6861,6 +7294,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6861 7294
6862 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type) 7295 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type)
6863 { 7296 {
7297 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7298 return;
7299
6864 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 7300 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6865 UUID sculptId; 7301 UUID sculptId;
6866 7302
@@ -6876,13 +7312,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6876 shapeBlock.PathScaleX = 100; 7312 shapeBlock.PathScaleX = 100;
6877 shapeBlock.PathScaleY = 150; 7313 shapeBlock.PathScaleY = 150;
6878 7314
6879 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER && 7315 if ((type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER) == 0 &&
6880 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE && 7316 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE) == 0 &&
6881 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE && 7317 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE) == 0 &&
6882 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) 7318 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) == 0)
6883 { 7319 {
6884 // default 7320 // default
6885 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; 7321 type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
6886 } 7322 }
6887 7323
6888 // retain pathcurve 7324 // retain pathcurve
@@ -6901,32 +7337,87 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6901 ScriptSleep(200); 7337 ScriptSleep(200);
6902 } 7338 }
6903 7339
6904 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) 7340 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
6905 { 7341 {
6906 m_host.AddScriptLPS(1); 7342 m_host.AddScriptLPS(1);
6907 7343
6908 List<SceneObjectPart> parts = GetLinkParts(linknumber); 7344 List<SceneObjectPart> parts = GetLinkParts(linknumber);
7345 List<ScenePresence> avatars = GetLinkAvatars(linknumber);
7346 if (parts.Count>0)
7347 {
7348 try
7349 {
7350 parts[0].ParentGroup.areUpdatesSuspended = true;
7351 foreach (SceneObjectPart part in parts)
7352 SetPrimParams(part, rules);
7353 }
7354 finally
7355 {
7356 parts[0].ParentGroup.areUpdatesSuspended = false;
7357 }
7358 }
7359 if (avatars.Count > 0)
7360 {
7361 foreach (ScenePresence avatar in avatars)
7362 SetPrimParams(avatar, rules);
7363 }
7364 }
6909 7365
6910 foreach (SceneObjectPart part in parts) 7366 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
6911 SetPrimParams(part, rules); 7367 {
6912 7368 llSetLinkPrimitiveParamsFast(linknumber, rules);
6913 ScriptSleep(200); 7369 ScriptSleep(200);
6914 } 7370 }
6915 7371
6916 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules) 7372 protected void SetPrimParams(ScenePresence av, LSL_List rules)
6917 { 7373 {
6918 m_host.AddScriptLPS(1); 7374 //This is a special version of SetPrimParams to deal with avatars which are sat on the linkset.
7375 //We only support PRIM_POSITION and PRIM_ROTATION
6919 7376
6920 List<SceneObjectPart> parts = GetLinkParts(linknumber); 7377 int idx = 0;
6921 7378
6922 foreach (SceneObjectPart part in parts) 7379 while (idx < rules.Length)
6923 SetPrimParams(part, rules); 7380 {
7381 int code = rules.GetLSLIntegerItem(idx++);
7382
7383 int remain = rules.Length - idx;
7384
7385
7386
7387 switch (code)
7388 {
7389 case (int)ScriptBaseClass.PRIM_POSITION:
7390 if (remain < 1)
7391 return;
7392 LSL_Vector v;
7393 v = rules.GetVector3Item(idx++);
7394 av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
7395 av.SendAvatarDataToAllAgents();
7396
7397 break;
7398
7399 case (int)ScriptBaseClass.PRIM_ROTATION:
7400 if (remain < 1)
7401 return;
7402 LSL_Rotation r;
7403 r = rules.GetQuaternionItem(idx++);
7404 av.OffsetRotation = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
7405 av.SendAvatarDataToAllAgents();
7406 break;
7407 }
7408 }
6924 } 7409 }
6925 7410
6926 protected void SetPrimParams(SceneObjectPart part, LSL_List rules) 7411 protected void SetPrimParams(SceneObjectPart part, LSL_List rules)
6927 { 7412 {
7413 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7414 return;
7415
6928 int idx = 0; 7416 int idx = 0;
6929 7417
7418 bool positionChanged = false;
7419 LSL_Vector currentPosition = GetPartLocalPos(part);
7420
6930 while (idx < rules.Length) 7421 while (idx < rules.Length)
6931 { 7422 {
6932 int code = rules.GetLSLIntegerItem(idx++); 7423 int code = rules.GetLSLIntegerItem(idx++);
@@ -6935,7 +7426,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6935 7426
6936 int face; 7427 int face;
6937 LSL_Vector v; 7428 LSL_Vector v;
6938 7429
6939 switch (code) 7430 switch (code)
6940 { 7431 {
6941 case (int)ScriptBaseClass.PRIM_POSITION: 7432 case (int)ScriptBaseClass.PRIM_POSITION:
@@ -6943,7 +7434,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6943 return; 7434 return;
6944 7435
6945 v=rules.GetVector3Item(idx++); 7436 v=rules.GetVector3Item(idx++);
6946 SetPos(part, v); 7437 positionChanged = true;
7438 currentPosition = GetSetPosTarget(part, v, currentPosition);
6947 7439
6948 break; 7440 break;
6949 case (int)ScriptBaseClass.PRIM_SIZE: 7441 case (int)ScriptBaseClass.PRIM_SIZE:
@@ -7311,6 +7803,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7311 break; 7803 break;
7312 } 7804 }
7313 } 7805 }
7806
7807 if (positionChanged)
7808 {
7809 if (part.ParentGroup.RootPart == part)
7810 {
7811 SceneObjectGroup parent = part.ParentGroup;
7812 parent.UpdateGroupPosition(new Vector3((float)currentPosition.x, (float)currentPosition.y, (float)currentPosition.z));
7813 }
7814 else
7815 {
7816 part.OffsetPosition = new Vector3((float)currentPosition.x, (float)currentPosition.y, (float)currentPosition.z);
7817 SceneObjectGroup parent = part.ParentGroup;
7818 parent.HasGroupChanged = true;
7819 parent.ScheduleGroupForTerseUpdate();
7820 }
7821 }
7314 } 7822 }
7315 7823
7316 public LSL_String llStringToBase64(string str) 7824 public LSL_String llStringToBase64(string str)
@@ -7459,13 +7967,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7459 public LSL_Integer llGetNumberOfPrims() 7967 public LSL_Integer llGetNumberOfPrims()
7460 { 7968 {
7461 m_host.AddScriptLPS(1); 7969 m_host.AddScriptLPS(1);
7462 int avatarCount = 0; 7970 int avatarCount = m_host.ParentGroup.GetLinkedAvatars().Count;
7463 World.ForEachScenePresence(delegate(ScenePresence presence) 7971
7464 {
7465 if (!presence.IsChildAgent && presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID))
7466 avatarCount++;
7467 });
7468
7469 return m_host.ParentGroup.PrimCount + avatarCount; 7972 return m_host.ParentGroup.PrimCount + avatarCount;
7470 } 7973 }
7471 7974
@@ -7481,55 +7984,98 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7481 m_host.AddScriptLPS(1); 7984 m_host.AddScriptLPS(1);
7482 UUID objID = UUID.Zero; 7985 UUID objID = UUID.Zero;
7483 LSL_List result = new LSL_List(); 7986 LSL_List result = new LSL_List();
7987
7988 // If the ID is not valid, return null result
7484 if (!UUID.TryParse(obj, out objID)) 7989 if (!UUID.TryParse(obj, out objID))
7485 { 7990 {
7486 result.Add(new LSL_Vector()); 7991 result.Add(new LSL_Vector());
7487 result.Add(new LSL_Vector()); 7992 result.Add(new LSL_Vector());
7488 return result; 7993 return result;
7489 } 7994 }
7995
7996 // Check if this is an attached prim. If so, replace
7997 // the UUID with the avatar UUID and report it's bounding box
7998 SceneObjectPart part = World.GetSceneObjectPart(objID);
7999 if (part != null && part.ParentGroup.IsAttachment)
8000 objID = part.ParentGroup.RootPart.AttachedAvatar;
8001
8002 // Find out if this is an avatar ID. If so, return it's box
7490 ScenePresence presence = World.GetScenePresence(objID); 8003 ScenePresence presence = World.GetScenePresence(objID);
7491 if (presence != null) 8004 if (presence != null)
7492 { 8005 {
7493 if (presence.ParentID == 0) // not sat on an object 8006 // As per LSL Wiki, there is no difference between sitting
8007 // and standing avatar since server 1.36
8008 LSL_Vector lower;
8009 LSL_Vector upper;
8010 if (presence.Animator.Animations.DefaultAnimation.AnimID
8011 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
7494 { 8012 {
7495 LSL_Vector lower; 8013 // This is for ground sitting avatars
7496 LSL_Vector upper; 8014 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7497 if (presence.Animator.Animations.DefaultAnimation.AnimID 8015 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7498 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) 8016 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7499 {
7500 // This is for ground sitting avatars
7501 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7502 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7503 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7504 }
7505 else
7506 {
7507 // This is for standing/flying avatars
7508 float height = presence.Appearance.AvatarHeight / 2.0f;
7509 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7510 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7511 }
7512 result.Add(lower);
7513 result.Add(upper);
7514 return result;
7515 } 8017 }
7516 else 8018 else
7517 { 8019 {
7518 // sitting on an object so we need the bounding box of that 8020 // This is for standing/flying avatars
7519 // which should include the avatar so set the UUID to the 8021 float height = presence.Appearance.AvatarHeight / 2.0f;
7520 // UUID of the object the avatar is sat on and allow it to fall through 8022 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7521 // to processing an object 8023 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7522 SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
7523 objID = p.UUID;
7524 } 8024 }
8025
8026 // Adjust to the documented error offsets (see LSL Wiki)
8027 lower += new LSL_Vector(0.05f, 0.05f, 0.05f);
8028 upper -= new LSL_Vector(0.05f, 0.05f, 0.05f);
8029
8030 if (lower.x > upper.x)
8031 lower.x = upper.x;
8032 if (lower.y > upper.y)
8033 lower.y = upper.y;
8034 if (lower.z > upper.z)
8035 lower.z = upper.z;
8036
8037 result.Add(lower);
8038 result.Add(upper);
8039 return result;
7525 } 8040 }
7526 SceneObjectPart part = World.GetSceneObjectPart(objID); 8041
8042 part = World.GetSceneObjectPart(objID);
7527 // Currently only works for single prims without a sitting avatar 8043 // Currently only works for single prims without a sitting avatar
7528 if (part != null) 8044 if (part != null)
7529 { 8045 {
7530 Vector3 halfSize = part.Scale / 2.0f; 8046 float minX;
7531 LSL_Vector lower = new LSL_Vector(halfSize.X * -1.0f, halfSize.Y * -1.0f, halfSize.Z * -1.0f); 8047 float maxX;
7532 LSL_Vector upper = new LSL_Vector(halfSize.X, halfSize.Y, halfSize.Z); 8048 float minY;
8049 float maxY;
8050 float minZ;
8051 float maxZ;
8052
8053 // This BBox is in sim coordinates, with the offset being
8054 // a contained point.
8055 Vector3[] offsets = World.GetCombinedBoundingBox(new List<SceneObjectGroup> { part.ParentGroup },
8056 out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
8057
8058 minX -= offsets[0].X;
8059 maxX -= offsets[0].X;
8060 minY -= offsets[0].Y;
8061 maxY -= offsets[0].Y;
8062 minZ -= offsets[0].Z;
8063 maxZ -= offsets[0].Z;
8064
8065 LSL_Vector lower;
8066 LSL_Vector upper;
8067
8068 // Adjust to the documented error offsets (see LSL Wiki)
8069 lower = new LSL_Vector(minX + 0.05f, minY + 0.05f, minZ + 0.05f);
8070 upper = new LSL_Vector(maxX - 0.05f, maxY - 0.05f, maxZ - 0.05f);
8071
8072 if (lower.x > upper.x)
8073 lower.x = upper.x;
8074 if (lower.y > upper.y)
8075 lower.y = upper.y;
8076 if (lower.z > upper.z)
8077 lower.z = upper.z;
8078
7533 result.Add(lower); 8079 result.Add(lower);
7534 result.Add(upper); 8080 result.Add(upper);
7535 return result; 8081 return result;
@@ -7609,13 +8155,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7609 LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X, 8155 LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
7610 part.AbsolutePosition.Y, 8156 part.AbsolutePosition.Y,
7611 part.AbsolutePosition.Z); 8157 part.AbsolutePosition.Z);
7612 // For some reason, the part.AbsolutePosition.* values do not change if the
7613 // linkset is rotated; they always reflect the child prim's world position
7614 // as though the linkset is unrotated. This is incompatible behavior with SL's
7615 // implementation, so will break scripts imported from there (not to mention it
7616 // makes it more difficult to determine a child prim's actual inworld position).
7617 if (part.ParentID != 0)
7618 v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
7619 res.Add(v); 8158 res.Add(v);
7620 break; 8159 break;
7621 8160
@@ -7776,56 +8315,92 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7776 case (int)ScriptBaseClass.PRIM_BUMP_SHINY: 8315 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
7777 if (remain < 1) 8316 if (remain < 1)
7778 return res; 8317 return res;
7779 8318 face = (int)rules.GetLSLIntegerItem(idx++);
7780 face=(int)rules.GetLSLIntegerItem(idx++);
7781 8319
7782 tex = part.Shape.Textures; 8320 tex = part.Shape.Textures;
8321 int shiny;
7783 if (face == ScriptBaseClass.ALL_SIDES) 8322 if (face == ScriptBaseClass.ALL_SIDES)
7784 { 8323 {
7785 for (face = 0; face < GetNumberOfSides(part); face++) 8324 for (face = 0; face < GetNumberOfSides(part); face++)
7786 { 8325 {
7787 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8326 Shininess shinyness = tex.GetFace((uint)face).Shiny;
7788 // Convert Shininess to PRIM_SHINY_* 8327 if (shinyness == Shininess.High)
7789 res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); 8328 {
7790 // PRIM_BUMP_* 8329 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
7791 res.Add(new LSL_Integer((int)texface.Bump)); 8330 }
8331 else if (shinyness == Shininess.Medium)
8332 {
8333 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
8334 }
8335 else if (shinyness == Shininess.Low)
8336 {
8337 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8338 }
8339 else
8340 {
8341 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8342 }
8343 res.Add(new LSL_Integer(shiny));
8344 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
7792 } 8345 }
7793 } 8346 }
7794 else 8347 else
7795 { 8348 {
7796 if (face >= 0 && face < GetNumberOfSides(part)) 8349 Shininess shinyness = tex.GetFace((uint)face).Shiny;
8350 if (shinyness == Shininess.High)
7797 { 8351 {
7798 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8352 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
7799 // Convert Shininess to PRIM_SHINY_* 8353 }
7800 res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); 8354 else if (shinyness == Shininess.Medium)
7801 // PRIM_BUMP_* 8355 {
7802 res.Add(new LSL_Integer((int)texface.Bump)); 8356 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
7803 } 8357 }
8358 else if (shinyness == Shininess.Low)
8359 {
8360 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8361 }
8362 else
8363 {
8364 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8365 }
8366 res.Add(new LSL_Integer(shiny));
8367 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
7804 } 8368 }
7805 break; 8369 break;
7806 8370
7807 case (int)ScriptBaseClass.PRIM_FULLBRIGHT: 8371 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
7808 if (remain < 1) 8372 if (remain < 1)
7809 return res; 8373 return res;
7810 8374 face = (int)rules.GetLSLIntegerItem(idx++);
7811 face=(int)rules.GetLSLIntegerItem(idx++);
7812 8375
7813 tex = part.Shape.Textures; 8376 tex = part.Shape.Textures;
8377 int fullbright;
7814 if (face == ScriptBaseClass.ALL_SIDES) 8378 if (face == ScriptBaseClass.ALL_SIDES)
7815 { 8379 {
7816 for (face = 0; face < GetNumberOfSides(part); face++) 8380 for (face = 0; face < GetNumberOfSides(part); face++)
7817 { 8381 {
7818 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8382 if (tex.GetFace((uint)face).Fullbright == true)
7819 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0)); 8383 {
8384 fullbright = ScriptBaseClass.TRUE;
8385 }
8386 else
8387 {
8388 fullbright = ScriptBaseClass.FALSE;
8389 }
8390 res.Add(new LSL_Integer(fullbright));
7820 } 8391 }
7821 } 8392 }
7822 else 8393 else
7823 { 8394 {
7824 if (face >= 0 && face < GetNumberOfSides(part)) 8395 if (tex.GetFace((uint)face).Fullbright == true)
7825 { 8396 {
7826 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8397 fullbright = ScriptBaseClass.TRUE;
7827 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0)); 8398 }
8399 else
8400 {
8401 fullbright = ScriptBaseClass.FALSE;
7828 } 8402 }
8403 res.Add(new LSL_Integer(fullbright));
7829 } 8404 }
7830 break; 8405 break;
7831 8406
@@ -7847,27 +8422,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7847 break; 8422 break;
7848 8423
7849 case (int)ScriptBaseClass.PRIM_TEXGEN: 8424 case (int)ScriptBaseClass.PRIM_TEXGEN:
8425 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
7850 if (remain < 1) 8426 if (remain < 1)
7851 return res; 8427 return res;
7852 8428 face = (int)rules.GetLSLIntegerItem(idx++);
7853 face=(int)rules.GetLSLIntegerItem(idx++);
7854 8429
7855 tex = part.Shape.Textures; 8430 tex = part.Shape.Textures;
7856 if (face == ScriptBaseClass.ALL_SIDES) 8431 if (face == ScriptBaseClass.ALL_SIDES)
7857 { 8432 {
7858 for (face = 0; face < GetNumberOfSides(part); face++) 8433 for (face = 0; face < GetNumberOfSides(part); face++)
7859 { 8434 {
7860 MappingType texgen = tex.GetFace((uint)face).TexMapType; 8435 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
7861 // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc. 8436 {
7862 res.Add(new LSL_Integer((uint)texgen >> 1)); 8437 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
8438 }
8439 else
8440 {
8441 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
8442 }
7863 } 8443 }
7864 } 8444 }
7865 else 8445 else
7866 { 8446 {
7867 if (face >= 0 && face < GetNumberOfSides(part)) 8447 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
7868 { 8448 {
7869 MappingType texgen = tex.GetFace((uint)face).TexMapType; 8449 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
7870 res.Add(new LSL_Integer((uint)texgen >> 1)); 8450 }
8451 else
8452 {
8453 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
7871 } 8454 }
7872 } 8455 }
7873 break; 8456 break;
@@ -7890,28 +8473,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7890 case (int)ScriptBaseClass.PRIM_GLOW: 8473 case (int)ScriptBaseClass.PRIM_GLOW:
7891 if (remain < 1) 8474 if (remain < 1)
7892 return res; 8475 return res;
7893 8476 face = (int)rules.GetLSLIntegerItem(idx++);
7894 face=(int)rules.GetLSLIntegerItem(idx++);
7895 8477
7896 tex = part.Shape.Textures; 8478 tex = part.Shape.Textures;
8479 float primglow;
7897 if (face == ScriptBaseClass.ALL_SIDES) 8480 if (face == ScriptBaseClass.ALL_SIDES)
7898 { 8481 {
7899 for (face = 0; face < GetNumberOfSides(part); face++) 8482 for (face = 0; face < GetNumberOfSides(part); face++)
7900 { 8483 {
7901 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8484 primglow = tex.GetFace((uint)face).Glow;
7902 res.Add(new LSL_Float(texface.Glow)); 8485 res.Add(new LSL_Float(primglow));
7903 } 8486 }
7904 } 8487 }
7905 else 8488 else
7906 { 8489 {
7907 if (face >= 0 && face < GetNumberOfSides(part)) 8490 primglow = tex.GetFace((uint)face).Glow;
7908 { 8491 res.Add(new LSL_Float(primglow));
7909 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
7910 res.Add(new LSL_Float(texface.Glow));
7911 }
7912 } 8492 }
7913 break; 8493 break;
7914
7915 case (int)ScriptBaseClass.PRIM_TEXT: 8494 case (int)ScriptBaseClass.PRIM_TEXT:
7916 Color4 textColor = part.GetTextColor(); 8495 Color4 textColor = part.GetTextColor();
7917 res.Add(part.Text); 8496 res.Add(part.Text);
@@ -8460,8 +9039,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8460 // The function returns an ordered list 9039 // The function returns an ordered list
8461 // representing the tokens found in the supplied 9040 // representing the tokens found in the supplied
8462 // sources string. If two successive tokenizers 9041 // sources string. If two successive tokenizers
8463 // are encountered, then a NULL entry is added 9042 // are encountered, then a null-string entry is
8464 // to the list. 9043 // added to the list.
8465 // 9044 //
8466 // It is a precondition that the source and 9045 // It is a precondition that the source and
8467 // toekizer lisst are non-null. If they are null, 9046 // toekizer lisst are non-null. If they are null,
@@ -8469,7 +9048,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8469 // while their lengths are being determined. 9048 // while their lengths are being determined.
8470 // 9049 //
8471 // A small amount of working memoryis required 9050 // A small amount of working memoryis required
8472 // of approximately 8*#tokenizers. 9051 // of approximately 8*#tokenizers + 8*srcstrlen.
8473 // 9052 //
8474 // There are many ways in which this function 9053 // There are many ways in which this function
8475 // can be implemented, this implementation is 9054 // can be implemented, this implementation is
@@ -8485,155 +9064,124 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8485 // and eliminates redundant tokenizers as soon 9064 // and eliminates redundant tokenizers as soon
8486 // as is possible. 9065 // as is possible.
8487 // 9066 //
8488 // The implementation tries to avoid any copying 9067 // The implementation tries to minimize temporary
8489 // of arrays or other objects. 9068 // garbage generation.
8490 // </remarks> 9069 // </remarks>
8491 9070
8492 private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls) 9071 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8493 { 9072 {
8494 int beginning = 0; 9073 return ParseString2List(src, separators, spacers, true);
8495 int srclen = src.Length; 9074 }
8496 int seplen = separators.Length;
8497 object[] separray = separators.Data;
8498 int spclen = spacers.Length;
8499 object[] spcarray = spacers.Data;
8500 int mlen = seplen+spclen;
8501
8502 int[] offset = new int[mlen+1];
8503 bool[] active = new bool[mlen];
8504
8505 int best;
8506 int j;
8507
8508 // Initial capacity reduces resize cost
8509 9075
8510 LSL_List tokens = new LSL_List(); 9076 private LSL_List ParseString2List(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
9077 {
9078 int srclen = src.Length;
9079 int seplen = separators.Length;
9080 object[] separray = separators.Data;
9081 int spclen = spacers.Length;
9082 object[] spcarray = spacers.Data;
9083 int dellen = 0;
9084 string[] delarray = new string[seplen+spclen];
8511 9085
8512 // All entries are initially valid 9086 int outlen = 0;
9087 string[] outarray = new string[srclen*2+1];
8513 9088
8514 for (int i = 0; i < mlen; i++) 9089 int i, j;
8515 active[i] = true; 9090 string d;
8516 9091
8517 offset[mlen] = srclen; 9092 m_host.AddScriptLPS(1);
8518 9093
8519 while (beginning < srclen) 9094 /*
9095 * Convert separator and spacer lists to C# strings.
9096 * Also filter out null strings so we don't hang.
9097 */
9098 for (i = 0; i < seplen; i ++)
8520 { 9099 {
9100 d = separray[i].ToString();
9101 if (d.Length > 0)
9102 {
9103 delarray[dellen++] = d;
9104 }
9105 }
9106 seplen = dellen;
8521 9107
8522 best = mlen; // as bad as it gets 9108 for (i = 0; i < spclen; i ++)
9109 {
9110 d = spcarray[i].ToString();
9111 if (d.Length > 0)
9112 {
9113 delarray[dellen++] = d;
9114 }
9115 }
8523 9116
8524 // Scan for separators 9117 /*
9118 * Scan through source string from beginning to end.
9119 */
9120 for (i = 0;;)
9121 {
8525 9122
8526 for (j = 0; j < seplen; j++) 9123 /*
9124 * Find earliest delimeter in src starting at i (if any).
9125 */
9126 int earliestDel = -1;
9127 int earliestSrc = srclen;
9128 string earliestStr = null;
9129 for (j = 0; j < dellen; j ++)
8527 { 9130 {
8528 if (separray[j].ToString() == String.Empty) 9131 d = delarray[j];
8529 active[j] = false; 9132 if (d != null)
8530
8531 if (active[j])
8532 { 9133 {
8533 // scan all of the markers 9134 int index = src.IndexOf(d, i);
8534 if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1) 9135 if (index < 0)
8535 { 9136 {
8536 // not present at all 9137 delarray[j] = null; // delim nowhere in src, don't check it anymore
8537 active[j] = false;
8538 } 9138 }
8539 else 9139 else if (index < earliestSrc)
8540 { 9140 {
8541 // present and correct 9141 earliestSrc = index; // where delimeter starts in source string
8542 if (offset[j] < offset[best]) 9142 earliestDel = j; // where delimeter is in delarray[]
8543 { 9143 earliestStr = d; // the delimeter string from delarray[]
8544 // closest so far 9144 if (index == i) break; // can't do any better than found at beg of string
8545 best = j;
8546 if (offset[best] == beginning)
8547 break;
8548 }
8549 } 9145 }
8550 } 9146 }
8551 } 9147 }
8552 9148
8553 // Scan for spacers 9149 /*
8554 9150 * Output source string starting at i through start of earliest delimeter.
8555 if (offset[best] != beginning) 9151 */
9152 if (keepNulls || (earliestSrc > i))
8556 { 9153 {
8557 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++) 9154 outarray[outlen++] = src.Substring(i, earliestSrc - i);
8558 {
8559 if (spcarray[j-seplen].ToString() == String.Empty)
8560 active[j] = false;
8561
8562 if (active[j])
8563 {
8564 // scan all of the markers
8565 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
8566 {
8567 // not present at all
8568 active[j] = false;
8569 }
8570 else
8571 {
8572 // present and correct
8573 if (offset[j] < offset[best])
8574 {
8575 // closest so far
8576 best = j;
8577 }
8578 }
8579 }
8580 }
8581 } 9155 }
8582 9156
8583 // This is the normal exit from the scanning loop 9157 /*
9158 * If no delimeter found at or after i, we're done scanning.
9159 */
9160 if (earliestDel < 0) break;
8584 9161
8585 if (best == mlen) 9162 /*
9163 * If delimeter was a spacer, output the spacer.
9164 */
9165 if (earliestDel >= seplen)
8586 { 9166 {
8587 // no markers were found on this pass 9167 outarray[outlen++] = earliestStr;
8588 // so we're pretty much done
8589 if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
8590 tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
8591 break;
8592 } 9168 }
8593 9169
8594 // Otherwise we just add the newly delimited token 9170 /*
8595 // and recalculate where the search should continue. 9171 * Look at rest of src string following delimeter.
8596 if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0)) 9172 */
8597 tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning))); 9173 i = earliestSrc + earliestStr.Length;
8598
8599 if (best < seplen)
8600 {
8601 beginning = offset[best] + (separray[best].ToString()).Length;
8602 }
8603 else
8604 {
8605 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
8606 string str = spcarray[best - seplen].ToString();
8607 if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
8608 tokens.Add(new LSL_String(str));
8609 }
8610 } 9174 }
8611 9175
8612 // This an awkward an not very intuitive boundary case. If the 9176 /*
8613 // last substring is a tokenizer, then there is an implied trailing 9177 * Make up an exact-sized output array suitable for an LSL_List object.
8614 // null list entry. Hopefully the single comparison will not be too 9178 */
8615 // arduous. Alternatively the 'break' could be replced with a return 9179 object[] outlist = new object[outlen];
8616 // but that's shabby programming. 9180 for (i = 0; i < outlen; i ++)
8617
8618 if ((beginning == srclen) && (keepNulls))
8619 { 9181 {
8620 if (srclen != 0) 9182 outlist[i] = new LSL_String(outarray[i]);
8621 tokens.Add(new LSL_String(""));
8622 } 9183 }
8623 9184 return new LSL_List(outlist);
8624 return tokens;
8625 }
8626
8627 public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers)
8628 {
8629 m_host.AddScriptLPS(1);
8630 return this.ParseString(src, separators, spacers, false);
8631 }
8632
8633 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8634 {
8635 m_host.AddScriptLPS(1);
8636 return this.ParseString(src, separators, spacers, true);
8637 } 9185 }
8638 9186
8639 public LSL_Integer llGetObjectPermMask(int mask) 9187 public LSL_Integer llGetObjectPermMask(int mask)
@@ -8710,28 +9258,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8710 { 9258 {
8711 m_host.AddScriptLPS(1); 9259 m_host.AddScriptLPS(1);
8712 9260
8713 lock (m_host.TaskInventory) 9261 m_host.TaskInventory.LockItemsForRead(true);
9262 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8714 { 9263 {
8715 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9264 if (inv.Value.Name == item)
8716 { 9265 {
8717 if (inv.Value.Name == item) 9266 m_host.TaskInventory.LockItemsForRead(false);
9267 switch (mask)
8718 { 9268 {
8719 switch (mask) 9269 case 0:
8720 { 9270 return (int)inv.Value.BasePermissions;
8721 case 0: 9271 case 1:
8722 return (int)inv.Value.BasePermissions; 9272 return (int)inv.Value.CurrentPermissions;
8723 case 1: 9273 case 2:
8724 return (int)inv.Value.CurrentPermissions; 9274 return (int)inv.Value.GroupPermissions;
8725 case 2: 9275 case 3:
8726 return (int)inv.Value.GroupPermissions; 9276 return (int)inv.Value.EveryonePermissions;
8727 case 3: 9277 case 4:
8728 return (int)inv.Value.EveryonePermissions; 9278 return (int)inv.Value.NextPermissions;
8729 case 4:
8730 return (int)inv.Value.NextPermissions;
8731 }
8732 } 9279 }
8733 } 9280 }
8734 } 9281 }
9282 m_host.TaskInventory.LockItemsForRead(false);
8735 9283
8736 return -1; 9284 return -1;
8737 } 9285 }
@@ -8778,16 +9326,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8778 { 9326 {
8779 m_host.AddScriptLPS(1); 9327 m_host.AddScriptLPS(1);
8780 9328
8781 lock (m_host.TaskInventory) 9329 m_host.TaskInventory.LockItemsForRead(true);
9330 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8782 { 9331 {
8783 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9332 if (inv.Value.Name == item)
8784 { 9333 {
8785 if (inv.Value.Name == item) 9334 m_host.TaskInventory.LockItemsForRead(false);
8786 { 9335 return inv.Value.CreatorID.ToString();
8787 return inv.Value.CreatorID.ToString();
8788 }
8789 } 9336 }
8790 } 9337 }
9338 m_host.TaskInventory.LockItemsForRead(false);
8791 9339
8792 llSay(0, "No item name '" + item + "'"); 9340 llSay(0, "No item name '" + item + "'");
8793 9341
@@ -8935,7 +9483,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8935 } 9483 }
8936 9484
8937 /// <summary> 9485 /// <summary>
8938 /// illListReplaceList removes the sub-list defined by the inclusive indices 9486 /// llListReplaceList removes the sub-list defined by the inclusive indices
8939 /// start and end and inserts the src list in its place. The inclusive 9487 /// start and end and inserts the src list in its place. The inclusive
8940 /// nature of the indices means that at least one element must be deleted 9488 /// nature of the indices means that at least one element must be deleted
8941 /// if the indices are within the bounds of the existing list. I.e. 2,2 9489 /// if the indices are within the bounds of the existing list. I.e. 2,2
@@ -8992,16 +9540,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8992 // based upon end. Note that if end exceeds the upper 9540 // based upon end. Note that if end exceeds the upper
8993 // bound in this case, the entire destination list 9541 // bound in this case, the entire destination list
8994 // is removed. 9542 // is removed.
8995 else 9543 else if (start == 0)
8996 { 9544 {
8997 if (end + 1 < dest.Length) 9545 if (end + 1 < dest.Length)
8998 {
8999 return src + dest.GetSublist(end + 1, -1); 9546 return src + dest.GetSublist(end + 1, -1);
9000 }
9001 else 9547 else
9002 {
9003 return src; 9548 return src;
9004 } 9549 }
9550 else // Start < 0
9551 {
9552 if (end + 1 < dest.Length)
9553 return dest.GetSublist(end + 1, -1);
9554 else
9555 return new LSL_List();
9005 } 9556 }
9006 } 9557 }
9007 // Finally, if start > end, we strip away a prefix and 9558 // Finally, if start > end, we strip away a prefix and
@@ -9052,17 +9603,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9052 int width = 0; 9603 int width = 0;
9053 int height = 0; 9604 int height = 0;
9054 9605
9055 ParcelMediaCommandEnum? commandToSend = null; 9606 uint commandToSend = 0;
9056 float time = 0.0f; // default is from start 9607 float time = 0.0f; // default is from start
9057 9608
9058 ScenePresence presence = null; 9609 ScenePresence presence = null;
9059 9610
9060 for (int i = 0; i < commandList.Data.Length; i++) 9611 for (int i = 0; i < commandList.Data.Length; i++)
9061 { 9612 {
9062 ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i]; 9613 uint command = (uint)(commandList.GetLSLIntegerItem(i));
9063 switch (command) 9614 switch (command)
9064 { 9615 {
9065 case ParcelMediaCommandEnum.Agent: 9616 case (uint)ParcelMediaCommandEnum.Agent:
9066 // we send only to one agent 9617 // we send only to one agent
9067 if ((i + 1) < commandList.Length) 9618 if ((i + 1) < commandList.Length)
9068 { 9619 {
@@ -9079,25 +9630,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9079 } 9630 }
9080 break; 9631 break;
9081 9632
9082 case ParcelMediaCommandEnum.Loop: 9633 case (uint)ParcelMediaCommandEnum.Loop:
9083 loop = 1; 9634 loop = 1;
9084 commandToSend = command; 9635 commandToSend = command;
9085 update = true; //need to send the media update packet to set looping 9636 update = true; //need to send the media update packet to set looping
9086 break; 9637 break;
9087 9638
9088 case ParcelMediaCommandEnum.Play: 9639 case (uint)ParcelMediaCommandEnum.Play:
9089 loop = 0; 9640 loop = 0;
9090 commandToSend = command; 9641 commandToSend = command;
9091 update = true; //need to send the media update packet to make sure it doesn't loop 9642 update = true; //need to send the media update packet to make sure it doesn't loop
9092 break; 9643 break;
9093 9644
9094 case ParcelMediaCommandEnum.Pause: 9645 case (uint)ParcelMediaCommandEnum.Pause:
9095 case ParcelMediaCommandEnum.Stop: 9646 case (uint)ParcelMediaCommandEnum.Stop:
9096 case ParcelMediaCommandEnum.Unload: 9647 case (uint)ParcelMediaCommandEnum.Unload:
9097 commandToSend = command; 9648 commandToSend = command;
9098 break; 9649 break;
9099 9650
9100 case ParcelMediaCommandEnum.Url: 9651 case (uint)ParcelMediaCommandEnum.Url:
9101 if ((i + 1) < commandList.Length) 9652 if ((i + 1) < commandList.Length)
9102 { 9653 {
9103 if (commandList.Data[i + 1] is LSL_String) 9654 if (commandList.Data[i + 1] is LSL_String)
@@ -9110,7 +9661,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9110 } 9661 }
9111 break; 9662 break;
9112 9663
9113 case ParcelMediaCommandEnum.Texture: 9664 case (uint)ParcelMediaCommandEnum.Texture:
9114 if ((i + 1) < commandList.Length) 9665 if ((i + 1) < commandList.Length)
9115 { 9666 {
9116 if (commandList.Data[i + 1] is LSL_String) 9667 if (commandList.Data[i + 1] is LSL_String)
@@ -9123,7 +9674,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9123 } 9674 }
9124 break; 9675 break;
9125 9676
9126 case ParcelMediaCommandEnum.Time: 9677 case (uint)ParcelMediaCommandEnum.Time:
9127 if ((i + 1) < commandList.Length) 9678 if ((i + 1) < commandList.Length)
9128 { 9679 {
9129 if (commandList.Data[i + 1] is LSL_Float) 9680 if (commandList.Data[i + 1] is LSL_Float)
@@ -9135,7 +9686,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9135 } 9686 }
9136 break; 9687 break;
9137 9688
9138 case ParcelMediaCommandEnum.AutoAlign: 9689 case (uint)ParcelMediaCommandEnum.AutoAlign:
9139 if ((i + 1) < commandList.Length) 9690 if ((i + 1) < commandList.Length)
9140 { 9691 {
9141 if (commandList.Data[i + 1] is LSL_Integer) 9692 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9149,7 +9700,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9149 } 9700 }
9150 break; 9701 break;
9151 9702
9152 case ParcelMediaCommandEnum.Type: 9703 case (uint)ParcelMediaCommandEnum.Type:
9153 if ((i + 1) < commandList.Length) 9704 if ((i + 1) < commandList.Length)
9154 { 9705 {
9155 if (commandList.Data[i + 1] is LSL_String) 9706 if (commandList.Data[i + 1] is LSL_String)
@@ -9162,7 +9713,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9162 } 9713 }
9163 break; 9714 break;
9164 9715
9165 case ParcelMediaCommandEnum.Desc: 9716 case (uint)ParcelMediaCommandEnum.Desc:
9166 if ((i + 1) < commandList.Length) 9717 if ((i + 1) < commandList.Length)
9167 { 9718 {
9168 if (commandList.Data[i + 1] is LSL_String) 9719 if (commandList.Data[i + 1] is LSL_String)
@@ -9175,7 +9726,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9175 } 9726 }
9176 break; 9727 break;
9177 9728
9178 case ParcelMediaCommandEnum.Size: 9729 case (uint)ParcelMediaCommandEnum.Size:
9179 if ((i + 2) < commandList.Length) 9730 if ((i + 2) < commandList.Length)
9180 { 9731 {
9181 if (commandList.Data[i + 1] is LSL_Integer) 9732 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9245,7 +9796,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9245 } 9796 }
9246 } 9797 }
9247 9798
9248 if (commandToSend != null) 9799 if (commandToSend != 0)
9249 { 9800 {
9250 // the commandList contained a start/stop/... command, too 9801 // the commandList contained a start/stop/... command, too
9251 if (presence == null) 9802 if (presence == null)
@@ -9282,7 +9833,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9282 9833
9283 if (aList.Data[i] != null) 9834 if (aList.Data[i] != null)
9284 { 9835 {
9285 switch ((ParcelMediaCommandEnum) aList.Data[i]) 9836 switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString()))
9286 { 9837 {
9287 case ParcelMediaCommandEnum.Url: 9838 case ParcelMediaCommandEnum.Url:
9288 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL)); 9839 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
@@ -9325,16 +9876,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9325 { 9876 {
9326 m_host.AddScriptLPS(1); 9877 m_host.AddScriptLPS(1);
9327 9878
9328 lock (m_host.TaskInventory) 9879 m_host.TaskInventory.LockItemsForRead(true);
9880 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
9329 { 9881 {
9330 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9882 if (inv.Value.Name == name)
9331 { 9883 {
9332 if (inv.Value.Name == name) 9884 m_host.TaskInventory.LockItemsForRead(false);
9333 { 9885 return inv.Value.Type;
9334 return inv.Value.Type;
9335 }
9336 } 9886 }
9337 } 9887 }
9888 m_host.TaskInventory.LockItemsForRead(false);
9338 9889
9339 return -1; 9890 return -1;
9340 } 9891 }
@@ -9345,15 +9896,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9345 9896
9346 if (quick_pay_buttons.Data.Length < 4) 9897 if (quick_pay_buttons.Data.Length < 4)
9347 { 9898 {
9348 LSLError("List must have at least 4 elements"); 9899 int x;
9349 return; 9900 for (x=quick_pay_buttons.Data.Length; x<= 4; x++)
9901 {
9902 quick_pay_buttons.Add(ScriptBaseClass.PAY_HIDE);
9903 }
9350 } 9904 }
9351 m_host.ParentGroup.RootPart.PayPrice[0]=price; 9905 int[] nPrice = new int[5];
9352 9906 nPrice[0] = price;
9353 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0]; 9907 nPrice[1] = quick_pay_buttons.GetLSLIntegerItem(0);
9354 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1]; 9908 nPrice[2] = quick_pay_buttons.GetLSLIntegerItem(1);
9355 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2]; 9909 nPrice[3] = quick_pay_buttons.GetLSLIntegerItem(2);
9356 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3]; 9910 nPrice[4] = quick_pay_buttons.GetLSLIntegerItem(3);
9911 m_host.ParentGroup.RootPart.PayPrice = nPrice;
9357 m_host.ParentGroup.HasGroupChanged = true; 9912 m_host.ParentGroup.HasGroupChanged = true;
9358 } 9913 }
9359 9914
@@ -9365,17 +9920,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9365 if (invItemID == UUID.Zero) 9920 if (invItemID == UUID.Zero)
9366 return new LSL_Vector(); 9921 return new LSL_Vector();
9367 9922
9368 lock (m_host.TaskInventory) 9923 m_host.TaskInventory.LockItemsForRead(true);
9924 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9369 { 9925 {
9370 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 9926 m_host.TaskInventory.LockItemsForRead(false);
9371 return new LSL_Vector(); 9927 return new LSL_Vector();
9928 }
9372 9929
9373 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 9930 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9374 { 9931 {
9375 ShoutError("No permissions to track the camera"); 9932 ShoutError("No permissions to track the camera");
9376 return new LSL_Vector(); 9933 m_host.TaskInventory.LockItemsForRead(false);
9377 } 9934 return new LSL_Vector();
9378 } 9935 }
9936 m_host.TaskInventory.LockItemsForRead(false);
9379 9937
9380 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 9938 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9381 if (presence != null) 9939 if (presence != null)
@@ -9393,17 +9951,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9393 if (invItemID == UUID.Zero) 9951 if (invItemID == UUID.Zero)
9394 return new LSL_Rotation(); 9952 return new LSL_Rotation();
9395 9953
9396 lock (m_host.TaskInventory) 9954 m_host.TaskInventory.LockItemsForRead(true);
9955 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9397 { 9956 {
9398 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 9957 m_host.TaskInventory.LockItemsForRead(false);
9399 return new LSL_Rotation(); 9958 return new LSL_Rotation();
9400
9401 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9402 {
9403 ShoutError("No permissions to track the camera");
9404 return new LSL_Rotation();
9405 }
9406 } 9959 }
9960 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9961 {
9962 ShoutError("No permissions to track the camera");
9963 m_host.TaskInventory.LockItemsForRead(false);
9964 return new LSL_Rotation();
9965 }
9966 m_host.TaskInventory.LockItemsForRead(false);
9407 9967
9408 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 9968 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9409 if (presence != null) 9969 if (presence != null)
@@ -9465,8 +10025,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9465 { 10025 {
9466 m_host.AddScriptLPS(1); 10026 m_host.AddScriptLPS(1);
9467 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0); 10027 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0);
9468 if (detectedParams == null) return; // only works on the first detected avatar 10028 if (detectedParams == null)
9469 10029 {
10030 if (m_host.IsAttachment == true)
10031 {
10032 detectedParams = new DetectParams();
10033 detectedParams.Key = m_host.OwnerID;
10034 }
10035 else
10036 {
10037 return;
10038 }
10039 }
10040
9470 ScenePresence avatar = World.GetScenePresence(detectedParams.Key); 10041 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
9471 if (avatar != null) 10042 if (avatar != null)
9472 { 10043 {
@@ -9474,6 +10045,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9474 new Vector3((float)pos.x, (float)pos.y, (float)pos.z), 10045 new Vector3((float)pos.x, (float)pos.y, (float)pos.z),
9475 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z)); 10046 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z));
9476 } 10047 }
10048
9477 ScriptSleep(1000); 10049 ScriptSleep(1000);
9478 } 10050 }
9479 10051
@@ -9566,14 +10138,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9566 if (objectID == UUID.Zero) return; 10138 if (objectID == UUID.Zero) return;
9567 10139
9568 UUID agentID; 10140 UUID agentID;
9569 lock (m_host.TaskInventory) 10141 m_host.TaskInventory.LockItemsForRead(true);
9570 { 10142 // we need the permission first, to know which avatar we want to set the camera for
9571 // we need the permission first, to know which avatar we want to set the camera for 10143 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9572 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9573 10144
9574 if (agentID == UUID.Zero) return; 10145 if (agentID == UUID.Zero)
9575 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; 10146 {
10147 m_host.TaskInventory.LockItemsForRead(false);
10148 return;
9576 } 10149 }
10150 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10151 {
10152 m_host.TaskInventory.LockItemsForRead(false);
10153 return;
10154 }
10155 m_host.TaskInventory.LockItemsForRead(false);
9577 10156
9578 ScenePresence presence = World.GetScenePresence(agentID); 10157 ScenePresence presence = World.GetScenePresence(agentID);
9579 10158
@@ -9582,12 +10161,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9582 10161
9583 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>(); 10162 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
9584 object[] data = rules.Data; 10163 object[] data = rules.Data;
9585 for (int i = 0; i < data.Length; ++i) { 10164 for (int i = 0; i < data.Length; ++i)
10165 {
9586 int type = Convert.ToInt32(data[i++].ToString()); 10166 int type = Convert.ToInt32(data[i++].ToString());
9587 if (i >= data.Length) break; // odd number of entries => ignore the last 10167 if (i >= data.Length) break; // odd number of entries => ignore the last
9588 10168
9589 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3) 10169 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
9590 switch (type) { 10170 switch (type)
10171 {
9591 case ScriptBaseClass.CAMERA_FOCUS: 10172 case ScriptBaseClass.CAMERA_FOCUS:
9592 case ScriptBaseClass.CAMERA_FOCUS_OFFSET: 10173 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
9593 case ScriptBaseClass.CAMERA_POSITION: 10174 case ScriptBaseClass.CAMERA_POSITION:
@@ -9623,12 +10204,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9623 10204
9624 // we need the permission first, to know which avatar we want to clear the camera for 10205 // we need the permission first, to know which avatar we want to clear the camera for
9625 UUID agentID; 10206 UUID agentID;
9626 lock (m_host.TaskInventory) 10207 m_host.TaskInventory.LockItemsForRead(true);
10208 agentID = m_host.TaskInventory[invItemID].PermsGranter;
10209 if (agentID == UUID.Zero)
10210 {
10211 m_host.TaskInventory.LockItemsForRead(false);
10212 return;
10213 }
10214 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
9627 { 10215 {
9628 agentID = m_host.TaskInventory[invItemID].PermsGranter; 10216 m_host.TaskInventory.LockItemsForRead(false);
9629 if (agentID == UUID.Zero) return; 10217 return;
9630 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
9631 } 10218 }
10219 m_host.TaskInventory.LockItemsForRead(false);
9632 10220
9633 ScenePresence presence = World.GetScenePresence(agentID); 10221 ScenePresence presence = World.GetScenePresence(agentID);
9634 10222
@@ -9695,19 +10283,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9695 public LSL_String llXorBase64StringsCorrect(string str1, string str2) 10283 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
9696 { 10284 {
9697 m_host.AddScriptLPS(1); 10285 m_host.AddScriptLPS(1);
9698 string ret = String.Empty; 10286
9699 string src1 = llBase64ToString(str1); 10287 if (str1 == String.Empty)
9700 string src2 = llBase64ToString(str2); 10288 return String.Empty;
9701 int c = 0; 10289 if (str2 == String.Empty)
9702 for (int i = 0; i < src1.Length; i++) 10290 return str1;
10291
10292 int len = str2.Length;
10293 if ((len % 4) != 0) // LL is EVIL!!!!
9703 { 10294 {
9704 ret += (char) (src1[i] ^ src2[c]); 10295 while (str2.EndsWith("="))
10296 str2 = str2.Substring(0, str2.Length - 1);
9705 10297
9706 c++; 10298 len = str2.Length;
9707 if (c >= src2.Length) 10299 int mod = len % 4;
9708 c = 0; 10300
10301 if (mod == 1)
10302 str2 = str2.Substring(0, str2.Length - 1);
10303 else if (mod == 2)
10304 str2 += "==";
10305 else if (mod == 3)
10306 str2 += "=";
10307 }
10308
10309 byte[] data1;
10310 byte[] data2;
10311 try
10312 {
10313 data1 = Convert.FromBase64String(str1);
10314 data2 = Convert.FromBase64String(str2);
9709 } 10315 }
9710 return llStringToBase64(ret); 10316 catch (Exception)
10317 {
10318 return new LSL_String(String.Empty);
10319 }
10320
10321 byte[] d2 = new Byte[data1.Length];
10322 int pos = 0;
10323
10324 if (data1.Length <= data2.Length)
10325 {
10326 Array.Copy(data2, 0, d2, 0, data1.Length);
10327 }
10328 else
10329 {
10330 while (pos < data1.Length)
10331 {
10332 len = data1.Length - pos;
10333 if (len > data2.Length)
10334 len = data2.Length;
10335
10336 Array.Copy(data2, 0, d2, pos, len);
10337 pos += len;
10338 }
10339 }
10340
10341 for (pos = 0 ; pos < data1.Length ; pos++ )
10342 data1[pos] ^= d2[pos];
10343
10344 return Convert.ToBase64String(data1);
9711 } 10345 }
9712 10346
9713 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body) 10347 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
@@ -9766,12 +10400,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9766 Regex r = new Regex(authregex); 10400 Regex r = new Regex(authregex);
9767 int[] gnums = r.GetGroupNumbers(); 10401 int[] gnums = r.GetGroupNumbers();
9768 Match m = r.Match(url); 10402 Match m = r.Match(url);
9769 if (m.Success) { 10403 if (m.Success)
9770 for (int i = 1; i < gnums.Length; i++) { 10404 {
10405 for (int i = 1; i < gnums.Length; i++)
10406 {
9771 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]]; 10407 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
9772 //CaptureCollection cc = g.Captures; 10408 //CaptureCollection cc = g.Captures;
9773 } 10409 }
9774 if (m.Groups.Count == 5) { 10410 if (m.Groups.Count == 5)
10411 {
9775 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString()))); 10412 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
9776 url = m.Groups[1].ToString() + m.Groups[4].ToString(); 10413 url = m.Groups[1].ToString() + m.Groups[4].ToString();
9777 } 10414 }
@@ -9883,7 +10520,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9883 { 10520 {
9884 foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners()) 10521 foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners())
9885 { 10522 {
9886 ret.Add(detectedParams.Key.ToString()); 10523 ret.Add(new LSL_String(detectedParams.Key.ToString()));
9887 ret.Add(detectedParams.Value); 10524 ret.Add(detectedParams.Value);
9888 } 10525 }
9889 } 10526 }
@@ -10067,15 +10704,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10067 10704
10068 internal UUID ScriptByName(string name) 10705 internal UUID ScriptByName(string name)
10069 { 10706 {
10070 lock (m_host.TaskInventory) 10707 m_host.TaskInventory.LockItemsForRead(true);
10708
10709 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
10071 { 10710 {
10072 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 10711 if (item.Type == 10 && item.Name == name)
10073 { 10712 {
10074 if (item.Type == 10 && item.Name == name) 10713 m_host.TaskInventory.LockItemsForRead(false);
10075 return item.ItemID; 10714 return item.ItemID;
10076 } 10715 }
10077 } 10716 }
10078 10717
10718 m_host.TaskInventory.LockItemsForRead(false);
10719
10079 return UUID.Zero; 10720 return UUID.Zero;
10080 } 10721 }
10081 10722
@@ -10116,6 +10757,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10116 { 10757 {
10117 m_host.AddScriptLPS(1); 10758 m_host.AddScriptLPS(1);
10118 10759
10760 //Clone is thread safe
10119 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10761 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10120 10762
10121 UUID assetID = UUID.Zero; 10763 UUID assetID = UUID.Zero;
@@ -10178,6 +10820,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10178 { 10820 {
10179 m_host.AddScriptLPS(1); 10821 m_host.AddScriptLPS(1);
10180 10822
10823 //Clone is thread safe
10181 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10824 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10182 10825
10183 UUID assetID = UUID.Zero; 10826 UUID assetID = UUID.Zero;
@@ -10258,15 +10901,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10258 return GetLinkPrimitiveParams(obj, rules); 10901 return GetLinkPrimitiveParams(obj, rules);
10259 } 10902 }
10260 10903
10261 public void print(string str) 10904 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
10262 { 10905 {
10263 // yes, this is a real LSL function. See: http://wiki.secondlife.com/wiki/Print 10906 List<SceneObjectPart> parts = GetLinkParts(link);
10264 IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_itemID, "OSSL"); 10907 if (parts.Count < 1)
10265 if (ossl != null) 10908 return 0;
10266 { 10909
10267 ossl.CheckThreatLevel(ThreatLevel.High, "print"); 10910 return GetNumberOfSides(parts[0]);
10268 m_log.Info("LSL print():" + str);
10269 }
10270 } 10911 }
10271 10912
10272 private string Name2Username(string name) 10913 private string Name2Username(string name)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 64931d0..39e1a27 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()
@@ -831,18 +840,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
831 if (target != null) 840 if (target != null)
832 { 841 {
833 UUID animID=UUID.Zero; 842 UUID animID=UUID.Zero;
834 lock (m_host.TaskInventory) 843 m_host.TaskInventory.LockItemsForRead(true);
844 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
835 { 845 {
836 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 846 if (inv.Value.Name == animation)
837 { 847 {
838 if (inv.Value.Name == animation) 848 if (inv.Value.Type == (int)AssetType.Animation)
839 { 849 animID = inv.Value.AssetID;
840 if (inv.Value.Type == (int)AssetType.Animation) 850 continue;
841 animID = inv.Value.AssetID;
842 continue;
843 }
844 } 851 }
845 } 852 }
853 m_host.TaskInventory.LockItemsForRead(false);
846 if (animID == UUID.Zero) 854 if (animID == UUID.Zero)
847 target.Animator.AddAnimation(animation, m_host.UUID); 855 target.Animator.AddAnimation(animation, m_host.UUID);
848 else 856 else
@@ -864,18 +872,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
864 if (target != null) 872 if (target != null)
865 { 873 {
866 UUID animID=UUID.Zero; 874 UUID animID=UUID.Zero;
867 lock (m_host.TaskInventory) 875 m_host.TaskInventory.LockItemsForRead(true);
876 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
868 { 877 {
869 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 878 if (inv.Value.Name == animation)
870 { 879 {
871 if (inv.Value.Name == animation) 880 if (inv.Value.Type == (int)AssetType.Animation)
872 { 881 animID = inv.Value.AssetID;
873 if (inv.Value.Type == (int)AssetType.Animation) 882 continue;
874 animID = inv.Value.AssetID;
875 continue;
876 }
877 } 883 }
878 } 884 }
885 m_host.TaskInventory.LockItemsForRead(false);
879 886
880 if (animID == UUID.Zero) 887 if (animID == UUID.Zero)
881 target.Animator.RemoveAnimation(animation); 888 target.Animator.RemoveAnimation(animation);
@@ -1768,6 +1775,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1768 1775
1769 if (!UUID.TryParse(name, out assetID)) 1776 if (!UUID.TryParse(name, out assetID))
1770 { 1777 {
1778 m_host.TaskInventory.LockItemsForRead(true);
1771 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1779 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1772 { 1780 {
1773 if (item.Type == 7 && item.Name == name) 1781 if (item.Type == 7 && item.Name == name)
@@ -1775,6 +1783,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1775 assetID = item.AssetID; 1783 assetID = item.AssetID;
1776 } 1784 }
1777 } 1785 }
1786 m_host.TaskInventory.LockItemsForRead(false);
1778 } 1787 }
1779 1788
1780 if (assetID == UUID.Zero) 1789 if (assetID == UUID.Zero)
@@ -1821,6 +1830,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1821 1830
1822 if (!UUID.TryParse(name, out assetID)) 1831 if (!UUID.TryParse(name, out assetID))
1823 { 1832 {
1833 m_host.TaskInventory.LockItemsForRead(true);
1824 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1834 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1825 { 1835 {
1826 if (item.Type == 7 && item.Name == name) 1836 if (item.Type == 7 && item.Name == name)
@@ -1828,6 +1838,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1828 assetID = item.AssetID; 1838 assetID = item.AssetID;
1829 } 1839 }
1830 } 1840 }
1841 m_host.TaskInventory.LockItemsForRead(false);
1831 } 1842 }
1832 1843
1833 if (assetID == UUID.Zero) 1844 if (assetID == UUID.Zero)
@@ -1878,6 +1889,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1878 1889
1879 if (!UUID.TryParse(name, out assetID)) 1890 if (!UUID.TryParse(name, out assetID))
1880 { 1891 {
1892 m_host.TaskInventory.LockItemsForRead(true);
1881 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1893 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1882 { 1894 {
1883 if (item.Type == 7 && item.Name == name) 1895 if (item.Type == 7 && item.Name == name)
@@ -1885,6 +1897,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1885 assetID = item.AssetID; 1897 assetID = item.AssetID;
1886 } 1898 }
1887 } 1899 }
1900 m_host.TaskInventory.LockItemsForRead(false);
1888 } 1901 }
1889 1902
1890 if (assetID == UUID.Zero) 1903 if (assetID == UUID.Zero)
@@ -2364,9 +2377,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2364 { 2377 {
2365 if (avatar.IsChildAgent == false) 2378 if (avatar.IsChildAgent == false)
2366 { 2379 {
2367 result.Add(avatar.UUID); 2380 result.Add(new LSL_Key(avatar.UUID.ToString()));
2368 result.Add(avatar.AbsolutePosition); 2381 result.Add(new LSL_Vector(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z));
2369 result.Add(avatar.Name); 2382 result.Add(new LSL_String(avatar.Name));
2370 } 2383 }
2371 } 2384 }
2372 }); 2385 });
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 47c7915..3afedc7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -205,7 +205,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
205 // Is the sensor type is AGENT and not SCRIPTED then include agents 205 // Is the sensor type is AGENT and not SCRIPTED then include agents
206 if ((ts.type & (AGENT | AGENT_BY_USERNAME)) != 0 && (ts.type & SCRIPTED) == 0) 206 if ((ts.type & (AGENT | AGENT_BY_USERNAME)) != 0 && (ts.type & SCRIPTED) == 0)
207 { 207 {
208 sensedEntities.AddRange(doAgentSensor(ts)); 208 sensedEntities.AddRange(doAgentSensor(ts));
209 } 209 }
210 210
211 // If SCRIPTED or PASSIVE or ACTIVE check objects 211 // If SCRIPTED or PASSIVE or ACTIVE check objects
@@ -302,7 +302,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
302 float dy; 302 float dy;
303 float dz; 303 float dz;
304 304
305 Quaternion q = SensePoint.RotationOffset; 305// Quaternion q = SensePoint.RotationOffset;
306 Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation!
306 if (SensePoint.ParentGroup.RootPart.IsAttachment) 307 if (SensePoint.ParentGroup.RootPart.IsAttachment)
307 { 308 {
308 // In attachments, the sensor cone always orients with the 309 // In attachments, the sensor cone always orients with the
@@ -310,6 +311,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
310 // in mouselook. 311 // in mouselook.
311 312
312 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar); 313 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar);
314 fromRegionPos = avatar.AbsolutePosition;
313 q = avatar.Rotation; 315 q = avatar.Rotation;
314 } 316 }
315 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 317 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
@@ -423,6 +425,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
423 SceneObjectPart SensePoint = ts.host; 425 SceneObjectPart SensePoint = ts.host;
424 Vector3 fromRegionPos = SensePoint.AbsolutePosition; 426 Vector3 fromRegionPos = SensePoint.AbsolutePosition;
425 Quaternion q = SensePoint.RotationOffset; 427 Quaternion q = SensePoint.RotationOffset;
428 if (SensePoint.ParentGroup.RootPart.IsAttachment)
429 {
430 // In attachments, the sensor cone always orients with the
431 // avatar rotation. This may include a nonzero elevation if
432 // in mouselook.
433
434 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.RootPart.AttachedAvatar);
435 fromRegionPos = avatar.AbsolutePosition;
436 q = avatar.Rotation;
437 }
426 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 438 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
427 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); 439 LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
428 double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); 440 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/ICM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs
new file mode 100644
index 0000000..ab215f3
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ICM_Api.cs
@@ -0,0 +1,46 @@
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.Collections;
29using OpenSim.Region.ScriptEngine.Interfaces;
30
31using key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
32using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
33using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
34using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
35using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
36using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
37using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
38
39namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
40{
41 public interface ICM_Api
42 {
43 string cmDetectedCountry(int num);
44 string cmGetAgentCountry(key key);
45 }
46}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
index 654ea81..0ae2388 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
@@ -402,7 +402,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
402 LSL_Vector llWind(LSL_Vector offset); 402 LSL_Vector llWind(LSL_Vector offset);
403 LSL_String llXorBase64Strings(string str1, string str2); 403 LSL_String llXorBase64Strings(string str1, string str2);
404 LSL_String llXorBase64StringsCorrect(string str1, string str2); 404 LSL_String llXorBase64StringsCorrect(string str1, string str2);
405 void print(string str); 405 LSL_Integer llGetLinkNumberOfSides(LSL_Integer link);
406 406
407 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 407 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
408 LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 408 LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 63007c6..c08ad3b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -83,7 +83,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
83 // Avatar Info Commands 83 // Avatar Info Commands
84 string osGetAgentIP(string agent); 84 string osGetAgentIP(string agent);
85 LSL_List osGetAgents(); 85 LSL_List osGetAgents();
86 86
87 // Teleport commands 87 // Teleport commands
88 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 88 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat);
89 void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 89 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/CM_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs
new file mode 100644
index 0000000..4132dfa
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/CM_Stub.cs
@@ -0,0 +1,71 @@
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.Runtime.Remoting.Lifetime;
30using System.Threading;
31using System.Reflection;
32using System.Collections;
33using System.Collections.Generic;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
38using integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
39using vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
40using rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
41using key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
42using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
43using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
44using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
45using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
46
47namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
48{
49 public partial class ScriptBaseClass : MarshalByRefObject
50 {
51 public ICM_Api m_CM_Functions;
52
53 public void ApiTypeCM(IScriptApi api)
54 {
55 if (!(api is ICM_Api))
56 return;
57
58 m_CM_Functions = (ICM_Api)api;
59 }
60
61 public string cmDetectedCountry(int num)
62 {
63 return m_CM_Functions.cmDetectedCountry(num);
64 }
65
66 public string cmGetAgentCountry(key key)
67 {
68 return m_CM_Functions.cmGetAgentCountry(key);
69 }
70 }
71}
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 9377cda..5f94ff5 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -281,6 +281,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
281 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART 281 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART
282 public const int CHANGED_MEDIA = 2048; 282 public const int CHANGED_MEDIA = 2048;
283 public const int CHANGED_ANIMATION = 16384; 283 public const int CHANGED_ANIMATION = 16384;
284 public const int CHANGED_POSITION = 32768;
284 public const int TYPE_INVALID = 0; 285 public const int TYPE_INVALID = 0;
285 public const int TYPE_INTEGER = 1; 286 public const int TYPE_INTEGER = 1;
286 public const int TYPE_FLOAT = 2; 287 public const int TYPE_FLOAT = 2;
@@ -374,6 +375,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
374 public const int PRIM_SCULPT_TYPE_TORUS = 2; 375 public const int PRIM_SCULPT_TYPE_TORUS = 2;
375 public const int PRIM_SCULPT_TYPE_PLANE = 3; 376 public const int PRIM_SCULPT_TYPE_PLANE = 3;
376 public const int PRIM_SCULPT_TYPE_CYLINDER = 4; 377 public const int PRIM_SCULPT_TYPE_CYLINDER = 4;
378 public const int PRIM_SCULPT_FLAG_INVERT = 64;
379 public const int PRIM_SCULPT_FLAG_MIRROR = 128;
377 380
378 public const int MASK_BASE = 0; 381 public const int MASK_BASE = 0;
379 public const int MASK_OWNER = 1; 382 public const int MASK_OWNER = 1;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
index 303d75e..63cac9a 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();
@@ -1868,9 +1870,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
1868 return m_LSL_Functions.llClearPrimMedia(face); 1870 return m_LSL_Functions.llClearPrimMedia(face);
1869 } 1871 }
1870 1872
1871 public void print(string str) 1873 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
1872 { 1874 {
1873 m_LSL_Functions.print(str); 1875 return m_LSL_Functions.llGetLinkNumberOfSides(link);
1874 } 1876 }
1875 } 1877 }
1876} 1878}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs
index 143b497..2e27f16 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LS_Stub.cs
@@ -72,9 +72,30 @@ 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
75 public void lsClearWindlightScene() 76 public void lsClearWindlightScene()
76 { 77 {
77 m_LS_Functions.lsClearWindlightScene(); 78 m_LS_Functions.lsClearWindlightScene();
78 } 79 }
80
81 public LSL_List cmGetWindlightScene(LSL_List rules)
82 {
83 return m_LS_Functions.lsGetWindlightScene(rules);
84 }
85
86 public int cmSetWindlightScene(LSL_List rules)
87 {
88 return m_LS_Functions.lsSetWindlightScene(rules);
89 }
90
91 public int cmSetWindlightSceneTargeted(LSL_List rules, key target)
92 {
93 return m_LS_Functions.lsSetWindlightSceneTargeted(rules, target);
94 }
95
96 public void cmClearWindlightScene()
97 {
98 m_LS_Functions.lsClearWindlightScene();
99 }
79 } 100 }
80} 101}
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/Helpers.cs b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
index 3575889..e9edf6c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Helpers.cs
@@ -35,6 +35,7 @@ using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Region.CoreModules; 36using OpenSim.Region.CoreModules;
37using OpenSim.Region.Framework.Scenes; 37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Services.Interfaces;
38 39
39namespace OpenSim.Region.ScriptEngine.Shared 40namespace OpenSim.Region.ScriptEngine.Shared
40{ 41{
@@ -95,6 +96,7 @@ namespace OpenSim.Region.ScriptEngine.Shared
95 Type = 0; 96 Type = 0;
96 Velocity = new LSL_Types.Vector3(); 97 Velocity = new LSL_Types.Vector3();
97 initializeSurfaceTouch(); 98 initializeSurfaceTouch();
99 Country = String.Empty;
98 } 100 }
99 101
100 public UUID Key; 102 public UUID Key;
@@ -126,6 +128,8 @@ namespace OpenSim.Region.ScriptEngine.Shared
126 private int touchFace; 128 private int touchFace;
127 public int TouchFace { get { return touchFace; } } 129 public int TouchFace { get { return touchFace; } }
128 130
131 public string Country;
132
129 // This can be done in two places including the constructor 133 // This can be done in two places including the constructor
130 // so be carefull what gets added here 134 // so be carefull what gets added here
131 private void initializeSurfaceTouch() 135 private void initializeSurfaceTouch()
@@ -173,6 +177,10 @@ namespace OpenSim.Region.ScriptEngine.Shared
173 return; 177 return;
174 178
175 Name = presence.Firstname + " " + presence.Lastname; 179 Name = presence.Firstname + " " + presence.Lastname;
180 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, Key);
181 if (account != null)
182 Country = account.UserCountry;
183
176 Owner = Key; 184 Owner = Key;
177 Position = new LSL_Types.Vector3( 185 Position = new LSL_Types.Vector3(
178 presence.AbsolutePosition.X, 186 presence.AbsolutePosition.X,
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 783791f..9548253 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
@@ -434,14 +435,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
434 { 435 {
435 int permsMask; 436 int permsMask;
436 UUID permsGranter; 437 UUID permsGranter;
437 lock (part.TaskInventory) 438 part.TaskInventory.LockItemsForRead(true);
439 if (!part.TaskInventory.ContainsKey(m_ItemID))
438 { 440 {
439 if (!part.TaskInventory.ContainsKey(m_ItemID)) 441 part.TaskInventory.LockItemsForRead(false);
440 return; 442 return;
441
442 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
443 permsMask = part.TaskInventory[m_ItemID].PermsMask;
444 } 443 }
444 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
445 permsMask = part.TaskInventory[m_ItemID].PermsMask;
446 part.TaskInventory.LockItemsForRead(false);
445 447
446 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) 448 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
447 { 449 {
@@ -550,6 +552,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
550 return true; 552 return true;
551 } 553 }
552 554
555 [DebuggerNonUserCode] //Prevents the debugger from farting in this function
553 public void SetState(string state) 556 public void SetState(string state)
554 { 557 {
555 if (state == State) 558 if (state == State)
@@ -561,7 +564,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
561 new DetectParams[0])); 564 new DetectParams[0]));
562 PostEvent(new EventParams("state_entry", new Object[0], 565 PostEvent(new EventParams("state_entry", new Object[0],
563 new DetectParams[0])); 566 new DetectParams[0]));
564 567
565 throw new EventAbortException(); 568 throw new EventAbortException();
566 } 569 }
567 570
@@ -644,14 +647,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
644 /// <returns></returns> 647 /// <returns></returns>
645 public object EventProcessor() 648 public object EventProcessor()
646 { 649 {
647 if (m_Suspended) 650 EventParams data = null;
648 return 0;
649 651
650 lock (m_Script) 652 lock (m_EventQueue)
651 { 653 {
652 EventParams data = null; 654 if (m_Suspended)
655 return 0;
653 656
654 lock (m_EventQueue) 657 lock (m_Script)
655 { 658 {
656 data = (EventParams) m_EventQueue.Dequeue(); 659 data = (EventParams) m_EventQueue.Dequeue();
657 if (data == null) // Shouldn't happen 660 if (data == null) // Shouldn't happen
@@ -677,6 +680,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
677 if (data.EventName == "collision") 680 if (data.EventName == "collision")
678 m_CollisionInQueue = false; 681 m_CollisionInQueue = false;
679 } 682 }
683 }
684 lock(m_Script)
685 {
680 686
681 //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this); 687 //m_log.DebugFormat("[XENGINE]: Processing event {0} for {1}", data.EventName, this);
682 688
@@ -833,6 +839,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
833 new Object[0], new DetectParams[0])); 839 new Object[0], new DetectParams[0]));
834 } 840 }
835 841
842 [DebuggerNonUserCode] //Stops the VS debugger from farting in this function
836 public void ApiResetScript() 843 public void ApiResetScript()
837 { 844 {
838 // bool running = Running; 845 // bool running = Running;
@@ -864,10 +871,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
864 871
865 public Dictionary<string, object> GetVars() 872 public Dictionary<string, object> GetVars()
866 { 873 {
867 if (m_Script != null) 874 return m_Script.GetVars();
868 return m_Script.GetVars();
869 else
870 return new Dictionary<string, object>();
871 } 875 }
872 876
873 public void SetVars(Dictionary<string, object> vars) 877 public void SetVars(Dictionary<string, object> vars)
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs
index 298d664..665f4a6 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
@@ -459,6 +459,8 @@ namespace OpenSim.Region.ScriptEngine.Shared
459 size += 64; 459 size += 64;
460 else if (o is int) 460 else if (o is int)
461 size += 4; 461 size += 4;
462 else if (o is uint)
463 size += 4;
462 else if (o is string) 464 else if (o is string)
463 size += ((string)o).Length; 465 size += ((string)o).Length;
464 else if (o is float) 466 else if (o is float)
@@ -613,24 +615,16 @@ namespace OpenSim.Region.ScriptEngine.Shared
613 615
614 public static bool operator ==(list a, list b) 616 public static bool operator ==(list a, list b)
615 { 617 {
616 int la = -1; 618 int la = a.Length;
617 int lb = -1; 619 int lb = b.Length;
618 try { la = a.Length; }
619 catch (NullReferenceException) { }
620 try { lb = b.Length; }
621 catch (NullReferenceException) { }
622 620
623 return la == lb; 621 return la == lb;
624 } 622 }
625 623
626 public static bool operator !=(list a, list b) 624 public static bool operator !=(list a, list b)
627 { 625 {
628 int la = -1; 626 int la = a.Length;
629 int lb = -1; 627 int lb = b.Length;
630 try { la = a.Length; }
631 catch (NullReferenceException) { }
632 try {lb = b.Length;}
633 catch (NullReferenceException) { }
634 628
635 return la != lb; 629 return la != lb;
636 } 630 }
@@ -1064,7 +1058,7 @@ namespace OpenSim.Region.ScriptEngine.Shared
1064 { 1058 {
1065 list ret = new list(); 1059 list ret = new list();
1066 double entry; 1060 double entry;
1067 for (int i = 0; i < src.Data.Length - 1; i++) 1061 for (int i = 0; i < src.Data.Length; i++)
1068 { 1062 {
1069 if (double.TryParse(src.Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry)) 1063 if (double.TryParse(src.Data[i].ToString(), NumberStyles.Float, Culture.NumberFormatInfo, out entry))
1070 { 1064 {
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 8629674..6bdd4c8 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 {
@@ -1616,5 +1695,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1616 1695
1617 instance.Resume(); 1696 instance.Resume();
1618 } 1697 }
1698
1699 public bool HasScript(UUID itemID, out bool running)
1700 {
1701 running = true;
1702
1703 IScriptInstance instance = GetInstance(itemID);
1704 if (instance == null)
1705 return false;
1706
1707 running = instance.Running;
1708 return true;
1709 }
1619 } 1710 }
1620} 1711}