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.cs93
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs703
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs65
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs4
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs4
-rw-r--r--OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs127
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs85
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs93
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs105
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs202
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs67
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs97
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs52
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs2
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs5
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs138
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs32
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs38
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs19
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs136
-rw-r--r--OpenSim/Region/CoreModules/LightShare/LightShareModule.cs3
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs31
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs153
-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.cs8
-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.cs79
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs302
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs71
-rw-r--r--OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs7
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Region/RestartModule.cs38
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs12
-rw-r--r--OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs50
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs6
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityInventory.cs3
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs4
-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/EventManager.cs24
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs328
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs504
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs37
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs230
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs589
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs199
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs804
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs188
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs28
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs87
-rw-r--r--OpenSim/Region/Framework/Scenes/UuidGatherer.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs9
-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/Avatar/XmlRpcGroups/GroupsModule.cs2
-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.cs12
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs1438
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs3875
-rw-r--r--OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs384
-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.cs3841
-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/Manager/PhysicsScene.cs3
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs6
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs11
-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.cs2905
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs97
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs9
-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.cs4
-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.cs21
-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.cs85
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs32
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs361
110 files changed, 17070 insertions, 2873 deletions
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 145875b..7a40751 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -484,7 +484,7 @@ namespace OpenSim
484 if (alert != null) 484 if (alert != null)
485 presence.ControllingClient.Kick(alert); 485 presence.ControllingClient.Kick(alert);
486 else 486 else
487 presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); 487 presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n");
488 488
489 // ...and close on our side 489 // ...and close on our side
490 presence.Scene.IncomingCloseAgent(presence.UUID); 490 presence.Scene.IncomingCloseAgent(presence.UUID);
@@ -1228,7 +1228,7 @@ namespace OpenSim
1228 MainConsole.Instance.Output(String.Format("loadOffsets <X,Y,Z> = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z)); 1228 MainConsole.Instance.Output(String.Format("loadOffsets <X,Y,Z> = <{0},{1},{2}>",loadOffset.X,loadOffset.Y,loadOffset.Z));
1229 } 1229 }
1230 } 1230 }
1231 m_sceneManager.LoadCurrentSceneFromXml(cmdparams[2], generateNewIDS, loadOffset); 1231 m_sceneManager.LoadCurrentSceneFromXml(cmdparams[0], generateNewIDS, loadOffset);
1232 } 1232 }
1233 else 1233 else
1234 { 1234 {
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs
index f482d8f..80bff17 100644
--- a/OpenSim/Region/Application/OpenSimBase.cs
+++ b/OpenSim/Region/Application/OpenSimBase.cs
@@ -93,6 +93,10 @@ namespace OpenSim
93 93
94 protected List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>(); 94 protected List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>();
95 95
96 private List<string> m_permsModules;
97
98 private bool m_securePermissionsLoading = true;
99
96 /// <value> 100 /// <value>
97 /// The config information passed into the OpenSimulator region server. 101 /// The config information passed into the OpenSimulator region server.
98 /// </value> 102 /// </value>
@@ -197,6 +201,11 @@ namespace OpenSim
197 CreatePIDFile(pidFile); 201 CreatePIDFile(pidFile);
198 202
199 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty); 203 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty);
204
205 m_securePermissionsLoading = startupConfig.GetBoolean("SecurePermissionsLoading", true);
206
207 string permissionModules = startupConfig.GetString("permissionmodules", "DefaultPermissionsModule");
208 m_permsModules = new List<string>(permissionModules.Split(','));
200 } 209 }
201 210
202 // Load the simulation data service 211 // Load the simulation data service
@@ -225,6 +234,12 @@ namespace OpenSim
225 m_moduleLoader = new ModuleLoader(m_config.Source); 234 m_moduleLoader = new ModuleLoader(m_config.Source);
226 235
227 LoadPlugins(); 236 LoadPlugins();
237
238 if (m_plugins.Count == 0) // We failed to load any modules. Mono Addins glitch!
239 {
240 Environment.Exit(1);
241 }
242
228 foreach (IApplicationPlugin plugin in m_plugins) 243 foreach (IApplicationPlugin plugin in m_plugins)
229 { 244 {
230 plugin.PostInitialise(); 245 plugin.PostInitialise();
@@ -372,7 +387,41 @@ namespace OpenSim
372 } 387 }
373 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing..."); 388 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing...");
374 389
390 if (m_securePermissionsLoading)
391 {
392 foreach (string s in m_permsModules)
393 {
394 if (!scene.RegionModules.ContainsKey(s))
395 {
396 bool found = false;
397 foreach (IRegionModule m in modules)
398 {
399 if (m.Name == s)
400 {
401 found = true;
402 }
403 }
404 if (!found)
405 {
406 m_log.Fatal("[MODULES]: Required module " + s + " not found.");
407 Environment.Exit(0);
408 }
409 }
410 }
411 }
412
375 scene.SetModuleInterfaces(); 413 scene.SetModuleInterfaces();
414// First Step of bootreport sequence
415 if (scene.SnmpService != null)
416 {
417 scene.SnmpService.ColdStart(1,scene);
418 scene.SnmpService.LinkDown(scene);
419 }
420
421 if (scene.SnmpService != null)
422 {
423 scene.SnmpService.BootInfo("Loading prins", scene);
424 }
376 425
377 while (regionInfo.EstateSettings.EstateOwner == UUID.Zero && MainConsole.Instance != null) 426 while (regionInfo.EstateSettings.EstateOwner == UUID.Zero && MainConsole.Instance != null)
378 SetUpEstateOwner(scene); 427 SetUpEstateOwner(scene);
@@ -386,6 +435,11 @@ namespace OpenSim
386 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID); 435 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
387 scene.EventManager.TriggerParcelPrimCountUpdate(); 436 scene.EventManager.TriggerParcelPrimCountUpdate();
388 437
438 if (scene.SnmpService != null)
439 {
440 scene.SnmpService.BootInfo("Grid Registration in progress", scene);
441 }
442
389 try 443 try
390 { 444 {
391 scene.RegisterRegionWithGrid(); 445 scene.RegisterRegionWithGrid();
@@ -396,15 +450,29 @@ namespace OpenSim
396 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}", 450 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}",
397 e.Message, e.StackTrace); 451 e.Message, e.StackTrace);
398 452
453 if (scene.SnmpService != null)
454 {
455 scene.SnmpService.Critical("Grid registration failed. Startup aborted.", scene);
456 }
399 // Carrying on now causes a lot of confusion down the 457 // Carrying on now causes a lot of confusion down the
400 // line - we need to get the user's attention 458 // line - we need to get the user's attention
401 Environment.Exit(1); 459 Environment.Exit(1);
402 } 460 }
403 461
462 if (scene.SnmpService != null)
463 {
464 scene.SnmpService.BootInfo("Grid Registration done", scene);
465 }
466
404 // We need to do this after we've initialized the 467 // We need to do this after we've initialized the
405 // scripting engines. 468 // scripting engines.
406 scene.CreateScriptInstances(); 469 scene.CreateScriptInstances();
407 470
471 if (scene.SnmpService != null)
472 {
473 scene.SnmpService.BootInfo("ScriptEngine started", scene);
474 }
475
408 m_sceneManager.Add(scene); 476 m_sceneManager.Add(scene);
409 477
410 if (m_autoCreateClientStack) 478 if (m_autoCreateClientStack)
@@ -413,6 +481,10 @@ namespace OpenSim
413 clientServer.Start(); 481 clientServer.Start();
414 } 482 }
415 483
484 if (scene.SnmpService != null)
485 {
486 scene.SnmpService.BootInfo("Initializing region modules", scene);
487 }
416 if (do_post_init) 488 if (do_post_init)
417 { 489 {
418 foreach (IRegionModule module in modules) 490 foreach (IRegionModule module in modules)
@@ -424,7 +496,14 @@ namespace OpenSim
424 496
425 mscene = scene; 497 mscene = scene;
426 498
499 if (scene.SnmpService != null)
500 {
501 scene.SnmpService.BootInfo("The region is operational", scene);
502 scene.SnmpService.LinkUp(scene);
503 }
504
427 scene.StartTimer(); 505 scene.StartTimer();
506 scene.StartTimerWatchdog();
428 507
429 scene.StartScripts(); 508 scene.StartScripts();
430 509
@@ -501,6 +580,11 @@ namespace OpenSim
501 private void ShutdownRegion(Scene scene) 580 private void ShutdownRegion(Scene scene)
502 { 581 {
503 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName); 582 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName);
583 if (scene.SnmpService != null)
584 {
585 scene.SnmpService.BootInfo("The region is shutting down", scene);
586 scene.SnmpService.LinkDown(scene);
587 }
504 IRegionModulesController controller; 588 IRegionModulesController controller;
505 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller)) 589 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller))
506 { 590 {
@@ -944,7 +1028,7 @@ namespace OpenSim
944 = MainConsole.Instance.CmdPrompt( 1028 = MainConsole.Instance.CmdPrompt(
945 string.Format( 1029 string.Format(
946 "Do you wish to join region {0} to an existing estate (yes/no)?", regInfo.RegionName), 1030 "Do you wish to join region {0} to an existing estate (yes/no)?", regInfo.RegionName),
947 "yes", 1031 "no",
948 new List<string>() { "yes", "no" }); 1032 new List<string>() { "yes", "no" });
949 1033
950 if (response == "no") 1034 if (response == "no")
@@ -960,12 +1044,15 @@ namespace OpenSim
960 = MainConsole.Instance.CmdPrompt( 1044 = MainConsole.Instance.CmdPrompt(
961 string.Format( 1045 string.Format(
962 "Name of estate to join. Existing estate names are ({0})", string.Join(", ", estateNames.ToArray())), 1046 "Name of estate to join. Existing estate names are ({0})", string.Join(", ", estateNames.ToArray())),
963 estateNames[0]); 1047 "None");
1048
1049 if (response == "None")
1050 continue;
964 1051
965 List<int> estateIDs = EstateDataService.GetEstates(response); 1052 List<int> estateIDs = EstateDataService.GetEstates(response);
966 if (estateIDs.Count < 1) 1053 if (estateIDs.Count < 1)
967 { 1054 {
968 MainConsole.Instance.Output("The name you have entered matches no known estate. Please try again."); 1055 MainConsole.Instance.Output("The name you have entered matches no known estate. Please try again.");
969 continue; 1056 continue;
970 } 1057 }
971 1058
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
index afbe56b..3995620 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs
@@ -234,6 +234,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
234 m_stopPacket = TexturePacketCount(); 234 m_stopPacket = TexturePacketCount();
235 } 235 }
236 236
237 //Give them at least two packets, to play nice with some broken viewers (SL also behaves this way)
238 if (m_stopPacket == 1 && m_layers[0].End > FIRST_PACKET_SIZE) m_stopPacket++;
239
237 m_currentPacket = StartPacket; 240 m_currentPacket = StartPacket;
238 } 241 }
239 } 242 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 8273c6f..f019a83 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -158,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
158 public event RequestTaskInventory OnRequestTaskInventory; 158 public event RequestTaskInventory OnRequestTaskInventory;
159 public event UpdateInventoryItem OnUpdateInventoryItem; 159 public event UpdateInventoryItem OnUpdateInventoryItem;
160 public event CopyInventoryItem OnCopyInventoryItem; 160 public event CopyInventoryItem OnCopyInventoryItem;
161 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
161 public event MoveInventoryItem OnMoveInventoryItem; 162 public event MoveInventoryItem OnMoveInventoryItem;
162 public event RemoveInventoryItem OnRemoveInventoryItem; 163 public event RemoveInventoryItem OnRemoveInventoryItem;
163 public event RemoveInventoryFolder OnRemoveInventoryFolder; 164 public event RemoveInventoryFolder OnRemoveInventoryFolder;
@@ -256,7 +257,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
256 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 257 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
257 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 258 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
258 public event ClassifiedDelete OnClassifiedDelete; 259 public event ClassifiedDelete OnClassifiedDelete;
259 public event ClassifiedDelete OnClassifiedGodDelete; 260 public event ClassifiedGodDelete OnClassifiedGodDelete;
260 public event EventNotificationAddRequest OnEventNotificationAddRequest; 261 public event EventNotificationAddRequest OnEventNotificationAddRequest;
261 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 262 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
262 public event EventGodDelete OnEventGodDelete; 263 public event EventGodDelete OnEventGodDelete;
@@ -287,6 +288,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
287 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 288 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
288 public event SimWideDeletesDelegate OnSimWideDeletes; 289 public event SimWideDeletesDelegate OnSimWideDeletes;
289 public event SendPostcard OnSendPostcard; 290 public event SendPostcard OnSendPostcard;
291 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
290 public event MuteListEntryUpdate OnUpdateMuteListEntry; 292 public event MuteListEntryUpdate OnUpdateMuteListEntry;
291 public event MuteListEntryRemove OnRemoveMuteListEntry; 293 public event MuteListEntryRemove OnRemoveMuteListEntry;
292 public event GodlikeMessage onGodlikeMessage; 294 public event GodlikeMessage onGodlikeMessage;
@@ -337,7 +339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
337 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an 339 /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an
338 /// ownerless phantom. 340 /// ownerless phantom.
339 /// 341 ///
340 /// All manipulation of this set has to occur under a lock 342 /// All manipulation of this set has to occur under an m_entityUpdates.SyncRoot lock
341 /// 343 ///
342 /// </value> 344 /// </value>
343 protected HashSet<uint> m_killRecord; 345 protected HashSet<uint> m_killRecord;
@@ -345,6 +347,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
345// protected HashSet<uint> m_attachmentsSent; 347// protected HashSet<uint> m_attachmentsSent;
346 348
347 private int m_moneyBalance; 349 private int m_moneyBalance;
350 private bool m_deliverPackets = true;
348 private int m_animationSequenceNumber = 1; 351 private int m_animationSequenceNumber = 1;
349 private bool m_SendLogoutPacketWhenClosing = true; 352 private bool m_SendLogoutPacketWhenClosing = true;
350 private AgentUpdateArgs lastarg; 353 private AgentUpdateArgs lastarg;
@@ -384,6 +387,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
384 get { return m_startpos; } 387 get { return m_startpos; }
385 set { m_startpos = value; } 388 set { m_startpos = value; }
386 } 389 }
390 public bool DeliverPackets
391 {
392 get { return m_deliverPackets; }
393 set {
394 m_deliverPackets = value;
395 m_udpClient.m_deliverPackets = value;
396 }
397 }
387 public UUID AgentId { get { return m_agentId; } } 398 public UUID AgentId { get { return m_agentId; } }
388 public ISceneAgent SceneAgent { get; private set; } 399 public ISceneAgent SceneAgent { get; private set; }
389 public UUID ActiveGroupId { get { return m_activeGroupID; } } 400 public UUID ActiveGroupId { get { return m_activeGroupID; } }
@@ -488,18 +499,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
488 499
489 #region Client Methods 500 #region Client Methods
490 501
502
491 /// <summary> 503 /// <summary>
492 /// Shut down the client view 504 /// Shut down the client view
493 /// </summary> 505 /// </summary>
494 public void Close() 506 public void Close()
495 { 507 {
508 Close(true);
509 }
510
511 /// <summary>
512 /// Shut down the client view
513 /// </summary>
514 public void Close(bool sendStop)
515 {
496 m_log.DebugFormat( 516 m_log.DebugFormat(
497 "[CLIENT]: Close has been called for {0} attached to scene {1}", 517 "[CLIENT]: Close has been called for {0} attached to scene {1}",
498 Name, m_scene.RegionInfo.RegionName); 518 Name, m_scene.RegionInfo.RegionName);
499 519
500 // Send the STOP packet 520 if (sendStop)
501 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator); 521 {
502 OutPacket(disable, ThrottleOutPacketType.Unknown); 522 // Send the STOP packet
523 DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
524 OutPacket(disable, ThrottleOutPacketType.Unknown);
525 }
503 526
504 IsActive = false; 527 IsActive = false;
505 528
@@ -799,7 +822,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
799 reply.ChatData.OwnerID = fromAgentID; 822 reply.ChatData.OwnerID = fromAgentID;
800 reply.ChatData.SourceID = fromAgentID; 823 reply.ChatData.SourceID = fromAgentID;
801 824
802 OutPacket(reply, ThrottleOutPacketType.Task); 825 OutPacket(reply, ThrottleOutPacketType.Unknown);
803 } 826 }
804 827
805 /// <summary> 828 /// <summary>
@@ -1085,6 +1108,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1085 public virtual void SendLayerData(float[] map) 1108 public virtual void SendLayerData(float[] map)
1086 { 1109 {
1087 Util.FireAndForget(DoSendLayerData, map); 1110 Util.FireAndForget(DoSendLayerData, map);
1111
1112 // Send it sync, and async. It's not that much data
1113 // and it improves user experience just so much!
1114 DoSendLayerData(map);
1088 } 1115 }
1089 1116
1090 /// <summary> 1117 /// <summary>
@@ -1097,16 +1124,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1097 1124
1098 try 1125 try
1099 { 1126 {
1100 //for (int y = 0; y < 16; y++) 1127 for (int y = 0; y < 16; y++)
1101 //{ 1128 {
1102 // for (int x = 0; x < 16; x++) 1129 for (int x = 0; x < 16; x+=4)
1103 // { 1130 {
1104 // SendLayerData(x, y, map); 1131 SendLayerPacket(x, y, map);
1105 // } 1132 }
1106 //} 1133 }
1107
1108 // Send LayerData in a spiral pattern. Fun!
1109 SendLayerTopRight(map, 0, 0, 15, 15);
1110 } 1134 }
1111 catch (Exception e) 1135 catch (Exception e)
1112 { 1136 {
@@ -1114,51 +1138,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1114 } 1138 }
1115 } 1139 }
1116 1140
1117 private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
1118 {
1119 // Row
1120 for (int i = x1; i <= x2; i++)
1121 SendLayerData(i, y1, map);
1122
1123 // Column
1124 for (int j = y1 + 1; j <= y2; j++)
1125 SendLayerData(x2, j, map);
1126
1127 if (x2 - x1 > 0)
1128 SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
1129 }
1130
1131 void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
1132 {
1133 // Row in reverse
1134 for (int i = x2; i >= x1; i--)
1135 SendLayerData(i, y2, map);
1136
1137 // Column in reverse
1138 for (int j = y2 - 1; j >= y1; j--)
1139 SendLayerData(x1, j, map);
1140
1141 if (x2 - x1 > 0)
1142 SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
1143 }
1144
1145 /// <summary> 1141 /// <summary>
1146 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1142 /// Sends a set of four patches (x, x+1, ..., x+3) to the client
1147 /// </summary> 1143 /// </summary>
1148 /// <param name="map">heightmap</param> 1144 /// <param name="map">heightmap</param>
1149 /// <param name="px">X coordinate for patches 0..12</param> 1145 /// <param name="px">X coordinate for patches 0..12</param>
1150 /// <param name="py">Y coordinate for patches 0..15</param> 1146 /// <param name="py">Y coordinate for patches 0..15</param>
1151 // private void SendLayerPacket(float[] map, int y, int x) 1147 private void SendLayerPacket(int x, int y, float[] map)
1152 // { 1148 {
1153 // int[] patches = new int[4]; 1149 int[] patches = new int[4];
1154 // patches[0] = x + 0 + y * 16; 1150 patches[0] = x + 0 + y * 16;
1155 // patches[1] = x + 1 + y * 16; 1151 patches[1] = x + 1 + y * 16;
1156 // patches[2] = x + 2 + y * 16; 1152 patches[2] = x + 2 + y * 16;
1157 // patches[3] = x + 3 + y * 16; 1153 patches[3] = x + 3 + y * 16;
1158 1154
1159 // Packet layerpack = LLClientView.TerrainManager.CreateLandPacket(map, patches); 1155 float[] heightmap = (map.Length == 65536) ?
1160 // OutPacket(layerpack, ThrottleOutPacketType.Land); 1156 map :
1161 // } 1157 LLHeightFieldMoronize(map);
1158
1159 try
1160 {
1161 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1162 OutPacket(layerpack, ThrottleOutPacketType.Land);
1163 }
1164 catch
1165 {
1166 for (int px = x ; px < x + 4 ; px++)
1167 SendLayerData(px, y, map);
1168 }
1169 }
1162 1170
1163 /// <summary> 1171 /// <summary>
1164 /// Sends a specified patch to a client 1172 /// Sends a specified patch to a client
@@ -1178,7 +1186,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1178 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1186 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1179 layerpack.Header.Reliable = true; 1187 layerpack.Header.Reliable = true;
1180 1188
1181 OutPacket(layerpack, ThrottleOutPacketType.Land); 1189 OutPacket(layerpack, ThrottleOutPacketType.Task);
1182 } 1190 }
1183 catch (Exception e) 1191 catch (Exception e)
1184 { 1192 {
@@ -2302,6 +2310,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2302 OutPacket(sound, ThrottleOutPacketType.Task); 2310 OutPacket(sound, ThrottleOutPacketType.Task);
2303 } 2311 }
2304 2312
2313 public void SendTransferAbort(TransferRequestPacket transferRequest)
2314 {
2315 TransferAbortPacket abort = (TransferAbortPacket)PacketPool.Instance.GetPacket(PacketType.TransferAbort);
2316 abort.TransferInfo.TransferID = transferRequest.TransferInfo.TransferID;
2317 abort.TransferInfo.ChannelType = transferRequest.TransferInfo.ChannelType;
2318 m_log.Debug("[Assets] Aborting transfer; asset request failed");
2319 OutPacket(abort, ThrottleOutPacketType.Task);
2320 }
2321
2305 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain) 2322 public void SendTriggeredSound(UUID soundID, UUID ownerID, UUID objectID, UUID parentID, ulong handle, Vector3 position, float gain)
2306 { 2323 {
2307 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger); 2324 SoundTriggerPacket sound = (SoundTriggerPacket)PacketPool.Instance.GetPacket(PacketType.SoundTrigger);
@@ -2749,7 +2766,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2749 reply.Data.ParcelID = parcelID; 2766 reply.Data.ParcelID = parcelID;
2750 reply.Data.OwnerID = land.OwnerID; 2767 reply.Data.OwnerID = land.OwnerID;
2751 reply.Data.Name = Utils.StringToBytes(land.Name); 2768 reply.Data.Name = Utils.StringToBytes(land.Name);
2752 reply.Data.Desc = Utils.StringToBytes(land.Description); 2769 if (land != null && land.Description != null && land.Description != String.Empty)
2770 reply.Data.Desc = Utils.StringToBytes(land.Description.Substring(0, land.Description.Length > 254 ? 254: land.Description.Length));
2771 else
2772 reply.Data.Desc = new Byte[0];
2753 reply.Data.ActualArea = land.Area; 2773 reply.Data.ActualArea = land.Area;
2754 reply.Data.BillableArea = land.Area; // TODO: what is this? 2774 reply.Data.BillableArea = land.Area; // TODO: what is this?
2755 2775
@@ -3612,7 +3632,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3612 /// </summary> 3632 /// </summary>
3613 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) 3633 public void SendEntityUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
3614 { 3634 {
3615 //double priority = m_prioritizer.GetUpdatePriority(this, entity); 3635 if (entity is SceneObjectPart)
3636 {
3637 SceneObjectPart e = (SceneObjectPart)entity;
3638 SceneObjectGroup g = e.ParentGroup;
3639 if (g.RootPart.Shape.State > 30) // HUD
3640 if (g.OwnerID != AgentId)
3641 return; // Don't send updates for other people's HUDs
3642 }
3643
3616 uint priority = m_prioritizer.GetUpdatePriority(this, entity); 3644 uint priority = m_prioritizer.GetUpdatePriority(this, entity);
3617 3645
3618 lock (m_entityUpdates.SyncRoot) 3646 lock (m_entityUpdates.SyncRoot)
@@ -3679,211 +3707,230 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3679 3707
3680 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race 3708 // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
3681 // condition where a kill can be processed before an out-of-date update for the same object. 3709 // condition where a kill can be processed before an out-of-date update for the same object.
3682 lock (m_killRecord) 3710 float avgTimeDilation = 1.0f;
3711 IEntityUpdate iupdate;
3712 Int32 timeinqueue; // this is just debugging code & can be dropped later
3713
3714 while (updatesThisCall < maxUpdates)
3683 { 3715 {
3684 float avgTimeDilation = 1.0f; 3716 lock (m_entityUpdates.SyncRoot)
3685 IEntityUpdate iupdate; 3717 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3686 Int32 timeinqueue; // this is just debugging code & can be dropped later 3718 break;
3687
3688 while (updatesThisCall < maxUpdates)
3689 {
3690 lock (m_entityUpdates.SyncRoot)
3691 if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue))
3692 break;
3693 3719
3694 EntityUpdate update = (EntityUpdate)iupdate; 3720 EntityUpdate update = (EntityUpdate)iupdate;
3695 3721
3696 avgTimeDilation += update.TimeDilation; 3722 avgTimeDilation += update.TimeDilation;
3697 avgTimeDilation *= 0.5f; 3723 avgTimeDilation *= 0.5f;
3698 3724
3699 if (update.Entity is SceneObjectPart) 3725 if (update.Entity is SceneObjectPart)
3726 {
3727 SceneObjectPart part = (SceneObjectPart)update.Entity;
3728
3729 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3730 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3731 // safety measure.
3732 //
3733 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3734 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3735 // updates and kills on different threads with different scheduling strategies, hence this protection.
3736 //
3737 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3738 // after the root prim has been deleted.
3739 lock (m_killRecord)
3700 { 3740 {
3701 SceneObjectPart part = (SceneObjectPart)update.Entity;
3702
3703 // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client
3704 // will never receive an update after a prim kill. Even then, keeping the kill record may be a good
3705 // safety measure.
3706 //
3707 // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update
3708 // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs
3709 // updates and kills on different threads with different scheduling strategies, hence this protection.
3710 //
3711 // This doesn't appear to apply to child prims - a client will happily ignore these updates
3712 // after the root prim has been deleted.
3713 if (m_killRecord.Contains(part.LocalId)) 3741 if (m_killRecord.Contains(part.LocalId))
3714 {
3715 // m_log.WarnFormat(
3716 // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted",
3717 // part.LocalId, Name);
3718 continue; 3742 continue;
3719 } 3743 if (m_killRecord.Contains(part.ParentGroup.RootPart.LocalId))
3720 3744 continue;
3721 if (part.ParentGroup.IsAttachment && m_disableFacelights) 3745 }
3746
3747 if (part.ParentGroup.IsDeleted)
3748 continue;
3749
3750 if (part.ParentGroup.IsAttachment)
3751 { // Someone else's HUD, why are we getting these?
3752 if (part.ParentGroup.OwnerID != AgentId &&
3753 part.ParentGroup.RootPart.Shape.State >= 30)
3754 continue;
3755 ScenePresence sp;
3756 // Owner is not in the sim, don't update it to
3757 // anyone
3758 if (!m_scene.TryGetScenePresence(part.OwnerID, out sp))
3759 continue;
3760
3761 List<SceneObjectGroup> atts = sp.GetAttachments();
3762 bool found = false;
3763 foreach (SceneObjectGroup att in atts)
3722 { 3764 {
3723 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && 3765 if (att == part.ParentGroup)
3724 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3725 { 3766 {
3726 part.Shape.LightEntry = false; 3767 found = true;
3768 break;
3727 } 3769 }
3728 } 3770 }
3771
3772 // It's an attachment of a valid avatar, but
3773 // doesn't seem to be attached, skip
3774 if (!found)
3775 continue;
3729 } 3776 }
3730 3777 if (part.ParentGroup.IsAttachment && m_disableFacelights)
3731 ++updatesThisCall;
3732
3733 #region UpdateFlags to packet type conversion
3734
3735 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3736
3737 bool canUseCompressed = true;
3738 bool canUseImproved = true;
3739
3740 // Compressed object updates only make sense for LL primitives
3741 if (!(update.Entity is SceneObjectPart))
3742 {
3743 canUseCompressed = false;
3744 }
3745
3746 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3747 {
3748 canUseCompressed = false;
3749 canUseImproved = false;
3750 }
3751 else
3752 { 3778 {
3753 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) || 3779 if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand &&
3754 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) || 3780 part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.RightHand)
3755 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3756 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3757 { 3781 {
3758 canUseCompressed = false; 3782 part.Shape.LightEntry = false;
3759 }
3760
3761 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3762 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3763 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3764 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3765 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3766 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3767 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3768 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3769 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3770 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3771 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3772 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3773 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3774 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3775 {
3776 canUseImproved = false;
3777 } 3783 }
3778 } 3784 }
3779 3785 }
3780 #endregion UpdateFlags to packet type conversion 3786
3781 3787 ++updatesThisCall;
3782 #region Block Construction 3788
3783 3789 #region UpdateFlags to packet type conversion
3784 // TODO: Remove this once we can build compressed updates 3790
3791 PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
3792
3793 bool canUseCompressed = true;
3794 bool canUseImproved = true;
3795
3796 // Compressed object updates only make sense for LL primitives
3797 if (!(update.Entity is SceneObjectPart))
3798 {
3785 canUseCompressed = false; 3799 canUseCompressed = false;
3786 3800 }
3787 if (!canUseImproved && !canUseCompressed) 3801
3788 { 3802 if (updateFlags.HasFlag(PrimUpdateFlags.FullUpdate))
3789 if (update.Entity is ScenePresence) 3803 {
3790 { 3804 canUseCompressed = false;
3791 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); 3805 canUseImproved = false;
3792 objectUpdates.Value.Add(update); 3806 }
3793 } 3807 else
3794 else 3808 {
3795 { 3809 if (updateFlags.HasFlag(PrimUpdateFlags.Velocity) ||
3796 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); 3810 updateFlags.HasFlag(PrimUpdateFlags.Acceleration) ||
3797 objectUpdates.Value.Add(update); 3811 updateFlags.HasFlag(PrimUpdateFlags.CollisionPlane) ||
3798 } 3812 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3799 }
3800 else if (!canUseImproved)
3801 { 3813 {
3802 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3814 canUseCompressed = false;
3803 compressedUpdates.Value.Add(update);
3804 } 3815 }
3805 else 3816
3817 if (updateFlags.HasFlag(PrimUpdateFlags.PrimFlags) ||
3818 updateFlags.HasFlag(PrimUpdateFlags.ParentID) ||
3819 updateFlags.HasFlag(PrimUpdateFlags.Scale) ||
3820 updateFlags.HasFlag(PrimUpdateFlags.PrimData) ||
3821 updateFlags.HasFlag(PrimUpdateFlags.Text) ||
3822 updateFlags.HasFlag(PrimUpdateFlags.NameValue) ||
3823 updateFlags.HasFlag(PrimUpdateFlags.ExtraData) ||
3824 updateFlags.HasFlag(PrimUpdateFlags.TextureAnim) ||
3825 updateFlags.HasFlag(PrimUpdateFlags.Sound) ||
3826 updateFlags.HasFlag(PrimUpdateFlags.Particles) ||
3827 updateFlags.HasFlag(PrimUpdateFlags.Material) ||
3828 updateFlags.HasFlag(PrimUpdateFlags.ClickAction) ||
3829 updateFlags.HasFlag(PrimUpdateFlags.MediaURL) ||
3830 updateFlags.HasFlag(PrimUpdateFlags.Joint))
3806 { 3831 {
3807 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3832 canUseImproved = false;
3808 {
3809 // Self updates go into a special list
3810 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3811 terseAgentUpdates.Value.Add(update);
3812 }
3813 else
3814 {
3815 // Everything else goes here
3816 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3817 terseUpdates.Value.Add(update);
3818 }
3819 } 3833 }
3820
3821 #endregion Block Construction
3822 } 3834 }
3823
3824
3825 #region Packet Sending
3826 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3827 3835
3828 if (terseAgentUpdateBlocks.IsValueCreated) 3836 #endregion UpdateFlags to packet type conversion
3829 {
3830 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3831 3837
3832 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3838 #region Block Construction
3833 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3834 packet.RegionData.TimeDilation = timeDilation;
3835 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3836 3839
3837 for (int i = 0; i < blocks.Count; i++) 3840 // TODO: Remove this once we can build compressed updates
3838 packet.ObjectData[i] = blocks[i]; 3841 canUseCompressed = false;
3839 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3840 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); });
3841 }
3842 3842
3843 if (objectUpdateBlocks.IsValueCreated) 3843 if (!canUseImproved && !canUseCompressed)
3844 { 3844 {
3845 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3845 if (update.Entity is ScenePresence)
3846 3846 {
3847 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); 3847 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3848 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3848 }
3849 packet.RegionData.TimeDilation = timeDilation; 3849 else
3850 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3850 {
3851 3851 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3852 for (int i = 0; i < blocks.Count; i++) 3852 }
3853 packet.ObjectData[i] = blocks[i];
3854 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3855 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); });
3856 } 3853 }
3857 3854 else if (!canUseImproved)
3858 if (compressedUpdateBlocks.IsValueCreated)
3859 { 3855 {
3860 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value; 3856 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3861
3862 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3863 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3864 packet.RegionData.TimeDilation = timeDilation;
3865 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3866
3867 for (int i = 0; i < blocks.Count; i++)
3868 packet.ObjectData[i] = blocks[i];
3869 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3870 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); });
3871 } 3857 }
3872 3858 else
3873 if (terseUpdateBlocks.IsValueCreated)
3874 { 3859 {
3875 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 3860 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3876 3861 // Self updates go into a special list
3877 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3862 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3878 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3863 else
3879 packet.RegionData.TimeDilation = timeDilation; 3864 // Everything else goes here
3880 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3865 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3881
3882 for (int i = 0; i < blocks.Count; i++)
3883 packet.ObjectData[i] = blocks[i];
3884 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3885 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); });
3886 } 3866 }
3867
3868 #endregion Block Construction
3869 }
3870
3871 #region Packet Sending
3872
3873 const float TIME_DILATION = 1.0f;
3874 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3875
3876 if (terseAgentUpdateBlocks.IsValueCreated)
3877 {
3878 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3879
3880 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3881 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3882 packet.RegionData.TimeDilation = timeDilation;
3883 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3884
3885 for (int i = 0; i < blocks.Count; i++)
3886 packet.ObjectData[i] = blocks[i];
3887
3888 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3889 }
3890
3891 if (objectUpdateBlocks.IsValueCreated)
3892 {
3893 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
3894
3895 ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
3896 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3897 packet.RegionData.TimeDilation = timeDilation;
3898 packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3899
3900 for (int i = 0; i < blocks.Count; i++)
3901 packet.ObjectData[i] = blocks[i];
3902
3903 OutPacket(packet, ThrottleOutPacketType.Task, true);
3904 }
3905
3906 if (compressedUpdateBlocks.IsValueCreated)
3907 {
3908 List<ObjectUpdateCompressedPacket.ObjectDataBlock> blocks = compressedUpdateBlocks.Value;
3909
3910 ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed);
3911 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3912 packet.RegionData.TimeDilation = timeDilation;
3913 packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count];
3914
3915 for (int i = 0; i < blocks.Count; i++)
3916 packet.ObjectData[i] = blocks[i];
3917
3918 OutPacket(packet, ThrottleOutPacketType.Task, true);
3919 }
3920
3921 if (terseUpdateBlocks.IsValueCreated)
3922 {
3923 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
3924
3925 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3926 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3927 packet.RegionData.TimeDilation = timeDilation;
3928 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3929
3930 for (int i = 0; i < blocks.Count; i++)
3931 packet.ObjectData[i] = blocks[i];
3932
3933 OutPacket(packet, ThrottleOutPacketType.Task, true);
3887 } 3934 }
3888 3935
3889 #endregion Packet Sending 3936 #endregion Packet Sending
@@ -4176,11 +4223,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4176 4223
4177 // Pass in the delegate so that if this packet needs to be resent, we send the current properties 4224 // Pass in the delegate so that if this packet needs to be resent, we send the current properties
4178 // of the object rather than the properties when the packet was created 4225 // of the object rather than the properties when the packet was created
4179 OutPacket(packet, ThrottleOutPacketType.Task, true, 4226 // HACK : Remove intelligent resending until it's fixed in core
4180 delegate(OutgoingPacket oPacket) 4227 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4181 { 4228 // delegate(OutgoingPacket oPacket)
4182 ResendPropertyUpdates(updates, oPacket); 4229 // {
4183 }); 4230 // ResendPropertyUpdates(updates, oPacket);
4231 // });
4232 OutPacket(packet, ThrottleOutPacketType.Task, true);
4184 4233
4185 // pbcnt += blocks.Count; 4234 // pbcnt += blocks.Count;
4186 // ppcnt++; 4235 // ppcnt++;
@@ -4206,11 +4255,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4206 // of the object rather than the properties when the packet was created 4255 // of the object rather than the properties when the packet was created
4207 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); 4256 List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>();
4208 updates.Add(familyUpdates.Value[i]); 4257 updates.Add(familyUpdates.Value[i]);
4209 OutPacket(packet, ThrottleOutPacketType.Task, true, 4258 // HACK : Remove intelligent resending until it's fixed in core
4210 delegate(OutgoingPacket oPacket) 4259 //OutPacket(packet, ThrottleOutPacketType.Task, true,
4211 { 4260 // delegate(OutgoingPacket oPacket)
4212 ResendPropertyUpdates(updates, oPacket); 4261 // {
4213 }); 4262 // ResendPropertyUpdates(updates, oPacket);
4263 // });
4264 OutPacket(packet, ThrottleOutPacketType.Task, true);
4214 4265
4215 // fpcnt++; 4266 // fpcnt++;
4216 // fbcnt++; 4267 // fbcnt++;
@@ -4359,37 +4410,44 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4359 if (bl[i].BannedUserID == UUID.Zero) 4410 if (bl[i].BannedUserID == UUID.Zero)
4360 continue; 4411 continue;
4361 BannedUsers.Add(bl[i].BannedUserID); 4412 BannedUsers.Add(bl[i].BannedUserID);
4362 }
4363 4413
4364 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); 4414 if (BannedUsers.Count >= 50 || (i == (bl.Length - 1) && BannedUsers.Count > 0))
4365 packet.AgentData.TransactionID = UUID.Random(); 4415 {
4366 packet.AgentData.AgentID = AgentId; 4416 EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
4367 packet.AgentData.SessionID = SessionId; 4417 packet.AgentData.TransactionID = UUID.Random();
4368 packet.MethodData.Invoice = invoice; 4418 packet.AgentData.AgentID = AgentId;
4369 packet.MethodData.Method = Utils.StringToBytes("setaccess"); 4419 packet.AgentData.SessionID = SessionId;
4420 packet.MethodData.Invoice = invoice;
4421 packet.MethodData.Method = Utils.StringToBytes("setaccess");
4370 4422
4371 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count]; 4423 EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[6 + BannedUsers.Count];
4372 4424
4373 for (int i = 0; i < (6 + BannedUsers.Count); i++) 4425 int j;
4374 { 4426 for (j = 0; j < (6 + BannedUsers.Count); j++)
4375 returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock(); 4427 {
4376 } 4428 returnblock[j] = new EstateOwnerMessagePacket.ParamListBlock();
4377 int j = 0; 4429 }
4430 j = 0;
4378 4431
4379 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++; 4432 returnblock[j].Parameter = Utils.StringToBytes(estateID.ToString()); j++;
4380 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++; 4433 returnblock[j].Parameter = Utils.StringToBytes(((int)Constants.EstateAccessCodex.EstateBans).ToString()); j++;
4381 returnblock[j].Parameter = Utils.StringToBytes("0"); j++; 4434 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4382 returnblock[j].Parameter = Utils.StringToBytes("0"); j++; 4435 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4383 returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++; 4436 returnblock[j].Parameter = Utils.StringToBytes(BannedUsers.Count.ToString()); j++;
4384 returnblock[j].Parameter = Utils.StringToBytes("0"); j++; 4437 returnblock[j].Parameter = Utils.StringToBytes("0"); j++;
4385 4438
4386 foreach (UUID banned in BannedUsers) 4439 foreach (UUID banned in BannedUsers)
4387 { 4440 {
4388 returnblock[j].Parameter = banned.GetBytes(); j++; 4441 returnblock[j].Parameter = banned.GetBytes(); j++;
4442 }
4443 packet.ParamList = returnblock;
4444 packet.Header.Reliable = true;
4445 OutPacket(packet, ThrottleOutPacketType.Task);
4446
4447 BannedUsers.Clear();
4448 }
4389 } 4449 }
4390 packet.ParamList = returnblock; 4450
4391 packet.Header.Reliable = false;
4392 OutPacket(packet, ThrottleOutPacketType.Task);
4393 } 4451 }
4394 4452
4395 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args) 4453 public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
@@ -4575,7 +4633,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4575 4633
4576 if (landData.SimwideArea > 0) 4634 if (landData.SimwideArea > 0)
4577 { 4635 {
4578 int simulatorCapacity = (int)(((float)landData.SimwideArea / 65536.0f) * (float)m_scene.RegionInfo.ObjectCapacity * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 4636 int simulatorCapacity = (int)((long)landData.SimwideArea * (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus / 65536L);
4637 // Never report more than sim total capacity
4638 if (simulatorCapacity > m_scene.RegionInfo.ObjectCapacity)
4639 simulatorCapacity = m_scene.RegionInfo.ObjectCapacity;
4579 updateMessage.SimWideMaxPrims = simulatorCapacity; 4640 updateMessage.SimWideMaxPrims = simulatorCapacity;
4580 } 4641 }
4581 else 4642 else
@@ -4704,14 +4765,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4704 4765
4705 if (notifyCount > 0) 4766 if (notifyCount > 0)
4706 { 4767 {
4707 if (notifyCount > 32) 4768// if (notifyCount > 32)
4708 { 4769// {
4709 m_log.InfoFormat( 4770// m_log.InfoFormat(
4710 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" 4771// "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
4711 + " - a developer might want to investigate whether this is a hard limit", 32); 4772// + " - a developer might want to investigate whether this is a hard limit", 32);
4712 4773//
4713 notifyCount = 32; 4774// notifyCount = 32;
4714 } 4775// }
4715 4776
4716 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock 4777 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
4717 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; 4778 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
@@ -5244,6 +5305,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5244 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false); 5305 AddLocalPacketHandler(PacketType.TransferAbort, HandleTransferAbort, false);
5245 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false); 5306 AddLocalPacketHandler(PacketType.MuteListRequest, HandleMuteListRequest, false);
5246 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode); 5307 AddLocalPacketHandler(PacketType.UseCircuitCode, HandleUseCircuitCode);
5308 AddLocalPacketHandler(PacketType.CreateNewOutfitAttachments, HandleCreateNewOutfitAttachments);
5247 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false); 5309 AddLocalPacketHandler(PacketType.AgentHeightWidth, HandleAgentHeightWidth, false);
5248 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents); 5310 AddLocalPacketHandler(PacketType.InventoryDescendents, HandleInventoryDescendents);
5249 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery); 5311 AddLocalPacketHandler(PacketType.DirPlacesQuery, HandleDirPlacesQuery);
@@ -5310,6 +5372,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5310 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest); 5372 AddLocalPacketHandler(PacketType.GroupVoteHistoryRequest, HandleGroupVoteHistoryRequest);
5311 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes); 5373 AddLocalPacketHandler(PacketType.SimWideDeletes, HandleSimWideDeletes);
5312 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard); 5374 AddLocalPacketHandler(PacketType.SendPostcard, HandleSendPostcard);
5375 AddLocalPacketHandler(PacketType.ChangeInventoryItemFlags, HandleChangeInventoryItemFlags);
5313 5376
5314 AddGenericPacketHandler("autopilot", HandleAutopilot); 5377 AddGenericPacketHandler("autopilot", HandleAutopilot);
5315 } 5378 }
@@ -5345,6 +5408,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5345 (x.CameraLeftAxis != lastarg.CameraLeftAxis) || 5408 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5346 (x.CameraUpAxis != lastarg.CameraUpAxis) || 5409 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5347 (x.ControlFlags != lastarg.ControlFlags) || 5410 (x.ControlFlags != lastarg.ControlFlags) ||
5411 (x.ControlFlags != 0) ||
5348 (x.Far != lastarg.Far) || 5412 (x.Far != lastarg.Far) ||
5349 (x.Flags != lastarg.Flags) || 5413 (x.Flags != lastarg.Flags) ||
5350 (x.State != lastarg.State) || 5414 (x.State != lastarg.State) ||
@@ -5722,7 +5786,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5722 args.Channel = ch; 5786 args.Channel = ch;
5723 args.From = String.Empty; 5787 args.From = String.Empty;
5724 args.Message = Utils.BytesToString(msg); 5788 args.Message = Utils.BytesToString(msg);
5725 args.Type = ChatTypeEnum.Shout; 5789 args.Type = ChatTypeEnum.Region; //Behaviour in SL is that the response can be heard from any distance
5726 args.Position = new Vector3(); 5790 args.Position = new Vector3();
5727 args.Scene = Scene; 5791 args.Scene = Scene;
5728 args.Sender = this; 5792 args.Sender = this;
@@ -9760,7 +9824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9760 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID, 9824 handlerUpdateMuteListEntry(this, UpdateMuteListEntry.MuteData.MuteID,
9761 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName), 9825 Utils.BytesToString(UpdateMuteListEntry.MuteData.MuteName),
9762 UpdateMuteListEntry.MuteData.MuteType, 9826 UpdateMuteListEntry.MuteData.MuteType,
9763 UpdateMuteListEntry.AgentData.AgentID); 9827 UpdateMuteListEntry.MuteData.MuteFlags);
9764 return true; 9828 return true;
9765 } 9829 }
9766 return false; 9830 return false;
@@ -9775,8 +9839,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9775 { 9839 {
9776 handlerRemoveMuteListEntry(this, 9840 handlerRemoveMuteListEntry(this,
9777 RemoveMuteListEntry.MuteData.MuteID, 9841 RemoveMuteListEntry.MuteData.MuteID,
9778 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName), 9842 Utils.BytesToString(RemoveMuteListEntry.MuteData.MuteName));
9779 RemoveMuteListEntry.AgentData.AgentID);
9780 return true; 9843 return true;
9781 } 9844 }
9782 return false; 9845 return false;
@@ -9820,10 +9883,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9820 return false; 9883 return false;
9821 } 9884 }
9822 9885
9886 private bool HandleChangeInventoryItemFlags(IClientAPI client, Packet packet)
9887 {
9888 ChangeInventoryItemFlagsPacket ChangeInventoryItemFlags =
9889 (ChangeInventoryItemFlagsPacket)packet;
9890 ChangeInventoryItemFlags handlerChangeInventoryItemFlags = OnChangeInventoryItemFlags;
9891 if (handlerChangeInventoryItemFlags != null)
9892 {
9893 foreach(ChangeInventoryItemFlagsPacket.InventoryDataBlock b in ChangeInventoryItemFlags.InventoryData)
9894 handlerChangeInventoryItemFlags(this, b.ItemID, b.Flags);
9895 return true;
9896 }
9897 return false;
9898 }
9899
9823 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack) 9900 private bool HandleUseCircuitCode(IClientAPI sender, Packet Pack)
9824 { 9901 {
9825 return true; 9902 return true;
9826 } 9903 }
9904
9905 private bool HandleCreateNewOutfitAttachments(IClientAPI sender, Packet Pack)
9906 {
9907 CreateNewOutfitAttachmentsPacket packet = (CreateNewOutfitAttachmentsPacket)Pack;
9908
9909 #region Packet Session and User Check
9910 if (m_checkPackets)
9911 {
9912 if (packet.AgentData.SessionID != SessionId ||
9913 packet.AgentData.AgentID != AgentId)
9914 return true;
9915 }
9916 #endregion
9917 MoveItemsAndLeaveCopy handlerMoveItemsAndLeaveCopy = null;
9918 List<InventoryItemBase> items = new List<InventoryItemBase>();
9919 foreach (CreateNewOutfitAttachmentsPacket.ObjectDataBlock n in packet.ObjectData)
9920 {
9921 InventoryItemBase b = new InventoryItemBase();
9922 b.ID = n.OldItemID;
9923 b.Folder = n.OldFolderID;
9924 items.Add(b);
9925 }
9926
9927 handlerMoveItemsAndLeaveCopy = OnMoveItemsAndLeaveCopy;
9928 if (handlerMoveItemsAndLeaveCopy != null)
9929 {
9930 handlerMoveItemsAndLeaveCopy(this, items, packet.HeaderData.NewFolderID);
9931 }
9932
9933 return true;
9934 }
9827 9935
9828 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack) 9936 private bool HandleAgentHeightWidth(IClientAPI sender, Packet Pack)
9829 { 9937 {
@@ -10250,6 +10358,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10250 groupProfileReply.GroupData.MaturePublish = d.MaturePublish; 10358 groupProfileReply.GroupData.MaturePublish = d.MaturePublish;
10251 groupProfileReply.GroupData.OwnerRole = d.OwnerRole; 10359 groupProfileReply.GroupData.OwnerRole = d.OwnerRole;
10252 10360
10361 Scene scene = (Scene)m_scene;
10362 if (scene.Permissions.IsGod(sender.AgentId) && (!sender.IsGroupMember(groupProfileRequest.GroupData.GroupID)))
10363 {
10364 ScenePresence p;
10365 if (scene.TryGetScenePresence(sender.AgentId, out p))
10366 {
10367 if (p.GodLevel >= 200)
10368 {
10369 groupProfileReply.GroupData.OpenEnrollment = true;
10370 groupProfileReply.GroupData.MembershipFee = 0;
10371 }
10372 }
10373 }
10374
10253 OutPacket(groupProfileReply, ThrottleOutPacketType.Task); 10375 OutPacket(groupProfileReply, ThrottleOutPacketType.Task);
10254 } 10376 }
10255 return true; 10377 return true;
@@ -10823,11 +10945,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10823 10945
10824 StartLure handlerStartLure = OnStartLure; 10946 StartLure handlerStartLure = OnStartLure;
10825 if (handlerStartLure != null) 10947 if (handlerStartLure != null)
10826 handlerStartLure(startLureRequest.Info.LureType, 10948 {
10827 Utils.BytesToString( 10949 for (int i = 0 ; i < startLureRequest.TargetData.Length ; i++)
10828 startLureRequest.Info.Message), 10950 {
10829 startLureRequest.TargetData[0].TargetID, 10951 handlerStartLure(startLureRequest.Info.LureType,
10830 this); 10952 Utils.BytesToString(
10953 startLureRequest.Info.Message),
10954 startLureRequest.TargetData[i].TargetID,
10955 this);
10956 }
10957 }
10831 return true; 10958 return true;
10832 } 10959 }
10833 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack) 10960 private bool HandleTeleportLureRequest(IClientAPI sender, Packet Pack)
@@ -10941,10 +11068,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
10941 } 11068 }
10942 #endregion 11069 #endregion
10943 11070
10944 ClassifiedDelete handlerClassifiedGodDelete = OnClassifiedGodDelete; 11071 ClassifiedGodDelete handlerClassifiedGodDelete = OnClassifiedGodDelete;
10945 if (handlerClassifiedGodDelete != null) 11072 if (handlerClassifiedGodDelete != null)
10946 handlerClassifiedGodDelete( 11073 handlerClassifiedGodDelete(
10947 classifiedGodDelete.Data.ClassifiedID, 11074 classifiedGodDelete.Data.ClassifiedID,
11075 classifiedGodDelete.Data.QueryID,
10948 this); 11076 this);
10949 return true; 11077 return true;
10950 } 11078 }
@@ -11988,7 +12116,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11988 12116
11989// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); 12117// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
11990 12118
12119
12120 //Note, the bool returned from the below function is useless since it is always false.
11991 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived); 12121 m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
12122
11992 } 12123 }
11993 12124
11994 /// <summary> 12125 /// <summary>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index ffa3be4..ae72175 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -158,6 +158,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
158 158
159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 159 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
160 private int m_maxRTO = 60000; 160 private int m_maxRTO = 60000;
161 public bool m_deliverPackets = true;
161 162
162 /// <summary> 163 /// <summary>
163 /// Default constructor 164 /// Default constructor
@@ -439,6 +440,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
439 if (category >= 0 && category < m_packetOutboxes.Length) 440 if (category >= 0 && category < m_packetOutboxes.Length)
440 { 441 {
441 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 442 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
443
444 if (m_deliverPackets == false)
445 {
446 queue.Enqueue(packet);
447 return true;
448 }
449
442 TokenBucket bucket = m_throttleCategories[category]; 450 TokenBucket bucket = m_throttleCategories[category];
443 451
444 // Don't send this packet if there is already a packet waiting in the queue 452 // Don't send this packet if there is already a packet waiting in the queue
@@ -488,7 +496,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
488 /// <returns>True if any packets were sent, otherwise false</returns> 496 /// <returns>True if any packets were sent, otherwise false</returns>
489 public bool DequeueOutgoing() 497 public bool DequeueOutgoing()
490 { 498 {
491 OutgoingPacket packet; 499 if (m_deliverPackets == false) return false;
500
501 OutgoingPacket packet = null;
492 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 502 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
493 TokenBucket bucket; 503 TokenBucket bucket;
494 bool packetSent = false; 504 bool packetSent = false;
@@ -520,32 +530,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP
520 // No dequeued packet waiting to be sent, try to pull one off 530 // No dequeued packet waiting to be sent, try to pull one off
521 // this queue 531 // this queue
522 queue = m_packetOutboxes[i]; 532 queue = m_packetOutboxes[i];
523 if (queue.Dequeue(out packet)) 533 if (queue != null)
524 { 534 {
525 // A packet was pulled off the queue. See if we have 535 bool success = false;
526 // enough tokens in the bucket to send it out 536 try
527 if (bucket.RemoveTokens(packet.Buffer.DataLength))
528 { 537 {
529 // Send the packet 538 success = queue.Dequeue(out packet);
530 m_udpServer.SendPacketFinal(packet);
531 packetSent = true;
532 } 539 }
533 else 540 catch
534 { 541 {
535 // Save the dequeued packet for the next iteration 542 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
536 m_nextPackets[i] = packet;
537 } 543 }
538 544 if (success)
539 // If the queue is empty after this dequeue, fire the queue 545 {
540 // empty callback now so it has a chance to fill before we 546 // A packet was pulled off the queue. See if we have
541 // get back here 547 // enough tokens in the bucket to send it out
542 if (queue.Count == 0) 548 if (bucket.RemoveTokens(packet.Buffer.DataLength))
549 {
550 // Send the packet
551 m_udpServer.SendPacketFinal(packet);
552 packetSent = true;
553 }
554 else
555 {
556 // Save the dequeued packet for the next iteration
557 m_nextPackets[i] = packet;
558 }
559
560 // If the queue is empty after this dequeue, fire the queue
561 // empty callback now so it has a chance to fill before we
562 // get back here
563 if (queue.Count == 0)
564 emptyCategories |= CategoryToFlag(i);
565 }
566 else
567 {
568 // No packets in this queue. Fire the queue empty callback
569 // if it has not been called recently
543 emptyCategories |= CategoryToFlag(i); 570 emptyCategories |= CategoryToFlag(i);
571 }
544 } 572 }
545 else 573 else
546 { 574 {
547 // No packets in this queue. Fire the queue empty callback 575 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
548 // if it has not been called recently
549 emptyCategories |= CategoryToFlag(i); 576 emptyCategories |= CategoryToFlag(i);
550 } 577 }
551 } 578 }
@@ -703,4 +730,4 @@ namespace OpenSim.Region.ClientStack.LindenUDP
703 } 730 }
704 } 731 }
705 } 732 }
706} \ No newline at end of file 733}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 7b1aa2c..3139112 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -1031,7 +1031,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1031 if (m_scene.TryGetClient(udpClient.AgentID, out client)) 1031 if (m_scene.TryGetClient(udpClient.AgentID, out client))
1032 { 1032 {
1033 client.IsLoggingOut = true; 1033 client.IsLoggingOut = true;
1034 client.Close(); 1034 client.Close(false);
1035 } 1035 }
1036 } 1036 }
1037 1037
@@ -1043,6 +1043,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1043 1043
1044 while (base.IsRunning) 1044 while (base.IsRunning)
1045 { 1045 {
1046 m_scene.ThreadAlive(1);
1046 try 1047 try
1047 { 1048 {
1048 IncomingPacket incomingPacket = null; 1049 IncomingPacket incomingPacket = null;
@@ -1085,6 +1086,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1085 1086
1086 while (base.IsRunning) 1087 while (base.IsRunning)
1087 { 1088 {
1089 m_scene.ThreadAlive(2);
1088 try 1090 try
1089 { 1091 {
1090 m_packetSent = false; 1092 m_packetSent = false;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 039379d..cfe7c9d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/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/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetXferUploader.cs
index ec4dfd0..4cedfe6 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 /// <summary> 51 /// <summary>
@@ -65,6 +73,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
65 private UUID TransactionID = UUID.Zero; 73 private UUID TransactionID = UUID.Zero;
66 private sbyte type = 0; 74 private sbyte type = 0;
67 private byte wearableType = 0; 75 private byte wearableType = 0;
76 private byte[] m_oldData = null;
68 public ulong XferID; 77 public ulong XferID;
69 private Scene m_Scene; 78 private Scene m_Scene;
70 79
@@ -302,6 +311,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
302 311
303 private void DoCreateItem(uint callbackID) 312 private void DoCreateItem(uint callbackID)
304 { 313 {
314 ValidateAssets();
305 m_Scene.AssetService.Store(m_asset); 315 m_Scene.AssetService.Store(m_asset);
306 316
307 InventoryItemBase item = new InventoryItemBase(); 317 InventoryItemBase item = new InventoryItemBase();
@@ -322,12 +332,84 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
322 item.Flags = (uint) wearableType; 332 item.Flags = (uint) wearableType;
323 item.CreationDate = Util.UnixTimeSinceEpoch(); 333 item.CreationDate = Util.UnixTimeSinceEpoch();
324 334
335 m_log.DebugFormat("[XFER]: Created item {0} with asset {1}",
336 item.ID, item.AssetID);
337
325 if (m_Scene.AddInventoryItem(item)) 338 if (m_Scene.AddInventoryItem(item))
326 ourClient.SendInventoryItemCreateUpdate(item, callbackID); 339 ourClient.SendInventoryItemCreateUpdate(item, callbackID);
327 else 340 else
328 ourClient.SendAlertMessage("Unable to create inventory item"); 341 ourClient.SendAlertMessage("Unable to create inventory item");
329 } 342 }
330 343
344 private void ValidateAssets()
345 {
346 if (m_asset.Type == (sbyte)AssetType.Clothing ||
347 m_asset.Type == (sbyte)AssetType.Bodypart)
348 {
349 string content = System.Text.Encoding.ASCII.GetString(m_asset.Data);
350 string[] lines = content.Split(new char[] {'\n'});
351
352 List<string> validated = new List<string>();
353
354 Dictionary<int, UUID> allowed = ExtractTexturesFromOldData();
355
356 int textures = 0;
357
358 foreach (string line in lines)
359 {
360 try
361 {
362 if (line.StartsWith("textures "))
363 {
364 textures = Convert.ToInt32(line.Substring(9));
365 validated.Add(line);
366 }
367 else if (textures > 0)
368 {
369 string[] parts = line.Split(new char[] {' '});
370
371 UUID tx = new UUID(parts[1]);
372 int id = Convert.ToInt32(parts[0]);
373
374 if (defaultIDs.Contains(tx) || tx == UUID.Zero ||
375 (allowed.ContainsKey(id) && allowed[id] == tx))
376 {
377 validated.Add(parts[0] + " " + tx.ToString());
378 }
379 else
380 {
381 int perms = m_Scene.InventoryService.GetAssetPermissions(ourClient.AgentId, tx);
382 int full = (int)(PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Copy);
383
384 if ((perms & full) != full)
385 {
386 m_log.ErrorFormat("[ASSET UPLOADER]: REJECTED update with texture {0} from {1} because they do not own the texture", tx, ourClient.AgentId);
387 validated.Add(parts[0] + " " + UUID.Zero.ToString());
388 }
389 else
390 {
391 validated.Add(line);
392 }
393 }
394 textures--;
395 }
396 else
397 {
398 validated.Add(line);
399 }
400 }
401 catch
402 {
403 // If it's malformed, skip it
404 }
405 }
406
407 string final = String.Join("\n", validated.ToArray());
408
409 m_asset.Data = System.Text.Encoding.ASCII.GetBytes(final);
410 }
411 }
412
331 /// <summary> 413 /// <summary>
332 /// Get the asset data uploaded in this transfer. 414 /// Get the asset data uploaded in this transfer.
333 /// </summary> 415 /// </summary>
@@ -336,10 +418,55 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
336 { 418 {
337 if (m_finished) 419 if (m_finished)
338 { 420 {
421 ValidateAssets();
339 return m_asset; 422 return m_asset;
340 } 423 }
341 424
342 return null; 425 return null;
343 } 426 }
427
428 public void SetOldData(byte[] d)
429 {
430 m_oldData = d;
431 }
432
433 private Dictionary<int,UUID> ExtractTexturesFromOldData()
434 {
435 Dictionary<int,UUID> result = new Dictionary<int,UUID>();
436 if (m_oldData == null)
437 return result;
438
439 string content = System.Text.Encoding.ASCII.GetString(m_oldData);
440 string[] lines = content.Split(new char[] {'\n'});
441
442 int textures = 0;
443
444 foreach (string line in lines)
445 {
446 try
447 {
448 if (line.StartsWith("textures "))
449 {
450 textures = Convert.ToInt32(line.Substring(9));
451 }
452 else if (textures > 0)
453 {
454 string[] parts = line.Split(new char[] {' '});
455
456 UUID tx = new UUID(parts[1]);
457 int id = Convert.ToInt32(parts[0]);
458 result[id] = tx;
459 textures--;
460 }
461 }
462 catch
463 {
464 // If it's malformed, skip it
465 }
466 }
467
468 return result;
469 }
344 } 470 }
345} 471}
472
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 22c301b..8e2dba4 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -257,53 +257,66 @@ namespace Flotsam.RegionModules.AssetCache
257 257
258 private void UpdateFileCache(string key, AssetBase asset) 258 private void UpdateFileCache(string key, AssetBase asset)
259 { 259 {
260 string filename = GetFileName(asset.ID); 260 // TODO: Spawn this off to some seperate thread to do the actual writing
261 261 if (asset != null)
262 try
263 { 262 {
264 // If the file is already cached, don't cache it, just touch it so access time is updated 263 string filename = GetFileName(key);
265 if (File.Exists(filename)) 264
266 { 265 try
267 File.SetLastAccessTime(filename, DateTime.Now);
268 }
269 else
270 { 266 {
271 // Once we start writing, make sure we flag that we're writing 267 // If the file is already cached, don't cache it, just touch it so access time is updated
272 // that object to the cache so that we don't try to write the 268 if (File.Exists(filename))
273 // same file multiple times.
274 lock (m_CurrentlyWriting)
275 { 269 {
276#if WAIT_ON_INPROGRESS_REQUESTS 270 // We don't really want to know about sharing
277 if (m_CurrentlyWriting.ContainsKey(filename)) 271 // violations here. If the file is locked, then
272 // the other thread has updated the time for us.
273 try
278 { 274 {
279 return; 275 File.SetLastAccessTime(filename, DateTime.Now);
280 } 276 }
281 else 277 catch
282 {
283 m_CurrentlyWriting.Add(filename, new ManualResetEvent(false));
284 }
285
286#else
287 if (m_CurrentlyWriting.Contains(filename))
288 { 278 {
289 return;
290 } 279 }
291 else 280 } else {
281
282 // Once we start writing, make sure we flag that we're writing
283 // that object to the cache so that we don't try to write the
284 // same file multiple times.
285 lock (m_CurrentlyWriting)
292 { 286 {
293 m_CurrentlyWriting.Add(filename); 287#if WAIT_ON_INPROGRESS_REQUESTS
294 } 288 if (m_CurrentlyWriting.ContainsKey(filename))
289 {
290 return;
291 }
292 else
293 {
294 m_CurrentlyWriting.Add(filename, new ManualResetEvent(false));
295 }
296
297#else
298 if (m_CurrentlyWriting.Contains(filename))
299 {
300 return;
301 }
302 else
303 {
304 m_CurrentlyWriting.Add(filename);
305 }
295#endif 306#endif
296 }
297 307
298 Util.FireAndForget( 308 }
299 delegate { WriteFileCache(filename, asset); }); 309
310 Util.FireAndForget(
311 delegate { WriteFileCache(filename, asset); });
312 }
313 }
314 catch (Exception e)
315 {
316 m_log.ErrorFormat(
317 "[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}",
318 asset.ID, e.Message, e.StackTrace);
300 } 319 }
301 }
302 catch (Exception e)
303 {
304 m_log.ErrorFormat(
305 "[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}",
306 asset.ID, e.Message, e.StackTrace);
307 } 320 }
308 } 321 }
309 322
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 7086e6c..5ca2ce4 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;
@@ -38,6 +39,7 @@ using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.Framework.Scenes.Serialization; 41using OpenSim.Region.Framework.Scenes.Serialization;
42using OpenSim.Services.Interfaces;
41 43
42namespace OpenSim.Region.CoreModules.Avatar.Attachments 44namespace OpenSim.Region.CoreModules.Avatar.Attachments
43{ 45{
@@ -115,6 +117,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
115 117
116// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name); 118// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name);
117 119
120 XmlDocument doc = new XmlDocument();
121 string stateData = String.Empty;
122
123 IAttachmentsService attServ = m_scene.RequestModuleInterface<IAttachmentsService>();
124 if (attServ != null)
125 {
126 m_log.DebugFormat("[ATTACHMENT]: Loading attachment data from attachment service");
127 stateData = attServ.Get(sp.UUID.ToString());
128 if (stateData != String.Empty)
129 {
130 try
131 {
132 doc.LoadXml(stateData);
133 }
134 catch { }
135 }
136 }
137
138 Dictionary<UUID, string> itemData = new Dictionary<UUID, string>();
139
140 XmlNodeList nodes = doc.GetElementsByTagName("Attachment");
141 if (nodes.Count > 0)
142 {
143 foreach (XmlNode n in nodes)
144 {
145 XmlElement elem = (XmlElement)n;
146 string itemID = elem.GetAttribute("ItemID");
147 string xml = elem.InnerXml;
148
149 itemData[new UUID(itemID)] = xml;
150 }
151 }
152
153
118 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); 154 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
119 foreach (AvatarAttachment attach in attachments) 155 foreach (AvatarAttachment attach in attachments)
120 { 156 {
@@ -134,12 +170,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
134 170
135 try 171 try
136 { 172 {
173 string xmlData;
174 XmlDocument d = null;
175 UUID asset;
176 if (itemData.TryGetValue(attach.ItemID, out xmlData))
177 {
178 d = new XmlDocument();
179 d.LoadXml(xmlData);
180 m_log.InfoFormat("[ATTACHMENT]: Found saved state for item {0}, loading it", attach.ItemID);
181 }
182
137 // If we're an NPC then skip all the item checks and manipulations since we don't have an 183 // If we're an NPC then skip all the item checks and manipulations since we don't have an
138 // inventory right now. 184 // inventory right now.
139 if (sp.PresenceType == PresenceType.Npc) 185 if (sp.PresenceType == PresenceType.Npc)
140 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p); 186 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null);
141 else 187 else
142 RezSingleAttachmentFromInventory(sp, attach.ItemID, p); 188 RezSingleAttachmentFromInventory(sp, attach.ItemID, p, true, d);
143 } 189 }
144 catch (Exception e) 190 catch (Exception e)
145 { 191 {
@@ -264,6 +310,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
264 } 310 }
265 311
266 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) 312 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
313 {
314 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, true, null);
315 }
316
317 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc)
267 { 318 {
268 if (!Enabled) 319 if (!Enabled)
269 return null; 320 return null;
@@ -302,7 +353,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
302 return null; 353 return null;
303 } 354 }
304 355
305 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); 356 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc);
306 357
307 if (att == null) 358 if (att == null)
308 DetachSingleAttachmentToInv(sp, itemID); 359 DetachSingleAttachmentToInv(sp, itemID);
@@ -582,11 +633,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
582 633
583 Vector3 inventoryStoredPosition = new Vector3 634 Vector3 inventoryStoredPosition = new Vector3
584 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) 635 (((grp.AbsolutePosition.X > (int)Constants.RegionSize)
585 ? Constants.RegionSize - 6 636 ? (float)Constants.RegionSize - 6
586 : grp.AbsolutePosition.X) 637 : grp.AbsolutePosition.X)
587 , 638 ,
588 (grp.AbsolutePosition.Y > (int)Constants.RegionSize) 639 (grp.AbsolutePosition.Y > (int)Constants.RegionSize)
589 ? Constants.RegionSize - 6 640 ? (float)Constants.RegionSize - 6
590 : grp.AbsolutePosition.Y, 641 : grp.AbsolutePosition.Y,
591 grp.AbsolutePosition.Z); 642 grp.AbsolutePosition.Z);
592 643
@@ -704,8 +755,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
704 } 755 }
705 } 756 }
706 757
707 private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 758 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
708 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) 759 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc)
709 { 760 {
710 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 761 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
711 if (invAccess != null) 762 if (invAccess != null)
@@ -713,7 +764,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
713 lock (sp.AttachmentsSyncLock) 764 lock (sp.AttachmentsSyncLock)
714 { 765 {
715 SceneObjectGroup objatt; 766 SceneObjectGroup objatt;
716 767
717 if (itemID != UUID.Zero) 768 if (itemID != UUID.Zero)
718 objatt = invAccess.RezObject(sp.ControllingClient, 769 objatt = invAccess.RezObject(sp.ControllingClient,
719 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 770 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
@@ -722,11 +773,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
722 objatt = invAccess.RezObject(sp.ControllingClient, 773 objatt = invAccess.RezObject(sp.ControllingClient,
723 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 774 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
724 false, false, sp.UUID, true); 775 false, false, sp.UUID, true);
725 776
726 // m_log.DebugFormat( 777 // m_log.DebugFormat(
727 // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", 778 // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
728 // objatt.Name, remoteClient.Name, AttachmentPt); 779 // objatt.Name, remoteClient.Name, AttachmentPt);
729 780
730 if (objatt != null) 781 if (objatt != null)
731 { 782 {
732 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. 783 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
@@ -734,7 +785,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
734 bool tainted = false; 785 bool tainted = false;
735 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) 786 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
736 tainted = true; 787 tainted = true;
737 788
738 // This will throw if the attachment fails 789 // This will throw if the attachment fails
739 try 790 try
740 { 791 {
@@ -745,21 +796,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
745 m_log.ErrorFormat( 796 m_log.ErrorFormat(
746 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", 797 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
747 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); 798 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
748 799
749 // Make sure the object doesn't stick around and bail 800 // Make sure the object doesn't stick around and bail
750 sp.RemoveAttachment(objatt); 801 sp.RemoveAttachment(objatt);
751 m_scene.DeleteSceneObject(objatt, false); 802 m_scene.DeleteSceneObject(objatt, false);
752 return null; 803 return null;
753 } 804 }
754 805
755 if (tainted) 806 if (tainted)
756 objatt.HasGroupChanged = true; 807 objatt.HasGroupChanged = true;
808
809 if (doc != null)
810 {
811 objatt.LoadScriptState(doc);
812 objatt.ResetOwnerChangeFlag();
813 }
757 814
758 // Fire after attach, so we don't get messy perms dialogs 815 // Fire after attach, so we don't get messy perms dialogs
759 // 4 == AttachedRez 816 // 4 == AttachedRez
760 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 817 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
761 objatt.ResumeScripts(); 818 objatt.ResumeScripts();
762 819
763 // Do this last so that event listeners have access to all the effects of the attachment 820 // Do this last so that event listeners have access to all the effects of the attachment
764 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 821 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
765 822
@@ -773,7 +830,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
773 } 830 }
774 } 831 }
775 } 832 }
776 833
777 return null; 834 return null;
778 } 835 }
779 836
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index 10b4c37..4d8fb90 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:
@@ -233,8 +247,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
233 s.ForEachRootScenePresence( 247 s.ForEachRootScenePresence(
234 delegate(ScenePresence presence) 248 delegate(ScenePresence presence)
235 { 249 {
236 if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromName, c.Type, message, sourceType)) 250 ILandObject Presencecheck = s.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
237 receiverIDs.Add(presence.UUID); 251 if (Presencecheck != null)
252 {
253 // This will pass all chat from objects. Not
254 // perfect, but it will do. For now. Better
255 // than the prior behavior of muting all
256 // objects on a parcel with access restrictions
257 if (c.Sender == null || Presencecheck.IsEitherBannedOrRestricted(c.Sender.AgentId) != true)
258 {
259 if (TrySendChatMessage(presence, fromPos, regionPos, fromID, fromNamePrefix + fromName, c.Type, message, sourceType))
260 receiverIDs.Add(presence.UUID);
261 }
262 }
263
238 } 264 }
239 ); 265 );
240 } 266 }
@@ -278,26 +304,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
278 } 304 }
279 305
280 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType); 306 // m_log.DebugFormat("[CHAT] Broadcast: fromID {0} fromName {1}, cType {2}, sType {3}", fromID, fromName, cType, sourceType);
281
282 HashSet<UUID> receiverIDs = new HashSet<UUID>(); 307 HashSet<UUID> receiverIDs = new HashSet<UUID>();
283 308
284 ((Scene)c.Scene).ForEachRootClient( 309 if (c.Scene != null)
285 delegate(IClientAPI client) 310 {
286 { 311 ((Scene)c.Scene).ForEachRootClient
287 // don't forward SayOwner chat from objects to 312 (
288 // non-owner agents 313 delegate(IClientAPI client)
289 if ((c.Type == ChatTypeEnum.Owner) && 314 {
290 (null != c.SenderObject) && 315 // don't forward SayOwner chat from objects to
291 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId)) 316 // non-owner agents
292 return; 317 if ((c.Type == ChatTypeEnum.Owner) &&
293 318 (null != c.SenderObject) &&
294 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID, 319 (((SceneObjectPart)c.SenderObject).OwnerID != client.AgentId))
295 (byte)sourceType, (byte)ChatAudibleLevel.Fully); 320 return;
296 receiverIDs.Add(client.AgentId); 321
297 }); 322 client.SendChatMessage(c.Message, (byte)cType, CenterOfRegion, fromName, fromID,
298 323 (byte)sourceType, (byte)ChatAudibleLevel.Fully);
299 (c.Scene as Scene).EventManager.TriggerOnChatToClients( 324 receiverIDs.Add(client.AgentId);
300 fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully); 325 }
326 );
327 (c.Scene as Scene).EventManager.TriggerOnChatToClients(
328 fromID, receiverIDs, c.Message, cType, CenterOfRegion, fromName, sourceType, ChatAudibleLevel.Fully);
329 }
301 } 330 }
302 331
303 /// <summary> 332 /// <summary>
@@ -340,5 +369,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
340 369
341 return true; 370 return true;
342 } 371 }
372
373 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
374 public void ParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
375 {
376 System.Threading.Timer Timer;
377 if (flags == 0)
378 {
379 FreezeCache.Add(target.ToString());
380 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
381 Timer = new System.Threading.Timer(timeCB, target, 30000, 0);
382 Timers.Add(target, Timer);
383 }
384 else
385 {
386 FreezeCache.Remove(target.ToString());
387 Timers.TryGetValue(target, out Timer);
388 Timers.Remove(target);
389 Timer.Dispose();
390 }
391 }
392
393 private void OnEndParcelFrozen(object avatar)
394 {
395 UUID target = (UUID)avatar;
396 FreezeCache.Remove(target.ToString());
397 System.Threading.Timer Timer;
398 Timers.TryGetValue(target, out Timer);
399 Timers.Remove(target);
400 Timer.Dispose();
401 }
343 } 402 }
344} 403}
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index ffe7718..bb2cd1f 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -216,4 +216,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
216 return result; 216 return result;
217 } 217 }
218 } 218 }
219} \ No newline at end of file 219}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index c266fe5..5d94ff7 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -328,7 +328,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
328 //m_log.DebugFormat("[XXX]: OnClientLogin!"); 328 //m_log.DebugFormat("[XXX]: OnClientLogin!");
329 // Inform the friends that this user is online 329 // Inform the friends that this user is online
330 StatusChange(agentID, true); 330 StatusChange(agentID, true);
331 331
332 // Register that we need to send the list of online friends to this user 332 // Register that we need to send the list of online friends to this user
333 lock (m_NeedsListOfOnlineFriends) 333 lock (m_NeedsListOfOnlineFriends)
334 m_NeedsListOfOnlineFriends.Add(agentID); 334 m_NeedsListOfOnlineFriends.Add(agentID);
@@ -603,6 +603,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
603 { 603 {
604 StoreFriendships(client.AgentId, friendID); 604 StoreFriendships(client.AgentId, friendID);
605 605
606 ICallingCardModule ccm = client.Scene.RequestModuleInterface<ICallingCardModule>();
607 if (ccm != null)
608 {
609 ccm.CreateCallingCard(client.AgentId, friendID, UUID.Zero);
610 }
611
606 // Update the local cache 612 // Update the local cache
607 RecacheFriends(client); 613 RecacheFriends(client);
608 614
@@ -779,6 +785,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
779 (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero); 785 (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero);
780 friendClient.SendInstantMessage(im); 786 friendClient.SendInstantMessage(im);
781 787
788 ICallingCardModule ccm = friendClient.Scene.RequestModuleInterface<ICallingCardModule>();
789 if (ccm != null)
790 {
791 ccm.CreateCallingCard(friendID, userID, UUID.Zero);
792 }
793
794
782 // Update the local cache 795 // Update the local cache
783 RecacheFriends(friendClient); 796 RecacheFriends(friendClient);
784 797
@@ -801,7 +814,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
801 // we're done 814 // we're done
802 return true; 815 return true;
803 } 816 }
804 817
805 return false; 818 return false;
806 } 819 }
807 820
@@ -853,7 +866,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
853 866
854 public bool LocalStatusNotification(UUID userID, UUID friendID, bool online) 867 public bool LocalStatusNotification(UUID userID, UUID friendID, bool online)
855 { 868 {
856// m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online); 869 //m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online);
857 IClientAPI friendClient = LocateClientObject(friendID); 870 IClientAPI friendClient = LocateClientObject(friendID);
858 if (friendClient != null) 871 if (friendClient != null)
859 { 872 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs
index 2e3312f..1492302 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, IOSHttpRequest httpRequest,
115 IOSHttpResponse 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,69 +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.ForEachRootClient(
144 delegate(IClientAPI client)
145 {
146 if (client.AgentId != godID)
147 {
148 client.Close();
149 }
150 }
151 );
152 }
153 else
154 {
155 m_scene.SceneGraph.removeUserCount(!sp.IsChildAgent);
156 214
157 sp.ControllingClient.Kick(Utils.BytesToString(reason)); 215 switch (kickflags)
158 sp.ControllingClient.Close(); 216 {
159 } 217 case 0:
160 } 218 if (sp != null)
161 219 {
162 if (kickflags == 1) 220 KickPresence(sp, Utils.BytesToString(reason));
163 {
164 sp.AllowMovement = false;
165 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
166 m_dialogModule.SendAlertToUser(godID, "User Frozen");
167 }
168
169 if (kickflags == 2)
170 {
171 sp.AllowMovement = true;
172 m_dialogModule.SendAlertToUser(agentID, Utils.BytesToString(reason));
173 m_dialogModule.SendAlertToUser(godID, "User Unfrozen");
174 }
175 } 221 }
176 else 222 else if (agentID == ALL_AGENTS)
177 { 223 {
178 m_dialogModule.SendAlertToUser(godID, "Kick request denied"); 224 m_scene.ForEachRootScenePresence(
225 delegate(ScenePresence p)
226 {
227 if (p.UUID != godID && (!m_scene.Permissions.IsGod(p.UUID)))
228 KickPresence(p, Utils.BytesToString(reason));
229 }
230 );
179 } 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));
180 } 272 }
181 } 273 }
182 } 274 }
183} \ 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 ca5d485..727f1c9 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs
@@ -27,6 +27,7 @@
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using System.Timers;
30using log4net; 31using log4net;
31using Nini.Config; 32using Nini.Config;
32using OpenMetaverse; 33using OpenMetaverse;
@@ -42,6 +43,10 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
42 private static readonly ILog m_log = LogManager.GetLogger( 43 private static readonly ILog m_log = LogManager.GetLogger(
43 MethodBase.GetCurrentMethod().DeclaringType); 44 MethodBase.GetCurrentMethod().DeclaringType);
44 45
46 private Timer m_logTimer = new Timer(10000);
47 private List<GridInstantMessage> m_logData = new List<GridInstantMessage>();
48 private string m_restUrl;
49
45 /// <value> 50 /// <value>
46 /// Is this module enabled? 51 /// Is this module enabled?
47 /// </value> 52 /// </value>
@@ -61,9 +66,12 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
61 "InstantMessageModule", "InstantMessageModule") != 66 "InstantMessageModule", "InstantMessageModule") !=
62 "InstantMessageModule") 67 "InstantMessageModule")
63 return; 68 return;
69 m_restUrl = config.Configs["Messaging"].GetString("LogURL", String.Empty);
64 } 70 }
65 71
66 m_enabled = true; 72 m_enabled = true;
73 m_logTimer.AutoReset = false;
74 m_logTimer.Elapsed += LogTimerElapsed;
67 } 75 }
68 76
69 public void AddRegion(Scene scene) 77 public void AddRegion(Scene scene)
@@ -148,6 +156,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
148 { 156 {
149 byte dialog = im.dialog; 157 byte dialog = im.dialog;
150 158
159 if (client != null && dialog == (byte)InstantMessageDialog.MessageFromAgent)
160 LogInstantMesssage(im);
161
151 if (dialog != (byte)InstantMessageDialog.MessageFromAgent 162 if (dialog != (byte)InstantMessageDialog.MessageFromAgent
152 && dialog != (byte)InstantMessageDialog.StartTyping 163 && dialog != (byte)InstantMessageDialog.StartTyping
153 && dialog != (byte)InstantMessageDialog.StopTyping 164 && dialog != (byte)InstantMessageDialog.StopTyping
@@ -157,6 +168,32 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
157 return; 168 return;
158 } 169 }
159 170
171 //DateTime dt = DateTime.UtcNow;
172
173 // Ticks from UtcNow, but make it look like local. Evil, huh?
174 //dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
175
176 //try
177 //{
178 // // Convert that to the PST timezone
179 // TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
180 // dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
181 //}
182 //catch
183 //{
184 // //m_log.Info("[OFFLINE MESSAGING]: No PST timezone found on this machine. Saving with local timestamp.");
185 //}
186
187 //// And make it look local again to fool the unix time util
188 //dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
189
190 // If client is null, this message comes from storage and IS offline
191 if (client != null)
192 im.offline = 0;
193
194 if (im.offline == 0)
195 im.timestamp = (uint)Util.UnixTimeSinceEpoch();
196
160 if (m_TransferModule != null) 197 if (m_TransferModule != null)
161 { 198 {
162 if (client != null) 199 if (client != null)
@@ -200,5 +237,35 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
200 // 237 //
201 OnInstantMessage(null, msg); 238 OnInstantMessage(null, msg);
202 } 239 }
240
241 private void LogInstantMesssage(GridInstantMessage im)
242 {
243 if (m_logData.Count < 20)
244 {
245 // Restart the log write timer
246 m_logTimer.Stop();
247 }
248 if (!m_logTimer.Enabled)
249 m_logTimer.Start();
250
251 lock (m_logData)
252 {
253 m_logData.Add(im);
254 }
255 }
256
257 private void LogTimerElapsed(object source, ElapsedEventArgs e)
258 {
259 lock (m_logData)
260 {
261 if (m_restUrl != String.Empty && m_logData.Count > 0)
262 {
263 bool success = SynchronousRestObjectRequester.MakeRequest<List<GridInstantMessage>, bool>("POST", m_restUrl + "/LogMessages/", m_logData);
264 if (!success)
265 m_log.ErrorFormat("[INSTANT MESSAGE]: Failed to save log data");
266 }
267 m_logData.Clear();
268 }
269 }
203 } 270 }
204} 271}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
index 0dad3c4..6064ddc 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs
@@ -48,6 +48,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 49
50 private bool m_Enabled = false; 50 private bool m_Enabled = false;
51 protected string m_MessageKey = String.Empty;
51 protected List<Scene> m_Scenes = new List<Scene>(); 52 protected List<Scene> m_Scenes = new List<Scene>();
52 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>(); 53 protected Dictionary<UUID, UUID> m_UserRegionMap = new Dictionary<UUID, UUID>();
53 54
@@ -67,14 +68,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
67 public virtual void Initialise(IConfigSource config) 68 public virtual void Initialise(IConfigSource config)
68 { 69 {
69 IConfig cnf = config.Configs["Messaging"]; 70 IConfig cnf = config.Configs["Messaging"];
70 if (cnf != null && cnf.GetString( 71 if (cnf != null)
71 "MessageTransferModule", "MessageTransferModule") !=
72 "MessageTransferModule")
73 { 72 {
74 m_log.Debug("[MESSAGE TRANSFER]: Disabled by configuration"); 73 if (cnf.GetString("MessageTransferModule",
75 return; 74 "MessageTransferModule") != "MessageTransferModule")
76 } 75 {
76 return;
77 }
77 78
79 m_MessageKey = cnf.GetString("MessageKey", String.Empty);
80 }
81 m_log.Debug("[MESSAGE TRANSFER]: Module enabled");
78 m_Enabled = true; 82 m_Enabled = true;
79 } 83 }
80 84
@@ -244,6 +248,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
244 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") 248 && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id")
245 && requestData.ContainsKey("binary_bucket")) 249 && requestData.ContainsKey("binary_bucket"))
246 { 250 {
251 if (m_MessageKey != String.Empty)
252 {
253 XmlRpcResponse error_resp = new XmlRpcResponse();
254 Hashtable error_respdata = new Hashtable();
255 error_respdata["success"] = "FALSE";
256 error_resp.Value = error_respdata;
257
258 if (!requestData.Contains("message_key"))
259 return error_resp;
260 if (m_MessageKey != (string)requestData["message_key"])
261 return error_resp;
262 }
263
247 // Do the easy way of validating the UUIDs 264 // Do the easy way of validating the UUIDs
248 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); 265 UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID);
249 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); 266 UUID.TryParse((string)requestData["to_agent_id"], out toAgentID);
@@ -420,24 +437,37 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
420 return resp; 437 return resp;
421 } 438 }
422 439
423 /// <summary> 440 private delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result);
424 /// delegate for sending a grid instant message asynchronously
425 /// </summary>
426 public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID);
427 441
428 protected virtual void GridInstantMessageCompleted(IAsyncResult iar) 442 private class GIM {
429 { 443 public GridInstantMessage im;
430 GridInstantMessageDelegate icon = 444 public MessageResultNotification result;
431 (GridInstantMessageDelegate)iar.AsyncState; 445 };
432 icon.EndInvoke(iar);
433 }
434 446
447 private Queue<GIM> pendingInstantMessages = new Queue<GIM>();
448 private int numInstantMessageThreads = 0;
435 449
436 protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) 450 private void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result)
437 { 451 {
438 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; 452 lock (pendingInstantMessages) {
453 if (numInstantMessageThreads >= 4) {
454 GIM gim = new GIM();
455 gim.im = im;
456 gim.result = result;
457 pendingInstantMessages.Enqueue(gim);
458 } else {
459 ++ numInstantMessageThreads;
460 //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: ++numInstantMessageThreads={0}", numInstantMessageThreads);
461 GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsyncMain;
462 d.BeginInvoke(im, result, GridInstantMessageCompleted, d);
463 }
464 }
465 }
439 466
440 d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); 467 private void GridInstantMessageCompleted(IAsyncResult iar)
468 {
469 GridInstantMessageDelegate d = (GridInstantMessageDelegate)iar.AsyncState;
470 d.EndInvoke(iar);
441 } 471 }
442 472
443 /// <summary> 473 /// <summary>
@@ -452,8 +482,31 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
452 /// Pass in 0 the first time this method is called. It will be called recursively with the last 482 /// Pass in 0 the first time this method is called. It will be called recursively with the last
453 /// regionhandle tried 483 /// regionhandle tried
454 /// </param> 484 /// </param>
455 protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) 485 private void SendGridInstantMessageViaXMLRPCAsyncMain(GridInstantMessage im, MessageResultNotification result)
456 { 486 {
487 GIM gim;
488 do {
489 try {
490 SendGridInstantMessageViaXMLRPCAsync(im, result, UUID.Zero);
491 } catch (Exception e) {
492 m_log.Error("[SendGridInstantMessageViaXMLRPC]: exception " + e.Message);
493 }
494 lock (pendingInstantMessages) {
495 if (pendingInstantMessages.Count > 0) {
496 gim = pendingInstantMessages.Dequeue();
497 im = gim.im;
498 result = gim.result;
499 } else {
500 gim = null;
501 -- numInstantMessageThreads;
502 //m_log.DebugFormat("[SendGridInstantMessageViaXMLRPC]: --numInstantMessageThreads={0}", numInstantMessageThreads);
503 }
504 }
505 } while (gim != null);
506 }
507 private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID)
508 {
509
457 UUID toAgentID = new UUID(im.toAgentID); 510 UUID toAgentID = new UUID(im.toAgentID);
458 511
459 PresenceInfo upd = null; 512 PresenceInfo upd = null;
@@ -520,7 +573,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
520 573
521 if (upd != null) 574 if (upd != null)
522 { 575 {
523 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, 576 GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(UUID.Zero,
524 upd.RegionID); 577 upd.RegionID);
525 if (reginfo != null) 578 if (reginfo != null)
526 { 579 {
@@ -669,6 +722,8 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
669 gim["position_z"] = msg.Position.Z.ToString(); 722 gim["position_z"] = msg.Position.Z.ToString();
670 gim["region_id"] = msg.RegionID.ToString(); 723 gim["region_id"] = msg.RegionID.ToString();
671 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); 724 gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None);
725 if (m_MessageKey != String.Empty)
726 gim["message_key"] = m_MessageKey;
672 return gim; 727 return gim;
673 } 728 }
674 729
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index de25048..b27b07d 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -171,7 +171,11 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
171 171
172 private void RetrieveInstantMessages(IClientAPI client) 172 private void RetrieveInstantMessages(IClientAPI client)
173 { 173 {
174 if (m_RestURL != "") 174 if (m_RestURL == String.Empty)
175 {
176 return;
177 }
178 else
175 { 179 {
176 m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId); 180 m_log.DebugFormat("[OFFLINE MESSAGING]: Retrieving stored messages for {0}", client.AgentId);
177 181
@@ -179,22 +183,25 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
179 = SynchronousRestObjectRequester.MakeRequest<UUID, List<GridInstantMessage>>( 183 = SynchronousRestObjectRequester.MakeRequest<UUID, List<GridInstantMessage>>(
180 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId); 184 "POST", m_RestURL + "/RetrieveMessages/", client.AgentId);
181 185
182 if (msglist == null) 186 if (msglist != null)
183 m_log.WarnFormat("[OFFLINE MESSAGING]: WARNING null message list.");
184
185 foreach (GridInstantMessage im in msglist)
186 { 187 {
187 // client.SendInstantMessage(im); 188 foreach (GridInstantMessage im in msglist)
188 189 {
189 // Send through scene event manager so all modules get a chance 190 // client.SendInstantMessage(im);
190 // to look at this message before it gets delivered. 191
191 // 192 // Send through scene event manager so all modules get a chance
192 // Needed for proper state management for stored group 193 // to look at this message before it gets delivered.
193 // invitations 194 //
194 // 195 // Needed for proper state management for stored group
195 Scene s = FindScene(client.AgentId); 196 // invitations
196 if (s != null) 197 //
197 s.EventManager.TriggerIncomingInstantMessage(im); 198
199 im.offline = 1;
200
201 Scene s = FindScene(client.AgentId);
202 if (s != null)
203 s.EventManager.TriggerIncomingInstantMessage(im);
204 }
198 } 205 }
199 } 206 }
200 } 207 }
@@ -205,24 +212,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
205 im.dialog != (byte)InstantMessageDialog.MessageFromAgent && 212 im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
206 im.dialog != (byte)InstantMessageDialog.GroupNotice && 213 im.dialog != (byte)InstantMessageDialog.GroupNotice &&
207 im.dialog != (byte)InstantMessageDialog.GroupInvitation && 214 im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
208 im.dialog != (byte)InstantMessageDialog.InventoryOffered) 215 im.dialog != (byte)InstantMessageDialog.InventoryOffered &&
216 im.dialog != (byte)InstantMessageDialog.TaskInventoryOffered)
209 { 217 {
210 return; 218 return;
211 } 219 }
212 220
213 if (!m_ForwardOfflineGroupMessages)
214 {
215 if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
216 im.dialog != (byte)InstantMessageDialog.GroupInvitation)
217 return;
218 }
219
220 Scene scene = FindScene(new UUID(im.fromAgentID)); 221 Scene scene = FindScene(new UUID(im.fromAgentID));
221 if (scene == null) 222 if (scene == null)
222 scene = m_SceneList[0]; 223 scene = m_SceneList[0];
223 224
224 bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( 225 bool success = SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>(
225 "POST", m_RestURL+"/SaveMessage/", im); 226 "POST", m_RestURL+"/SaveMessage/?scope=" +
227 scene.RegionInfo.ScopeID.ToString(), im);
226 228
227 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent) 229 if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
228 { 230 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index ee10d04..0833154 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -635,4 +635,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
635 m_assetsLoaded = true; 635 m_assetsLoaded = true;
636 } 636 }
637 } 637 }
638} \ No newline at end of file 638}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
index 5238325..c6e9964 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs
@@ -178,9 +178,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
178 InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself, 178 InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself,
179 Dictionary<string, object> options, IUserAccountService userAccountService) 179 Dictionary<string, object> options, IUserAccountService userAccountService)
180 { 180 {
181 if (options.ContainsKey("verbose"))
182 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saving folder {0}", inventoryFolder.Name);
183
184 if (saveThisFolderItself) 181 if (saveThisFolderItself)
185 { 182 {
186 path += CreateArchiveFolderName(inventoryFolder); 183 path += CreateArchiveFolderName(inventoryFolder);
@@ -449,4 +446,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
449 return s; 446 return s;
450 } 447 }
451 } 448 }
452} \ No newline at end of file 449}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs
index 19c774f..da708d2 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 {
@@ -244,6 +244,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
244 im.imSessionID = itemID.Guid; 244 im.imSessionID = itemID.Guid;
245 } 245 }
246 246
247 im.offline = 0;
248
247 // Send the IM to the recipient. The item is already 249 // Send the IM to the recipient. The item is already
248 // in their inventory, so it will not be lost if 250 // in their inventory, so it will not be lost if
249 // they are offline. 251 // they are offline.
@@ -263,7 +265,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
263 }); 265 });
264 } 266 }
265 } 267 }
266 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted) 268 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted ||
269 im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
267 { 270 {
268 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID)); 271 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
269 272
@@ -274,30 +277,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
274 else 277 else
275 { 278 {
276 if (m_TransferModule != null) 279 if (m_TransferModule != null)
277 m_TransferModule.SendInstantMessage(im, delegate(bool success) { 280 m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
278
279 // justincc - FIXME: Comment out for now. This code was added in commit db91044 Mon Aug 22 2011
280 // and is apparently supposed to fix bulk inventory updates after accepting items. But
281 // instead it appears to cause two copies of an accepted folder for the receiving user in
282 // at least some cases. Folder/item update is already done when the offer is made (see code above)
283
284// // Send BulkUpdateInventory
285// IInventoryService invService = scene.InventoryService;
286// UUID inventoryEntityID = new UUID(im.imSessionID); // The inventory item /folder, back from it's trip
287//
288// InventoryFolderBase folder = new InventoryFolderBase(inventoryEntityID, client.AgentId);
289// folder = invService.GetFolder(folder);
290//
291// ScenePresence fromUser = scene.GetScenePresence(new UUID(im.fromAgentID));
292//
293// // If the user has left the scene by the time the message comes back then we can't send
294// // them the update.
295// if (fromUser != null)
296// fromUser.ControllingClient.SendBulkUpdateInventory(folder);
297 });
298 } 281 }
299 } 282 }
300 else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined) 283 else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined ||
284 im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined)
301 { 285 {
302 // Here, the recipient is local and we can assume that the 286 // Here, the recipient is local and we can assume that the
303 // inventory is loaded. Courtesy of the above bulk update, 287 // inventory is loaded. Courtesy of the above bulk update,
@@ -333,6 +317,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
333 { 317 {
334 folder.ParentID = trashFolder.ID; 318 folder.ParentID = trashFolder.ID;
335 invService.MoveFolder(folder); 319 invService.MoveFolder(folder);
320 client.SendBulkUpdateInventory(folder);
336 } 321 }
337 } 322 }
338 323
@@ -433,22 +418,113 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
433 /// 418 ///
434 /// </summary> 419 /// </summary>
435 /// <param name="msg"></param> 420 /// <param name="msg"></param>
436 private void OnGridInstantMessage(GridInstantMessage msg) 421 private void OnGridInstantMessage(GridInstantMessage im)
437 { 422 {
438 // Check if this is ours to handle 423 // Check if this is ours to handle
439 // 424 //
440 Scene scene = FindClientScene(new UUID(msg.toAgentID)); 425 Scene scene = FindClientScene(new UUID(im.toAgentID));
441 426
442 if (scene == null) 427 if (scene == null)
443 return; 428 return;
444 429
445 // Find agent to deliver to 430 // Find agent to deliver to
446 // 431 //
447 ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID)); 432 ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
433 if (user == null)
434 return;
435
436 // This requires a little bit of processing because we have to make the
437 // new item visible in the recipient's inventory here
438 //
439 if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
440 {
441 if (im.binaryBucket.Length < 17) // Invalid
442 return;
443
444 UUID recipientID = new UUID(im.toAgentID);
445
446 // First byte is the asset type
447 AssetType assetType = (AssetType)im.binaryBucket[0];
448
449 if (AssetType.Folder == assetType)
450 {
451 UUID folderID = new UUID(im.binaryBucket, 1);
448 452
449 // Just forward to local handling 453 InventoryFolderBase given =
450 OnInstantMessage(user.ControllingClient, msg); 454 new InventoryFolderBase(folderID, recipientID);
455 InventoryFolderBase folder =
456 scene.InventoryService.GetFolder(given);
451 457
458 if (folder != null)
459 user.ControllingClient.SendBulkUpdateInventory(folder);
460 }
461 else
462 {
463 UUID itemID = new UUID(im.binaryBucket, 1);
464
465 InventoryItemBase given =
466 new InventoryItemBase(itemID, recipientID);
467 InventoryItemBase item =
468 scene.InventoryService.GetItem(given);
469
470 if (item != null)
471 {
472 user.ControllingClient.SendBulkUpdateInventory(item);
473 }
474 }
475 user.ControllingClient.SendInstantMessage(im);
476 }
477 if (im.dialog == (byte) InstantMessageDialog.TaskInventoryOffered)
478 {
479 if (im.binaryBucket.Length < 1) // Invalid
480 return;
481
482 UUID recipientID = new UUID(im.toAgentID);
483
484 // Bucket is the asset type
485 AssetType assetType = (AssetType)im.binaryBucket[0];
486
487 if (AssetType.Folder == assetType)
488 {
489 UUID folderID = new UUID(im.imSessionID);
490
491 InventoryFolderBase given =
492 new InventoryFolderBase(folderID, recipientID);
493 InventoryFolderBase folder =
494 scene.InventoryService.GetFolder(given);
495
496 if (folder != null)
497 user.ControllingClient.SendBulkUpdateInventory(folder);
498 }
499 else
500 {
501 UUID itemID = new UUID(im.imSessionID);
502
503 InventoryItemBase given =
504 new InventoryItemBase(itemID, recipientID);
505 InventoryItemBase item =
506 scene.InventoryService.GetItem(given);
507
508 if (item != null)
509 {
510 user.ControllingClient.SendBulkUpdateInventory(item);
511 }
512 }
513
514 // Fix up binary bucket since this may be 17 chars long here
515 Byte[] bucket = new Byte[1];
516 bucket[0] = im.binaryBucket[0];
517 im.binaryBucket = bucket;
518
519 user.ControllingClient.SendInstantMessage(im);
520 }
521 else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted ||
522 im.dialog == (byte) InstantMessageDialog.InventoryDeclined ||
523 im.dialog == (byte) InstantMessageDialog.TaskInventoryDeclined ||
524 im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
525 {
526 user.ControllingClient.SendInstantMessage(im);
527 }
452 } 528 }
453 } 529 }
454} 530}
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
index d295384..dcfdf8f 100644
--- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs
@@ -155,16 +155,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
155 scene.RegionInfo.RegionHandle, 155 scene.RegionInfo.RegionHandle,
156 (uint)presence.AbsolutePosition.X, 156 (uint)presence.AbsolutePosition.X,
157 (uint)presence.AbsolutePosition.Y, 157 (uint)presence.AbsolutePosition.Y,
158 (uint)presence.AbsolutePosition.Z); 158 (uint)presence.AbsolutePosition.Z + 2);
159 159
160 m_log.DebugFormat("TP invite with message {0}", message); 160 m_log.DebugFormat("[LURE]: TP invite with message {0}", message);
161
162 GridInstantMessage m;
163
164 if (scene.Permissions.IsAdministrator(client.AgentId) && presence.GodLevel >= 200 && (!scene.Permissions.IsAdministrator(targetid)))
165 {
166 m = new GridInstantMessage(scene, client.AgentId,
167 client.FirstName+" "+client.LastName, targetid,
168 (byte)InstantMessageDialog.GodLikeRequestTeleport, false,
169 message, dest, false, presence.AbsolutePosition,
170 new Byte[0]);
171 }
172 else
173 {
174 m = new GridInstantMessage(scene, client.AgentId,
175 client.FirstName+" "+client.LastName, targetid,
176 (byte)InstantMessageDialog.RequestTeleport, false,
177 message, dest, false, presence.AbsolutePosition,
178 new Byte[0]);
179 }
161 180
162 GridInstantMessage m = new GridInstantMessage(scene, client.AgentId,
163 client.FirstName+" "+client.LastName, targetid,
164 (byte)InstantMessageDialog.RequestTeleport, false,
165 message, dest, false, presence.AbsolutePosition,
166 new Byte[0]);
167
168 if (m_TransferModule != null) 181 if (m_TransferModule != null)
169 { 182 {
170 m_TransferModule.SendInstantMessage(m, 183 m_TransferModule.SendInstantMessage(m,
@@ -199,7 +212,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
199 { 212 {
200 // Forward remote teleport requests 213 // Forward remote teleport requests
201 // 214 //
202 if (msg.dialog != 22) 215 if (msg.dialog != (byte)InstantMessageDialog.RequestTeleport &&
216 msg.dialog != (byte)InstantMessageDialog.GodLikeRequestTeleport)
203 return; 217 return;
204 218
205 if (m_TransferModule != null) 219 if (m_TransferModule != null)
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 9d1538f..97cd738 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -101,7 +101,8 @@ namespace OpenSim.Region.CoreModules.Framework
101 101
102 public void CreateCaps(UUID agentId) 102 public void CreateCaps(UUID agentId)
103 { 103 {
104 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) 104 int flags = m_scene.GetUserFlags(agentId);
105 if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags))
105 return; 106 return;
106 107
107 String capsObjectPath = GetCapsPath(agentId); 108 String capsObjectPath = GetCapsPath(agentId);
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 928bcd0..f1399af 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -126,7 +126,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
126 126
127 protected virtual void OnNewClient(IClientAPI client) 127 protected virtual void OnNewClient(IClientAPI client)
128 { 128 {
129 client.OnTeleportHomeRequest += TeleportHome; 129 client.OnTeleportHomeRequest += TriggerTeleportHome;
130 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 130 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
131 } 131 }
132 132
@@ -204,6 +204,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
204 sp.ControllingClient.SendTeleportStart(teleportFlags); 204 sp.ControllingClient.SendTeleportStart(teleportFlags);
205 205
206 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); 206 sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
207 sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags;
207 sp.Teleport(position); 208 sp.Teleport(position);
208 209
209 foreach (SceneObjectGroup grp in sp.GetAttachments()) 210 foreach (SceneObjectGroup grp in sp.GetAttachments())
@@ -319,7 +320,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
319 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, 320 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
320 // it's actually doing a lot of work. 321 // it's actually doing a lot of work.
321 IPEndPoint endPoint = finalDestination.ExternalEndPoint; 322 IPEndPoint endPoint = finalDestination.ExternalEndPoint;
322 if (endPoint.Address != null) 323 if (endPoint != null && endPoint.Address != null)
323 { 324 {
324 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from 325 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
325 // both regions 326 // both regions
@@ -630,7 +631,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
630 631
631 #region Teleport Home 632 #region Teleport Home
632 633
633 public virtual void TeleportHome(UUID id, IClientAPI client) 634 public virtual void TriggerTeleportHome(UUID id, IClientAPI client)
635 {
636 TeleportHome(id, client);
637 }
638
639 public virtual bool TeleportHome(UUID id, IClientAPI client)
634 { 640 {
635 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 641 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
636 642
@@ -639,12 +645,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
639 645
640 if (uinfo != null) 646 if (uinfo != null)
641 { 647 {
648 if (uinfo.HomeRegionID == UUID.Zero)
649 {
650 // can't find the Home region: Tell viewer and abort
651 client.SendTeleportFailed("You don't have a home position set.");
652 return false;
653 }
642 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); 654 GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID);
643 if (regionInfo == null) 655 if (regionInfo == null)
644 { 656 {
645 // can't find the Home region: Tell viewer and abort 657 // can't find the Home region: Tell viewer and abort
646 client.SendTeleportFailed("Your home region could not be found."); 658 client.SendTeleportFailed("Your home region could not be found.");
647 return; 659 return false;
648 } 660 }
649 661
650 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})", 662 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})",
@@ -655,6 +667,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
655 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt, 667 client, regionInfo.RegionHandle, uinfo.HomePosition, uinfo.HomeLookAt,
656 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); 668 (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome));
657 } 669 }
670 else
671 {
672 // can't find the Home region: Tell viewer and abort
673 client.SendTeleportFailed("Your home region could not be found.");
674 return false;
675 }
676 return true;
658 } 677 }
659 678
660 #endregion 679 #endregion
@@ -1124,10 +1143,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1124 agent.Id0 = currentAgentCircuit.Id0; 1143 agent.Id0 = currentAgentCircuit.Id0;
1125 } 1144 }
1126 1145
1127 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1146 IPEndPoint external = region.ExternalEndPoint;
1128 d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, 1147 if (external != null)
1148 {
1149 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1150 d.BeginInvoke(sp, agent, region, external, true,
1129 InformClientOfNeighbourCompleted, 1151 InformClientOfNeighbourCompleted,
1130 d); 1152 d);
1153 }
1131 } 1154 }
1132 #endregion 1155 #endregion
1133 1156
@@ -1261,6 +1284,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1261 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; 1284 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
1262 try 1285 try
1263 { 1286 {
1287 //neighbour.ExternalEndPoint may return null, which will be caught
1264 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, 1288 d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
1265 InformClientOfNeighbourCompleted, 1289 InformClientOfNeighbourCompleted,
1266 d); 1290 d);
@@ -1374,8 +1398,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1374 1398
1375 m_log.Debug("[ENTITY TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString()); 1399 m_log.Debug("[ENTITY TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString());
1376 } 1400 }
1377 if (!regionAccepted)
1378 m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Region {0} did not accept agent: {1}", reg.RegionName, reason);
1379 } 1401 }
1380 1402
1381 /// <summary> 1403 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 38a7805..5c7ca22 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
84 84
85 protected override void OnNewClient(IClientAPI client) 85 protected override void OnNewClient(IClientAPI client)
86 { 86 {
87 client.OnTeleportHomeRequest += TeleportHome; 87 client.OnTeleportHomeRequest += TriggerTeleportHome;
88 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 88 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
89 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 89 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
90 } 90 }
@@ -182,7 +182,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
182 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason); 182 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason);
183 } 183 }
184 184
185 public override void TeleportHome(UUID id, IClientAPI client) 185 public void TriggerTeleportHome(UUID id, IClientAPI client)
186 {
187 TeleportHome(id, client);
188 }
189
190 public override bool TeleportHome(UUID id, IClientAPI client)
186 { 191 {
187 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); 192 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName);
188 193
@@ -192,8 +197,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
192 { 197 {
193 // local grid user 198 // local grid user
194 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local"); 199 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
195 base.TeleportHome(id, client); 200 return base.TeleportHome(id, client);
196 return;
197 } 201 }
198 202
199 // Foreign user wants to go home 203 // Foreign user wants to go home
@@ -203,7 +207,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 { 207 {
204 client.SendTeleportFailed("Your information has been lost"); 208 client.SendTeleportFailed("Your information has been lost");
205 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information"); 209 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Unable to locate agent's gateway information");
206 return; 210 return false;
207 } 211 }
208 212
209 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString()); 213 IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
@@ -213,7 +217,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
213 { 217 {
214 client.SendTeleportFailed("Your home region could not be found"); 218 client.SendTeleportFailed("Your home region could not be found");
215 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found"); 219 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent's home region not found");
216 return; 220 return false;
217 } 221 }
218 222
219 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId); 223 ScenePresence sp = ((Scene)(client.Scene)).GetScenePresence(client.AgentId);
@@ -221,7 +225,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
221 { 225 {
222 client.SendTeleportFailed("Internal error"); 226 client.SendTeleportFailed("Internal error");
223 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be"); 227 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent not found in the scene where it is supposed to be");
224 return; 228 return false;
225 } 229 }
226 230
227 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>(); 231 IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
@@ -231,6 +235,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
231 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); 235 aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName);
232 236
233 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); 237 DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq);
238 return true;
234 } 239 }
235 240
236 /// <summary> 241 /// <summary>
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 54b422b..fe75271 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -367,6 +367,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
367 367
368 originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; 368 originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
369 369
370 // Restore attachment data after trip through the sim
371 if (objectGroup.RootPart.AttachPoint > 0)
372 inventoryStoredPosition = objectGroup.RootPart.AttachOffset;
373 objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint;
374
370 objectGroup.AbsolutePosition = inventoryStoredPosition; 375 objectGroup.AbsolutePosition = inventoryStoredPosition;
371 376
372 // Make sure all bits but the ones we want are clear 377 // Make sure all bits but the ones we want are clear
@@ -476,8 +481,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
476 IClientAPI remoteClient) 481 IClientAPI remoteClient)
477 { 482 {
478 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; 483 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7;
484 // For the porposes of inventory, an object is modify if the prims
485 // are modify. This allows renaming an object that contains no
486 // mod items.
479 foreach (SceneObjectGroup grp in objsForEffectivePermissions) 487 foreach (SceneObjectGroup grp in objsForEffectivePermissions)
480 effectivePerms &= grp.GetEffectivePermissions(); 488 {
489 uint groupPerms = grp.GetEffectivePermissions(true);
490 if ((grp.RootPart.BaseMask & (uint)PermissionMask.Modify) != 0)
491 groupPerms |= (uint)PermissionMask.Modify;
492
493 effectivePerms &= groupPerms;
494 }
481 effectivePerms |= (uint)PermissionMask.Move; 495 effectivePerms |= (uint)PermissionMask.Move;
482 496
483 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) 497 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
@@ -644,7 +658,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
644 if (so.RootPart.FromFolderID != UUID.Zero) 658 if (so.RootPart.FromFolderID != UUID.Zero)
645 { 659 {
646 InventoryFolderBase f = new InventoryFolderBase(so.RootPart.FromFolderID, userID); 660 InventoryFolderBase f = new InventoryFolderBase(so.RootPart.FromFolderID, userID);
647 folder = m_Scene.InventoryService.GetFolder(f); 661 if (f != null)
662 folder = m_Scene.InventoryService.GetFolder(f);
648 } 663 }
649 } 664 }
650 665
@@ -674,15 +689,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
674 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) 689 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
675 { 690 {
676// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); 691// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID);
677
678 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 692 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
679 item = m_Scene.InventoryService.GetItem(item); 693 item = m_Scene.InventoryService.GetItem(item);
680 694
681 if (item == null) 695 if (item == null)
682 { 696 {
683 m_log.WarnFormat(
684 "[InventoryAccessModule]: Could not find item {0} for {1} in RezObject()",
685 itemID, remoteClient.Name);
686 697
687 return null; 698 return null;
688 } 699 }
@@ -734,6 +745,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
734 if (e == null || attachment) // Single 745 if (e == null || attachment) // Single
735 { 746 {
736 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); 747 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
748 if (!attachment)
749 {
750 g.RootPart.AttachPoint = g.RootPart.Shape.State;
751 g.RootPart.AttachOffset = g.AbsolutePosition;
752 }
737 753
738 objlist.Add(g); 754 objlist.Add(g);
739 veclist.Add(new Vector3(0, 0, 0)); 755 veclist.Add(new Vector3(0, 0, 0));
@@ -763,6 +779,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
763 foreach (XmlNode n in groups) 779 foreach (XmlNode n in groups)
764 { 780 {
765 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml); 781 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
782 g.RootPart.AttachPoint = g.RootPart.Shape.State;
783 g.RootPart.AttachOffset = g.AbsolutePosition;
766 784
767 objlist.Add(g); 785 objlist.Add(g);
768 XmlElement el = (XmlElement)n; 786 XmlElement el = (XmlElement)n;
@@ -782,12 +800,35 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
782 } 800 }
783 } 801 }
784 802
803 int primcount = 0;
804 foreach (SceneObjectGroup g in objlist)
805 primcount += g.PrimCount;
806
807 if (!m_Scene.Permissions.CanRezObject(
808 primcount, remoteClient.AgentId, pos)
809 && !attachment)
810 {
811 // The client operates in no fail mode. It will
812 // have already removed the item from the folder
813 // if it's no copy.
814 // Put it back if it's not an attachment
815 //
816 if (item != null)
817 {
818 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!attachment))
819 remoteClient.SendBulkUpdateInventory(item);
820 }
821
822 return null;
823 }
824
785 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment)) 825 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment))
786 return null; 826 return null;
787 827
788 for (int i = 0; i < objlist.Count; i++) 828 for (int i = 0; i < objlist.Count; i++)
789 { 829 {
790 group = objlist[i]; 830 group = objlist[i];
831 SceneObjectPart rootPart = group.RootPart;
791 832
792// Vector3 storedPosition = group.AbsolutePosition; 833// Vector3 storedPosition = group.AbsolutePosition;
793 if (group.UUID == UUID.Zero) 834 if (group.UUID == UUID.Zero)
@@ -842,8 +883,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
842 883
843 if (!attachment) 884 if (!attachment)
844 { 885 {
845 SceneObjectPart rootPart = group.RootPart;
846
847 if (rootPart.Shape.PCode == (byte)PCode.Prim) 886 if (rootPart.Shape.PCode == (byte)PCode.Prim)
848 group.ClearPartAttachmentData(); 887 group.ClearPartAttachmentData();
849 888
@@ -853,12 +892,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
853 892
854 rootPart.ScheduleFullUpdate(); 893 rootPart.ScheduleFullUpdate();
855 } 894 }
856
857// m_log.DebugFormat(
858// "[InventoryAccessModule]: Rezzed {0} {1} {2} for {3}",
859// group.Name, group.LocalId, group.UUID, remoteClient.Name);
860 } 895 }
861 896
897 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
898
862 if (item != null) 899 if (item != null)
863 DoPostRezWhenFromItem(item, attachment); 900 DoPostRezWhenFromItem(item, attachment);
864 901
@@ -898,25 +935,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
898 } 935 }
899 } 936 }
900 937
901 int primcount = 0;
902 foreach (SceneObjectGroup g in objlist)
903 primcount += g.PrimCount;
904
905 if (!m_Scene.Permissions.CanRezObject(
906 primcount, remoteClient.AgentId, pos)
907 && !isAttachment)
908 {
909 // The client operates in no fail mode. It will
910 // have already removed the item from the folder
911 // if it's no copy.
912 // Put it back if it's not an attachment
913 //
914 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
915 remoteClient.SendBulkUpdateInventory(item);
916
917 return false;
918 }
919
920 for (int i = 0; i < objlist.Count; i++) 938 for (int i = 0; i < objlist.Count; i++)
921 { 939 {
922 SceneObjectGroup so = objlist[i]; 940 SceneObjectGroup so = objlist[i];
@@ -932,14 +950,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
932 { 950 {
933 rootPart.Name = item.Name; 951 rootPart.Name = item.Name;
934 rootPart.Description = item.Description; 952 rootPart.Description = item.Description;
935 rootPart.ObjectSaleType = item.SaleType; 953 if ((item.Flags & (uint)InventoryItemFlags.ObjectSlamSale) != 0)
936 rootPart.SalePrice = item.SalePrice; 954 {
955 rootPart.ObjectSaleType = item.SaleType;
956 rootPart.SalePrice = item.SalePrice;
957 }
937 } 958 }
938 959
939 rootPart.FromFolderID = item.Folder; 960 rootPart.FromFolderID = item.Folder;
940 961
941 if ((rootPart.OwnerID != item.Owner) || 962 if ((rootPart.OwnerID != item.Owner) ||
942 (item.CurrentPermissions & 16) != 0) 963 (item.CurrentPermissions & 16) != 0 ||
964 (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0)
943 { 965 {
944 //Need to kill the for sale here 966 //Need to kill the for sale here
945 rootPart.ObjectSaleType = 0; 967 rootPart.ObjectSaleType = 0;
@@ -949,31 +971,43 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
949 { 971 {
950 foreach (SceneObjectPart part in so.Parts) 972 foreach (SceneObjectPart part in so.Parts)
951 { 973 {
952 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
953 {
954 part.EveryoneMask = item.EveryOnePermissions;
955 part.NextOwnerMask = item.NextPermissions;
956 }
957 part.GroupMask = 0; // DO NOT propagate here 974 part.GroupMask = 0; // DO NOT propagate here
975
976 part.LastOwnerID = part.OwnerID;
977 part.OwnerID = item.Owner;
978 part.Inventory.ChangeInventoryOwner(item.Owner);
958 } 979 }
959 980
960 so.ApplyNextOwnerPermissions(); 981 so.ApplyNextOwnerPermissions();
982
983 // In case the user has changed flags on a received item
984 // we have to apply those changes after the slam. Else we
985 // get a net loss of permissions
986 foreach (SceneObjectPart part in so.Parts)
987 {
988 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
989 {
990 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
991 part.EveryoneMask = item.EveryOnePermissions & part.BaseMask;
992 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
993 part.NextOwnerMask = item.NextPermissions & part.BaseMask;
994 }
995 }
961 } 996 }
962 } 997 }
963 998 else
964 foreach (SceneObjectPart part in so.Parts)
965 { 999 {
966 part.FromUserInventoryItemID = fromUserInventoryItemId; 1000 foreach (SceneObjectPart part in so.Parts)
967
968 if ((part.OwnerID != item.Owner) ||
969 (item.CurrentPermissions & 16) != 0)
970 { 1001 {
971 part.Inventory.ChangeInventoryOwner(item.Owner); 1002 part.FromUserInventoryItemID = fromUserInventoryItemId;
972 part.GroupMask = 0; // DO NOT propagate here 1003
1004 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
1005 part.EveryoneMask = item.EveryOnePermissions;
1006 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
1007 part.NextOwnerMask = item.NextPermissions;
1008 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
1009 part.GroupMask = item.GroupPermissions;
973 } 1010 }
974
975 part.EveryoneMask = item.EveryOnePermissions;
976 part.NextOwnerMask = item.NextPermissions;
977 } 1011 }
978 1012
979 rootPart.TrimPermissions(); 1013 rootPart.TrimPermissions();
@@ -1111,4 +1145,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1111 1145
1112 #endregion 1146 #endregion
1113 } 1147 }
1114} \ No newline at end of file 1148}
diff --git a/OpenSim/Region/CoreModules/LightShare/LightShareModule.cs b/OpenSim/Region/CoreModules/LightShare/LightShareModule.cs
index 16cbbf5..f49641f 100644
--- a/OpenSim/Region/CoreModules/LightShare/LightShareModule.cs
+++ b/OpenSim/Region/CoreModules/LightShare/LightShareModule.cs
@@ -170,7 +170,8 @@ namespace OpenSim.Region.CoreModules.World.LightShare
170 170
171 private void EventManager_OnMakeRootAgent(ScenePresence presence) 171 private void EventManager_OnMakeRootAgent(ScenePresence presence)
172 { 172 {
173 m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client"); 173 if (m_enableWindlight && m_scene.RegionInfo.WindlightSettings.valid)
174 m_log.Debug("[WINDLIGHT]: Sending windlight scene to new client");
174 SendProfileToClient(presence.ControllingClient); 175 SendProfileToClient(presence.ControllingClient);
175 } 176 }
176 177
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index d328eb3..9dac6b9 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -382,6 +382,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
382 try 382 try
383 { 383 {
384 Request = (HttpWebRequest) WebRequest.Create(Url); 384 Request = (HttpWebRequest) WebRequest.Create(Url);
385
386 //This works around some buggy HTTP Servers like Lighttpd
387 Request.ServicePoint.Expect100Continue = false;
388
385 Request.Method = HttpMethod; 389 Request.Method = HttpMethod;
386 Request.ContentType = HttpMIMEType; 390 Request.ContentType = HttpMIMEType;
387 391
@@ -458,15 +462,36 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
458 462
459 // continue building the string 463 // continue building the string
460 sb.Append(tempString); 464 sb.Append(tempString);
465 if (sb.Length > 2048)
466 break;
461 } 467 }
462 } while (count > 0); // any more data to read? 468 } while (count > 0); // any more data to read?
463 469
464 ResponseBody = sb.ToString(); 470 ResponseBody = sb.ToString().Replace("\r", "");
465 } 471 }
466 catch (Exception e) 472 catch (Exception e)
467 { 473 {
468 Status = (int)OSHttpStatusCode.ClientErrorJoker; 474 if (e is WebException && ((WebException)e).Status == WebExceptionStatus.ProtocolError)
469 ResponseBody = e.Message; 475 {
476 HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response;
477 Status = (int)webRsp.StatusCode;
478 try
479 {
480 using (Stream responseStream = webRsp.GetResponseStream())
481 {
482 ResponseBody = responseStream.GetStreamString();
483 }
484 }
485 catch
486 {
487 ResponseBody = webRsp.StatusDescription;
488 }
489 }
490 else
491 {
492 Status = (int)OSHttpStatusCode.ClientErrorJoker;
493 ResponseBody = e.Message;
494 }
470 495
471 _finished = true; 496 _finished = true;
472 return; 497 return;
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 93e75b3..f4cf6b4 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -61,6 +61,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
61 //public ManualResetEvent ev; 61 //public ManualResetEvent ev;
62 public bool requestDone; 62 public bool requestDone;
63 public int startTime; 63 public int startTime;
64 public bool responseSent;
64 public string uri; 65 public string uri;
65 } 66 }
66 67
@@ -77,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
77 new Dictionary<string, UrlData>(); 78 new Dictionary<string, UrlData>();
78 79
79 80
80 private int m_TotalUrls = 100; 81 private int m_TotalUrls = 5000;
81 82
82 private uint https_port = 0; 83 private uint https_port = 0;
83 private IHttpServer m_HttpServer = null; 84 private IHttpServer m_HttpServer = null;
@@ -157,7 +158,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
157 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); 158 engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
158 return urlcode; 159 return urlcode;
159 } 160 }
160 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString() + "/"; 161 string url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + "/lslhttp/" + urlcode.ToString();
161 162
162 UrlData urlData = new UrlData(); 163 UrlData urlData = new UrlData();
163 urlData.hostID = host.UUID; 164 urlData.hostID = host.UUID;
@@ -166,10 +167,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
166 urlData.url = url; 167 urlData.url = url;
167 urlData.urlcode = urlcode; 168 urlData.urlcode = urlcode;
168 urlData.requests = new Dictionary<UUID, RequestData>(); 169 urlData.requests = new Dictionary<UUID, RequestData>();
169 170
170 m_UrlMap[url] = urlData; 171 m_UrlMap[url] = urlData;
171 172
172 string uri = "/lslhttp/" + urlcode.ToString() + "/"; 173 string uri = "/lslhttp/" + urlcode.ToString();
173 174
174 m_HttpServer.AddPollServiceHTTPHandler( 175 m_HttpServer.AddPollServiceHTTPHandler(
175 uri, 176 uri,
@@ -234,9 +235,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
234 return; 235 return;
235 } 236 }
236 237
237 foreach (UUID req in data.requests.Keys) 238 lock (m_RequestMap)
238 m_RequestMap.Remove(req); 239 {
239 240 foreach (UUID req in data.requests.Keys)
241 m_RequestMap.Remove(req);
242 }
243
240 RemoveUrl(data); 244 RemoveUrl(data);
241 m_UrlMap.Remove(url); 245 m_UrlMap.Remove(url);
242 } 246 }
@@ -244,32 +248,42 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
244 248
245 public void HttpResponse(UUID request, int status, string body) 249 public void HttpResponse(UUID request, int status, string body)
246 { 250 {
247 if (m_RequestMap.ContainsKey(request)) 251 lock (m_RequestMap)
248 {
249 UrlData urlData = m_RequestMap[request];
250 urlData.requests[request].responseCode = status;
251 urlData.requests[request].responseBody = body;
252 //urlData.requests[request].ev.Set();
253 urlData.requests[request].requestDone =true;
254 }
255 else
256 { 252 {
257 m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString()); 253 if (m_RequestMap.ContainsKey(request))
254 {
255 UrlData urlData = m_RequestMap[request];
256 if (!urlData.requests[request].responseSent)
257 {
258 urlData.requests[request].responseCode = status;
259 urlData.requests[request].responseBody = body;
260 //urlData.requests[request].ev.Set();
261 urlData.requests[request].requestDone = true;
262 urlData.requests[request].responseSent = true;
263 }
264 }
265 else
266 {
267 m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString());
268 }
258 } 269 }
259 } 270 }
260 271
261 public string GetHttpHeader(UUID requestId, string header) 272 public string GetHttpHeader(UUID requestId, string header)
262 { 273 {
263 if (m_RequestMap.ContainsKey(requestId)) 274 lock (m_RequestMap)
264 {
265 UrlData urlData=m_RequestMap[requestId];
266 string value;
267 if (urlData.requests[requestId].headers.TryGetValue(header,out value))
268 return value;
269 }
270 else
271 { 275 {
272 m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); 276 if (m_RequestMap.ContainsKey(requestId))
277 {
278 UrlData urlData = m_RequestMap[requestId];
279 string value;
280 if (urlData.requests[requestId].headers.TryGetValue(header, out value))
281 return value;
282 }
283 else
284 {
285 m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId);
286 }
273 } 287 }
274 return String.Empty; 288 return String.Empty;
275 } 289 }
@@ -293,8 +307,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
293 { 307 {
294 RemoveUrl(url.Value); 308 RemoveUrl(url.Value);
295 removeURLs.Add(url.Key); 309 removeURLs.Add(url.Key);
296 foreach (UUID req in url.Value.requests.Keys) 310 lock (m_RequestMap)
297 m_RequestMap.Remove(req); 311 {
312 foreach (UUID req in url.Value.requests.Keys)
313 m_RequestMap.Remove(req);
314 }
298 } 315 }
299 } 316 }
300 317
@@ -315,8 +332,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
315 { 332 {
316 RemoveUrl(url.Value); 333 RemoveUrl(url.Value);
317 removeURLs.Add(url.Key); 334 removeURLs.Add(url.Key);
318 foreach (UUID req in url.Value.requests.Keys) 335 lock (m_RequestMap)
319 m_RequestMap.Remove(req); 336 {
337 foreach (UUID req in url.Value.requests.Keys)
338 m_RequestMap.Remove(req);
339 }
320 } 340 }
321 } 341 }
322 342
@@ -335,14 +355,16 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
335 { 355 {
336 Hashtable response = new Hashtable(); 356 Hashtable response = new Hashtable();
337 UrlData url; 357 UrlData url;
358 int startTime = 0;
338 lock (m_RequestMap) 359 lock (m_RequestMap)
339 { 360 {
340 if (!m_RequestMap.ContainsKey(requestID)) 361 if (!m_RequestMap.ContainsKey(requestID))
341 return response; 362 return response;
342 url = m_RequestMap[requestID]; 363 url = m_RequestMap[requestID];
364 startTime = url.requests[requestID].startTime;
343 } 365 }
344 366
345 if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) 367 if (System.Environment.TickCount - startTime > 25000)
346 { 368 {
347 response["int_response_code"] = 500; 369 response["int_response_code"] = 500;
348 response["str_response_string"] = "Script timeout"; 370 response["str_response_string"] = "Script timeout";
@@ -351,9 +373,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
351 response["reusecontext"] = false; 373 response["reusecontext"] = false;
352 374
353 //remove from map 375 //remove from map
354 lock (url) 376 lock (url.requests)
355 { 377 {
356 url.requests.Remove(requestID); 378 url.requests.Remove(requestID);
379 }
380 lock (m_RequestMap)
381 {
357 m_RequestMap.Remove(requestID); 382 m_RequestMap.Remove(requestID);
358 } 383 }
359 384
@@ -375,22 +400,25 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
375 return false; 400 return false;
376 } 401 }
377 url = m_RequestMap[requestID]; 402 url = m_RequestMap[requestID];
403 }
404 lock (url.requests)
405 {
378 if (!url.requests.ContainsKey(requestID)) 406 if (!url.requests.ContainsKey(requestID))
379 { 407 {
380 return false; 408 return false;
381 } 409 }
410 else
411 {
412 if (System.Environment.TickCount - url.requests[requestID].startTime > 25000)
413 {
414 return true;
415 }
416 if (url.requests[requestID].requestDone)
417 return true;
418 else
419 return false;
420 }
382 } 421 }
383
384 if (System.Environment.TickCount-url.requests[requestID].startTime>25000)
385 {
386 return true;
387 }
388
389 if (url.requests[requestID].requestDone)
390 return true;
391 else
392 return false;
393
394 } 422 }
395 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) 423 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request)
396 { 424 {
@@ -402,9 +430,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
402 if (!m_RequestMap.ContainsKey(requestID)) 430 if (!m_RequestMap.ContainsKey(requestID))
403 return NoEvents(requestID,sessionID); 431 return NoEvents(requestID,sessionID);
404 url = m_RequestMap[requestID]; 432 url = m_RequestMap[requestID];
433 }
434 lock (url.requests)
435 {
405 requestData = url.requests[requestID]; 436 requestData = url.requests[requestID];
406 } 437 }
407 438
408 if (!requestData.requestDone) 439 if (!requestData.requestDone)
409 return NoEvents(requestID,sessionID); 440 return NoEvents(requestID,sessionID);
410 441
@@ -427,14 +458,18 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
427 response["reusecontext"] = false; 458 response["reusecontext"] = false;
428 459
429 //remove from map 460 //remove from map
430 lock (url) 461 lock (url.requests)
431 { 462 {
432 url.requests.Remove(requestID); 463 url.requests.Remove(requestID);
464 }
465 lock (m_RequestMap)
466 {
433 m_RequestMap.Remove(requestID); 467 m_RequestMap.Remove(requestID);
434 } 468 }
435 469
436 return response; 470 return response;
437 } 471 }
472
438 public void HttpRequestHandler(UUID requestID, Hashtable request) 473 public void HttpRequestHandler(UUID requestID, Hashtable request)
439 { 474 {
440 lock (request) 475 lock (request)
@@ -450,8 +485,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
450 485
451 int pos1 = uri.IndexOf("/");// /lslhttp 486 int pos1 = uri.IndexOf("/");// /lslhttp
452 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ 487 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/
453 int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp/<UUID>/ 488 int pos3 = pos2 + 37; // /lslhttp/urlcode
454 string uri_tmp = uri.Substring(0, pos3 + 1); 489 string uri_tmp = uri.Substring(0, pos3);
455 //HTTP server code doesn't provide us with QueryStrings 490 //HTTP server code doesn't provide us with QueryStrings
456 string pathInfo; 491 string pathInfo;
457 string queryString; 492 string queryString;
@@ -460,10 +495,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
460 pathInfo = uri.Substring(pos3); 495 pathInfo = uri.Substring(pos3);
461 496
462 UrlData url = null; 497 UrlData url = null;
498 string urlkey;
463 if (!is_ssl) 499 if (!is_ssl)
464 url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp]; 500 urlkey = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp;
501 //m_UrlMap[];
465 else 502 else
466 url = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp]; 503 urlkey = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp;
504
505 if (m_UrlMap.ContainsKey(urlkey))
506 {
507 url = m_UrlMap[urlkey];
508 }
509 else
510 {
511 m_log.Warn("[HttpRequestHandler]: http-in request failed; no such url: "+urlkey.ToString());
512 }
467 513
468 //for llGetHttpHeader support we need to store original URI here 514 //for llGetHttpHeader support we need to store original URI here
469 //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers 515 //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers
@@ -493,7 +539,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
493 if (request.ContainsKey(key)) 539 if (request.ContainsKey(key))
494 { 540 {
495 string val = (String)request[key]; 541 string val = (String)request[key];
496 queryString = queryString + key + "=" + val + "&"; 542 if (key != "")
543 {
544 queryString = queryString + key + "=" + val + "&";
545 }
546 else
547 {
548 queryString = queryString + val + "&";
549 }
497 } 550 }
498 } 551 }
499 if (queryString.Length > 1) 552 if (queryString.Length > 1)
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
index a17c6ae..faa1def 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs
@@ -271,7 +271,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
271 if (s.RegionInfo.RegionID == destination.RegionID) 271 if (s.RegionInfo.RegionID == destination.RegionID)
272 return s.QueryAccess(id, position, out reason); 272 return s.QueryAccess(id, position, out reason);
273 } 273 }
274 //m_log.Debug("[LOCAL COMMS]: region not found for QueryAccess");
275 return false; 274 return false;
276 } 275 }
277 276
@@ -301,10 +300,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
301 if (s.RegionInfo.RegionID == destination.RegionID) 300 if (s.RegionInfo.RegionID == destination.RegionID)
302 { 301 {
303 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent"); 302 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent");
304 // Let's spawn a threadlet right here, because this may take 303 return s.IncomingCloseAgent(id);
305 // a while 304 }
306 Util.FireAndForget(delegate { s.IncomingCloseAgent(id); }); 305 }
307 return true; 306 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
307 return false;
308 }
309
310 public bool CloseChildAgent(GridRegion destination, UUID id)
311 {
312 if (destination == null)
313 return false;
314
315 foreach (Scene s in m_sceneList)
316 {
317 if (s.RegionInfo.RegionID == destination.RegionID)
318 {
319 //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent");
320 return s.IncomingCloseChildAgent(id);
308 } 321 }
309 } 322 }
310 //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); 323 //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 f8cea71..391b1a1 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs
@@ -261,6 +261,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
261 return false; 261 return false;
262 } 262 }
263 263
264 public bool CloseChildAgent(GridRegion destination, UUID id)
265 {
266 if (destination == null)
267 return false;
268
269 // Try local first
270 if (m_localBackend.CloseChildAgent(destination, id))
271 return true;
272
273 // else do the remote thing
274 if (!m_localBackend.IsLocalRegion(destination.RegionHandle))
275 return m_remoteConnector.CloseChildAgent(destination, id);
276
277 return false;
278 }
264 279
265 public bool CloseAgent(GridRegion destination, UUID id) 280 public bool CloseAgent(GridRegion destination, UUID id)
266 { 281 {
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
index 0a0ce3c..1ffd480 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs
@@ -127,6 +127,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
127 // FIXME: Why do we bother setting this module and caching up if we just end up registering the inner 127 // FIXME: Why do we bother setting this module and caching up if we just end up registering the inner
128 // user account service?! 128 // user account service?!
129 scene.RegisterModuleInterface<IUserAccountService>(UserAccountService); 129 scene.RegisterModuleInterface<IUserAccountService>(UserAccountService);
130 scene.RegisterModuleInterface<IUserAccountCacheModule>(m_Cache);
130 } 131 }
131 132
132 public void RemoveRegion(Scene scene) 133 public void RemoveRegion(Scene scene)
@@ -179,6 +180,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
179 return UserAccountService.GetUserAccount(scopeID, Email); 180 return UserAccountService.GetUserAccount(scopeID, Email);
180 } 181 }
181 182
183 public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query)
184 {
185 return null;
186 }
187
182 public List<UserAccount> GetUserAccounts(UUID scopeID, string query) 188 public List<UserAccount> GetUserAccounts(UUID scopeID, string query)
183 { 189 {
184 return UserAccountService.GetUserAccounts(scopeID, query); 190 return UserAccountService.GetUserAccounts(scopeID, query);
@@ -193,4 +199,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts
193 199
194 #endregion 200 #endregion
195 } 201 }
196} \ No newline at end of file 202}
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 a6dbaba..38db239 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -298,6 +298,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
298 // being no copy/no mod for everyone 298 // being no copy/no mod for everyone
299 lock (part.TaskInventory) 299 lock (part.TaskInventory)
300 { 300 {
301 if (!ResolveUserUuid(part.CreatorID))
302 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
303
304 if (!ResolveUserUuid(part.OwnerID))
305 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
306
307 if (!ResolveUserUuid(part.LastOwnerID))
308 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
309
310 // And zap any troublesome sit target information
311 part.SitTargetOrientation = new Quaternion(0, 0, 0, 1);
312 part.SitTargetPosition = new Vector3(0, 0, 0);
313
314 // Fix ownership/creator of inventory items
315 // Not doing so results in inventory items
316 // being no copy/no mod for everyone
317 part.TaskInventory.LockItemsForRead(true);
301 TaskInventoryDictionary inv = part.TaskInventory; 318 TaskInventoryDictionary inv = part.TaskInventory;
302 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) 319 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
303 { 320 {
@@ -313,6 +330,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
313 if (UserManager != null) 330 if (UserManager != null)
314 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); 331 UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData);
315 } 332 }
333 part.TaskInventory.LockItemsForRead(false);
316 } 334 }
317 } 335 }
318 336
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index 8e29e3c..7b872b9 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -251,18 +251,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
251 251
252 if (asset != null) 252 if (asset != null)
253 { 253 {
254 if (m_options.ContainsKey("verbose")) 254// m_log.DebugFormat("[ARCHIVER]: Writing asset {0}", id);
255 m_log.InfoFormat("[ARCHIVER]: Writing asset {0}", id);
256
257 m_foundAssetUuids.Add(asset.FullID); 255 m_foundAssetUuids.Add(asset.FullID);
258 256
259 m_assetsArchiver.WriteAsset(PostProcess(asset)); 257 m_assetsArchiver.WriteAsset(PostProcess(asset));
260 } 258 }
261 else 259 else
262 { 260 {
263 if (m_options.ContainsKey("verbose")) 261// m_log.DebugFormat("[ARCHIVER]: Recording asset {0} as not found", id);
264 m_log.InfoFormat("[ARCHIVER]: Recording asset {0} as not found", id);
265
266 m_notFoundAssetUuids.Add(new UUID(id)); 262 m_notFoundAssetUuids.Add(new UUID(id));
267 } 263 }
268 264
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index c303d6d..35f47d2 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
@@ -61,6 +63,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
61 63
62 #region Packet Data Responders 64 #region Packet Data Responders
63 65
66 private void clientSendDetailedEstateData(IClientAPI remote_client, UUID invoice)
67 {
68 sendDetailedEstateData(remote_client, invoice);
69 sendEstateLists(remote_client, invoice);
70 }
71
64 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice) 72 private void sendDetailedEstateData(IClientAPI remote_client, UUID invoice)
65 { 73 {
66 uint sun = 0; 74 uint sun = 0;
@@ -83,7 +91,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
83 (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime, 91 (uint) Scene.RegionInfo.RegionSettings.CovenantChangedDateTime,
84 Scene.RegionInfo.EstateSettings.AbuseEmail, 92 Scene.RegionInfo.EstateSettings.AbuseEmail,
85 estateOwner); 93 estateOwner);
94 }
86 95
96 private void sendEstateLists(IClientAPI remote_client, UUID invoice)
97 {
87 remote_client.SendEstateList(invoice, 98 remote_client.SendEstateList(invoice,
88 (int)Constants.EstateAccessCodex.EstateManagers, 99 (int)Constants.EstateAccessCodex.EstateManagers,
89 Scene.RegionInfo.EstateSettings.EstateManagers, 100 Scene.RegionInfo.EstateSettings.EstateManagers,
@@ -246,6 +257,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
246 IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>(); 257 IRestartModule restartModule = Scene.RequestModuleInterface<IRestartModule>();
247 if (restartModule != null) 258 if (restartModule != null)
248 { 259 {
260 if (timeInSeconds == -1)
261 {
262 restartModule.AbortRestart("Restart aborted by region manager");
263 return;
264 }
265
249 List<int> times = new List<int>(); 266 List<int> times = new List<int>();
250 while (timeInSeconds > 0) 267 while (timeInSeconds > 0)
251 { 268 {
@@ -258,7 +275,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
258 timeInSeconds -= 15; 275 timeInSeconds -= 15;
259 } 276 }
260 277
261 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), true); 278 restartModule.ScheduleRestart(UUID.Zero, "Region will restart in {0}", times.ToArray(), false);
262 } 279 }
263 } 280 }
264 281
@@ -466,7 +483,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
466 { 483 {
467 if (!s.IsChildAgent) 484 if (!s.IsChildAgent)
468 { 485 {
469 Scene.TeleportClientHome(user, s.ControllingClient); 486 if (!Scene.TeleportClientHome(user, s.ControllingClient))
487 {
488 s.ControllingClient.Kick("Your access to the region was revoked and TP home failed - you have been logged out.");
489 s.ControllingClient.Close();
490 }
470 } 491 }
471 } 492 }
472 493
@@ -475,7 +496,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
475 { 496 {
476 remote_client.SendAlertMessage("User is already on the region ban list"); 497 remote_client.SendAlertMessage("User is already on the region ban list");
477 } 498 }
478 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 499 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
479 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 500 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
480 } 501 }
481 else 502 else
@@ -530,7 +551,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
530 remote_client.SendAlertMessage("User is not on the region ban list"); 551 remote_client.SendAlertMessage("User is not on the region ban list");
531 } 552 }
532 553
533 //m_scene.RegionInfo.regionBanlist.Add(Manager(user); 554 //Scene.RegionInfo.regionBanlist.Add(Manager(user);
534 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID); 555 remote_client.SendBannedUserList(invoice, Scene.RegionInfo.EstateSettings.EstateBans, Scene.RegionInfo.EstateSettings.EstateID);
535 } 556 }
536 else 557 else
@@ -695,7 +716,11 @@ namespace OpenSim.Region.CoreModules.World.Estate
695 ScenePresence s = Scene.GetScenePresence(prey); 716 ScenePresence s = Scene.GetScenePresence(prey);
696 if (s != null) 717 if (s != null)
697 { 718 {
698 Scene.TeleportClientHome(prey, s.ControllingClient); 719 if (!Scene.TeleportClientHome(prey, s.ControllingClient))
720 {
721 s.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
722 s.ControllingClient.Close();
723 }
699 } 724 }
700 } 725 }
701 } 726 }
@@ -713,7 +738,13 @@ namespace OpenSim.Region.CoreModules.World.Estate
713 // Also make sure they are actually in the region 738 // Also make sure they are actually in the region
714 ScenePresence p; 739 ScenePresence p;
715 if(Scene.TryGetScenePresence(client.AgentId, out p)) 740 if(Scene.TryGetScenePresence(client.AgentId, out p))
716 Scene.TeleportClientHome(p.UUID, p.ControllingClient); 741 {
742 if (!Scene.TeleportClientHome(p.UUID, p.ControllingClient))
743 {
744 p.ControllingClient.Kick("You were teleported home by the region owner, but the TP failed - you have been logged out.");
745 p.ControllingClient.Close();
746 }
747 }
717 } 748 }
718 }); 749 });
719 } 750 }
@@ -957,7 +988,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
957 988
958 for (int i = 0; i < uuidarr.Length; i++) 989 for (int i = 0; i < uuidarr.Length; i++)
959 { 990 {
960 // string lookupname = m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]); 991 // string lookupname = Scene.CommsManager.UUIDNameRequestString(uuidarr[i]);
961 992
962 IUserManagement userManager = Scene.RequestModuleInterface<IUserManagement>(); 993 IUserManagement userManager = Scene.RequestModuleInterface<IUserManagement>();
963 if (userManager != null) 994 if (userManager != null)
@@ -1098,6 +1129,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
1098 1129
1099 public void AddRegion(Scene scene) 1130 public void AddRegion(Scene scene)
1100 { 1131 {
1132 m_regionChangeTimer.AutoReset = false;
1133 m_regionChangeTimer.Interval = 2000;
1134 m_regionChangeTimer.Elapsed += RaiseRegionInfoChange;
1135
1101 Scene = scene; 1136 Scene = scene;
1102 Scene.RegisterModuleInterface<IEstateModule>(this); 1137 Scene.RegisterModuleInterface<IEstateModule>(this);
1103 Scene.EventManager.OnNewClient += EventManager_OnNewClient; 1138 Scene.EventManager.OnNewClient += EventManager_OnNewClient;
@@ -1148,7 +1183,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
1148 1183
1149 private void EventManager_OnNewClient(IClientAPI client) 1184 private void EventManager_OnNewClient(IClientAPI client)
1150 { 1185 {
1151 client.OnDetailedEstateDataRequest += sendDetailedEstateData; 1186 client.OnDetailedEstateDataRequest += clientSendDetailedEstateData;
1152 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler; 1187 client.OnSetEstateFlagsRequest += estateSetRegionInfoHandler;
1153// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture; 1188// client.OnSetEstateTerrainBaseTexture += setEstateTerrainBaseTexture;
1154 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture; 1189 client.OnSetEstateTerrainDetailTexture += setEstateTerrainBaseTexture;
@@ -1200,6 +1235,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
1200 flags |= RegionFlags.AllowParcelChanges; 1235 flags |= RegionFlags.AllowParcelChanges;
1201 if (Scene.RegionInfo.RegionSettings.BlockShowInSearch) 1236 if (Scene.RegionInfo.RegionSettings.BlockShowInSearch)
1202 flags |= RegionFlags.BlockParcelSearch; 1237 flags |= RegionFlags.BlockParcelSearch;
1238 if (Scene.RegionInfo.RegionSettings.GodBlockSearch)
1239 flags |= (RegionFlags)(1 << 11);
1240 if (Scene.RegionInfo.RegionSettings.Casino)
1241 flags |= (RegionFlags)(1 << 10);
1203 1242
1204 if (Scene.RegionInfo.RegionSettings.FixedSun) 1243 if (Scene.RegionInfo.RegionSettings.FixedSun)
1205 flags |= RegionFlags.SunFixed; 1244 flags |= RegionFlags.SunFixed;
@@ -1207,11 +1246,15 @@ namespace OpenSim.Region.CoreModules.World.Estate
1207 flags |= RegionFlags.Sandbox; 1246 flags |= RegionFlags.Sandbox;
1208 if (Scene.RegionInfo.EstateSettings.AllowVoice) 1247 if (Scene.RegionInfo.EstateSettings.AllowVoice)
1209 flags |= RegionFlags.AllowVoice; 1248 flags |= RegionFlags.AllowVoice;
1249 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
1250 flags |= RegionFlags.AllowLandmark;
1251 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
1252 flags |= RegionFlags.AllowSetHome;
1253 if (Scene.RegionInfo.EstateSettings.BlockDwell)
1254 flags |= RegionFlags.BlockDwell;
1255 if (Scene.RegionInfo.EstateSettings.ResetHomeOnTeleport)
1256 flags |= RegionFlags.ResetHomeOnTeleport;
1210 1257
1211 // Fudge these to always on, so the menu options activate
1212 //
1213 flags |= RegionFlags.AllowLandmark;
1214 flags |= RegionFlags.AllowSetHome;
1215 1258
1216 // TODO: SkipUpdateInterestList 1259 // TODO: SkipUpdateInterestList
1217 1260
@@ -1252,6 +1295,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1252 flags |= RegionFlags.ResetHomeOnTeleport; 1295 flags |= RegionFlags.ResetHomeOnTeleport;
1253 if (Scene.RegionInfo.EstateSettings.TaxFree) 1296 if (Scene.RegionInfo.EstateSettings.TaxFree)
1254 flags |= RegionFlags.TaxFree; 1297 flags |= RegionFlags.TaxFree;
1298 if (Scene.RegionInfo.EstateSettings.AllowLandmark)
1299 flags |= RegionFlags.AllowLandmark;
1300 if (Scene.RegionInfo.EstateSettings.AllowParcelChanges)
1301 flags |= RegionFlags.AllowParcelChanges;
1302 if (Scene.RegionInfo.EstateSettings.AllowSetHome)
1303 flags |= RegionFlags.AllowSetHome;
1255 if (Scene.RegionInfo.EstateSettings.DenyMinors) 1304 if (Scene.RegionInfo.EstateSettings.DenyMinors)
1256 flags |= (RegionFlags)(1 << 30); 1305 flags |= (RegionFlags)(1 << 30);
1257 1306
@@ -1272,6 +1321,12 @@ namespace OpenSim.Region.CoreModules.World.Estate
1272 1321
1273 public void TriggerRegionInfoChange() 1322 public void TriggerRegionInfoChange()
1274 { 1323 {
1324 m_regionChangeTimer.Stop();
1325 m_regionChangeTimer.Start();
1326 }
1327
1328 protected void RaiseRegionInfoChange(object sender, ElapsedEventArgs e)
1329 {
1275 ChangeDelegate change = OnRegionInfoChange; 1330 ChangeDelegate change = OnRegionInfoChange;
1276 1331
1277 if (change != null) 1332 if (change != null)
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index 1c503aa..0f83d82 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -91,6 +91,8 @@ 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;
@@ -106,6 +108,12 @@ namespace OpenSim.Region.CoreModules.World.Land
106 108
107 public void Initialise(IConfigSource source) 109 public void Initialise(IConfigSource source)
108 { 110 {
111 IConfig cnf = source.Configs["LandManagement"];
112 if (cnf != null)
113 {
114 DefaultGodParcelGroup = new UUID(cnf.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString()));
115 DefaultGodParcelName = cnf.GetString("DefaultAdministratorParcelName", "Default Parcel");
116 }
109 } 117 }
110 118
111 public void AddRegion(Scene scene) 119 public void AddRegion(Scene scene)
@@ -157,13 +165,6 @@ namespace OpenSim.Region.CoreModules.World.Land
157 m_scene.UnregisterModuleCommander(m_commander.Name); 165 m_scene.UnregisterModuleCommander(m_commander.Name);
158 } 166 }
159 167
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> 168 /// <summary>
168 /// Processes commandline input. Do not call directly. 169 /// Processes commandline input. Do not call directly.
169 /// </summary> 170 /// </summary>
@@ -204,6 +205,8 @@ namespace OpenSim.Region.CoreModules.World.Land
204 client.OnParcelInfoRequest += ClientOnParcelInfoRequest; 205 client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
205 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; 206 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
206 client.OnPreAgentUpdate += ClientOnPreAgentUpdate; 207 client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
208 client.OnParcelEjectUser += ClientOnParcelEjectUser;
209 client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
207 210
208 EntityBase presenceEntity; 211 EntityBase presenceEntity;
209 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) 212 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence)
@@ -215,36 +218,6 @@ namespace OpenSim.Region.CoreModules.World.Land
215 218
216 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) 219 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
217 { 220 {
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 } 221 }
249 222
250 public void Close() 223 public void Close()
@@ -363,10 +336,16 @@ namespace OpenSim.Region.CoreModules.World.Land
363 private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position) 336 private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position)
364 { 337 {
365 if (m_scene.Permissions.IsGod(avatar.UUID)) return; 338 if (m_scene.Permissions.IsGod(avatar.UUID)) return;
366 if (position.HasValue) 339
367 { 340 if (!position.HasValue)
368 forcedPosition[avatar.ControllingClient.AgentId] = (Vector3)position; 341 return;
369 } 342
343 bool isFlying = avatar.PhysicsActor.Flying;
344 avatar.RemoveFromPhysicalScene();
345
346 avatar.AbsolutePosition = (Vector3)position;
347
348 avatar.AddToPhysicalScene(isFlying);
370 } 349 }
371 350
372 public void SendYouAreRestrictedNotice(ScenePresence avatar) 351 public void SendYouAreRestrictedNotice(ScenePresence avatar)
@@ -386,29 +365,7 @@ namespace OpenSim.Region.CoreModules.World.Land
386 } 365 }
387 366
388 if (parcelAvatarIsEntering != null) 367 if (parcelAvatarIsEntering != null)
389 { 368 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 } 369 }
413 } 370 }
414 371
@@ -512,6 +469,7 @@ namespace OpenSim.Region.CoreModules.World.Land
512 //when we are finally in a safe place, lets release the forced position lock 469 //when we are finally in a safe place, lets release the forced position lock
513 forcedPosition.Remove(clientAvatar.ControllingClient.AgentId); 470 forcedPosition.Remove(clientAvatar.ControllingClient.AgentId);
514 } 471 }
472 EnforceBans(parcel, clientAvatar);
515 } 473 }
516 } 474 }
517 475
@@ -720,7 +678,7 @@ namespace OpenSim.Region.CoreModules.World.Land
720 int x; 678 int x;
721 int y; 679 int y;
722 680
723 if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) 681 if (x_float > Constants.RegionSize || x_float < 0 || y_float > Constants.RegionSize || y_float < 0)
724 return null; 682 return null;
725 683
726 try 684 try
@@ -770,14 +728,13 @@ namespace OpenSim.Region.CoreModules.World.Land
770 { 728 {
771 try 729 try
772 { 730 {
773 return m_landList[m_landIDList[x / 4, y / 4]]; 731 //if (m_landList.ContainsKey(m_landIDList[x / 4, y / 4]))
732 return m_landList[m_landIDList[x / 4, y / 4]];
733 //else
734 // return null;
774 } 735 }
775 catch (IndexOutOfRangeException) 736 catch (IndexOutOfRangeException)
776 { 737 {
777// m_log.WarnFormat(
778// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
779// x, y, m_scene.RegionInfo.RegionName);
780
781 return null; 738 return null;
782 } 739 }
783 } 740 }
@@ -1060,6 +1017,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1060 //Owner Flag 1017 //Owner Flag
1061 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 1018 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1062 } 1019 }
1020 else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID))
1021 {
1022 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_GROUP);
1023 }
1063 else if (currentParcelBlock.LandData.SalePrice > 0 && 1024 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1064 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero || 1025 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1065 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId)) 1026 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
@@ -1360,18 +1321,31 @@ namespace OpenSim.Region.CoreModules.World.Land
1360 1321
1361 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1322 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1362 { 1323 {
1363 for (int i = 0; i < data.Count; i++) 1324 lock (m_landList)
1364 { 1325 {
1365 IncomingLandObjectFromStorage(data[i]); 1326 //Remove all the land objects in the sim and then process our new data
1327 foreach (int n in m_landList.Keys)
1328 {
1329 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[n].LandData.GlobalID);
1330 }
1331 m_landIDList.Initialize();
1332 m_landList.Clear();
1333
1334 for (int i = 0; i < data.Count; i++)
1335 {
1336 IncomingLandObjectFromStorage(data[i]);
1337 }
1366 } 1338 }
1367 } 1339 }
1368 1340
1369 public void IncomingLandObjectFromStorage(LandData data) 1341 public void IncomingLandObjectFromStorage(LandData data)
1370 { 1342 {
1343
1371 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1344 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1372 new_land.LandData = data.Copy(); 1345 new_land.LandData = data.Copy();
1373 new_land.SetLandBitmapFromByteArray(); 1346 new_land.SetLandBitmapFromByteArray();
1374 AddLandObject(new_land); 1347 AddLandObject(new_land);
1348 new_land.SendLandUpdateToAvatarsOverMe();
1375 } 1349 }
1376 1350
1377 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) 1351 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
@@ -1649,6 +1623,168 @@ namespace OpenSim.Region.CoreModules.World.Land
1649 1623
1650 UpdateLandObject(localID, land.LandData); 1624 UpdateLandObject(localID, land.LandData);
1651 } 1625 }
1626
1627 public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
1628 {
1629 ILandObject land = null;
1630 List<ILandObject> Land = ((Scene)client.Scene).LandChannel.AllParcels();
1631 foreach (ILandObject landObject in Land)
1632 {
1633 if (landObject.LandData.LocalID == landID)
1634 {
1635 land = landObject;
1636 }
1637 }
1638 land.DeedToGroup(DefaultGodParcelGroup);
1639 land.LandData.Name = DefaultGodParcelName;
1640 land.SendLandUpdateToAvatarsOverMe();
1641 }
1642
1643 private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID)
1644 {
1645 ScenePresence SP;
1646 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out SP);
1647 List<SceneObjectGroup> returns = new List<SceneObjectGroup>();
1648 if (SP.UserLevel != 0)
1649 {
1650 if (flags == 0) //All parcels, scripted or not
1651 {
1652 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1653 {
1654 if (e.OwnerID == targetID)
1655 {
1656 returns.Add(e);
1657 }
1658 }
1659 );
1660 }
1661 if (flags == 4) //All parcels, scripted object
1662 {
1663 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1664 {
1665 if (e.OwnerID == targetID)
1666 {
1667 if (e.scriptScore >= 0.01)
1668 {
1669 returns.Add(e);
1670 }
1671 }
1672 }
1673 );
1674 }
1675 if (flags == 4) //not target parcel, scripted object
1676 {
1677 ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1678 {
1679 if (e.OwnerID == targetID)
1680 {
1681 ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y);
1682 if (landobject.LandData.OwnerID != e.OwnerID)
1683 {
1684 if (e.scriptScore >= 0.01)
1685 {
1686 returns.Add(e);
1687 }
1688 }
1689 }
1690 }
1691 );
1692 }
1693 foreach (SceneObjectGroup ol in returns)
1694 {
1695 ReturnObject(ol, client);
1696 }
1697 }
1698 }
1699 public void ReturnObject(SceneObjectGroup obj, IClientAPI client)
1700 {
1701 SceneObjectGroup[] objs = new SceneObjectGroup[1];
1702 objs[0] = obj;
1703 ((Scene)client.Scene).returnObjects(objs, client.AgentId);
1704 }
1705
1706 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1707
1708 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1709 {
1710 ScenePresence targetAvatar = null;
1711 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1712 ScenePresence parcelManager = null;
1713 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1714 System.Threading.Timer Timer;
1715
1716 if (targetAvatar.UserLevel == 0)
1717 {
1718 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1719 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1720 return;
1721 if (flags == 0)
1722 {
1723 targetAvatar.AllowMovement = false;
1724 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1725 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1726 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1727 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1728 Timers.Add(targetAvatar.UUID, Timer);
1729 }
1730 else
1731 {
1732 targetAvatar.AllowMovement = true;
1733 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1734 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1735 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1736 Timers.Remove(targetAvatar.UUID);
1737 Timer.Dispose();
1738 }
1739 }
1740 }
1741 private void OnEndParcelFrozen(object avatar)
1742 {
1743 ScenePresence targetAvatar = (ScenePresence)avatar;
1744 targetAvatar.AllowMovement = true;
1745 System.Threading.Timer Timer;
1746 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1747 Timers.Remove(targetAvatar.UUID);
1748 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1749 }
1750
1751
1752 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1753 {
1754 ScenePresence targetAvatar = null;
1755 ScenePresence parcelManager = null;
1756
1757 // Must have presences
1758 if (!m_scene.TryGetScenePresence(target, out targetAvatar) ||
1759 !m_scene.TryGetScenePresence(client.AgentId, out parcelManager))
1760 return;
1761
1762 // Cannot eject estate managers or gods
1763 if (m_scene.Permissions.IsAdministrator(target))
1764 return;
1765
1766 // Check if you even have permission to do this
1767 ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1768 if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) &&
1769 !m_scene.Permissions.IsAdministrator(client.AgentId))
1770 return;
1771
1772 Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
1773
1774 targetAvatar.TeleportWithMomentum(pos);
1775 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1776 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1777
1778 if ((flags & 1) != 0) // Ban TODO: Remove magic number
1779 {
1780 LandAccessEntry entry = new LandAccessEntry();
1781 entry.AgentID = targetAvatar.UUID;
1782 entry.Flags = AccessList.Ban;
1783 entry.Expires = 0; // Perm
1784
1785 land.LandData.ParcelAccessList.Add(entry);
1786 }
1787 }
1652 1788
1653 protected void InstallInterfaces() 1789 protected void InstallInterfaces()
1654 { 1790 {
@@ -1711,5 +1847,27 @@ namespace OpenSim.Region.CoreModules.World.Land
1711 1847
1712 MainConsole.Instance.Output(report.ToString()); 1848 MainConsole.Instance.Output(report.ToString());
1713 } 1849 }
1850
1851 public void EnforceBans(ILandObject land, ScenePresence avatar)
1852 {
1853 if (avatar.AbsolutePosition.Z > LandChannel.BAN_LINE_SAFETY_HIEGHT)
1854 return;
1855
1856 if (land.IsEitherBannedOrRestricted(avatar.UUID))
1857 {
1858 if (land.ContainsPoint(Convert.ToInt32(avatar.lastKnownAllowedPosition.X), Convert.ToInt32(avatar.lastKnownAllowedPosition.Y)))
1859 {
1860 Vector3? pos = m_scene.GetNearestAllowedPosition(avatar);
1861 if (pos == null)
1862 m_scene.TeleportClientHome(avatar.UUID, avatar.ControllingClient);
1863 else
1864 ForceAvatarToPosition(avatar, (Vector3)pos);
1865 }
1866 else
1867 {
1868 ForceAvatarToPosition(avatar, avatar.lastKnownAllowedPosition);
1869 }
1870 }
1871 }
1714 } 1872 }
1715} 1873}
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index d146901..91aa228 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -190,10 +190,27 @@ namespace OpenSim.Region.CoreModules.World.Land
190 else 190 else
191 { 191 {
192 // Normal Calculations 192 // Normal Calculations
193 int parcelMax = (int)(((float)LandData.Area / 65536.0f) 193 int parcelMax = (int)((long)LandData.Area
194 * (float)m_scene.RegionInfo.ObjectCapacity 194 * (long)m_scene.RegionInfo.ObjectCapacity
195 * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); 195 * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus
196 // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL! 196 / 65536L);
197 m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax);
198 return parcelMax;
199 }
200 }
201
202 private int GetParcelBasePrimCount()
203 {
204 if (overrideParcelMaxPrimCount != null)
205 {
206 return overrideParcelMaxPrimCount(this);
207 }
208 else
209 {
210 // Normal Calculations
211 int parcelMax = (int)((long)LandData.Area
212 * (long)m_scene.RegionInfo.ObjectCapacity
213 / 65536L);
197 return parcelMax; 214 return parcelMax;
198 } 215 }
199 } 216 }
@@ -207,8 +224,9 @@ namespace OpenSim.Region.CoreModules.World.Land
207 else 224 else
208 { 225 {
209 //Normal Calculations 226 //Normal Calculations
210 int simMax = (int)(((float)LandData.SimwideArea / 65536.0f) 227 int simMax = (int)((long)LandData.SimwideArea
211 * (float)m_scene.RegionInfo.ObjectCapacity); 228 * (long)m_scene.RegionInfo.ObjectCapacity / 65536L);
229 // m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}", LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax);
212 return simMax; 230 return simMax;
213 } 231 }
214 } 232 }
@@ -245,7 +263,7 @@ namespace OpenSim.Region.CoreModules.World.Land
245 remote_client.SendLandProperties(seq_id, 263 remote_client.SendLandProperties(seq_id,
246 snap_selection, request_result, this, 264 snap_selection, request_result, this,
247 (float)m_scene.RegionInfo.RegionSettings.ObjectBonus, 265 (float)m_scene.RegionInfo.RegionSettings.ObjectBonus,
248 GetParcelMaxPrimCount(), 266 GetParcelBasePrimCount(),
249 GetSimulatorMaxPrimCount(), regionFlags); 267 GetSimulatorMaxPrimCount(), regionFlags);
250 } 268 }
251 269
@@ -304,7 +322,7 @@ namespace OpenSim.Region.CoreModules.World.Land
304 322
305 allowedDelta |= (uint)(ParcelFlags.ShowDirectory | 323 allowedDelta |= (uint)(ParcelFlags.ShowDirectory |
306 ParcelFlags.AllowPublish | 324 ParcelFlags.AllowPublish |
307 ParcelFlags.MaturePublish); 325 ParcelFlags.MaturePublish) | (uint)(1 << 23);
308 } 326 }
309 327
310 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity)) 328 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity))
@@ -416,6 +434,37 @@ namespace OpenSim.Region.CoreModules.World.Land
416 return false; 434 return false;
417 } 435 }
418 436
437 public bool HasGroupAccess(UUID avatar)
438 {
439 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
440 {
441 ScenePresence sp;
442 if (!m_scene.TryGetScenePresence(avatar, out sp))
443 {
444 IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
445 if (groupsModule == null)
446 return false;
447
448 GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
449 if (membership == null || membership.Length == 0)
450 return false;
451
452 foreach (GroupMembershipData d in membership)
453 {
454 if (d.GroupID == LandData.GroupID)
455 return true;
456 }
457 return false;
458 }
459
460 if (!sp.ControllingClient.IsGroupMember(LandData.GroupID))
461 return false;
462
463 return true;
464 }
465 return false;
466 }
467
419 public bool IsBannedFromLand(UUID avatar) 468 public bool IsBannedFromLand(UUID avatar)
420 { 469 {
421 ExpireAccessList(); 470 ExpireAccessList();
@@ -468,9 +517,13 @@ namespace OpenSim.Region.CoreModules.World.Land
468 return false; 517 return false;
469 }) == -1) 518 }) == -1)
470 { 519 {
471 return true; 520 if (!HasGroupAccess(avatar))
521 {
522 return true;
523 }
472 } 524 }
473 } 525 }
526
474 return false; 527 return false;
475 } 528 }
476 529
diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs
index efede5c..5122734 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/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
index 1e4f0a4..eb4731c 100644
--- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
@@ -176,6 +176,13 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
176 return false; 176 return false;
177 } 177 }
178 178
179 if ((perms & (uint)PermissionMask.Copy) == 0)
180 {
181 if (m_dialogModule != null)
182 m_dialogModule.SendAlertToUser(remoteClient, "This sale has been blocked by the permissions system");
183 return false;
184 }
185
179 AssetBase asset = m_scene.CreateAsset( 186 AssetBase asset = m_scene.CreateAsset(
180 group.GetPartName(localID), 187 group.GetPartName(localID),
181 group.GetPartDescription(localID), 188 group.GetPartDescription(localID),
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index cdecd2f..5e7d37a 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -363,7 +363,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
363 363
364 public string Name 364 public string Name
365 { 365 {
366 get { return "PermissionsModule"; } 366 get { return "DefaultPermissionsModule"; }
367 } 367 }
368 368
369 public bool IsSharedModule 369 public bool IsSharedModule
diff --git a/OpenSim/Region/CoreModules/World/Region/RestartModule.cs b/OpenSim/Region/CoreModules/World/Region/RestartModule.cs
index 0f37ddd..86821c6 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 79
68 scene.RegisterModuleInterface<IRestartModule>(this); 80 scene.RegisterModuleInterface<IRestartModule>(this);
@@ -121,6 +133,7 @@ namespace OpenSim.Region.CoreModules.World.Region
121 133
122 if (alerts == null) 134 if (alerts == null)
123 { 135 {
136 CreateMarkerFile();
124 m_Scene.RestartNow(); 137 m_Scene.RestartNow();
125 return; 138 return;
126 } 139 }
@@ -134,6 +147,7 @@ namespace OpenSim.Region.CoreModules.World.Region
134 147
135 if (m_Alerts[0] == 0) 148 if (m_Alerts[0] == 0)
136 { 149 {
150 CreateMarkerFile();
137 m_Scene.RestartNow(); 151 m_Scene.RestartNow();
138 return; 152 return;
139 } 153 }
@@ -147,6 +161,7 @@ namespace OpenSim.Region.CoreModules.World.Region
147 { 161 {
148 if (m_Alerts.Count == 0 || m_Alerts[0] == 0) 162 if (m_Alerts.Count == 0 || m_Alerts[0] == 0)
149 { 163 {
164 CreateMarkerFile();
150 m_Scene.RestartNow(); 165 m_Scene.RestartNow();
151 return 0; 166 return 0;
152 } 167 }
@@ -225,6 +240,9 @@ namespace OpenSim.Region.CoreModules.World.Region
225 if (m_DialogModule != null && message != String.Empty) 240 if (m_DialogModule != null && message != String.Empty)
226 m_DialogModule.SendGeneralAlert(message); 241 m_DialogModule.SendGeneralAlert(message);
227 } 242 }
243 if (m_MarkerPath != String.Empty)
244 File.Delete(Path.Combine(m_MarkerPath,
245 m_Scene.RegionInfo.RegionID.ToString()));
228 } 246 }
229 247
230 private void HandleRegionRestart(string module, string[] args) 248 private void HandleRegionRestart(string module, string[] args)
@@ -266,5 +284,25 @@ namespace OpenSim.Region.CoreModules.World.Region
266 284
267 ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice); 285 ScheduleRestart(UUID.Zero, args[3], times.ToArray(), notice);
268 } 286 }
287
288 protected void CreateMarkerFile()
289 {
290 if (m_MarkerPath == String.Empty)
291 return;
292
293 string path = Path.Combine(m_MarkerPath, m_Scene.RegionInfo.RegionID.ToString());
294 try
295 {
296 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
297 FileStream fs = File.Create(path);
298 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
299 Byte[] buf = enc.GetBytes(pidstring);
300 fs.Write(buf, 0, buf.Length);
301 fs.Close();
302 }
303 catch (Exception)
304 {
305 }
306 }
269 } 307 }
270} 308}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index cf000a4..4805ccb 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -606,6 +606,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
606 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); 606 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
607 m_scene.SaveTerrain(); 607 m_scene.SaveTerrain();
608 608
609 m_scene.EventManager.TriggerTerrainUpdate();
610
609 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. 611 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
610 //m_scene.CreateTerrainTexture(true); 612 //m_scene.CreateTerrainTexture(true);
611 } 613 }
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs
index 657975b..f9384e9 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, uint flags) 87 private void OnMapNameRequest(IClientAPI remoteClient, string mapName, uint flags)
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
@@ -96,10 +96,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
96 96
97 // try to fetch from GridServer 97 // try to fetch from GridServer
98 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20); 98 List<GridRegion> regionInfos = m_scene.GridService.GetRegionsByName(m_scene.RegionInfo.ScopeID, mapName, 20);
99 if (regionInfos.Count == 0) 99// if (regionInfos.Count == 0)
100 remoteClient.SendAlertMessage("Hyperlink could not be established."); 100// remoteClient.SendAlertMessage("Hyperlink could not be established.");
101 101
102 m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions. Flags={2}", mapName, regionInfos.Count, flags); 102 //m_log.DebugFormat("[MAPSEARCHMODULE]: search {0} returned {1} regions", mapName, regionInfos.Count);
103 List<MapBlockData> blocks = new List<MapBlockData>(); 103 List<MapBlockData> blocks = new List<MapBlockData>();
104 104
105 MapBlockData data; 105 MapBlockData data;
@@ -128,7 +128,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
128 data.Agents = 0; 128 data.Agents = 0;
129 data.Access = 255; 129 data.Access = 255;
130 data.MapImageId = UUID.Zero; 130 data.MapImageId = UUID.Zero;
131 data.Name = ""; // mapName; 131 data.Name = mapName;
132 data.RegionFlags = 0; 132 data.RegionFlags = 0;
133 data.WaterHeight = 0; // not used 133 data.WaterHeight = 0; // not used
134 data.X = 0; 134 data.X = 0;
diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
index b315d2c..4ebfb21 100644
--- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
+++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs
@@ -1239,7 +1239,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1239 } 1239 }
1240 else 1240 else
1241 { 1241 {
1242 OSDArray responsearr = new OSDArray(m_scene.GetRootAgentCount()); 1242 OSDArray responsearr = new OSDArray(); // Don't preallocate. MT (m_scene.GetRootAgentCount());
1243 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) 1243 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
1244 { 1244 {
1245 OSDMap responsemapdata = new OSDMap(); 1245 OSDMap responsemapdata = new OSDMap();
@@ -1458,9 +1458,10 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1458 Color background = Color.FromArgb(0, 0, 0, 0); 1458 Color background = Color.FromArgb(0, 0, 0, 0);
1459 SolidBrush transparent = new SolidBrush(background); 1459 SolidBrush transparent = new SolidBrush(background);
1460 Graphics g = Graphics.FromImage(overlay); 1460 Graphics g = Graphics.FromImage(overlay);
1461 g.FillRectangle(transparent, 0, 0, 256, 256); 1461 g.FillRectangle(transparent, 0, 0, 255, 255);
1462 1462
1463 SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9)); 1463 SolidBrush yellow = new SolidBrush(Color.FromArgb(255, 249, 223, 9));
1464 Pen grey = new Pen(Color.FromArgb(255, 92, 92, 92));
1464 1465
1465 foreach (ILandObject land in parcels) 1466 foreach (ILandObject land in parcels)
1466 { 1467 {
@@ -1469,7 +1470,41 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1469 { 1470 {
1470 landForSale = true; 1471 landForSale = true;
1471 1472
1472 saleBitmap = land.MergeLandBitmaps(saleBitmap, land.GetLandBitmap()); 1473 bool[,] landBitmap = land.GetLandBitmap();
1474
1475 for (int x = 0 ; x < 64 ; x++)
1476 {
1477 for (int y = 0 ; y < 64 ; y++)
1478 {
1479 if (landBitmap[x, y])
1480 {
1481 g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
1482
1483 if (x > 0)
1484 {
1485 if ((saleBitmap[x - 1, y] || landBitmap[x - 1, y]) == false)
1486 g.DrawLine(grey, x * 4, 252 - (y * 4), x * 4, 255 - (y * 4));
1487 }
1488 if (y > 0)
1489 {
1490 if ((saleBitmap[x, y-1] || landBitmap[x, y-1]) == false)
1491 g.DrawLine(grey, x * 4, 255 - (y * 4), x * 4 + 3, 255 - (y * 4));
1492 }
1493 if (x < 63)
1494 {
1495 if ((saleBitmap[x + 1, y] || landBitmap[x + 1, y]) == false)
1496 g.DrawLine(grey, x * 4 + 3, 252 - (y * 4), x * 4 + 3, 255 - (y * 4));
1497 }
1498 if (y < 63)
1499 {
1500 if ((saleBitmap[x, y + 1] || landBitmap[x, y + 1]) == false)
1501 g.DrawLine(grey, x * 4, 252 - (y * 4), x * 4 + 3, 252 - (y * 4));
1502 }
1503 }
1504 }
1505 }
1506
1507 saleBitmap = land.MergeLandBitmaps(saleBitmap, landBitmap);
1473 } 1508 }
1474 } 1509 }
1475 1510
@@ -1481,15 +1516,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
1481 1516
1482 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, genrating overlay", m_scene.RegionInfo.RegionName); 1517 m_log.DebugFormat("[WORLD MAP]: Region {0} has parcels for sale, genrating overlay", m_scene.RegionInfo.RegionName);
1483 1518
1484 for (int x = 0 ; x < 64 ; x++)
1485 {
1486 for (int y = 0 ; y < 64 ; y++)
1487 {
1488 if (saleBitmap[x, y])
1489 g.FillRectangle(yellow, x * 4, 252 - (y * 4), 4, 4);
1490 }
1491 }
1492
1493 try 1519 try
1494 { 1520 {
1495 return OpenJPEG.EncodeFromImage(overlay, true); 1521 return OpenJPEG.EncodeFromImage(overlay, true);
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index eb07165..69ce967 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 System.Collections.Generic; 30using System.Collections.Generic;
30using OpenMetaverse; 31using OpenMetaverse;
31using OpenSim.Framework; 32using OpenSim.Framework;
@@ -75,6 +76,10 @@ namespace OpenSim.Region.Framework.Interfaces
75 /// <returns>The scene object that was attached. Null if the scene object could not be found</returns> 76 /// <returns>The scene object that was attached. Null if the scene object could not be found</returns>
76 ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt); 77 ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt);
77 78
79 // Same as above, but also load script states from a separate doc
80 ISceneEntity RezSingleAttachmentFromInventory(
81 IScenePresence presence, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc);
82
78 /// <summary> 83 /// <summary>
79 /// Rez multiple attachments from a user's inventory 84 /// Rez multiple attachments from a user's inventory
80 /// </summary> 85 /// </summary>
@@ -96,7 +101,6 @@ namespace OpenSim.Region.Framework.Interfaces
96 /// <param name="itemID"></param> 101 /// <param name="itemID"></param>
97 void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID); 102 void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID);
98 103
99 /// <summary>
100 /// Update the position of an attachment. 104 /// Update the position of an attachment.
101 /// </summary> 105 /// </summary>
102 /// <param name="sog"></param> 106 /// <param name="sog"></param>
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 07e97d5..c38ecd9 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
@@ -40,11 +40,11 @@ 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 bool TeleportHome(UUID id, IClientAPI client);
44
43 void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, 45 void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination,
44 Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq); 46 Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq);
45 47
46 void TeleportHome(UUID id, IClientAPI client);
47
48 bool Cross(ScenePresence agent, bool isFlying); 48 bool Cross(ScenePresence agent, bool isFlying);
49 49
50 void AgentArrivedAtDestination(UUID agent); 50 void AgentArrivedAtDestination(UUID agent);
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 18c45dd..2d6758b 100644
--- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs
@@ -68,6 +68,8 @@ namespace OpenSim.Region.Framework.Interfaces
68 68
69 ArrayList GetScriptErrors(UUID itemID); 69 ArrayList GetScriptErrors(UUID itemID);
70 70
71 bool HasScript(UUID itemID, out bool running);
72
71 void SaveAllState(); 73 void SaveAllState();
72 74
73 /// <summary> 75 /// <summary>
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 14ecd44..32ee674 100644
--- a/OpenSim/Region/Framework/ModuleLoader.cs
+++ b/OpenSim/Region/Framework/ModuleLoader.cs
@@ -227,7 +227,8 @@ namespace OpenSim.Region.Framework
227 pluginAssembly.FullName, e.Message, e.StackTrace); 227 pluginAssembly.FullName, e.Message, e.StackTrace);
228 228
229 // justincc: Right now this is fatal to really get the user's attention 229 // justincc: Right now this is fatal to really get the user's attention
230 throw e; 230 // TomMeta: WTF? No, how about we /don't/ throw a fatal exception when there's no need to?
231 //throw e;
231 } 232 }
232 } 233 }
233 234
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index d31d380..57db4d6 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;
@@ -797,6 +801,26 @@ namespace OpenSim.Region.Framework.Scenes
797 } 801 }
798 } 802 }
799 } 803 }
804 public void TriggerTerrainUpdate()
805 {
806 OnTerrainUpdateDelegate handlerTerrainUpdate = OnTerrainUpdate;
807 if (handlerTerrainUpdate != null)
808 {
809 foreach (OnTerrainUpdateDelegate d in handlerTerrainUpdate.GetInvocationList())
810 {
811 try
812 {
813 d();
814 }
815 catch (Exception e)
816 {
817 m_log.ErrorFormat(
818 "[EVENT MANAGER]: Delegate for TriggerTerrainUpdate failed - continuing. {0} {1}",
819 e.Message, e.StackTrace);
820 }
821 }
822 }
823 }
800 824
801 public void TriggerTerrainTick() 825 public void TriggerTerrainTick()
802 { 826 {
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 1b10e3c..0a34a4c 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -157,7 +157,7 @@ namespace OpenSim.Region.Framework.Scenes
157 157
158 private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) 158 private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
159 { 159 {
160 uint pqueue = ComputeDistancePriority(client,entity,true); 160 uint pqueue = ComputeDistancePriority(client,entity,false);
161 161
162 ScenePresence presence = m_scene.GetScenePresence(client.AgentId); 162 ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
163 if (presence != null) 163 if (presence != null)
@@ -226,7 +226,7 @@ namespace OpenSim.Region.Framework.Scenes
226 226
227 for (int i = 0; i < queues - 1; i++) 227 for (int i = 0; i < queues - 1; i++)
228 { 228 {
229 if (distance < 10 * Math.Pow(2.0,i)) 229 if (distance < 30 * Math.Pow(2.0,i))
230 break; 230 break;
231 pqueue++; 231 pqueue++;
232 } 232 }
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index 6d7559e..58de44e 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -117,34 +117,22 @@ namespace OpenSim.Region.Framework.Scenes
117 /// <param name="item"></param> 117 /// <param name="item"></param>
118 public bool AddInventoryItem(InventoryItemBase item) 118 public bool AddInventoryItem(InventoryItemBase item)
119 { 119 {
120 if (UUID.Zero == item.Folder) 120 InventoryFolderBase folder;
121
122 if (item.Folder == UUID.Zero)
121 { 123 {
122 InventoryFolderBase f = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType); 124 folder = InventoryService.GetFolderForType(item.Owner, (AssetType)item.AssetType);
123 if (f != null) 125 if (folder == null)
124 { 126 {
125// m_log.DebugFormat( 127 folder = InventoryService.GetRootFolder(item.Owner);
126// "[LOCAL INVENTORY SERVICES CONNECTOR]: Found folder {0} type {1} for item {2}", 128
127// f.Name, (AssetType)f.Type, item.Name); 129 if (folder == null)
128
129 item.Folder = f.ID;
130 }
131 else
132 {
133 f = InventoryService.GetRootFolder(item.Owner);
134 if (f != null)
135 {
136 item.Folder = f.ID;
137 }
138 else
139 {
140 m_log.WarnFormat(
141 "[AGENT INVENTORY]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
142 item.Owner, item.Name);
143 return false; 130 return false;
144 }
145 } 131 }
132
133 item.Folder = folder.ID;
146 } 134 }
147 135
148 if (InventoryService.AddItem(item)) 136 if (InventoryService.AddItem(item))
149 { 137 {
150 int userlevel = 0; 138 int userlevel = 0;
@@ -264,8 +252,7 @@ namespace OpenSim.Region.Framework.Scenes
264 252
265 // Update item with new asset 253 // Update item with new asset
266 item.AssetID = asset.FullID; 254 item.AssetID = asset.FullID;
267 if (group.UpdateInventoryItem(item)) 255 group.UpdateInventoryItem(item);
268 remoteClient.SendAgentAlertMessage("Script saved", false);
269 256
270 part.SendPropertiesToClient(remoteClient); 257 part.SendPropertiesToClient(remoteClient);
271 258
@@ -276,12 +263,7 @@ namespace OpenSim.Region.Framework.Scenes
276 { 263 {
277 // Needs to determine which engine was running it and use that 264 // Needs to determine which engine was running it and use that
278 // 265 //
279 part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0); 266 errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 0);
280 errors = part.Inventory.GetScriptErrors(item.ItemID);
281 }
282 else
283 {
284 remoteClient.SendAgentAlertMessage("Script saved", false);
285 } 267 }
286 part.ParentGroup.ResumeScripts(); 268 part.ParentGroup.ResumeScripts();
287 return errors; 269 return errors;
@@ -345,6 +327,7 @@ namespace OpenSim.Region.Framework.Scenes
345 327
346 if (UUID.Zero == transactionID) 328 if (UUID.Zero == transactionID)
347 { 329 {
330 item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255);
348 item.Name = itemUpd.Name; 331 item.Name = itemUpd.Name;
349 item.Description = itemUpd.Description; 332 item.Description = itemUpd.Description;
350 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions)) 333 if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
@@ -723,6 +706,8 @@ namespace OpenSim.Region.Framework.Scenes
723 return; 706 return;
724 } 707 }
725 708
709 if (newName == null) newName = item.Name;
710
726 AssetBase asset = AssetService.Get(item.AssetID.ToString()); 711 AssetBase asset = AssetService.Get(item.AssetID.ToString());
727 712
728 if (asset != null) 713 if (asset != null)
@@ -779,6 +764,24 @@ namespace OpenSim.Region.Framework.Scenes
779 } 764 }
780 765
781 /// <summary> 766 /// <summary>
767 /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit)
768 /// </summary>
769 public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List<InventoryItemBase> items, UUID destfolder)
770 {
771 List<InventoryItemBase> moveitems = new List<InventoryItemBase>();
772 foreach (InventoryItemBase b in items)
773 {
774 CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null);
775 InventoryItemBase n = InventoryService.GetItem(b);
776 n.Folder = destfolder;
777 moveitems.Add(n);
778 remoteClient.SendInventoryItemCreateUpdate(n, 0);
779 }
780
781 MoveInventoryItem(remoteClient, moveitems);
782 }
783
784 /// <summary>
782 /// Move an item within the agent's inventory. 785 /// Move an item within the agent's inventory.
783 /// </summary> 786 /// </summary>
784 /// <param name="remoteClient"></param> 787 /// <param name="remoteClient"></param>
@@ -1121,6 +1124,10 @@ namespace OpenSim.Region.Framework.Scenes
1121 { 1124 {
1122 SceneObjectPart part = GetSceneObjectPart(primLocalId); 1125 SceneObjectPart part = GetSceneObjectPart(primLocalId);
1123 1126
1127 // Can't move a null item
1128 if (itemId == UUID.Zero)
1129 return;
1130
1124 if (null == part) 1131 if (null == part)
1125 { 1132 {
1126 m_log.WarnFormat( 1133 m_log.WarnFormat(
@@ -1231,6 +1238,10 @@ namespace OpenSim.Region.Framework.Scenes
1231 if ((part.OwnerID != destPart.OwnerID) && ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)) 1238 if ((part.OwnerID != destPart.OwnerID) && ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
1232 return; 1239 return;
1233 1240
1241 bool overrideNoMod = false;
1242 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) != 0)
1243 overrideNoMod = true;
1244
1234 if (part.OwnerID != destPart.OwnerID && (part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0) 1245 if (part.OwnerID != destPart.OwnerID && (part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0)
1235 { 1246 {
1236 // object cannot copy items to an object owned by a different owner 1247 // object cannot copy items to an object owned by a different owner
@@ -1240,7 +1251,7 @@ namespace OpenSim.Region.Framework.Scenes
1240 } 1251 }
1241 1252
1242 // must have both move and modify permission to put an item in an object 1253 // must have both move and modify permission to put an item in an object
1243 if ((part.OwnerMask & ((uint)PermissionMask.Move | (uint)PermissionMask.Modify)) == 0) 1254 if (((part.OwnerMask & (uint)PermissionMask.Modify) == 0) && (!overrideNoMod))
1244 { 1255 {
1245 return; 1256 return;
1246 } 1257 }
@@ -1299,6 +1310,14 @@ namespace OpenSim.Region.Framework.Scenes
1299 1310
1300 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items) 1311 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items)
1301 { 1312 {
1313 SceneObjectPart destPart = GetSceneObjectPart(destID);
1314 if (destPart != null) // Move into a prim
1315 {
1316 foreach(UUID itemID in items)
1317 MoveTaskInventoryItem(destID, host, itemID);
1318 return destID; // Prim folder ID == prim ID
1319 }
1320
1302 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID); 1321 InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
1303 1322
1304 UUID newFolderID = UUID.Random(); 1323 UUID newFolderID = UUID.Random();
@@ -1484,12 +1503,12 @@ namespace OpenSim.Region.Framework.Scenes
1484 agentTransactions.HandleTaskItemUpdateFromTransaction( 1503 agentTransactions.HandleTaskItemUpdateFromTransaction(
1485 remoteClient, part, transactionID, currentItem); 1504 remoteClient, part, transactionID, currentItem);
1486 1505
1487 if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) 1506// if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
1488 remoteClient.SendAgentAlertMessage("Notecard saved", false); 1507// remoteClient.SendAgentAlertMessage("Notecard saved", false);
1489 else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) 1508// else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
1490 remoteClient.SendAgentAlertMessage("Script saved", false); 1509// remoteClient.SendAgentAlertMessage("Script saved", false);
1491 else 1510// else
1492 remoteClient.SendAgentAlertMessage("Item saved", false); 1511// remoteClient.SendAgentAlertMessage("Item saved", false);
1493 } 1512 }
1494 } 1513 }
1495 1514
@@ -1669,7 +1688,7 @@ namespace OpenSim.Region.Framework.Scenes
1669 } 1688 }
1670 1689
1671 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType, 1690 AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
1672 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"), 1691 Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n\n touch_start(integer num)\n {\n }\n}"),
1673 agentID); 1692 agentID);
1674 AssetService.Store(asset); 1693 AssetService.Store(asset);
1675 1694
@@ -1821,23 +1840,32 @@ namespace OpenSim.Region.Framework.Scenes
1821 // build a list of eligible objects 1840 // build a list of eligible objects
1822 List<uint> deleteIDs = new List<uint>(); 1841 List<uint> deleteIDs = new List<uint>();
1823 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>(); 1842 List<SceneObjectGroup> deleteGroups = new List<SceneObjectGroup>();
1824 1843 List<SceneObjectGroup> takeGroups = new List<SceneObjectGroup>();
1825 // Start with true for both, then remove the flags if objects
1826 // that we can't derez are part of the selection
1827 bool permissionToTake = true;
1828 bool permissionToTakeCopy = true;
1829 bool permissionToDelete = true;
1830 1844
1831 foreach (uint localID in localIDs) 1845 foreach (uint localID in localIDs)
1832 { 1846 {
1847 // Start with true for both, then remove the flags if objects
1848 // that we can't derez are part of the selection
1849 bool permissionToTake = true;
1850 bool permissionToTakeCopy = true;
1851 bool permissionToDelete = true;
1852
1833 // Invalid id 1853 // Invalid id
1834 SceneObjectPart part = GetSceneObjectPart(localID); 1854 SceneObjectPart part = GetSceneObjectPart(localID);
1835 if (part == null) 1855 if (part == null)
1856 {
1857 //Client still thinks the object exists, kill it
1858 deleteIDs.Add(localID);
1836 continue; 1859 continue;
1860 }
1837 1861
1838 // Already deleted by someone else 1862 // Already deleted by someone else
1839 if (part.ParentGroup.IsDeleted) 1863 if (part.ParentGroup.IsDeleted)
1864 {
1865 //Client still thinks the object exists, kill it
1866 deleteIDs.Add(localID);
1840 continue; 1867 continue;
1868 }
1841 1869
1842 // Can't delete child prims 1870 // Can't delete child prims
1843 if (part != part.ParentGroup.RootPart) 1871 if (part != part.ParentGroup.RootPart)
@@ -1845,9 +1873,6 @@ namespace OpenSim.Region.Framework.Scenes
1845 1873
1846 SceneObjectGroup grp = part.ParentGroup; 1874 SceneObjectGroup grp = part.ParentGroup;
1847 1875
1848 deleteIDs.Add(localID);
1849 deleteGroups.Add(grp);
1850
1851 if (remoteClient == null) 1876 if (remoteClient == null)
1852 { 1877 {
1853 // Autoreturn has a null client. Nothing else does. So 1878 // Autoreturn has a null client. Nothing else does. So
@@ -1864,83 +1889,195 @@ namespace OpenSim.Region.Framework.Scenes
1864 } 1889 }
1865 else 1890 else
1866 { 1891 {
1867 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId)) 1892 if (action == DeRezAction.TakeCopy)
1893 {
1894 if (!Permissions.CanTakeCopyObject(grp.UUID, remoteClient.AgentId))
1895 permissionToTakeCopy = false;
1896 }
1897 else
1898 {
1868 permissionToTakeCopy = false; 1899 permissionToTakeCopy = false;
1869 1900 }
1870 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId)) 1901 if (!Permissions.CanTakeObject(grp.UUID, remoteClient.AgentId))
1871 permissionToTake = false; 1902 permissionToTake = false;
1872 1903
1873 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId)) 1904 if (!Permissions.CanDeleteObject(grp.UUID, remoteClient.AgentId))
1874 permissionToDelete = false; 1905 permissionToDelete = false;
1875 } 1906 }
1876 }
1877 1907
1878 // Handle god perms 1908 // Handle god perms
1879 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId)) 1909 if ((remoteClient != null) && Permissions.IsGod(remoteClient.AgentId))
1880 { 1910 {
1881 permissionToTake = true; 1911 permissionToTake = true;
1882 permissionToTakeCopy = true; 1912 permissionToTakeCopy = true;
1883 permissionToDelete = true; 1913 permissionToDelete = true;
1884 } 1914 }
1885 1915
1886 // If we're re-saving, we don't even want to delete 1916 // If we're re-saving, we don't even want to delete
1887 if (action == DeRezAction.SaveToExistingUserInventoryItem) 1917 if (action == DeRezAction.SaveToExistingUserInventoryItem)
1888 permissionToDelete = false; 1918 permissionToDelete = false;
1889 1919
1890 // if we want to take a copy, we also don't want to delete 1920 // if we want to take a copy, we also don't want to delete
1891 // Note: after this point, the permissionToTakeCopy flag 1921 // Note: after this point, the permissionToTakeCopy flag
1892 // becomes irrelevant. It already includes the permissionToTake 1922 // becomes irrelevant. It already includes the permissionToTake
1893 // permission and after excluding no copy items here, we can 1923 // permission and after excluding no copy items here, we can
1894 // just use that. 1924 // just use that.
1895 if (action == DeRezAction.TakeCopy) 1925 if (action == DeRezAction.TakeCopy)
1896 { 1926 {
1897 // If we don't have permission, stop right here 1927 // If we don't have permission, stop right here
1898 if (!permissionToTakeCopy) 1928 if (!permissionToTakeCopy)
1899 return; 1929 return;
1900 1930
1901 permissionToTake = true; 1931 permissionToTake = true;
1902 // Don't delete 1932 // Don't delete
1903 permissionToDelete = false; 1933 permissionToDelete = false;
1904 } 1934 }
1905 1935
1906 if (action == DeRezAction.Return) 1936 if (action == DeRezAction.Return)
1907 {
1908 if (remoteClient != null)
1909 { 1937 {
1910 if (Permissions.CanReturnObjects( 1938 if (remoteClient != null)
1911 null,
1912 remoteClient.AgentId,
1913 deleteGroups))
1914 { 1939 {
1915 permissionToTake = true; 1940 if (Permissions.CanReturnObjects(
1916 permissionToDelete = true; 1941 null,
1917 1942 remoteClient.AgentId,
1918 foreach (SceneObjectGroup g in deleteGroups) 1943 deleteGroups))
1919 { 1944 {
1920 AddReturn(g.OwnerID, g.Name, g.AbsolutePosition, "parcel owner return"); 1945 permissionToTake = true;
1946 permissionToDelete = true;
1947
1948 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
1921 } 1949 }
1922 } 1950 }
1951 else // Auto return passes through here with null agent
1952 {
1953 permissionToTake = true;
1954 permissionToDelete = true;
1955 }
1923 } 1956 }
1924 else // Auto return passes through here with null agent 1957
1958 if (permissionToTake && (!permissionToDelete))
1959 takeGroups.Add(grp);
1960
1961 if (permissionToDelete)
1925 { 1962 {
1926 permissionToTake = true; 1963 if (permissionToTake)
1927 permissionToDelete = true; 1964 deleteGroups.Add(grp);
1965 deleteIDs.Add(grp.LocalId);
1928 } 1966 }
1929 } 1967 }
1930 1968
1931 if (permissionToTake) 1969 SendKillObject(deleteIDs);
1970
1971 if (deleteGroups.Count > 0)
1932 { 1972 {
1973 foreach (SceneObjectGroup g in deleteGroups)
1974 deleteIDs.Remove(g.LocalId);
1975
1933 m_asyncSceneObjectDeleter.DeleteToInventory( 1976 m_asyncSceneObjectDeleter.DeleteToInventory(
1934 action, destinationID, deleteGroups, remoteClient, 1977 action, destinationID, deleteGroups, remoteClient,
1935 permissionToDelete); 1978 true);
1979 }
1980 if (takeGroups.Count > 0)
1981 {
1982 m_asyncSceneObjectDeleter.DeleteToInventory(
1983 action, destinationID, takeGroups, remoteClient,
1984 false);
1936 } 1985 }
1937 else if (permissionToDelete) 1986 if (deleteIDs.Count > 0)
1938 { 1987 {
1939 foreach (SceneObjectGroup g in deleteGroups) 1988 foreach (SceneObjectGroup g in deleteGroups)
1940 DeleteSceneObject(g, false); 1989 DeleteSceneObject(g, true);
1941 } 1990 }
1942 } 1991 }
1943 1992
1993 public UUID attachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, out UUID itemID)
1994 {
1995 itemID = UUID.Zero;
1996 if (grp != null)
1997 {
1998 Vector3 inventoryStoredPosition = new Vector3
1999 (((grp.AbsolutePosition.X > (int)Constants.RegionSize)
2000 ? 250
2001 : grp.AbsolutePosition.X)
2002 ,
2003 (grp.AbsolutePosition.X > (int)Constants.RegionSize)
2004 ? 250
2005 : grp.AbsolutePosition.X,
2006 grp.AbsolutePosition.Z);
2007
2008 Vector3 originalPosition = grp.AbsolutePosition;
2009
2010 grp.AbsolutePosition = inventoryStoredPosition;
2011
2012 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
2013
2014 grp.AbsolutePosition = originalPosition;
2015
2016 AssetBase asset = CreateAsset(
2017 grp.GetPartName(grp.LocalId),
2018 grp.GetPartDescription(grp.LocalId),
2019 (sbyte)AssetType.Object,
2020 Utils.StringToBytes(sceneObjectXml),
2021 remoteClient.AgentId);
2022 AssetService.Store(asset);
2023
2024 InventoryItemBase item = new InventoryItemBase();
2025 item.CreatorId = grp.RootPart.CreatorID.ToString();
2026 item.CreatorData = grp.RootPart.CreatorData;
2027 item.Owner = remoteClient.AgentId;
2028 item.ID = UUID.Random();
2029 item.AssetID = asset.FullID;
2030 item.Description = asset.Description;
2031 item.Name = asset.Name;
2032 item.AssetType = asset.Type;
2033 item.InvType = (int)InventoryType.Object;
2034
2035 InventoryFolderBase folder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object);
2036 if (folder != null)
2037 item.Folder = folder.ID;
2038 else // oopsies
2039 item.Folder = UUID.Zero;
2040
2041 // Set up base perms properly
2042 uint permsBase = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify);
2043 permsBase &= grp.RootPart.BaseMask;
2044 permsBase |= (uint)PermissionMask.Move;
2045
2046 // Make sure we don't lock it
2047 grp.RootPart.NextOwnerMask |= (uint)PermissionMask.Move;
2048
2049 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions())
2050 {
2051 item.BasePermissions = permsBase & grp.RootPart.NextOwnerMask;
2052 item.CurrentPermissions = permsBase & grp.RootPart.NextOwnerMask;
2053 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
2054 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
2055 item.GroupPermissions = permsBase & grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
2056 }
2057 else
2058 {
2059 item.BasePermissions = permsBase;
2060 item.CurrentPermissions = permsBase & grp.RootPart.OwnerMask;
2061 item.NextPermissions = permsBase & grp.RootPart.NextOwnerMask;
2062 item.EveryOnePermissions = permsBase & grp.RootPart.EveryoneMask;
2063 item.GroupPermissions = permsBase & grp.RootPart.GroupMask;
2064 }
2065 item.CreationDate = Util.UnixTimeSinceEpoch();
2066
2067 // sets itemID so client can show item as 'attached' in inventory
2068 grp.SetFromItemID(item.ID);
2069
2070 if (AddInventoryItem(item))
2071 remoteClient.SendInventoryItemCreateUpdate(item, 0);
2072 else
2073 m_dialogModule.SendAlertToUser(remoteClient, "Operation failed");
2074
2075 itemID = item.ID;
2076 return item.AssetID;
2077 }
2078 return UUID.Zero;
2079 }
2080
1944 /// <summary> 2081 /// <summary>
1945 /// Event Handler Rez an object into a scene 2082 /// Event Handler Rez an object into a scene
1946 /// Calls the non-void event handler 2083 /// Calls the non-void event handler
@@ -2067,6 +2204,9 @@ namespace OpenSim.Region.Framework.Scenes
2067 2204
2068 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running) 2205 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running)
2069 { 2206 {
2207 if (!Permissions.CanEditScript(itemID, objectID, controllingClient.AgentId))
2208 return;
2209
2070 SceneObjectPart part = GetSceneObjectPart(objectID); 2210 SceneObjectPart part = GetSceneObjectPart(objectID);
2071 if (part == null) 2211 if (part == null)
2072 return; 2212 return;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
index 3355ebe..bf2e775 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -346,7 +346,10 @@ namespace OpenSim.Region.Framework.Scenes
346 List<UserAccount> accounts = UserAccountService.GetUserAccounts(RegionInfo.ScopeID, query); 346 List<UserAccount> accounts = UserAccountService.GetUserAccounts(RegionInfo.ScopeID, query);
347 347
348 if (accounts == null) 348 if (accounts == null)
349 {
350 m_log.DebugFormat("[LLCIENT]: ProcessAvatarPickerRequest: returned null result");
349 return; 351 return;
352 }
350 353
351 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket) PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); 354 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket) PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
352 // TODO: don't create new blocks if recycling an old packet 355 // TODO: don't create new blocks if recycling an old packet
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 3347822..ec5cf32 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -104,6 +104,7 @@ namespace OpenSim.Region.Framework.Scenes
104 // TODO: need to figure out how allow client agents but deny 104 // TODO: need to figure out how allow client agents but deny
105 // root agents when ACL denies access to root agent 105 // root agents when ACL denies access to root agent
106 public bool m_strictAccessControl = true; 106 public bool m_strictAccessControl = true;
107 public bool m_seeIntoBannedRegion = false;
107 public int MaxUndoCount = 5; 108 public int MaxUndoCount = 5;
108 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet; 109 // Using this for RegionReady module to prevent LoginsDisabled from changing under our feet;
109 public bool LoginLock = false; 110 public bool LoginLock = false;
@@ -119,12 +120,14 @@ namespace OpenSim.Region.Framework.Scenes
119 120
120 protected int m_splitRegionID; 121 protected int m_splitRegionID;
121 protected Timer m_restartWaitTimer = new Timer(); 122 protected Timer m_restartWaitTimer = new Timer();
123 protected Timer m_timerWatchdog = new Timer();
122 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>(); 124 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>();
123 protected List<RegionInfo> m_neighbours = new List<RegionInfo>(); 125 protected List<RegionInfo> m_neighbours = new List<RegionInfo>();
124 protected string m_simulatorVersion = "OpenSimulator Server"; 126 protected string m_simulatorVersion = "OpenSimulator Server";
125 protected ModuleLoader m_moduleLoader; 127 protected ModuleLoader m_moduleLoader;
126 protected AgentCircuitManager m_authenticateHandler; 128 protected AgentCircuitManager m_authenticateHandler;
127 protected SceneCommunicationService m_sceneGridService; 129 protected SceneCommunicationService m_sceneGridService;
130 protected ISnmpModule m_snmpService = null;
128 131
129 protected ISimulationDataService m_SimulationDataService; 132 protected ISimulationDataService m_SimulationDataService;
130 protected IEstateDataService m_EstateDataService; 133 protected IEstateDataService m_EstateDataService;
@@ -177,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes
177 private int m_update_events = 1; 180 private int m_update_events = 1;
178 private int m_update_backup = 200; 181 private int m_update_backup = 200;
179 private int m_update_terrain = 50; 182 private int m_update_terrain = 50;
180// private int m_update_land = 1; 183 private int m_update_land = 10;
181 private int m_update_coarse_locations = 50; 184 private int m_update_coarse_locations = 50;
182 185
183 private int agentMS; 186 private int agentMS;
@@ -192,6 +195,7 @@ namespace OpenSim.Region.Framework.Scenes
192 private int landMS; 195 private int landMS;
193 private int lastCompletedFrame; 196 private int lastCompletedFrame;
194 197
198 public bool CombineRegions = false;
195 /// <summary> 199 /// <summary>
196 /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched 200 /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched
197 /// asynchronously from the update loop. 201 /// asynchronously from the update loop.
@@ -214,11 +218,14 @@ namespace OpenSim.Region.Framework.Scenes
214 private bool m_scripts_enabled = true; 218 private bool m_scripts_enabled = true;
215 private string m_defaultScriptEngine; 219 private string m_defaultScriptEngine;
216 private int m_LastLogin; 220 private int m_LastLogin;
217 private Thread HeartbeatThread; 221 private Thread HeartbeatThread = null;
218 private volatile bool shuttingdown; 222 private volatile bool shuttingdown;
219 223
220 private int m_lastUpdate; 224 private int m_lastUpdate;
225 private int m_lastIncoming;
226 private int m_lastOutgoing;
221 private bool m_firstHeartbeat = true; 227 private bool m_firstHeartbeat = true;
228 private int m_hbRestarts = 0;
222 229
223 private object m_deleting_scene_object = new object(); 230 private object m_deleting_scene_object = new object();
224 231
@@ -265,6 +272,19 @@ namespace OpenSim.Region.Framework.Scenes
265 get { return m_sceneGridService; } 272 get { return m_sceneGridService; }
266 } 273 }
267 274
275 public ISnmpModule SnmpService
276 {
277 get
278 {
279 if (m_snmpService == null)
280 {
281 m_snmpService = RequestModuleInterface<ISnmpModule>();
282 }
283
284 return m_snmpService;
285 }
286 }
287
268 public ISimulationDataService SimulationDataService 288 public ISimulationDataService SimulationDataService
269 { 289 {
270 get 290 get
@@ -546,6 +566,9 @@ namespace OpenSim.Region.Framework.Scenes
546 m_EstateDataService = estateDataService; 566 m_EstateDataService = estateDataService;
547 m_regionHandle = m_regInfo.RegionHandle; 567 m_regionHandle = m_regInfo.RegionHandle;
548 m_regionName = m_regInfo.RegionName; 568 m_regionName = m_regInfo.RegionName;
569 m_lastUpdate = Util.EnvironmentTickCount();
570 m_lastIncoming = 0;
571 m_lastOutgoing = 0;
549 572
550 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); 573 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
551 m_asyncSceneObjectDeleter.Enabled = true; 574 m_asyncSceneObjectDeleter.Enabled = true;
@@ -677,6 +700,7 @@ namespace OpenSim.Region.Framework.Scenes
677 m_persistAfter *= 10000000; 700 m_persistAfter *= 10000000;
678 701
679 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine"); 702 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "XEngine");
703 m_log.InfoFormat("[SCENE]: Default script engine {0}", m_defaultScriptEngine);
680 704
681 IConfig packetConfig = m_config.Configs["PacketPool"]; 705 IConfig packetConfig = m_config.Configs["PacketPool"];
682 if (packetConfig != null) 706 if (packetConfig != null)
@@ -686,6 +710,8 @@ namespace OpenSim.Region.Framework.Scenes
686 } 710 }
687 711
688 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl); 712 m_strictAccessControl = startupConfig.GetBoolean("StrictAccessControl", m_strictAccessControl);
713 m_seeIntoBannedRegion = startupConfig.GetBoolean("SeeIntoBannedRegion", m_seeIntoBannedRegion);
714 CombineRegions = startupConfig.GetBoolean("CombineContiguousRegions", false);
689 715
690 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true); 716 m_generateMaptiles = startupConfig.GetBoolean("GenerateMaptiles", true);
691 if (m_generateMaptiles) 717 if (m_generateMaptiles)
@@ -721,9 +747,9 @@ namespace OpenSim.Region.Framework.Scenes
721 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain); 747 m_update_terrain = startupConfig.GetInt( "UpdateTerrainEveryNFrames", m_update_terrain);
722 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning); 748 m_update_temp_cleaning = startupConfig.GetInt( "UpdateTempCleaningEveryNFrames", m_update_temp_cleaning);
723 } 749 }
724 catch 750 catch (Exception e)
725 { 751 {
726 m_log.Warn("[SCENE]: Failed to load StartupConfig"); 752 m_log.Error("[SCENE]: Failed to load StartupConfig: " + e.ToString());
727 } 753 }
728 754
729 #endregion Region Config 755 #endregion Region Config
@@ -1134,7 +1160,22 @@ namespace OpenSim.Region.Framework.Scenes
1134 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat); 1160 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
1135 if (HeartbeatThread != null) 1161 if (HeartbeatThread != null)
1136 { 1162 {
1163 m_hbRestarts++;
1164 if(m_hbRestarts > 10)
1165 Environment.Exit(1);
1166 m_log.ErrorFormat("[SCENE]: Restarting heartbeat thread because it hasn't reported in in region {0}", RegionInfo.RegionName);
1167
1168//int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
1169//System.Diagnostics.Process proc = new System.Diagnostics.Process();
1170//proc.EnableRaisingEvents=false;
1171//proc.StartInfo.FileName = "/bin/kill";
1172//proc.StartInfo.Arguments = "-QUIT " + pid.ToString();
1173//proc.Start();
1174//proc.WaitForExit();
1175//Thread.Sleep(1000);
1176//Environment.Exit(1);
1137 HeartbeatThread.Abort(); 1177 HeartbeatThread.Abort();
1178 Watchdog.AbortThread(HeartbeatThread.ManagedThreadId);
1138 HeartbeatThread = null; 1179 HeartbeatThread = null;
1139 } 1180 }
1140 m_lastUpdate = Util.EnvironmentTickCount(); 1181 m_lastUpdate = Util.EnvironmentTickCount();
@@ -1181,9 +1222,6 @@ namespace OpenSim.Region.Framework.Scenes
1181 m_eventManager.TriggerOnRegionStarted(this); 1222 m_eventManager.TriggerOnRegionStarted(this);
1182 while (!shuttingdown) 1223 while (!shuttingdown)
1183 Update(); 1224 Update();
1184
1185 m_lastUpdate = Util.EnvironmentTickCount();
1186 m_firstHeartbeat = false;
1187 } 1225 }
1188 catch (ThreadAbortException) 1226 catch (ThreadAbortException)
1189 { 1227 {
@@ -1281,6 +1319,13 @@ namespace OpenSim.Region.Framework.Scenes
1281 eventMS = Util.EnvironmentTickCountSubtract(evMS); ; 1319 eventMS = Util.EnvironmentTickCountSubtract(evMS); ;
1282 } 1320 }
1283 1321
1322 // if (Frame % m_update_land == 0)
1323 // {
1324 // int ldMS = Util.EnvironmentTickCount();
1325 // UpdateLand();
1326 // landMS = Util.EnvironmentTickCountSubtract(ldMS);
1327 // }
1328
1284 if (Frame % m_update_backup == 0) 1329 if (Frame % m_update_backup == 0)
1285 { 1330 {
1286 int backMS = Util.EnvironmentTickCount(); 1331 int backMS = Util.EnvironmentTickCount();
@@ -1390,12 +1435,16 @@ namespace OpenSim.Region.Framework.Scenes
1390 maintc = Util.EnvironmentTickCountSubtract(maintc); 1435 maintc = Util.EnvironmentTickCountSubtract(maintc);
1391 maintc = (int)(MinFrameTime * 1000) - maintc; 1436 maintc = (int)(MinFrameTime * 1000) - maintc;
1392 1437
1438
1439 m_lastUpdate = Util.EnvironmentTickCount();
1440 m_firstHeartbeat = false;
1441
1393 if (maintc > 0) 1442 if (maintc > 0)
1394 Thread.Sleep(maintc); 1443 Thread.Sleep(maintc);
1395 1444
1396 // Tell the watchdog that this thread is still alive 1445 // Tell the watchdog that this thread is still alive
1397 Watchdog.UpdateThread(); 1446 Watchdog.UpdateThread();
1398 } 1447 }
1399 1448
1400 public void AddGroupTarget(SceneObjectGroup grp) 1449 public void AddGroupTarget(SceneObjectGroup grp)
1401 { 1450 {
@@ -1411,9 +1460,9 @@ namespace OpenSim.Region.Framework.Scenes
1411 1460
1412 private void CheckAtTargets() 1461 private void CheckAtTargets()
1413 { 1462 {
1414 Dictionary<UUID, SceneObjectGroup>.ValueCollection objs; 1463 List<SceneObjectGroup> objs = new List<SceneObjectGroup>();
1415 lock (m_groupsWithTargets) 1464 lock (m_groupsWithTargets)
1416 objs = m_groupsWithTargets.Values; 1465 objs = new List<SceneObjectGroup>(m_groupsWithTargets.Values);
1417 1466
1418 foreach (SceneObjectGroup entry in objs) 1467 foreach (SceneObjectGroup entry in objs)
1419 entry.checkAtTargets(); 1468 entry.checkAtTargets();
@@ -1495,7 +1544,7 @@ namespace OpenSim.Region.Framework.Scenes
1495 msg.fromAgentName = "Server"; 1544 msg.fromAgentName = "Server";
1496 msg.dialog = (byte)19; // Object msg 1545 msg.dialog = (byte)19; // Object msg
1497 msg.fromGroup = false; 1546 msg.fromGroup = false;
1498 msg.offline = (byte)0; 1547 msg.offline = (byte)1;
1499 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID; 1548 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID;
1500 msg.Position = Vector3.Zero; 1549 msg.Position = Vector3.Zero;
1501 msg.RegionID = RegionInfo.RegionID.Guid; 1550 msg.RegionID = RegionInfo.RegionID.Guid;
@@ -1726,14 +1775,24 @@ namespace OpenSim.Region.Framework.Scenes
1726 /// <returns></returns> 1775 /// <returns></returns>
1727 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter) 1776 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1728 { 1777 {
1778
1779 float wheight = (float)RegionInfo.RegionSettings.WaterHeight;
1780 Vector3 wpos = Vector3.Zero;
1781 // Check for water surface intersection from above
1782 if ( (RayStart.Z > wheight) && (RayEnd.Z < wheight) )
1783 {
1784 float ratio = (RayStart.Z - wheight) / (RayStart.Z - RayEnd.Z);
1785 wpos.X = RayStart.X - (ratio * (RayStart.X - RayEnd.X));
1786 wpos.Y = RayStart.Y - (ratio * (RayStart.Y - RayEnd.Y));
1787 wpos.Z = wheight;
1788 }
1789
1729 Vector3 pos = Vector3.Zero; 1790 Vector3 pos = Vector3.Zero;
1730 if (RayEndIsIntersection == (byte)1) 1791 if (RayEndIsIntersection == (byte)1)
1731 { 1792 {
1732 pos = RayEnd; 1793 pos = RayEnd;
1733 return pos;
1734 } 1794 }
1735 1795 else if (RayTargetID != UUID.Zero)
1736 if (RayTargetID != UUID.Zero)
1737 { 1796 {
1738 SceneObjectPart target = GetSceneObjectPart(RayTargetID); 1797 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1739 1798
@@ -1755,7 +1814,7 @@ namespace OpenSim.Region.Framework.Scenes
1755 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter); 1814 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1756 1815
1757 // Un-comment out the following line to Get Raytrace results printed to the console. 1816 // Un-comment out the following line to Get Raytrace results printed to the console.
1758 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString()); 1817 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1759 float ScaleOffset = 0.5f; 1818 float ScaleOffset = 0.5f;
1760 1819
1761 // If we hit something 1820 // If we hit something
@@ -1778,13 +1837,10 @@ namespace OpenSim.Region.Framework.Scenes
1778 //pos.Z -= 0.25F; 1837 //pos.Z -= 0.25F;
1779 1838
1780 } 1839 }
1781
1782 return pos;
1783 } 1840 }
1784 else 1841 else
1785 { 1842 {
1786 // We don't have a target here, so we're going to raytrace all the objects in the scene. 1843 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1787
1788 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false); 1844 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1789 1845
1790 // Un-comment the following line to print the raytrace results to the console. 1846 // Un-comment the following line to print the raytrace results to the console.
@@ -1793,13 +1849,12 @@ namespace OpenSim.Region.Framework.Scenes
1793 if (ei.HitTF) 1849 if (ei.HitTF)
1794 { 1850 {
1795 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z); 1851 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1796 } else 1852 }
1853 else
1797 { 1854 {
1798 // fall back to our stupid functionality 1855 // fall back to our stupid functionality
1799 pos = RayEnd; 1856 pos = RayEnd;
1800 } 1857 }
1801
1802 return pos;
1803 } 1858 }
1804 } 1859 }
1805 else 1860 else
@@ -1810,8 +1865,12 @@ namespace OpenSim.Region.Framework.Scenes
1810 //increase height so its above the ground. 1865 //increase height so its above the ground.
1811 //should be getting the normal of the ground at the rez point and using that? 1866 //should be getting the normal of the ground at the rez point and using that?
1812 pos.Z += scale.Z / 2f; 1867 pos.Z += scale.Z / 2f;
1813 return pos; 1868// return pos;
1814 } 1869 }
1870
1871 // check against posible water intercept
1872 if (wpos.Z > pos.Z) pos = wpos;
1873 return pos;
1815 } 1874 }
1816 1875
1817 1876
@@ -1895,7 +1954,10 @@ namespace OpenSim.Region.Framework.Scenes
1895 public bool AddRestoredSceneObject( 1954 public bool AddRestoredSceneObject(
1896 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 1955 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
1897 { 1956 {
1898 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates); 1957 bool result = m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted, sendClientUpdates);
1958 if (result)
1959 sceneObject.IsDeleted = false;
1960 return result;
1899 } 1961 }
1900 1962
1901 /// <summary> 1963 /// <summary>
@@ -1987,6 +2049,15 @@ namespace OpenSim.Region.Framework.Scenes
1987 /// </summary> 2049 /// </summary>
1988 public void DeleteAllSceneObjects() 2050 public void DeleteAllSceneObjects()
1989 { 2051 {
2052 DeleteAllSceneObjects(false);
2053 }
2054
2055 /// <summary>
2056 /// Delete every object from the scene. This does not include attachments worn by avatars.
2057 /// </summary>
2058 public void DeleteAllSceneObjects(bool exceptNoCopy)
2059 {
2060 List<SceneObjectGroup> toReturn = new List<SceneObjectGroup>();
1990 lock (Entities) 2061 lock (Entities)
1991 { 2062 {
1992 EntityBase[] entities = Entities.GetEntities(); 2063 EntityBase[] entities = Entities.GetEntities();
@@ -1995,11 +2066,24 @@ namespace OpenSim.Region.Framework.Scenes
1995 if (e is SceneObjectGroup) 2066 if (e is SceneObjectGroup)
1996 { 2067 {
1997 SceneObjectGroup sog = (SceneObjectGroup)e; 2068 SceneObjectGroup sog = (SceneObjectGroup)e;
1998 if (!sog.IsAttachment) 2069 if (sog != null && !sog.IsAttachment)
1999 DeleteSceneObject((SceneObjectGroup)e, false); 2070 {
2071 if (!exceptNoCopy || ((sog.GetEffectivePermissions() & (uint)PermissionMask.Copy) != 0))
2072 {
2073 DeleteSceneObject((SceneObjectGroup)e, false);
2074 }
2075 else
2076 {
2077 toReturn.Add((SceneObjectGroup)e);
2078 }
2079 }
2000 } 2080 }
2001 } 2081 }
2002 } 2082 }
2083 if (toReturn.Count > 0)
2084 {
2085 returnObjects(toReturn.ToArray(), UUID.Zero);
2086 }
2003 } 2087 }
2004 2088
2005 /// <summary> 2089 /// <summary>
@@ -2047,6 +2131,8 @@ namespace OpenSim.Region.Framework.Scenes
2047 } 2131 }
2048 2132
2049 group.DeleteGroupFromScene(silent); 2133 group.DeleteGroupFromScene(silent);
2134 if (!silent)
2135 SendKillObject(new List<uint>() { group.LocalId });
2050 2136
2051// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); 2137// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID);
2052 } 2138 }
@@ -2401,10 +2487,17 @@ namespace OpenSim.Region.Framework.Scenes
2401 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns> 2487 /// <returns>True if the SceneObjectGroup was added, False if it was not</returns>
2402 public bool AddSceneObject(SceneObjectGroup sceneObject) 2488 public bool AddSceneObject(SceneObjectGroup sceneObject)
2403 { 2489 {
2490 if (sceneObject.OwnerID == UUID.Zero)
2491 {
2492 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero", sceneObject.UUID);
2493 return false;
2494 }
2495
2404 // If the user is banned, we won't let any of their objects 2496 // If the user is banned, we won't let any of their objects
2405 // enter. Period. 2497 // enter. Period.
2406 // 2498 //
2407 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID)) 2499 int flags = GetUserFlags(sceneObject.OwnerID);
2500 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID, flags))
2408 { 2501 {
2409 m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", sceneObject.OwnerID); 2502 m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", sceneObject.OwnerID);
2410 2503
@@ -2450,12 +2543,23 @@ namespace OpenSim.Region.Framework.Scenes
2450 } 2543 }
2451 else 2544 else
2452 { 2545 {
2546 m_log.DebugFormat("[SCENE]: Attachment {0} arrived and scene presence was not found, setting to temp", sceneObject.UUID);
2453 RootPrim.RemFlag(PrimFlags.TemporaryOnRez); 2547 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2454 RootPrim.AddFlag(PrimFlags.TemporaryOnRez); 2548 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2455 } 2549 }
2550 if (sceneObject.OwnerID == UUID.Zero)
2551 {
2552 m_log.ErrorFormat("[SCENE]: Owner ID for {0} was zero after attachment processing. BUG!", sceneObject.UUID);
2553 return false;
2554 }
2456 } 2555 }
2457 else 2556 else
2458 { 2557 {
2558 if (sceneObject.OwnerID == UUID.Zero)
2559 {
2560 m_log.ErrorFormat("[SCENE]: Owner ID for non-attachment {0} was zero", sceneObject.UUID);
2561 return false;
2562 }
2459 AddRestoredSceneObject(sceneObject, true, false); 2563 AddRestoredSceneObject(sceneObject, true, false);
2460 2564
2461 if (!Permissions.CanObjectEntry(sceneObject.UUID, 2565 if (!Permissions.CanObjectEntry(sceneObject.UUID,
@@ -2484,6 +2588,24 @@ namespace OpenSim.Region.Framework.Scenes
2484 return 2; // StateSource.PrimCrossing 2588 return 2; // StateSource.PrimCrossing
2485 } 2589 }
2486 2590
2591 public int GetUserFlags(UUID user)
2592 {
2593 //Unfortunately the SP approach means that the value is cached until region is restarted
2594 /*
2595 ScenePresence sp;
2596 if (TryGetScenePresence(user, out sp))
2597 {
2598 return sp.UserFlags;
2599 }
2600 else
2601 {
2602 */
2603 UserAccount uac = UserAccountService.GetUserAccount(RegionInfo.ScopeID, user);
2604 if (uac == null)
2605 return 0;
2606 return uac.UserFlags;
2607 //}
2608 }
2487 #endregion 2609 #endregion
2488 2610
2489 #region Add/Remove Avatar Methods 2611 #region Add/Remove Avatar Methods
@@ -2498,6 +2620,7 @@ namespace OpenSim.Region.Framework.Scenes
2498 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; 2620 || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0;
2499 2621
2500 CheckHeartbeat(); 2622 CheckHeartbeat();
2623 ScenePresence presence;
2501 2624
2502 ScenePresence sp = GetScenePresence(client.AgentId); 2625 ScenePresence sp = GetScenePresence(client.AgentId);
2503 2626
@@ -2546,7 +2669,13 @@ namespace OpenSim.Region.Framework.Scenes
2546 2669
2547 EventManager.TriggerOnNewClient(client); 2670 EventManager.TriggerOnNewClient(client);
2548 if (vialogin) 2671 if (vialogin)
2672 {
2549 EventManager.TriggerOnClientLogin(client); 2673 EventManager.TriggerOnClientLogin(client);
2674 // Send initial parcel data
2675 Vector3 pos = sp.AbsolutePosition;
2676 ILandObject land = LandChannel.GetLandObject(pos.X, pos.Y);
2677 land.SendLandUpdateToClient(client);
2678 }
2550 2679
2551 return sp; 2680 return sp;
2552 } 2681 }
@@ -2636,19 +2765,12 @@ namespace OpenSim.Region.Framework.Scenes
2636 // and the scene presence and the client, if they exist 2765 // and the scene presence and the client, if they exist
2637 try 2766 try
2638 { 2767 {
2639 // We need to wait for the client to make UDP contact first. 2768 ScenePresence sp = GetScenePresence(agentID);
2640 // It's the UDP contact that creates the scene presence 2769 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2641 ScenePresence sp = WaitGetScenePresence(agentID); 2770
2642 if (sp != null) 2771 if (sp != null)
2643 {
2644 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2645
2646 sp.ControllingClient.Close(); 2772 sp.ControllingClient.Close();
2647 } 2773
2648 else
2649 {
2650 m_log.WarnFormat("[SCENE]: Could not find scene presence for {0}", agentID);
2651 }
2652 // BANG! SLASH! 2774 // BANG! SLASH!
2653 m_authenticateHandler.RemoveCircuit(agentID); 2775 m_authenticateHandler.RemoveCircuit(agentID);
2654 2776
@@ -2749,6 +2871,7 @@ namespace OpenSim.Region.Framework.Scenes
2749 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory; 2871 client.OnFetchInventory += m_asyncInventorySender.HandleFetchInventory;
2750 client.OnUpdateInventoryItem += UpdateInventoryItemAsset; 2872 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2751 client.OnCopyInventoryItem += CopyInventoryItem; 2873 client.OnCopyInventoryItem += CopyInventoryItem;
2874 client.OnMoveItemsAndLeaveCopy += MoveInventoryItemsLeaveCopy;
2752 client.OnMoveInventoryItem += MoveInventoryItem; 2875 client.OnMoveInventoryItem += MoveInventoryItem;
2753 client.OnRemoveInventoryItem += RemoveInventoryItem; 2876 client.OnRemoveInventoryItem += RemoveInventoryItem;
2754 client.OnRemoveInventoryFolder += RemoveInventoryFolder; 2877 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
@@ -2924,15 +3047,16 @@ namespace OpenSim.Region.Framework.Scenes
2924 /// </summary> 3047 /// </summary>
2925 /// <param name="agentId">The avatar's Unique ID</param> 3048 /// <param name="agentId">The avatar's Unique ID</param>
2926 /// <param name="client">The IClientAPI for the client</param> 3049 /// <param name="client">The IClientAPI for the client</param>
2927 public virtual void TeleportClientHome(UUID agentId, IClientAPI client) 3050 public virtual bool TeleportClientHome(UUID agentId, IClientAPI client)
2928 { 3051 {
2929 if (m_teleportModule != null) 3052 if (m_teleportModule != null)
2930 m_teleportModule.TeleportHome(agentId, client); 3053 return m_teleportModule.TeleportHome(agentId, client);
2931 else 3054 else
2932 { 3055 {
2933 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); 3056 m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active");
2934 client.SendTeleportFailed("Unable to perform teleports on this simulator."); 3057 client.SendTeleportFailed("Unable to perform teleports on this simulator.");
2935 } 3058 }
3059 return false;
2936 } 3060 }
2937 3061
2938 /// <summary> 3062 /// <summary>
@@ -3042,6 +3166,16 @@ namespace OpenSim.Region.Framework.Scenes
3042 /// <param name="flags"></param> 3166 /// <param name="flags"></param>
3043 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) 3167 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
3044 { 3168 {
3169 //Add half the avatar's height so that the user doesn't fall through prims
3170 ScenePresence presence;
3171 if (TryGetScenePresence(remoteClient.AgentId, out presence))
3172 {
3173 if (presence.Appearance != null)
3174 {
3175 position.Z = position.Z + (presence.Appearance.AvatarHeight / 2);
3176 }
3177 }
3178
3045 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) 3179 if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt))
3046 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. 3180 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
3047 m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); 3181 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
@@ -3110,8 +3244,9 @@ namespace OpenSim.Region.Framework.Scenes
3110 regions.Remove(RegionInfo.RegionHandle); 3244 regions.Remove(RegionInfo.RegionHandle);
3111 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); 3245 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
3112 } 3246 }
3113 3247 m_log.Debug("[Scene] Beginning ClientClosed");
3114 m_eventManager.TriggerClientClosed(agentID, this); 3248 m_eventManager.TriggerClientClosed(agentID, this);
3249 m_log.Debug("[Scene] Finished ClientClosed");
3115 } 3250 }
3116 catch (NullReferenceException) 3251 catch (NullReferenceException)
3117 { 3252 {
@@ -3173,9 +3308,10 @@ namespace OpenSim.Region.Framework.Scenes
3173 { 3308 {
3174 m_log.ErrorFormat("[SCENE] Scene.cs:RemoveClient exception {0}{1}", e.Message, e.StackTrace); 3309 m_log.ErrorFormat("[SCENE] Scene.cs:RemoveClient exception {0}{1}", e.Message, e.StackTrace);
3175 } 3310 }
3176 3311 m_log.Debug("[Scene] Done. Firing RemoveCircuit");
3177 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); 3312 m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode);
3178// CleanDroppedAttachments(); 3313// CleanDroppedAttachments();
3314 m_log.Debug("[Scene] The avatar has left the building");
3179 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); 3315 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
3180 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); 3316 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
3181 } 3317 }
@@ -3294,13 +3430,16 @@ namespace OpenSim.Region.Framework.Scenes
3294 sp = null; 3430 sp = null;
3295 } 3431 }
3296 3432
3297 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3298 3433
3299 //On login test land permisions 3434 //On login test land permisions
3300 if (vialogin) 3435 if (vialogin)
3301 { 3436 {
3302 if (land != null && !TestLandRestrictions(agent, land, out reason)) 3437 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
3438 if (cache != null)
3439 cache.Remove(agent.firstname + " " + agent.lastname);
3440 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y))
3303 { 3441 {
3442 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString());
3304 return false; 3443 return false;
3305 } 3444 }
3306 } 3445 }
@@ -3324,8 +3463,13 @@ namespace OpenSim.Region.Framework.Scenes
3324 3463
3325 try 3464 try
3326 { 3465 {
3327 if (!AuthorizeUser(agent, out reason)) 3466 // Always check estate if this is a login. Always
3328 return false; 3467 // check if banned regions are to be blacked out.
3468 if (vialogin || (!m_seeIntoBannedRegion))
3469 {
3470 if (!AuthorizeUser(agent, out reason))
3471 return false;
3472 }
3329 } 3473 }
3330 catch (Exception e) 3474 catch (Exception e)
3331 { 3475 {
@@ -3428,6 +3572,8 @@ namespace OpenSim.Region.Framework.Scenes
3428 } 3572 }
3429 } 3573 }
3430 // Honor parcel landing type and position. 3574 // Honor parcel landing type and position.
3575 /*
3576 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
3431 if (land != null) 3577 if (land != null)
3432 { 3578 {
3433 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3579 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
@@ -3435,26 +3581,34 @@ namespace OpenSim.Region.Framework.Scenes
3435 agent.startpos = land.LandData.UserLocation; 3581 agent.startpos = land.LandData.UserLocation;
3436 } 3582 }
3437 } 3583 }
3584 */// This is now handled properly in ScenePresence.MakeRootAgent
3438 } 3585 }
3439 3586
3440 return true; 3587 return true;
3441 } 3588 }
3442 3589
3443 private bool TestLandRestrictions(AgentCircuitData agent, ILandObject land, out string reason) 3590 public bool TestLandRestrictions(UUID agentID, out string reason, ref float posX, ref float posY)
3444 { 3591 {
3445 3592 reason = String.Empty;
3446 bool banned = land.IsBannedFromLand(agent.AgentID); 3593 if (Permissions.IsGod(agentID))
3447 bool restricted = land.IsRestrictedFromLand(agent.AgentID); 3594 return true;
3595
3596 ILandObject land = LandChannel.GetLandObject(posX, posY);
3597 if (land == null)
3598 return false;
3599
3600 bool banned = land.IsBannedFromLand(agentID);
3601 bool restricted = land.IsRestrictedFromLand(agentID);
3448 3602
3449 if (banned || restricted) 3603 if (banned || restricted)
3450 { 3604 {
3451 ILandObject nearestParcel = GetNearestAllowedParcel(agent.AgentID, agent.startpos.X, agent.startpos.Y); 3605 ILandObject nearestParcel = GetNearestAllowedParcel(agentID, posX, posY);
3452 if (nearestParcel != null) 3606 if (nearestParcel != null)
3453 { 3607 {
3454 //Move agent to nearest allowed 3608 //Move agent to nearest allowed
3455 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel); 3609 Vector3 newPosition = GetParcelCenterAtGround(nearestParcel);
3456 agent.startpos.X = newPosition.X; 3610 posX = newPosition.X;
3457 agent.startpos.Y = newPosition.Y; 3611 posY = newPosition.Y;
3458 } 3612 }
3459 else 3613 else
3460 { 3614 {
@@ -3516,7 +3670,7 @@ namespace OpenSim.Region.Framework.Scenes
3516 3670
3517 if (!m_strictAccessControl) return true; 3671 if (!m_strictAccessControl) return true;
3518 if (Permissions.IsGod(agent.AgentID)) return true; 3672 if (Permissions.IsGod(agent.AgentID)) return true;
3519 3673
3520 if (AuthorizationService != null) 3674 if (AuthorizationService != null)
3521 { 3675 {
3522 if (!AuthorizationService.IsAuthorizedForRegion( 3676 if (!AuthorizationService.IsAuthorizedForRegion(
@@ -3524,14 +3678,14 @@ namespace OpenSim.Region.Framework.Scenes
3524 { 3678 {
3525 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region", 3679 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the region",
3526 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3680 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
3527 3681
3528 return false; 3682 return false;
3529 } 3683 }
3530 } 3684 }
3531 3685
3532 if (m_regInfo.EstateSettings != null) 3686 if (m_regInfo.EstateSettings != null)
3533 { 3687 {
3534 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID)) 3688 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID,0))
3535 { 3689 {
3536 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", 3690 m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist",
3537 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); 3691 agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName);
@@ -3723,6 +3877,13 @@ namespace OpenSim.Region.Framework.Scenes
3723 3877
3724 // We have to wait until the viewer contacts this region after receiving EAC. 3878 // We have to wait until the viewer contacts this region after receiving EAC.
3725 // That calls AddNewClient, which finally creates the ScenePresence 3879 // That calls AddNewClient, which finally creates the ScenePresence
3880 int flags = GetUserFlags(cAgentData.AgentID);
3881 if (m_regInfo.EstateSettings.IsBanned(cAgentData.AgentID, flags))
3882 {
3883 m_log.DebugFormat("[SCENE]: Denying root agent entry to {0}: banned", cAgentData.AgentID);
3884 return false;
3885 }
3886
3726 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); 3887 ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
3727 if (nearestParcel == null) 3888 if (nearestParcel == null)
3728 { 3889 {
@@ -3804,12 +3965,22 @@ namespace OpenSim.Region.Framework.Scenes
3804 return false; 3965 return false;
3805 } 3966 }
3806 3967
3968 public bool IncomingCloseAgent(UUID agentID)
3969 {
3970 return IncomingCloseAgent(agentID, false);
3971 }
3972
3973 public bool IncomingCloseChildAgent(UUID agentID)
3974 {
3975 return IncomingCloseAgent(agentID, true);
3976 }
3977
3807 /// <summary> 3978 /// <summary>
3808 /// Tell a single agent to disconnect from the region. 3979 /// Tell a single agent to disconnect from the region.
3809 /// </summary> 3980 /// </summary>
3810 /// <param name="regionHandle"></param>
3811 /// <param name="agentID"></param> 3981 /// <param name="agentID"></param>
3812 public bool IncomingCloseAgent(UUID agentID) 3982 /// <param name="childOnly"></param>
3983 public bool IncomingCloseAgent(UUID agentID, bool childOnly)
3813 { 3984 {
3814 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 3985 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
3815 3986
@@ -3821,7 +3992,7 @@ namespace OpenSim.Region.Framework.Scenes
3821 { 3992 {
3822 m_sceneGraph.removeUserCount(false); 3993 m_sceneGraph.removeUserCount(false);
3823 } 3994 }
3824 else 3995 else if (!childOnly)
3825 { 3996 {
3826 m_sceneGraph.removeUserCount(true); 3997 m_sceneGraph.removeUserCount(true);
3827 } 3998 }
@@ -3837,9 +4008,12 @@ namespace OpenSim.Region.Framework.Scenes
3837 } 4008 }
3838 else 4009 else
3839 presence.ControllingClient.SendShutdownConnectionNotice(); 4010 presence.ControllingClient.SendShutdownConnectionNotice();
4011 presence.ControllingClient.Close(false);
4012 }
4013 else if (!childOnly)
4014 {
4015 presence.ControllingClient.Close(true);
3840 } 4016 }
3841
3842 presence.ControllingClient.Close();
3843 return true; 4017 return true;
3844 } 4018 }
3845 4019
@@ -4432,34 +4606,78 @@ namespace OpenSim.Region.Framework.Scenes
4432 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID); 4606 SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID);
4433 } 4607 }
4434 4608
4435 public int GetHealth() 4609 public int GetHealth(out int flags, out string message)
4436 { 4610 {
4437 // Returns: 4611 // Returns:
4438 // 1 = sim is up and accepting http requests. The heartbeat has 4612 // 1 = sim is up and accepting http requests. The heartbeat has
4439 // stopped and the sim is probably locked up, but a remote 4613 // stopped and the sim is probably locked up, but a remote
4440 // admin restart may succeed 4614 // admin restart may succeed
4441 // 4615 //
4442 // 2 = Sim is up and the heartbeat is running. The sim is likely 4616 // 2 = Sim is up and the heartbeat is running. The sim is likely
4443 // usable for people within and logins _may_ work 4617 // usable for people within
4618 //
4619 // 3 = Sim is up and one packet thread is running. Sim is
4620 // unstable and will not accept new logins
4621 //
4622 // 4 = Sim is up and both packet threads are running. Sim is
4623 // likely usable
4444 // 4624 //
4445 // 3 = We have seen a new user enter within the past 4 minutes 4625 // 5 = We have seen a new user enter within the past 4 minutes
4446 // which can be seen as positive confirmation of sim health 4626 // which can be seen as positive confirmation of sim health
4447 // 4627 //
4628
4629 flags = 0;
4630 message = String.Empty;
4631
4632 CheckHeartbeat();
4633
4634 if (m_firstHeartbeat || (m_lastIncoming == 0 && m_lastOutgoing == 0))
4635 {
4636 // We're still starting
4637 // 0 means "in startup", it can't happen another way, since
4638 // to get here, we must be able to accept http connections
4639 return 0;
4640 }
4641
4448 int health=1; // Start at 1, means we're up 4642 int health=1; // Start at 1, means we're up
4449 4643
4450 if ((Util.EnvironmentTickCountSubtract(m_lastUpdate)) < 1000) 4644 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) < 1000)
4645 {
4646 health+=1;
4647 flags |= 1;
4648 }
4649
4650 if (Util.EnvironmentTickCountSubtract(m_lastIncoming) < 1000)
4651 {
4652 health+=1;
4653 flags |= 2;
4654 }
4655
4656 if (Util.EnvironmentTickCountSubtract(m_lastOutgoing) < 1000)
4657 {
4451 health+=1; 4658 health+=1;
4659 flags |= 4;
4660 }
4452 else 4661 else
4662 {
4663int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
4664System.Diagnostics.Process proc = new System.Diagnostics.Process();
4665proc.EnableRaisingEvents=false;
4666proc.StartInfo.FileName = "/bin/kill";
4667proc.StartInfo.Arguments = "-QUIT " + pid.ToString();
4668proc.Start();
4669proc.WaitForExit();
4670Thread.Sleep(1000);
4671Environment.Exit(1);
4672 }
4673
4674 if (flags != 7)
4453 return health; 4675 return health;
4454 4676
4455 // A login in the last 4 mins? We can't be doing too badly 4677 // A login in the last 4 mins? We can't be doing too badly
4456 // 4678 //
4457 if ((Util.EnvironmentTickCountSubtract(m_LastLogin)) < 240000) 4679 if (Util.EnvironmentTickCountSubtract(m_LastLogin) < 240000)
4458 health++; 4680 health++;
4459 else
4460 return health;
4461
4462 CheckHeartbeat();
4463 4681
4464 return health; 4682 return health;
4465 } 4683 }
@@ -4652,7 +4870,7 @@ namespace OpenSim.Region.Framework.Scenes
4652 if (m_firstHeartbeat) 4870 if (m_firstHeartbeat)
4653 return; 4871 return;
4654 4872
4655 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) > 2000) 4873 if (Util.EnvironmentTickCountSubtract(m_lastUpdate) > 5000)
4656 StartTimer(); 4874 StartTimer();
4657 } 4875 }
4658 4876
@@ -4666,9 +4884,14 @@ namespace OpenSim.Region.Framework.Scenes
4666 get { return m_allowScriptCrossings; } 4884 get { return m_allowScriptCrossings; }
4667 } 4885 }
4668 4886
4669 public Vector3? GetNearestAllowedPosition(ScenePresence avatar) 4887 public Vector3 GetNearestAllowedPosition(ScenePresence avatar)
4888 {
4889 return GetNearestAllowedPosition(avatar, null);
4890 }
4891
4892 public Vector3 GetNearestAllowedPosition(ScenePresence avatar, ILandObject excludeParcel)
4670 { 4893 {
4671 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 4894 ILandObject nearestParcel = GetNearestAllowedParcel(avatar.UUID, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, excludeParcel);
4672 4895
4673 if (nearestParcel != null) 4896 if (nearestParcel != null)
4674 { 4897 {
@@ -4727,13 +4950,18 @@ namespace OpenSim.Region.Framework.Scenes
4727 4950
4728 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y) 4951 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y)
4729 { 4952 {
4953 return GetNearestAllowedParcel(avatarId, x, y, null);
4954 }
4955
4956 public ILandObject GetNearestAllowedParcel(UUID avatarId, float x, float y, ILandObject excludeParcel)
4957 {
4730 List<ILandObject> all = AllParcels(); 4958 List<ILandObject> all = AllParcels();
4731 float minParcelDistance = float.MaxValue; 4959 float minParcelDistance = float.MaxValue;
4732 ILandObject nearestParcel = null; 4960 ILandObject nearestParcel = null;
4733 4961
4734 foreach (var parcel in all) 4962 foreach (var parcel in all)
4735 { 4963 {
4736 if (!parcel.IsEitherBannedOrRestricted(avatarId)) 4964 if (!parcel.IsEitherBannedOrRestricted(avatarId) && parcel != excludeParcel)
4737 { 4965 {
4738 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y); 4966 float parcelDistance = GetParcelDistancefromPoint(parcel, x, y);
4739 if (parcelDistance < minParcelDistance) 4967 if (parcelDistance < minParcelDistance)
@@ -4975,7 +5203,55 @@ namespace OpenSim.Region.Framework.Scenes
4975 mapModule.GenerateMaptile(); 5203 mapModule.GenerateMaptile();
4976 } 5204 }
4977 5205
4978 private void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e) 5206// public void CleanDroppedAttachments()
5207// {
5208// List<SceneObjectGroup> objectsToDelete =
5209// new List<SceneObjectGroup>();
5210//
5211// lock (m_cleaningAttachments)
5212// {
5213// ForEachSOG(delegate (SceneObjectGroup grp)
5214// {
5215// if (grp.RootPart.Shape.PCode == 0 && grp.RootPart.Shape.State != 0 && (!objectsToDelete.Contains(grp)))
5216// {
5217// UUID agentID = grp.OwnerID;
5218// if (agentID == UUID.Zero)
5219// {
5220// objectsToDelete.Add(grp);
5221// return;
5222// }
5223//
5224// ScenePresence sp = GetScenePresence(agentID);
5225// if (sp == null)
5226// {
5227// objectsToDelete.Add(grp);
5228// return;
5229// }
5230// }
5231// });
5232// }
5233//
5234// foreach (SceneObjectGroup grp in objectsToDelete)
5235// {
5236// m_log.InfoFormat("[SCENE]: Deleting dropped attachment {0} of user {1}", grp.UUID, grp.OwnerID);
5237// DeleteSceneObject(grp, true);
5238// }
5239// }
5240
5241 public void ThreadAlive(int threadCode)
5242 {
5243 switch(threadCode)
5244 {
5245 case 1: // Incoming
5246 m_lastIncoming = Util.EnvironmentTickCount();
5247 break;
5248 case 2: // Incoming
5249 m_lastOutgoing = Util.EnvironmentTickCount();
5250 break;
5251 }
5252 }
5253
5254 public void RegenerateMaptileAndReregister(object sender, ElapsedEventArgs e)
4979 { 5255 {
4980 RegenerateMaptile(); 5256 RegenerateMaptile();
4981 5257
@@ -4994,6 +5270,14 @@ namespace OpenSim.Region.Framework.Scenes
4994 // child agent creation, thereby emulating the SL behavior. 5270 // child agent creation, thereby emulating the SL behavior.
4995 public bool QueryAccess(UUID agentID, Vector3 position, out string reason) 5271 public bool QueryAccess(UUID agentID, Vector3 position, out string reason)
4996 { 5272 {
5273 reason = "You are banned from the region";
5274
5275 if (Permissions.IsGod(agentID))
5276 {
5277 reason = String.Empty;
5278 return true;
5279 }
5280
4997 int num = m_sceneGraph.GetNumberOfScenePresences(); 5281 int num = m_sceneGraph.GetNumberOfScenePresences();
4998 5282
4999 if (num >= RegionInfo.RegionSettings.AgentLimit) 5283 if (num >= RegionInfo.RegionSettings.AgentLimit)
@@ -5005,6 +5289,41 @@ namespace OpenSim.Region.Framework.Scenes
5005 } 5289 }
5006 } 5290 }
5007 5291
5292 ScenePresence presence = GetScenePresence(agentID);
5293 IClientAPI client = null;
5294 AgentCircuitData aCircuit = null;
5295
5296 if (presence != null)
5297 {
5298 client = presence.ControllingClient;
5299 if (client != null)
5300 aCircuit = client.RequestClientInfo();
5301 }
5302
5303 // We may be called before there is a presence or a client.
5304 // Fake AgentCircuitData to keep IAuthorizationModule smiling
5305 if (client == null)
5306 {
5307 aCircuit = new AgentCircuitData();
5308 aCircuit.AgentID = agentID;
5309 aCircuit.firstname = String.Empty;
5310 aCircuit.lastname = String.Empty;
5311 }
5312
5313 try
5314 {
5315 if (!AuthorizeUser(aCircuit, out reason))
5316 {
5317 // m_log.DebugFormat("[SCENE]: Denying access for {0}", agentID);
5318 return false;
5319 }
5320 }
5321 catch (Exception e)
5322 {
5323 m_log.DebugFormat("[SCENE]: Exception authorizing agent: {0} "+ e.StackTrace, e.Message);
5324 return false;
5325 }
5326
5008 if (position == Vector3.Zero) // Teleport 5327 if (position == Vector3.Zero) // Teleport
5009 { 5328 {
5010 if (!RegionInfo.EstateSettings.AllowDirectTeleport) 5329 if (!RegionInfo.EstateSettings.AllowDirectTeleport)
@@ -5033,13 +5352,46 @@ namespace OpenSim.Region.Framework.Scenes
5033 } 5352 }
5034 } 5353 }
5035 } 5354 }
5355
5356 float posX = 128.0f;
5357 float posY = 128.0f;
5358
5359 if (!TestLandRestrictions(agentID, out reason, ref posX, ref posY))
5360 {
5361 // m_log.DebugFormat("[SCENE]: Denying {0} because they are banned on all parcels", agentID);
5362 return false;
5363 }
5364 }
5365 else // Walking
5366 {
5367 ILandObject land = LandChannel.GetLandObject(position.X, position.Y);
5368 if (land == null)
5369 return false;
5370
5371 bool banned = land.IsBannedFromLand(agentID);
5372 bool restricted = land.IsRestrictedFromLand(agentID);
5373
5374 if (banned || restricted)
5375 return false;
5036 } 5376 }
5037 5377
5038 reason = String.Empty; 5378 reason = String.Empty;
5039 return true; 5379 return true;
5040 } 5380 }
5041 5381
5042 /// <summary> 5382 public void StartTimerWatchdog()
5383 {
5384 m_timerWatchdog.Interval = 1000;
5385 m_timerWatchdog.Elapsed += TimerWatchdog;
5386 m_timerWatchdog.AutoReset = true;
5387 m_timerWatchdog.Start();
5388 }
5389
5390 public void TimerWatchdog(object sender, ElapsedEventArgs e)
5391 {
5392 CheckHeartbeat();
5393 }
5394
5043 /// This method deals with movement when an avatar is automatically moving (but this is distinct from the 5395 /// This method deals with movement when an avatar is automatically moving (but this is distinct from the
5044 /// autopilot that moves an avatar to a sit target!. 5396 /// autopilot that moves an avatar to a sit target!.
5045 /// </summary> 5397 /// </summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
index 712e094..da3b4dd 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 58a7b20..27833e8 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes
88 88
89 if (neighbour != null) 89 if (neighbour != null)
90 { 90 {
91 m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize); 91 // m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize);
92 m_scene.EventManager.TriggerOnRegionUp(neighbour); 92 m_scene.EventManager.TriggerOnRegionUp(neighbour);
93 } 93 }
94 else 94 else
@@ -102,7 +102,7 @@ namespace OpenSim.Region.Framework.Scenes
102 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName); 102 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName);
103 103
104 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); 104 List<GridRegion> neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID);
105 m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count); 105 //m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count);
106 foreach (GridRegion n in neighbours) 106 foreach (GridRegion n in neighbours)
107 { 107 {
108 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync; 108 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
@@ -176,10 +176,13 @@ namespace OpenSim.Region.Framework.Scenes
176 } 176 }
177 } 177 }
178 178
179 public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle);
180
179 /// <summary> 181 /// <summary>
180 /// Closes a child agent on a given region 182 /// This Closes child agents on neighboring regions
183 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
181 /// </summary> 184 /// </summary>
182 protected void SendCloseChildAgent(UUID agentID, ulong regionHandle) 185 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
183 { 186 {
184 // let's do our best, but there's not much we can do if the neighbour doesn't accept. 187 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
185 188
@@ -188,31 +191,29 @@ namespace OpenSim.Region.Framework.Scenes
188 Utils.LongToUInts(regionHandle, out x, out y); 191 Utils.LongToUInts(regionHandle, out x, out y);
189 192
190 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 193 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
194 m_scene.SimulationService.CloseChildAgent(destination, agentID);
195 }
191 196
192 m_log.DebugFormat( 197 private void SendCloseChildAgentCompleted(IAsyncResult iar)
193 "[INTERGRID]: Sending close agent {0} to region at {1}-{2}", 198 {
194 agentID, destination.RegionCoordX, destination.RegionCoordY); 199 SendCloseChildAgentDelegate icon = (SendCloseChildAgentDelegate)iar.AsyncState;
195 200 icon.EndInvoke(iar);
196 m_scene.SimulationService.CloseAgent(destination, agentID);
197 } 201 }
198 202
199 /// <summary>
200 /// Closes a child agents in a collection of regions. Does so asynchronously
201 /// so that the caller doesn't wait.
202 /// </summary>
203 /// <param name="agentID"></param>
204 /// <param name="regionslst"></param>
205 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst) 203 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst)
206 { 204 {
207 foreach (ulong handle in regionslst) 205 foreach (ulong handle in regionslst)
208 { 206 {
209 SendCloseChildAgent(agentID, handle); 207 SendCloseChildAgentDelegate d = SendCloseChildAgentAsync;
208 d.BeginInvoke(agentID, handle,
209 SendCloseChildAgentCompleted,
210 d);
210 } 211 }
211 } 212 }
212 213
213 public List<GridRegion> RequestNamedRegions(string name, int maxNumber) 214 public List<GridRegion> RequestNamedRegions(string name, int maxNumber)
214 { 215 {
215 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); 216 return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber);
216 } 217 }
217 } 218 }
218} \ No newline at end of file 219}
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 7d801b5..17563bd 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -41,6 +41,12 @@ namespace OpenSim.Region.Framework.Scenes
41{ 41{
42 public delegate void PhysicsCrash(); 42 public delegate void PhysicsCrash();
43 43
44 public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
45
46 public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
47
48 public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
49
44 /// <summary> 50 /// <summary>
45 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components 51 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
46 /// should be migrated out over time. 52 /// should be migrated out over time.
@@ -54,11 +60,15 @@ namespace OpenSim.Region.Framework.Scenes
54 protected internal event PhysicsCrash UnRecoverableError; 60 protected internal event PhysicsCrash UnRecoverableError;
55 private PhysicsCrash handlerPhysicsCrash = null; 61 private PhysicsCrash handlerPhysicsCrash = null;
56 62
63 public event AttachToBackupDelegate OnAttachToBackup;
64 public event DetachFromBackupDelegate OnDetachFromBackup;
65 public event ChangedBackupDelegate OnChangeBackup;
66
57 #endregion 67 #endregion
58 68
59 #region Fields 69 #region Fields
60 70
61 protected object m_presenceLock = new object(); 71 protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
62 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>(); 72 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
63 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>(); 73 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
64 74
@@ -120,13 +130,18 @@ namespace OpenSim.Region.Framework.Scenes
120 130
121 protected internal void Close() 131 protected internal void Close()
122 { 132 {
123 lock (m_presenceLock) 133 m_scenePresencesLock.EnterWriteLock();
134 try
124 { 135 {
125 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(); 136 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
126 List<ScenePresence> newlist = new List<ScenePresence>(); 137 List<ScenePresence> newlist = new List<ScenePresence>();
127 m_scenePresenceMap = newmap; 138 m_scenePresenceMap = newmap;
128 m_scenePresenceArray = newlist; 139 m_scenePresenceArray = newlist;
129 } 140 }
141 finally
142 {
143 m_scenePresencesLock.ExitWriteLock();
144 }
130 145
131 lock (SceneObjectGroupsByFullID) 146 lock (SceneObjectGroupsByFullID)
132 SceneObjectGroupsByFullID.Clear(); 147 SceneObjectGroupsByFullID.Clear();
@@ -265,6 +280,33 @@ namespace OpenSim.Region.Framework.Scenes
265 protected internal bool AddRestoredSceneObject( 280 protected internal bool AddRestoredSceneObject(
266 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) 281 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
267 { 282 {
283 if (!m_parentScene.CombineRegions)
284 {
285 // KF: Check for out-of-region, move inside and make static.
286 Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
287 sceneObject.RootPart.GroupPosition.Y,
288 sceneObject.RootPart.GroupPosition.Z);
289 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 ||
290 npos.X > Constants.RegionSize ||
291 npos.Y > Constants.RegionSize))
292 {
293 if (npos.X < 0.0) npos.X = 1.0f;
294 if (npos.Y < 0.0) npos.Y = 1.0f;
295 if (npos.Z < 0.0) npos.Z = 0.0f;
296 if (npos.X > Constants.RegionSize) npos.X = Constants.RegionSize - 1.0f;
297 if (npos.Y > Constants.RegionSize) npos.Y = Constants.RegionSize - 1.0f;
298
299 foreach (SceneObjectPart part in sceneObject.Parts)
300 {
301 part.GroupPosition = npos;
302 }
303 sceneObject.RootPart.Velocity = Vector3.Zero;
304 sceneObject.RootPart.AngularVelocity = Vector3.Zero;
305 sceneObject.RootPart.Acceleration = Vector3.Zero;
306 sceneObject.RootPart.Velocity = Vector3.Zero;
307 }
308 }
309
268 if (attachToBackup && (!alreadyPersisted)) 310 if (attachToBackup && (!alreadyPersisted))
269 { 311 {
270 sceneObject.ForceInventoryPersistence(); 312 sceneObject.ForceInventoryPersistence();
@@ -354,6 +396,11 @@ namespace OpenSim.Region.Framework.Scenes
354 /// </returns> 396 /// </returns>
355 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) 397 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
356 { 398 {
399 if (sceneObject == null)
400 {
401 m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object");
402 return false;
403 }
357 if (sceneObject.UUID == UUID.Zero) 404 if (sceneObject.UUID == UUID.Zero)
358 { 405 {
359 m_log.ErrorFormat( 406 m_log.ErrorFormat(
@@ -488,6 +535,30 @@ namespace OpenSim.Region.Framework.Scenes
488 m_updateList[obj.UUID] = obj; 535 m_updateList[obj.UUID] = obj;
489 } 536 }
490 537
538 public void FireAttachToBackup(SceneObjectGroup obj)
539 {
540 if (OnAttachToBackup != null)
541 {
542 OnAttachToBackup(obj);
543 }
544 }
545
546 public void FireDetachFromBackup(SceneObjectGroup obj)
547 {
548 if (OnDetachFromBackup != null)
549 {
550 OnDetachFromBackup(obj);
551 }
552 }
553
554 public void FireChangeBackup(SceneObjectGroup obj)
555 {
556 if (OnChangeBackup != null)
557 {
558 OnChangeBackup(obj);
559 }
560 }
561
491 /// <summary> 562 /// <summary>
492 /// Process all pending updates 563 /// Process all pending updates
493 /// </summary> 564 /// </summary>
@@ -605,7 +676,8 @@ namespace OpenSim.Region.Framework.Scenes
605 676
606 Entities[presence.UUID] = presence; 677 Entities[presence.UUID] = presence;
607 678
608 lock (m_presenceLock) 679 m_scenePresencesLock.EnterWriteLock();
680 try
609 { 681 {
610 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 682 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
611 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 683 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -629,6 +701,10 @@ namespace OpenSim.Region.Framework.Scenes
629 m_scenePresenceMap = newmap; 701 m_scenePresenceMap = newmap;
630 m_scenePresenceArray = newlist; 702 m_scenePresenceArray = newlist;
631 } 703 }
704 finally
705 {
706 m_scenePresencesLock.ExitWriteLock();
707 }
632 } 708 }
633 709
634 /// <summary> 710 /// <summary>
@@ -643,7 +719,8 @@ namespace OpenSim.Region.Framework.Scenes
643 agentID); 719 agentID);
644 } 720 }
645 721
646 lock (m_presenceLock) 722 m_scenePresencesLock.EnterWriteLock();
723 try
647 { 724 {
648 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap); 725 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
649 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray); 726 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
@@ -665,6 +742,10 @@ namespace OpenSim.Region.Framework.Scenes
665 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); 742 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
666 } 743 }
667 } 744 }
745 finally
746 {
747 m_scenePresencesLock.ExitWriteLock();
748 }
668 } 749 }
669 750
670 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F) 751 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
@@ -1380,8 +1461,13 @@ namespace OpenSim.Region.Framework.Scenes
1380 { 1461 {
1381 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) 1462 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1382 { 1463 {
1383 if (m_parentScene.AttachmentsModule != null) 1464 // Set the new attachment point data in the object
1384 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos); 1465 byte attachmentPoint = group.GetAttachmentPoint();
1466 group.UpdateGroupPosition(pos);
1467 group.IsAttachment = false;
1468 group.AbsolutePosition = group.RootPart.AttachedPos;
1469 group.AttachmentPoint = attachmentPoint;
1470 group.HasGroupChanged = true;
1385 } 1471 }
1386 else 1472 else
1387 { 1473 {
@@ -1653,8 +1739,11 @@ namespace OpenSim.Region.Framework.Scenes
1653 return; 1739 return;
1654 1740
1655 Monitor.Enter(m_updateLock); 1741 Monitor.Enter(m_updateLock);
1742
1656 try 1743 try
1657 { 1744 {
1745 parentGroup.areUpdatesSuspended = true;
1746
1658 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>(); 1747 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1659 1748
1660 // We do this in reverse to get the link order of the prims correct 1749 // We do this in reverse to get the link order of the prims correct
@@ -1665,9 +1754,13 @@ namespace OpenSim.Region.Framework.Scenes
1665 // Make sure no child prim is set for sale 1754 // Make sure no child prim is set for sale
1666 // So that, on delink, no prims are unwittingly 1755 // So that, on delink, no prims are unwittingly
1667 // left for sale and sold off 1756 // left for sale and sold off
1668 child.RootPart.ObjectSaleType = 0; 1757
1669 child.RootPart.SalePrice = 10; 1758 if (child != null)
1670 childGroups.Add(child); 1759 {
1760 child.RootPart.ObjectSaleType = 0;
1761 child.RootPart.SalePrice = 10;
1762 childGroups.Add(child);
1763 }
1671 } 1764 }
1672 1765
1673 foreach (SceneObjectGroup child in childGroups) 1766 foreach (SceneObjectGroup child in childGroups)
@@ -1686,12 +1779,19 @@ namespace OpenSim.Region.Framework.Scenes
1686 // occur on link to invoke this elsewhere (such as object selection) 1779 // occur on link to invoke this elsewhere (such as object selection)
1687 parentGroup.RootPart.CreateSelected = true; 1780 parentGroup.RootPart.CreateSelected = true;
1688 parentGroup.TriggerScriptChangedEvent(Changed.LINK); 1781 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1689 parentGroup.HasGroupChanged = true;
1690 parentGroup.ScheduleGroupForFullUpdate();
1691
1692 } 1782 }
1693 finally 1783 finally
1694 { 1784 {
1785 lock (SceneObjectGroupsByLocalPartID)
1786 {
1787 foreach (SceneObjectPart part in parentGroup.Parts)
1788 SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1789 }
1790
1791 parentGroup.areUpdatesSuspended = false;
1792 parentGroup.HasGroupChanged = true;
1793 parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1794 parentGroup.ScheduleGroupForFullUpdate();
1695 Monitor.Exit(m_updateLock); 1795 Monitor.Exit(m_updateLock);
1696 } 1796 }
1697 } 1797 }
@@ -1728,21 +1828,24 @@ namespace OpenSim.Region.Framework.Scenes
1728 1828
1729 SceneObjectGroup group = part.ParentGroup; 1829 SceneObjectGroup group = part.ParentGroup;
1730 if (!affectedGroups.Contains(group)) 1830 if (!affectedGroups.Contains(group))
1831 {
1832 group.areUpdatesSuspended = true;
1731 affectedGroups.Add(group); 1833 affectedGroups.Add(group);
1834 }
1732 } 1835 }
1733 } 1836 }
1734 } 1837 }
1735 1838
1736 foreach (SceneObjectPart child in childParts) 1839 if (childParts.Count > 0)
1737 { 1840 {
1738 // Unlink all child parts from their groups 1841 foreach (SceneObjectPart child in childParts)
1739 // 1842 {
1740 child.ParentGroup.DelinkFromGroup(child, true); 1843 // Unlink all child parts from their groups
1741 1844 //
1742 // These are not in affected groups and will not be 1845 child.ParentGroup.DelinkFromGroup(child, true);
1743 // handled further. Do the honors here. 1846 child.ParentGroup.HasGroupChanged = true;
1744 child.ParentGroup.HasGroupChanged = true; 1847 child.ParentGroup.ScheduleGroupForFullUpdate();
1745 child.ParentGroup.ScheduleGroupForFullUpdate(); 1848 }
1746 } 1849 }
1747 1850
1748 foreach (SceneObjectPart root in rootParts) 1851 foreach (SceneObjectPart root in rootParts)
@@ -1752,56 +1855,68 @@ namespace OpenSim.Region.Framework.Scenes
1752 // However, editing linked parts and unlinking may be different 1855 // However, editing linked parts and unlinking may be different
1753 // 1856 //
1754 SceneObjectGroup group = root.ParentGroup; 1857 SceneObjectGroup group = root.ParentGroup;
1858 group.areUpdatesSuspended = true;
1755 1859
1756 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts); 1860 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1757 int numChildren = newSet.Count; 1861 int numChildren = newSet.Count;
1758 1862
1863 if (numChildren == 1)
1864 break;
1865
1759 // If there are prims left in a link set, but the root is 1866 // If there are prims left in a link set, but the root is
1760 // slated for unlink, we need to do this 1867 // slated for unlink, we need to do this
1868 // Unlink the remaining set
1761 // 1869 //
1762 if (numChildren != 1) 1870 bool sendEventsToRemainder = true;
1763 { 1871 if (numChildren > 1)
1764 // Unlink the remaining set 1872 sendEventsToRemainder = false;
1765 //
1766 bool sendEventsToRemainder = true;
1767 if (numChildren > 1)
1768 sendEventsToRemainder = false;
1769 1873
1770 foreach (SceneObjectPart p in newSet) 1874 foreach (SceneObjectPart p in newSet)
1875 {
1876 if (p != group.RootPart)
1771 { 1877 {
1772 if (p != group.RootPart) 1878 group.DelinkFromGroup(p, sendEventsToRemainder);
1773 group.DelinkFromGroup(p, sendEventsToRemainder); 1879 if (numChildren > 2)
1880 {
1881 p.ParentGroup.areUpdatesSuspended = true;
1882 }
1883 else
1884 {
1885 p.ParentGroup.HasGroupChanged = true;
1886 p.ParentGroup.ScheduleGroupForFullUpdate();
1887 }
1774 } 1888 }
1889 }
1890
1891 // If there is more than one prim remaining, we
1892 // need to re-link
1893 //
1894 if (numChildren > 2)
1895 {
1896 // Remove old root
1897 //
1898 if (newSet.Contains(root))
1899 newSet.Remove(root);
1775 1900
1776 // If there is more than one prim remaining, we 1901 // Preserve link ordering
1777 // need to re-link
1778 // 1902 //
1779 if (numChildren > 2) 1903 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1780 { 1904 {
1781 // Remove old root 1905 return a.LinkNum.CompareTo(b.LinkNum);
1782 // 1906 });
1783 if (newSet.Contains(root))
1784 newSet.Remove(root);
1785
1786 // Preserve link ordering
1787 //
1788 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1789 {
1790 return a.LinkNum.CompareTo(b.LinkNum);
1791 });
1792 1907
1793 // Determine new root 1908 // Determine new root
1794 // 1909 //
1795 SceneObjectPart newRoot = newSet[0]; 1910 SceneObjectPart newRoot = newSet[0];
1796 newSet.RemoveAt(0); 1911 newSet.RemoveAt(0);
1797 1912
1798 foreach (SceneObjectPart newChild in newSet) 1913 foreach (SceneObjectPart newChild in newSet)
1799 newChild.ClearUpdateSchedule(); 1914 newChild.ClearUpdateSchedule();
1800 1915
1801 LinkObjects(newRoot, newSet); 1916 newRoot.ParentGroup.areUpdatesSuspended = true;
1802 if (!affectedGroups.Contains(newRoot.ParentGroup)) 1917 LinkObjects(newRoot, newSet);
1803 affectedGroups.Add(newRoot.ParentGroup); 1918 if (!affectedGroups.Contains(newRoot.ParentGroup))
1804 } 1919 affectedGroups.Add(newRoot.ParentGroup);
1805 } 1920 }
1806 } 1921 }
1807 1922
@@ -1809,8 +1924,14 @@ namespace OpenSim.Region.Framework.Scenes
1809 // 1924 //
1810 foreach (SceneObjectGroup g in affectedGroups) 1925 foreach (SceneObjectGroup g in affectedGroups)
1811 { 1926 {
1927 // Child prims that have been unlinked and deleted will
1928 // return unless the root is deleted. This will remove them
1929 // from the database. They will be rewritten immediately,
1930 // minus the rows for the unlinked child prims.
1931 m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
1812 g.TriggerScriptChangedEvent(Changed.LINK); 1932 g.TriggerScriptChangedEvent(Changed.LINK);
1813 g.HasGroupChanged = true; // Persist 1933 g.HasGroupChanged = true; // Persist
1934 g.areUpdatesSuspended = false;
1814 g.ScheduleGroupForFullUpdate(); 1935 g.ScheduleGroupForFullUpdate();
1815 } 1936 }
1816 } 1937 }
@@ -1912,9 +2033,6 @@ namespace OpenSim.Region.Framework.Scenes
1912 child.ApplyNextOwnerPermissions(); 2033 child.ApplyNextOwnerPermissions();
1913 } 2034 }
1914 } 2035 }
1915
1916 copy.RootPart.ObjectSaleType = 0;
1917 copy.RootPart.SalePrice = 10;
1918 } 2036 }
1919 2037
1920 // FIXME: This section needs to be refactored so that it just calls AddSceneObject() 2038 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index d73a959..e4eaf3a 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -356,7 +356,7 @@ namespace OpenSim.Region.Framework.Scenes
356 356
357 public bool TrySetCurrentScene(UUID regionID) 357 public bool TrySetCurrentScene(UUID regionID)
358 { 358 {
359 m_log.Debug("Searching for Region: '" + regionID + "'"); 359// m_log.Debug("Searching for Region: '" + regionID + "'");
360 360
361 lock (m_localScenes) 361 lock (m_localScenes)
362 { 362 {
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index f173c95..b56d3fc 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();
@@ -227,6 +223,11 @@ namespace OpenSim.Region.Framework.Scenes
227 223
228 public uint GetEffectivePermissions() 224 public uint GetEffectivePermissions()
229 { 225 {
226 return GetEffectivePermissions(false);
227 }
228
229 public uint GetEffectivePermissions(bool useBase)
230 {
230 uint perms=(uint)(PermissionMask.Modify | 231 uint perms=(uint)(PermissionMask.Modify |
231 PermissionMask.Copy | 232 PermissionMask.Copy |
232 PermissionMask.Move | 233 PermissionMask.Move |
@@ -238,7 +239,10 @@ namespace OpenSim.Region.Framework.Scenes
238 for (int i = 0; i < parts.Length; i++) 239 for (int i = 0; i < parts.Length; i++)
239 { 240 {
240 SceneObjectPart part = parts[i]; 241 SceneObjectPart part = parts[i];
241 ownerMask &= part.OwnerMask; 242 if (useBase)
243 ownerMask &= part.BaseMask;
244 else
245 ownerMask &= part.OwnerMask;
242 perms &= part.Inventory.MaskEffectivePermissions(); 246 perms &= part.Inventory.MaskEffectivePermissions();
243 } 247 }
244 248
@@ -378,6 +382,9 @@ namespace OpenSim.Region.Framework.Scenes
378 382
379 public void ResumeScripts() 383 public void ResumeScripts()
380 { 384 {
385 if (m_scene.RegionInfo.RegionSettings.DisableScripts)
386 return;
387
381 SceneObjectPart[] parts = m_parts.GetArray(); 388 SceneObjectPart[] parts = m_parts.GetArray();
382 for (int i = 0; i < parts.Length; i++) 389 for (int i = 0; i < parts.Length; i++)
383 parts[i].Inventory.ResumeScripts(); 390 parts[i].Inventory.ResumeScripts();
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index b724135..46c4d7b 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using 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
@@ -131,7 +183,7 @@ namespace OpenSim.Region.Framework.Scenes
131 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 183 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
132 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 184 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 185 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 186 public bool HasGroupChangedDueToDelink { get; set; }
135 187
136 private bool isTimeToPersist() 188 private bool isTimeToPersist()
137 { 189 {
@@ -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 }
@@ -247,10 +310,10 @@ namespace OpenSim.Region.Framework.Scenes
247 310
248 private bool m_scriptListens_atTarget; 311 private bool m_scriptListens_atTarget;
249 private bool m_scriptListens_notAtTarget; 312 private bool m_scriptListens_notAtTarget;
250
251 private bool m_scriptListens_atRotTarget; 313 private bool m_scriptListens_atRotTarget;
252 private bool m_scriptListens_notAtRotTarget; 314 private bool m_scriptListens_notAtRotTarget;
253 315
316 public bool m_dupeInProgress = false;
254 internal Dictionary<UUID, string> m_savedScriptState; 317 internal Dictionary<UUID, string> m_savedScriptState;
255 318
256 #region Properties 319 #region Properties
@@ -287,6 +350,16 @@ namespace OpenSim.Region.Framework.Scenes
287 get { return m_parts.Count; } 350 get { return m_parts.Count; }
288 } 351 }
289 352
353// protected Quaternion m_rotation = Quaternion.Identity;
354//
355// public virtual Quaternion Rotation
356// {
357// get { return m_rotation; }
358// set {
359// m_rotation = value;
360// }
361// }
362
290 public Quaternion GroupRotation 363 public Quaternion GroupRotation
291 { 364 {
292 get { return m_rootPart.RotationOffset; } 365 get { return m_rootPart.RotationOffset; }
@@ -395,7 +468,11 @@ namespace OpenSim.Region.Framework.Scenes
395 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 468 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
396 } 469 }
397 } 470 }
398 471
472 foreach (SceneObjectPart part in m_parts.GetArray())
473 {
474 part.IgnoreUndoUpdate = true;
475 }
399 if (RootPart.GetStatusSandbox()) 476 if (RootPart.GetStatusSandbox())
400 { 477 {
401 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 478 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -409,10 +486,30 @@ namespace OpenSim.Region.Framework.Scenes
409 return; 486 return;
410 } 487 }
411 } 488 }
412
413 SceneObjectPart[] parts = m_parts.GetArray(); 489 SceneObjectPart[] parts = m_parts.GetArray();
414 for (int i = 0; i < parts.Length; i++) 490 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
415 parts[i].GroupPosition = val; 491 if (m_dupeInProgress)
492 triggerScriptEvent = false;
493 foreach (SceneObjectPart part in parts)
494 {
495 part.GroupPosition = val;
496 if (triggerScriptEvent)
497 part.TriggerScriptChangedEvent(Changed.POSITION);
498 }
499 if (!m_dupeInProgress)
500 {
501 foreach (ScenePresence av in m_linkedAvatars)
502 {
503 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
504 if (m_parts.TryGetValue(p.UUID, out p))
505 {
506 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
507 av.AbsolutePosition += offset;
508 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
509 av.SendAvatarDataToAllAgents();
510 }
511 }
512 }
416 513
417 //if (m_rootPart.PhysActor != null) 514 //if (m_rootPart.PhysActor != null)
418 //{ 515 //{
@@ -578,6 +675,7 @@ namespace OpenSim.Region.Framework.Scenes
578 /// </summary> 675 /// </summary>
579 public SceneObjectGroup() 676 public SceneObjectGroup()
580 { 677 {
678
581 } 679 }
582 680
583 /// <summary> 681 /// <summary>
@@ -594,7 +692,7 @@ namespace OpenSim.Region.Framework.Scenes
594 /// Constructor. This object is added to the scene later via AttachToScene() 692 /// Constructor. This object is added to the scene later via AttachToScene()
595 /// </summary> 693 /// </summary>
596 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 694 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
597 { 695 {
598 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 696 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
599 } 697 }
600 698
@@ -642,6 +740,9 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 740 /// </summary>
643 public virtual void AttachToBackup() 741 public virtual void AttachToBackup()
644 { 742 {
743 if (IsAttachment) return;
744 m_scene.SceneGraph.FireAttachToBackup(this);
745
645 if (InSceneBackup) 746 if (InSceneBackup)
646 { 747 {
647 //m_log.DebugFormat( 748 //m_log.DebugFormat(
@@ -684,6 +785,9 @@ namespace OpenSim.Region.Framework.Scenes
684 785
685 ApplyPhysics(); 786 ApplyPhysics();
686 787
788 if (RootPart.PhysActor != null)
789 RootPart.Buoyancy = RootPart.Buoyancy;
790
687 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 791 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
688 // for the same object with very different properties. The caller must schedule the update. 792 // for the same object with very different properties. The caller must schedule the update.
689 //ScheduleGroupForFullUpdate(); 793 //ScheduleGroupForFullUpdate();
@@ -699,6 +803,10 @@ namespace OpenSim.Region.Framework.Scenes
699 EntityIntersection result = new EntityIntersection(); 803 EntityIntersection result = new EntityIntersection();
700 804
701 SceneObjectPart[] parts = m_parts.GetArray(); 805 SceneObjectPart[] parts = m_parts.GetArray();
806
807 // Find closest hit here
808 float idist = float.MaxValue;
809
702 for (int i = 0; i < parts.Length; i++) 810 for (int i = 0; i < parts.Length; i++)
703 { 811 {
704 SceneObjectPart part = parts[i]; 812 SceneObjectPart part = parts[i];
@@ -713,11 +821,6 @@ namespace OpenSim.Region.Framework.Scenes
713 821
714 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 822 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
715 823
716 // This may need to be updated to the maximum draw distance possible..
717 // We might (and probably will) be checking for prim creation from other sims
718 // when the camera crosses the border.
719 float idist = Constants.RegionSize;
720
721 if (inter.HitTF) 824 if (inter.HitTF)
722 { 825 {
723 // We need to find the closest prim to return to the testcaller along the ray 826 // We need to find the closest prim to return to the testcaller along the ray
@@ -728,10 +831,11 @@ namespace OpenSim.Region.Framework.Scenes
728 result.obj = part; 831 result.obj = part;
729 result.normal = inter.normal; 832 result.normal = inter.normal;
730 result.distance = inter.distance; 833 result.distance = inter.distance;
834
835 idist = inter.distance;
731 } 836 }
732 } 837 }
733 } 838 }
734
735 return result; 839 return result;
736 } 840 }
737 841
@@ -751,17 +855,19 @@ namespace OpenSim.Region.Framework.Scenes
751 minZ = 8192f; 855 minZ = 8192f;
752 856
753 SceneObjectPart[] parts = m_parts.GetArray(); 857 SceneObjectPart[] parts = m_parts.GetArray();
754 for (int i = 0; i < parts.Length; i++) 858 foreach (SceneObjectPart part in parts)
755 { 859 {
756 SceneObjectPart part = parts[i];
757
758 Vector3 worldPos = part.GetWorldPosition(); 860 Vector3 worldPos = part.GetWorldPosition();
759 Vector3 offset = worldPos - AbsolutePosition; 861 Vector3 offset = worldPos - AbsolutePosition;
760 Quaternion worldRot; 862 Quaternion worldRot;
761 if (part.ParentID == 0) 863 if (part.ParentID == 0)
864 {
762 worldRot = part.RotationOffset; 865 worldRot = part.RotationOffset;
866 }
763 else 867 else
868 {
764 worldRot = part.GetWorldRotation(); 869 worldRot = part.GetWorldRotation();
870 }
765 871
766 Vector3 frontTopLeft; 872 Vector3 frontTopLeft;
767 Vector3 frontTopRight; 873 Vector3 frontTopRight;
@@ -773,6 +879,8 @@ namespace OpenSim.Region.Framework.Scenes
773 Vector3 backBottomLeft; 879 Vector3 backBottomLeft;
774 Vector3 backBottomRight; 880 Vector3 backBottomRight;
775 881
882 // Vector3[] corners = new Vector3[8];
883
776 Vector3 orig = Vector3.Zero; 884 Vector3 orig = Vector3.Zero;
777 885
778 frontTopLeft.X = orig.X - (part.Scale.X / 2); 886 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -807,6 +915,38 @@ namespace OpenSim.Region.Framework.Scenes
807 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 915 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
808 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 916 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
809 917
918
919
920 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
921 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
922 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
923 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
924 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
925 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
926 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
927 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
928
929 //for (int i = 0; i < 8; i++)
930 //{
931 // corners[i] = corners[i] * worldRot;
932 // corners[i] += offset;
933
934 // if (corners[i].X > maxX)
935 // maxX = corners[i].X;
936 // if (corners[i].X < minX)
937 // minX = corners[i].X;
938
939 // if (corners[i].Y > maxY)
940 // maxY = corners[i].Y;
941 // if (corners[i].Y < minY)
942 // minY = corners[i].Y;
943
944 // if (corners[i].Z > maxZ)
945 // maxZ = corners[i].Y;
946 // if (corners[i].Z < minZ)
947 // minZ = corners[i].Z;
948 //}
949
810 frontTopLeft = frontTopLeft * worldRot; 950 frontTopLeft = frontTopLeft * worldRot;
811 frontTopRight = frontTopRight * worldRot; 951 frontTopRight = frontTopRight * worldRot;
812 frontBottomLeft = frontBottomLeft * worldRot; 952 frontBottomLeft = frontBottomLeft * worldRot;
@@ -828,6 +968,15 @@ namespace OpenSim.Region.Framework.Scenes
828 backTopLeft += offset; 968 backTopLeft += offset;
829 backTopRight += offset; 969 backTopRight += offset;
830 970
971 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
972 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
973 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
974 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
975 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
976 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
977 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
978 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
979
831 if (frontTopRight.X > maxX) 980 if (frontTopRight.X > maxX)
832 maxX = frontTopRight.X; 981 maxX = frontTopRight.X;
833 if (frontTopLeft.X > maxX) 982 if (frontTopLeft.X > maxX)
@@ -973,15 +1122,20 @@ namespace OpenSim.Region.Framework.Scenes
973 1122
974 public void SaveScriptedState(XmlTextWriter writer) 1123 public void SaveScriptedState(XmlTextWriter writer)
975 { 1124 {
1125 SaveScriptedState(writer, false);
1126 }
1127
1128 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1129 {
976 XmlDocument doc = new XmlDocument(); 1130 XmlDocument doc = new XmlDocument();
977 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1131 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
978 1132
979 SceneObjectPart[] parts = m_parts.GetArray(); 1133 SceneObjectPart[] parts = m_parts.GetArray();
980 for (int i = 0; i < parts.Length; i++) 1134 for (int i = 0; i < parts.Length; i++)
981 { 1135 {
982 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1136 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
983 foreach (KeyValuePair<UUID, string> kvp in pstates) 1137 foreach (KeyValuePair<UUID, string> kvp in pstates)
984 states.Add(kvp.Key, kvp.Value); 1138 states[kvp.Key] = kvp.Value;
985 } 1139 }
986 1140
987 if (states.Count > 0) 1141 if (states.Count > 0)
@@ -1001,6 +1155,168 @@ namespace OpenSim.Region.Framework.Scenes
1001 } 1155 }
1002 1156
1003 /// <summary> 1157 /// <summary>
1158 /// Add the avatar to this linkset (avatar is sat).
1159 /// </summary>
1160 /// <param name="agentID"></param>
1161 public void AddAvatar(UUID agentID)
1162 {
1163 ScenePresence presence;
1164 if (m_scene.TryGetScenePresence(agentID, out presence))
1165 {
1166 if (!m_linkedAvatars.Contains(presence))
1167 {
1168 m_linkedAvatars.Add(presence);
1169 }
1170 }
1171 }
1172
1173 /// <summary>
1174 /// Delete the avatar from this linkset (avatar is unsat).
1175 /// </summary>
1176 /// <param name="agentID"></param>
1177 public void DeleteAvatar(UUID agentID)
1178 {
1179 ScenePresence presence;
1180 if (m_scene.TryGetScenePresence(agentID, out presence))
1181 {
1182 if (m_linkedAvatars.Contains(presence))
1183 {
1184 m_linkedAvatars.Remove(presence);
1185 }
1186 }
1187 }
1188
1189 /// <summary>
1190 /// Returns the list of linked presences (avatars sat on this group)
1191 /// </summary>
1192 /// <param name="agentID"></param>
1193 public List<ScenePresence> GetLinkedAvatars()
1194 {
1195 return m_linkedAvatars;
1196 }
1197
1198 /// <summary>
1199 /// Attach this scene object to the given avatar.
1200 /// </summary>
1201 /// <param name="agentID"></param>
1202 /// <param name="attachmentpoint"></param>
1203 /// <param name="AttachOffset"></param>
1204 private void AttachToAgent(
1205 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1206 {
1207 if (avatar != null)
1208 {
1209 // don't attach attachments to child agents
1210 if (avatar.IsChildAgent) return;
1211
1212 // Remove from database and parcel prim count
1213 m_scene.DeleteFromStorage(so.UUID);
1214 m_scene.EventManager.TriggerParcelPrimCountTainted();
1215
1216 so.AttachedAvatar = avatar.UUID;
1217
1218 if (so.RootPart.PhysActor != null)
1219 {
1220 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1221 so.RootPart.PhysActor = null;
1222 }
1223
1224 so.AbsolutePosition = attachOffset;
1225 so.RootPart.AttachedPos = attachOffset;
1226 so.IsAttachment = true;
1227 so.RootPart.SetParentLocalId(avatar.LocalId);
1228 so.AttachmentPoint = attachmentpoint;
1229
1230 avatar.AddAttachment(this);
1231
1232 if (!silent)
1233 {
1234 // Killing it here will cause the client to deselect it
1235 // It then reappears on the avatar, deselected
1236 // through the full update below
1237 //
1238 if (IsSelected)
1239 {
1240 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1241 }
1242
1243 IsSelected = false; // fudge....
1244 ScheduleGroupForFullUpdate();
1245 }
1246 }
1247 else
1248 {
1249 m_log.WarnFormat(
1250 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1251 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1252 }
1253 }
1254
1255 public byte GetAttachmentPoint()
1256 {
1257 return m_rootPart.Shape.State;
1258 }
1259
1260 public void DetachToGround()
1261 {
1262 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1263 if (avatar == null)
1264 return;
1265
1266 avatar.RemoveAttachment(this);
1267
1268 Vector3 detachedpos = new Vector3(127f,127f,127f);
1269 if (avatar == null)
1270 return;
1271
1272 detachedpos = avatar.AbsolutePosition;
1273 RootPart.FromItemID = UUID.Zero;
1274
1275 AbsolutePosition = detachedpos;
1276 AttachedAvatar = UUID.Zero;
1277
1278 //SceneObjectPart[] parts = m_parts.GetArray();
1279 //for (int i = 0; i < parts.Length; i++)
1280 // parts[i].AttachedAvatar = UUID.Zero;
1281
1282 m_rootPart.SetParentLocalId(0);
1283 AttachmentPoint = (byte)0;
1284 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1285 HasGroupChanged = true;
1286 RootPart.Rezzed = DateTime.Now;
1287 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1288 AttachToBackup();
1289 m_scene.EventManager.TriggerParcelPrimCountTainted();
1290 m_rootPart.ScheduleFullUpdate();
1291 m_rootPart.ClearUndoState();
1292 }
1293
1294 public void DetachToInventoryPrep()
1295 {
1296 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1297 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1298 if (avatar != null)
1299 {
1300 //detachedpos = avatar.AbsolutePosition;
1301 avatar.RemoveAttachment(this);
1302 }
1303
1304 AttachedAvatar = UUID.Zero;
1305
1306 /*SceneObjectPart[] parts = m_parts.GetArray();
1307 for (int i = 0; i < parts.Length; i++)
1308 parts[i].AttachedAvatar = UUID.Zero;*/
1309
1310 m_rootPart.SetParentLocalId(0);
1311 //m_rootPart.SetAttachmentPoint((byte)0);
1312 IsAttachment = false;
1313 AbsolutePosition = m_rootPart.AttachedPos;
1314 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1315 //AttachToBackup();
1316 //m_rootPart.ScheduleFullUpdate();
1317 }
1318
1319 /// <summary>
1004 /// 1320 ///
1005 /// </summary> 1321 /// </summary>
1006 /// <param name="part"></param> 1322 /// <param name="part"></param>
@@ -1050,7 +1366,10 @@ namespace OpenSim.Region.Framework.Scenes
1050 public void AddPart(SceneObjectPart part) 1366 public void AddPart(SceneObjectPart part)
1051 { 1367 {
1052 part.SetParent(this); 1368 part.SetParent(this);
1053 part.LinkNum = m_parts.Add(part.UUID, part); 1369 m_parts.Add(part.UUID, part);
1370
1371 part.LinkNum = m_parts.Count;
1372
1054 if (part.LinkNum == 2) 1373 if (part.LinkNum == 2)
1055 RootPart.LinkNum = 1; 1374 RootPart.LinkNum = 1;
1056 } 1375 }
@@ -1158,6 +1477,11 @@ namespace OpenSim.Region.Framework.Scenes
1158 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1477 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1159 public void DeleteGroupFromScene(bool silent) 1478 public void DeleteGroupFromScene(bool silent)
1160 { 1479 {
1480 // We need to keep track of this state in case this group is still queued for backup.
1481 IsDeleted = true;
1482
1483 DetachFromBackup();
1484
1161 SceneObjectPart[] parts = m_parts.GetArray(); 1485 SceneObjectPart[] parts = m_parts.GetArray();
1162 for (int i = 0; i < parts.Length; i++) 1486 for (int i = 0; i < parts.Length; i++)
1163 { 1487 {
@@ -1180,6 +1504,8 @@ namespace OpenSim.Region.Framework.Scenes
1180 } 1504 }
1181 }); 1505 });
1182 } 1506 }
1507
1508
1183 } 1509 }
1184 1510
1185 public void AddScriptLPS(int count) 1511 public void AddScriptLPS(int count)
@@ -1275,7 +1601,12 @@ namespace OpenSim.Region.Framework.Scenes
1275 1601
1276 public void SetOwnerId(UUID userId) 1602 public void SetOwnerId(UUID userId)
1277 { 1603 {
1278 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1604 ForEachPart(delegate(SceneObjectPart part)
1605 {
1606
1607 part.OwnerID = userId;
1608
1609 });
1279 } 1610 }
1280 1611
1281 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1612 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1307,11 +1638,17 @@ namespace OpenSim.Region.Framework.Scenes
1307 return; 1638 return;
1308 } 1639 }
1309 1640
1641 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1642 return;
1643
1310 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1644 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1311 // any exception propogate upwards. 1645 // any exception propogate upwards.
1312 try 1646 try
1313 { 1647 {
1314 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1648 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1649 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1650 m_scene.LoadingPrims) // Land may not be valid yet
1651
1315 { 1652 {
1316 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1653 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1317 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1654 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1338,6 +1675,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 } 1675 }
1339 } 1676 }
1340 } 1677 }
1678
1341 } 1679 }
1342 1680
1343 if (m_scene.UseBackup && HasGroupChanged) 1681 if (m_scene.UseBackup && HasGroupChanged)
@@ -1345,6 +1683,20 @@ namespace OpenSim.Region.Framework.Scenes
1345 // don't backup while it's selected or you're asking for changes mid stream. 1683 // don't backup while it's selected or you're asking for changes mid stream.
1346 if (isTimeToPersist() || forcedBackup) 1684 if (isTimeToPersist() || forcedBackup)
1347 { 1685 {
1686 if (m_rootPart.PhysActor != null &&
1687 (!m_rootPart.PhysActor.IsPhysical))
1688 {
1689 // Possible ghost prim
1690 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1691 {
1692 foreach (SceneObjectPart part in m_parts.GetArray())
1693 {
1694 // Re-set physics actor positions and
1695 // orientations
1696 part.GroupPosition = m_rootPart.GroupPosition;
1697 }
1698 }
1699 }
1348// m_log.DebugFormat( 1700// m_log.DebugFormat(
1349// "[SCENE]: Storing {0}, {1} in {2}", 1701// "[SCENE]: Storing {0}, {1} in {2}",
1350// Name, UUID, m_scene.RegionInfo.RegionName); 1702// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -1428,7 +1780,7 @@ namespace OpenSim.Region.Framework.Scenes
1428 // This is only necessary when userExposed is false! 1780 // This is only necessary when userExposed is false!
1429 1781
1430 bool previousAttachmentStatus = dupe.IsAttachment; 1782 bool previousAttachmentStatus = dupe.IsAttachment;
1431 1783
1432 if (!userExposed) 1784 if (!userExposed)
1433 dupe.IsAttachment = true; 1785 dupe.IsAttachment = true;
1434 1786
@@ -1446,11 +1798,11 @@ namespace OpenSim.Region.Framework.Scenes
1446 dupe.m_rootPart.TrimPermissions(); 1798 dupe.m_rootPart.TrimPermissions();
1447 1799
1448 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 1800 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1449 1801
1450 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 1802 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1451 { 1803 {
1452 return p1.LinkNum.CompareTo(p2.LinkNum); 1804 return p1.LinkNum.CompareTo(p2.LinkNum);
1453 } 1805 }
1454 ); 1806 );
1455 1807
1456 foreach (SceneObjectPart part in partList) 1808 foreach (SceneObjectPart part in partList)
@@ -1470,7 +1822,7 @@ namespace OpenSim.Region.Framework.Scenes
1470 if (part.PhysActor != null && userExposed) 1822 if (part.PhysActor != null && userExposed)
1471 { 1823 {
1472 PrimitiveBaseShape pbs = newPart.Shape; 1824 PrimitiveBaseShape pbs = newPart.Shape;
1473 1825
1474 newPart.PhysActor 1826 newPart.PhysActor
1475 = m_scene.PhysicsScene.AddPrimShape( 1827 = m_scene.PhysicsScene.AddPrimShape(
1476 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 1828 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
@@ -1480,11 +1832,11 @@ namespace OpenSim.Region.Framework.Scenes
1480 newPart.RotationOffset, 1832 newPart.RotationOffset,
1481 part.PhysActor.IsPhysical, 1833 part.PhysActor.IsPhysical,
1482 newPart.LocalId); 1834 newPart.LocalId);
1483 1835
1484 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); 1836 newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true);
1485 } 1837 }
1486 } 1838 }
1487 1839
1488 if (userExposed) 1840 if (userExposed)
1489 { 1841 {
1490 dupe.UpdateParentIDs(); 1842 dupe.UpdateParentIDs();
@@ -1599,6 +1951,7 @@ namespace OpenSim.Region.Framework.Scenes
1599 return Vector3.Zero; 1951 return Vector3.Zero;
1600 } 1952 }
1601 1953
1954 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1602 public void moveToTarget(Vector3 target, float tau) 1955 public void moveToTarget(Vector3 target, float tau)
1603 { 1956 {
1604 if (IsAttachment) 1957 if (IsAttachment)
@@ -1626,6 +1979,46 @@ namespace OpenSim.Region.Framework.Scenes
1626 RootPart.PhysActor.PIDActive = false; 1979 RootPart.PhysActor.PIDActive = false;
1627 } 1980 }
1628 1981
1982 public void rotLookAt(Quaternion target, float strength, float damping)
1983 {
1984 SceneObjectPart rootpart = m_rootPart;
1985 if (rootpart != null)
1986 {
1987 if (IsAttachment)
1988 {
1989 /*
1990 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1991 if (avatar != null)
1992 {
1993 Rotate the Av?
1994 } */
1995 }
1996 else
1997 {
1998 if (rootpart.PhysActor != null)
1999 { // APID must be implemented in your physics system for this to function.
2000 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2001 rootpart.PhysActor.APIDStrength = strength;
2002 rootpart.PhysActor.APIDDamping = damping;
2003 rootpart.PhysActor.APIDActive = true;
2004 }
2005 }
2006 }
2007 }
2008
2009 public void stopLookAt()
2010 {
2011 SceneObjectPart rootpart = m_rootPart;
2012 if (rootpart != null)
2013 {
2014 if (rootpart.PhysActor != null)
2015 { // APID must be implemented in your physics system for this to function.
2016 rootpart.PhysActor.APIDActive = false;
2017 }
2018 }
2019
2020 }
2021
1629 /// <summary> 2022 /// <summary>
1630 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2023 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1631 /// </summary> 2024 /// </summary>
@@ -1681,6 +2074,8 @@ namespace OpenSim.Region.Framework.Scenes
1681 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2074 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1682 { 2075 {
1683 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2076 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2077 newPart.SetParent(this);
2078
1684 AddPart(newPart); 2079 AddPart(newPart);
1685 2080
1686 SetPartAsNonRoot(newPart); 2081 SetPartAsNonRoot(newPart);
@@ -1809,11 +2204,11 @@ namespace OpenSim.Region.Framework.Scenes
1809 /// Immediately send a full update for this scene object. 2204 /// Immediately send a full update for this scene object.
1810 /// </summary> 2205 /// </summary>
1811 public void SendGroupFullUpdate() 2206 public void SendGroupFullUpdate()
1812 { 2207 {
1813 if (IsDeleted) 2208 if (IsDeleted)
1814 return; 2209 return;
1815 2210
1816// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2211// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1817 2212
1818 RootPart.SendFullUpdateToAllClients(); 2213 RootPart.SendFullUpdateToAllClients();
1819 2214
@@ -1957,6 +2352,11 @@ namespace OpenSim.Region.Framework.Scenes
1957 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2352 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1958 public void LinkToGroup(SceneObjectGroup objectGroup) 2353 public void LinkToGroup(SceneObjectGroup objectGroup)
1959 { 2354 {
2355 LinkToGroup(objectGroup, false);
2356 }
2357
2358 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2359 {
1960// m_log.DebugFormat( 2360// m_log.DebugFormat(
1961// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2361// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1962// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); 2362// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1986,7 +2386,20 @@ namespace OpenSim.Region.Framework.Scenes
1986 2386
1987 lock (m_parts.SyncRoot) 2387 lock (m_parts.SyncRoot)
1988 { 2388 {
1989 int linkNum = PrimCount + 1; 2389 int linkNum;
2390 if (insert)
2391 {
2392 linkNum = 2;
2393 foreach (SceneObjectPart part in Parts)
2394 {
2395 if (part.LinkNum > 1)
2396 part.LinkNum++;
2397 }
2398 }
2399 else
2400 {
2401 linkNum = PrimCount + 1;
2402 }
1990 2403
1991 m_parts.Add(linkPart.UUID, linkPart); 2404 m_parts.Add(linkPart.UUID, linkPart);
1992 2405
@@ -2014,7 +2427,7 @@ namespace OpenSim.Region.Framework.Scenes
2014 objectGroup.IsDeleted = true; 2427 objectGroup.IsDeleted = true;
2015 2428
2016 objectGroup.m_parts.Clear(); 2429 objectGroup.m_parts.Clear();
2017 2430
2018 // Can't do this yet since backup still makes use of the root part without any synchronization 2431 // Can't do this yet since backup still makes use of the root part without any synchronization
2019// objectGroup.m_rootPart = null; 2432// objectGroup.m_rootPart = null;
2020 2433
@@ -2148,6 +2561,7 @@ namespace OpenSim.Region.Framework.Scenes
2148 /// <param name="objectGroup"></param> 2561 /// <param name="objectGroup"></param>
2149 public virtual void DetachFromBackup() 2562 public virtual void DetachFromBackup()
2150 { 2563 {
2564 m_scene.SceneGraph.FireDetachFromBackup(this);
2151 if (m_isBackedUp && Scene != null) 2565 if (m_isBackedUp && Scene != null)
2152 m_scene.EventManager.OnBackup -= ProcessBackup; 2566 m_scene.EventManager.OnBackup -= ProcessBackup;
2153 2567
@@ -2166,7 +2580,8 @@ namespace OpenSim.Region.Framework.Scenes
2166 2580
2167 axPos *= parentRot; 2581 axPos *= parentRot;
2168 part.OffsetPosition = axPos; 2582 part.OffsetPosition = axPos;
2169 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2583 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2584 part.GroupPosition = newPos;
2170 part.OffsetPosition = Vector3.Zero; 2585 part.OffsetPosition = Vector3.Zero;
2171 part.RotationOffset = worldRot; 2586 part.RotationOffset = worldRot;
2172 2587
@@ -2177,7 +2592,7 @@ namespace OpenSim.Region.Framework.Scenes
2177 2592
2178 part.LinkNum = linkNum; 2593 part.LinkNum = linkNum;
2179 2594
2180 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2595 part.OffsetPosition = newPos - AbsolutePosition;
2181 2596
2182 Quaternion rootRotation = m_rootPart.RotationOffset; 2597 Quaternion rootRotation = m_rootPart.RotationOffset;
2183 2598
@@ -2187,7 +2602,7 @@ namespace OpenSim.Region.Framework.Scenes
2187 2602
2188 parentRot = m_rootPart.RotationOffset; 2603 parentRot = m_rootPart.RotationOffset;
2189 oldRot = part.RotationOffset; 2604 oldRot = part.RotationOffset;
2190 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2605 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2191 part.RotationOffset = newRot; 2606 part.RotationOffset = newRot;
2192 } 2607 }
2193 2608
@@ -2434,8 +2849,12 @@ namespace OpenSim.Region.Framework.Scenes
2434 } 2849 }
2435 } 2850 }
2436 2851
2852 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2437 for (int i = 0; i < parts.Length; i++) 2853 for (int i = 0; i < parts.Length; i++)
2438 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 2854 {
2855 if (parts[i] != RootPart)
2856 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2857 }
2439 } 2858 }
2440 } 2859 }
2441 2860
@@ -2448,6 +2867,17 @@ namespace OpenSim.Region.Framework.Scenes
2448 } 2867 }
2449 } 2868 }
2450 2869
2870
2871
2872 /// <summary>
2873 /// Gets the number of parts
2874 /// </summary>
2875 /// <returns></returns>
2876 public int GetPartCount()
2877 {
2878 return Parts.Count();
2879 }
2880
2451 /// <summary> 2881 /// <summary>
2452 /// Update the texture entry for this part 2882 /// Update the texture entry for this part
2453 /// </summary> 2883 /// </summary>
@@ -2509,7 +2939,6 @@ namespace OpenSim.Region.Framework.Scenes
2509 { 2939 {
2510// m_log.DebugFormat( 2940// m_log.DebugFormat(
2511// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 2941// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2512
2513 RootPart.StoreUndoState(true); 2942 RootPart.StoreUndoState(true);
2514 2943
2515 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 2944 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
@@ -2610,7 +3039,6 @@ namespace OpenSim.Region.Framework.Scenes
2610 prevScale.X *= x; 3039 prevScale.X *= x;
2611 prevScale.Y *= y; 3040 prevScale.Y *= y;
2612 prevScale.Z *= z; 3041 prevScale.Z *= z;
2613
2614// RootPart.IgnoreUndoUpdate = true; 3042// RootPart.IgnoreUndoUpdate = true;
2615 RootPart.Resize(prevScale); 3043 RootPart.Resize(prevScale);
2616// RootPart.IgnoreUndoUpdate = false; 3044// RootPart.IgnoreUndoUpdate = false;
@@ -2641,7 +3069,9 @@ namespace OpenSim.Region.Framework.Scenes
2641 } 3069 }
2642 3070
2643// obPart.IgnoreUndoUpdate = false; 3071// obPart.IgnoreUndoUpdate = false;
2644// obPart.StoreUndoState(); 3072 HasGroupChanged = true;
3073 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3074 ScheduleGroupForTerseUpdate();
2645 } 3075 }
2646 3076
2647// m_log.DebugFormat( 3077// m_log.DebugFormat(
@@ -2701,9 +3131,9 @@ namespace OpenSim.Region.Framework.Scenes
2701 { 3131 {
2702 SceneObjectPart part = GetChildPart(localID); 3132 SceneObjectPart part = GetChildPart(localID);
2703 3133
2704// SceneObjectPart[] parts = m_parts.GetArray(); 3134 SceneObjectPart[] parts = m_parts.GetArray();
2705// for (int i = 0; i < parts.Length; i++) 3135 for (int i = 0; i < parts.Length; i++)
2706// parts[i].StoreUndoState(); 3136 parts[i].StoreUndoState();
2707 3137
2708 if (part != null) 3138 if (part != null)
2709 { 3139 {
@@ -2759,10 +3189,27 @@ namespace OpenSim.Region.Framework.Scenes
2759 obPart.OffsetPosition = obPart.OffsetPosition + diff; 3189 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2760 } 3190 }
2761 3191
2762 AbsolutePosition = newPos; 3192 //We have to set undoing here because otherwise an undo state will be saved
3193 if (!m_rootPart.Undoing)
3194 {
3195 m_rootPart.Undoing = true;
3196 AbsolutePosition = newPos;
3197 m_rootPart.Undoing = false;
3198 }
3199 else
3200 {
3201 AbsolutePosition = newPos;
3202 }
2763 3203
2764 HasGroupChanged = true; 3204 HasGroupChanged = true;
2765 ScheduleGroupForTerseUpdate(); 3205 if (m_rootPart.Undoing)
3206 {
3207 ScheduleGroupForFullUpdate();
3208 }
3209 else
3210 {
3211 ScheduleGroupForTerseUpdate();
3212 }
2766 } 3213 }
2767 3214
2768 #endregion 3215 #endregion
@@ -2839,10 +3286,7 @@ namespace OpenSim.Region.Framework.Scenes
2839 public void UpdateSingleRotation(Quaternion rot, uint localID) 3286 public void UpdateSingleRotation(Quaternion rot, uint localID)
2840 { 3287 {
2841 SceneObjectPart part = GetChildPart(localID); 3288 SceneObjectPart part = GetChildPart(localID);
2842
2843 SceneObjectPart[] parts = m_parts.GetArray(); 3289 SceneObjectPart[] parts = m_parts.GetArray();
2844 for (int i = 0; i < parts.Length; i++)
2845 parts[i].StoreUndoState();
2846 3290
2847 if (part != null) 3291 if (part != null)
2848 { 3292 {
@@ -2880,7 +3324,16 @@ namespace OpenSim.Region.Framework.Scenes
2880 if (part.UUID == m_rootPart.UUID) 3324 if (part.UUID == m_rootPart.UUID)
2881 { 3325 {
2882 UpdateRootRotation(rot); 3326 UpdateRootRotation(rot);
2883 AbsolutePosition = pos; 3327 if (!m_rootPart.Undoing)
3328 {
3329 m_rootPart.Undoing = true;
3330 AbsolutePosition = pos;
3331 m_rootPart.Undoing = false;
3332 }
3333 else
3334 {
3335 AbsolutePosition = pos;
3336 }
2884 } 3337 }
2885 else 3338 else
2886 { 3339 {
@@ -2904,9 +3357,10 @@ namespace OpenSim.Region.Framework.Scenes
2904 3357
2905 Quaternion axRot = rot; 3358 Quaternion axRot = rot;
2906 Quaternion oldParentRot = m_rootPart.RotationOffset; 3359 Quaternion oldParentRot = m_rootPart.RotationOffset;
2907
2908 m_rootPart.StoreUndoState(); 3360 m_rootPart.StoreUndoState();
2909 m_rootPart.UpdateRotation(rot); 3361
3362 //Don't use UpdateRotation because it schedules an update prematurely
3363 m_rootPart.RotationOffset = rot;
2910 if (m_rootPart.PhysActor != null) 3364 if (m_rootPart.PhysActor != null)
2911 { 3365 {
2912 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; 3366 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
@@ -2920,15 +3374,17 @@ namespace OpenSim.Region.Framework.Scenes
2920 if (prim.UUID != m_rootPart.UUID) 3374 if (prim.UUID != m_rootPart.UUID)
2921 { 3375 {
2922 prim.IgnoreUndoUpdate = true; 3376 prim.IgnoreUndoUpdate = true;
3377
3378 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3379 NewRot = Quaternion.Inverse(axRot) * NewRot;
3380 prim.RotationOffset = NewRot;
3381
2923 Vector3 axPos = prim.OffsetPosition; 3382 Vector3 axPos = prim.OffsetPosition;
3383
2924 axPos *= oldParentRot; 3384 axPos *= oldParentRot;
2925 axPos *= Quaternion.Inverse(axRot); 3385 axPos *= Quaternion.Inverse(axRot);
2926 prim.OffsetPosition = axPos; 3386 prim.OffsetPosition = axPos;
2927 Quaternion primsRot = prim.RotationOffset; 3387
2928 Quaternion newRot = oldParentRot * primsRot;
2929 newRot = Quaternion.Inverse(axRot) * newRot;
2930 prim.RotationOffset = newRot;
2931 prim.ScheduleTerseUpdate();
2932 prim.IgnoreUndoUpdate = false; 3388 prim.IgnoreUndoUpdate = false;
2933 } 3389 }
2934 } 3390 }
@@ -2942,8 +3398,8 @@ namespace OpenSim.Region.Framework.Scenes
2942//// childpart.StoreUndoState(); 3398//// childpart.StoreUndoState();
2943// } 3399// }
2944// } 3400// }
2945 3401 HasGroupChanged = true;
2946 m_rootPart.ScheduleTerseUpdate(); 3402 ScheduleGroupForFullUpdate();
2947 3403
2948// m_log.DebugFormat( 3404// m_log.DebugFormat(
2949// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3405// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
@@ -3171,7 +3627,6 @@ namespace OpenSim.Region.Framework.Scenes
3171 public float GetMass() 3627 public float GetMass()
3172 { 3628 {
3173 float retmass = 0f; 3629 float retmass = 0f;
3174
3175 SceneObjectPart[] parts = m_parts.GetArray(); 3630 SceneObjectPart[] parts = m_parts.GetArray();
3176 for (int i = 0; i < parts.Length; i++) 3631 for (int i = 0; i < parts.Length; i++)
3177 retmass += parts[i].GetMass(); 3632 retmass += parts[i].GetMass();
@@ -3267,6 +3722,14 @@ namespace OpenSim.Region.Framework.Scenes
3267 SetFromItemID(uuid); 3722 SetFromItemID(uuid);
3268 } 3723 }
3269 3724
3725 public void ResetOwnerChangeFlag()
3726 {
3727 ForEachPart(delegate(SceneObjectPart part)
3728 {
3729 part.ResetOwnerChangeFlag();
3730 });
3731 }
3732
3270 #endregion 3733 #endregion
3271 } 3734 }
3272} 3735}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 4c339d9..ac39b6b 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -62,7 +62,8 @@ namespace OpenSim.Region.Framework.Scenes
62 TELEPORT = 512, 62 TELEPORT = 512,
63 REGION_RESTART = 1024, 63 REGION_RESTART = 1024,
64 MEDIA = 2048, 64 MEDIA = 2048,
65 ANIMATION = 16384 65 ANIMATION = 16384,
66 POSITION = 32768
66 } 67 }
67 68
68 // I don't really know where to put this except here. 69 // I don't really know where to put this except here.
@@ -184,6 +185,15 @@ namespace OpenSim.Region.Framework.Scenes
184 185
185 public UUID FromFolderID; 186 public UUID FromFolderID;
186 187
188 // The following two are to hold the attachment data
189 // while an object is inworld
190 [XmlIgnore]
191 public byte AttachPoint = 0;
192
193 [XmlIgnore]
194 public Vector3 AttachOffset = Vector3.Zero;
195
196 [XmlIgnore]
187 public int STATUS_ROTATE_X; 197 public int STATUS_ROTATE_X;
188 198
189 public int STATUS_ROTATE_Y; 199 public int STATUS_ROTATE_Y;
@@ -210,8 +220,7 @@ namespace OpenSim.Region.Framework.Scenes
210 220
211 public Vector3 RotationAxis = Vector3.One; 221 public Vector3 RotationAxis = Vector3.One;
212 222
213 public bool VolumeDetectActive; // XmlIgnore set to avoid problems with persistance until I come to care for this 223 public bool VolumeDetectActive;
214 // Certainly this must be a persistant setting finally
215 224
216 public bool IsWaitingForFirstSpinUpdatePacket; 225 public bool IsWaitingForFirstSpinUpdatePacket;
217 226
@@ -251,6 +260,7 @@ namespace OpenSim.Region.Framework.Scenes
251 private Quaternion m_sitTargetOrientation = Quaternion.Identity; 260 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
252 private Vector3 m_sitTargetPosition; 261 private Vector3 m_sitTargetPosition;
253 private string m_sitAnimation = "SIT"; 262 private string m_sitAnimation = "SIT";
263 private bool m_occupied; // KF if any av is sitting on this prim
254 private string m_text = String.Empty; 264 private string m_text = String.Empty;
255 private string m_touchName = String.Empty; 265 private string m_touchName = String.Empty;
256 private readonly Stack<UndoState> m_undo = new Stack<UndoState>(5); 266 private readonly Stack<UndoState> m_undo = new Stack<UndoState>(5);
@@ -283,6 +293,7 @@ namespace OpenSim.Region.Framework.Scenes
283 protected Vector3 m_lastAcceleration; 293 protected Vector3 m_lastAcceleration;
284 protected Vector3 m_lastAngularVelocity; 294 protected Vector3 m_lastAngularVelocity;
285 protected int m_lastTerseSent; 295 protected int m_lastTerseSent;
296 protected float m_buoyancy = 0.0f;
286 297
287 /// <summary> 298 /// <summary>
288 /// Stores media texture data 299 /// Stores media texture data
@@ -338,7 +349,7 @@ namespace OpenSim.Region.Framework.Scenes
338 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, 349 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
339 Quaternion rotationOffset, Vector3 offsetPosition) : this() 350 Quaternion rotationOffset, Vector3 offsetPosition) : this()
340 { 351 {
341 m_name = "Primitive"; 352 m_name = "Object";
342 353
343 CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed); 354 CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed);
344 LastOwnerID = CreatorID = OwnerID = ownerID; 355 LastOwnerID = CreatorID = OwnerID = ownerID;
@@ -378,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes
378 private uint _ownerMask = (uint)PermissionMask.All; 389 private uint _ownerMask = (uint)PermissionMask.All;
379 private uint _groupMask = (uint)PermissionMask.None; 390 private uint _groupMask = (uint)PermissionMask.None;
380 private uint _everyoneMask = (uint)PermissionMask.None; 391 private uint _everyoneMask = (uint)PermissionMask.None;
381 private uint _nextOwnerMask = (uint)PermissionMask.All; 392 private uint _nextOwnerMask = (uint)(PermissionMask.Move | PermissionMask.Modify | PermissionMask.Transfer);
382 private PrimFlags _flags = PrimFlags.None; 393 private PrimFlags _flags = PrimFlags.None;
383 private DateTime m_expires; 394 private DateTime m_expires;
384 private DateTime m_rezzed; 395 private DateTime m_rezzed;
@@ -472,12 +483,16 @@ namespace OpenSim.Region.Framework.Scenes
472 } 483 }
473 484
474 /// <value> 485 /// <value>
475 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes 486 /// Get the inventory list
476 /// </value> 487 /// </value>
477 public TaskInventoryDictionary TaskInventory 488 public TaskInventoryDictionary TaskInventory
478 { 489 {
479 get { return m_inventory.Items; } 490 get {
480 set { m_inventory.Items = value; } 491 return m_inventory.Items;
492 }
493 set {
494 m_inventory.Items = value;
495 }
481 } 496 }
482 497
483 /// <summary> 498 /// <summary>
@@ -621,14 +636,12 @@ namespace OpenSim.Region.Framework.Scenes
621 set { m_LoopSoundSlavePrims = value; } 636 set { m_LoopSoundSlavePrims = value; }
622 } 637 }
623 638
624
625 public Byte[] TextureAnimation 639 public Byte[] TextureAnimation
626 { 640 {
627 get { return m_TextureAnimation; } 641 get { return m_TextureAnimation; }
628 set { m_TextureAnimation = value; } 642 set { m_TextureAnimation = value; }
629 } 643 }
630 644
631
632 public Byte[] ParticleSystem 645 public Byte[] ParticleSystem
633 { 646 {
634 get { return m_particleSystem; } 647 get { return m_particleSystem; }
@@ -665,9 +678,11 @@ namespace OpenSim.Region.Framework.Scenes
665 { 678 {
666 // If this is a linkset, we don't want the physics engine mucking up our group position here. 679 // If this is a linkset, we don't want the physics engine mucking up our group position here.
667 PhysicsActor actor = PhysActor; 680 PhysicsActor actor = PhysActor;
668 if (actor != null && ParentID == 0) 681 if (ParentID == 0)
669 { 682 {
670 m_groupPosition = actor.Position; 683 if (actor != null)
684 m_groupPosition = actor.Position;
685 return m_groupPosition;
671 } 686 }
672 687
673 if (ParentGroup.IsAttachment) 688 if (ParentGroup.IsAttachment)
@@ -677,12 +692,14 @@ namespace OpenSim.Region.Framework.Scenes
677 return sp.AbsolutePosition; 692 return sp.AbsolutePosition;
678 } 693 }
679 694
695 // use root prim's group position. Physics may have updated it
696 if (ParentGroup.RootPart != this)
697 m_groupPosition = ParentGroup.RootPart.GroupPosition;
680 return m_groupPosition; 698 return m_groupPosition;
681 } 699 }
682 set 700 set
683 { 701 {
684 m_groupPosition = value; 702 m_groupPosition = value;
685
686 PhysicsActor actor = PhysActor; 703 PhysicsActor actor = PhysActor;
687 if (actor != null) 704 if (actor != null)
688 { 705 {
@@ -708,16 +725,6 @@ namespace OpenSim.Region.Framework.Scenes
708 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); 725 m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
709 } 726 }
710 } 727 }
711
712 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
713 if (SitTargetAvatar != UUID.Zero)
714 {
715 ScenePresence avatar;
716 if (ParentGroup.Scene.TryGetScenePresence(SitTargetAvatar, out avatar))
717 {
718 avatar.ParentPosition = GetWorldPosition();
719 }
720 }
721 } 728 }
722 } 729 }
723 730
@@ -726,7 +733,7 @@ namespace OpenSim.Region.Framework.Scenes
726 get { return m_offsetPosition; } 733 get { return m_offsetPosition; }
727 set 734 set
728 { 735 {
729// StoreUndoState(); 736 Vector3 oldpos = m_offsetPosition;
730 m_offsetPosition = value; 737 m_offsetPosition = value;
731 738
732 if (ParentGroup != null && !ParentGroup.IsDeleted) 739 if (ParentGroup != null && !ParentGroup.IsDeleted)
@@ -741,7 +748,22 @@ namespace OpenSim.Region.Framework.Scenes
741 if (ParentGroup.Scene != null) 748 if (ParentGroup.Scene != null)
742 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); 749 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
743 } 750 }
751
752 if (!m_parentGroup.m_dupeInProgress)
753 {
754 List<ScenePresence> avs = ParentGroup.GetLinkedAvatars();
755 foreach (ScenePresence av in avs)
756 {
757 if (av.ParentID == m_localId)
758 {
759 Vector3 offset = (m_offsetPosition - oldpos);
760 av.AbsolutePosition += offset;
761 av.SendAvatarDataToAllAgents();
762 }
763 }
764 }
744 } 765 }
766 TriggerScriptChangedEvent(Changed.POSITION);
745 } 767 }
746 } 768 }
747 769
@@ -890,7 +912,16 @@ namespace OpenSim.Region.Framework.Scenes
890 /// <summary></summary> 912 /// <summary></summary>
891 public Vector3 Acceleration 913 public Vector3 Acceleration
892 { 914 {
893 get { return m_acceleration; } 915 get
916 {
917 PhysicsActor actor = PhysActor;
918 if (actor != null)
919 {
920 m_acceleration = actor.Acceleration;
921 }
922 return m_acceleration;
923 }
924
894 set { m_acceleration = value; } 925 set { m_acceleration = value; }
895 } 926 }
896 927
@@ -1027,10 +1058,7 @@ namespace OpenSim.Region.Framework.Scenes
1027 { 1058 {
1028 get 1059 get
1029 { 1060 {
1030 if (ParentGroup.IsAttachment) 1061 return GroupPosition + (m_offsetPosition * ParentGroup.RootPart.RotationOffset);
1031 return GroupPosition;
1032
1033 return m_offsetPosition + m_groupPosition;
1034 } 1062 }
1035 } 1063 }
1036 1064
@@ -1200,6 +1228,13 @@ namespace OpenSim.Region.Framework.Scenes
1200 _flags = value; 1228 _flags = value;
1201 } 1229 }
1202 } 1230 }
1231
1232 [XmlIgnore]
1233 public bool IsOccupied // KF If an av is sittingon this prim
1234 {
1235 get { return m_occupied; }
1236 set { m_occupied = value; }
1237 }
1203 1238
1204 /// <summary> 1239 /// <summary>
1205 /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero 1240 /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero
@@ -1259,6 +1294,19 @@ namespace OpenSim.Region.Framework.Scenes
1259 set { m_collisionSoundVolume = value; } 1294 set { m_collisionSoundVolume = value; }
1260 } 1295 }
1261 1296
1297 public float Buoyancy
1298 {
1299 get { return m_buoyancy; }
1300 set
1301 {
1302 m_buoyancy = value;
1303 if (PhysActor != null)
1304 {
1305 PhysActor.Buoyancy = value;
1306 }
1307 }
1308 }
1309
1262 #endregion Public Properties with only Get 1310 #endregion Public Properties with only Get
1263 1311
1264 private uint ApplyMask(uint val, bool set, uint mask) 1312 private uint ApplyMask(uint val, bool set, uint mask)
@@ -1579,6 +1627,9 @@ namespace OpenSim.Region.Framework.Scenes
1579 1627
1580 // Move afterwards ResetIDs as it clears the localID 1628 // Move afterwards ResetIDs as it clears the localID
1581 dupe.LocalId = localID; 1629 dupe.LocalId = localID;
1630 if(dupe.PhysActor != null)
1631 dupe.PhysActor.LocalID = localID;
1632
1582 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. 1633 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1583 dupe.LastOwnerID = OwnerID; 1634 dupe.LastOwnerID = OwnerID;
1584 1635
@@ -2584,17 +2635,18 @@ namespace OpenSim.Region.Framework.Scenes
2584 //Trys to fetch sound id from prim's inventory. 2635 //Trys to fetch sound id from prim's inventory.
2585 //Prim's inventory doesn't support non script items yet 2636 //Prim's inventory doesn't support non script items yet
2586 2637
2587 lock (TaskInventory) 2638 TaskInventory.LockItemsForRead(true);
2639
2640 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2588 { 2641 {
2589 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 2642 if (item.Value.Name == sound)
2590 { 2643 {
2591 if (item.Value.Name == sound) 2644 soundID = item.Value.ItemID;
2592 { 2645 break;
2593 soundID = item.Value.ItemID;
2594 break;
2595 }
2596 } 2646 }
2597 } 2647 }
2648
2649 TaskInventory.LockItemsForRead(false);
2598 } 2650 }
2599 2651
2600 ParentGroup.Scene.ForEachRootScenePresence(delegate(ScenePresence sp) 2652 ParentGroup.Scene.ForEachRootScenePresence(delegate(ScenePresence sp)
@@ -2914,8 +2966,8 @@ namespace OpenSim.Region.Framework.Scenes
2914 { 2966 {
2915 const float ROTATION_TOLERANCE = 0.01f; 2967 const float ROTATION_TOLERANCE = 0.01f;
2916 const float VELOCITY_TOLERANCE = 0.001f; 2968 const float VELOCITY_TOLERANCE = 0.001f;
2917 const float POSITION_TOLERANCE = 0.05f; 2969 const float POSITION_TOLERANCE = 0.05f; // I don't like this, but I suppose it's necessary
2918 const int TIME_MS_TOLERANCE = 3000; 2970 const int TIME_MS_TOLERANCE = 200; //llSetPos has a 200ms delay. This should NOT be 3 seconds.
2919 2971
2920 switch (UpdateFlag) 2972 switch (UpdateFlag)
2921 { 2973 {
@@ -2977,17 +3029,16 @@ namespace OpenSim.Region.Framework.Scenes
2977 if (!UUID.TryParse(sound, out soundID)) 3029 if (!UUID.TryParse(sound, out soundID))
2978 { 3030 {
2979 // search sound file from inventory 3031 // search sound file from inventory
2980 lock (TaskInventory) 3032 TaskInventory.LockItemsForRead(true);
3033 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory)
2981 { 3034 {
2982 foreach (KeyValuePair<UUID, TaskInventoryItem> item in TaskInventory) 3035 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound)
2983 { 3036 {
2984 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) 3037 soundID = item.Value.ItemID;
2985 { 3038 break;
2986 soundID = item.Value.ItemID;
2987 break;
2988 }
2989 } 3039 }
2990 } 3040 }
3041 TaskInventory.LockItemsForRead(false);
2991 } 3042 }
2992 3043
2993 if (soundID == UUID.Zero) 3044 if (soundID == UUID.Zero)
@@ -3454,10 +3505,10 @@ namespace OpenSim.Region.Framework.Scenes
3454 // TODO: May need to fix for group comparison 3505 // TODO: May need to fix for group comparison
3455 if (last.Compare(this)) 3506 if (last.Compare(this))
3456 { 3507 {
3457 // m_log.DebugFormat( 3508 // m_log.DebugFormat(
3458 // "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}", 3509 // "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}",
3459 // Name, LocalId, m_undo.Count); 3510 // Name, LocalId, m_undo.Count);
3460 3511
3461 return; 3512 return;
3462 } 3513 }
3463 } 3514 }
@@ -3470,29 +3521,29 @@ namespace OpenSim.Region.Framework.Scenes
3470 if (ParentGroup.GetSceneMaxUndo() > 0) 3521 if (ParentGroup.GetSceneMaxUndo() > 0)
3471 { 3522 {
3472 UndoState nUndo = new UndoState(this, forGroup); 3523 UndoState nUndo = new UndoState(this, forGroup);
3473 3524
3474 m_undo.Push(nUndo); 3525 m_undo.Push(nUndo);
3475 3526
3476 if (m_redo.Count > 0) 3527 if (m_redo.Count > 0)
3477 m_redo.Clear(); 3528 m_redo.Clear();
3478 3529
3479 // m_log.DebugFormat( 3530 // m_log.DebugFormat(
3480 // "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}", 3531 // "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}",
3481 // Name, LocalId, forGroup, m_undo.Count); 3532 // Name, LocalId, forGroup, m_undo.Count);
3482 } 3533 }
3483 } 3534 }
3484 } 3535 }
3485 } 3536 }
3486// else 3537 // else
3487// { 3538 // {
3488// m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId); 3539 // m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId);
3489// } 3540 // }
3490 } 3541 }
3491// else 3542 // else
3492// { 3543 // {
3493// m_log.DebugFormat( 3544 // m_log.DebugFormat(
3494// "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId); 3545 // "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId);
3495// } 3546 // }
3496 } 3547 }
3497 3548
3498 /// <summary> 3549 /// <summary>
@@ -4223,6 +4274,9 @@ namespace OpenSim.Region.Framework.Scenes
4223 bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0); 4274 bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0);
4224 bool wasVD = VolumeDetectActive; 4275 bool wasVD = VolumeDetectActive;
4225 4276
4277// m_log.DebugFormat("[SOP]: Old states: phys: {0} temp: {1} phan: {2} vd: {3}", wasUsingPhysics, wasTemporary, wasPhantom, wasVD);
4278// m_log.DebugFormat("[SOP]: New states: phys: {0} temp: {1} phan: {2} vd: {3}", UsePhysics, SetTemporary, SetPhantom, SetVD);
4279
4226 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD)) 4280 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD))
4227 return; 4281 return;
4228 4282
@@ -4252,6 +4306,11 @@ namespace OpenSim.Region.Framework.Scenes
4252 SetPhantom = false; 4306 SetPhantom = false;
4253 } 4307 }
4254 } 4308 }
4309 else if (wasVD)
4310 {
4311 // Correspondingly, if VD is turned off, also turn off phantom
4312 SetPhantom = false;
4313 }
4255 4314
4256 if (UsePhysics && IsJoint()) 4315 if (UsePhysics && IsJoint())
4257 { 4316 {
@@ -4750,5 +4809,17 @@ namespace OpenSim.Region.Framework.Scenes
4750 Color color = Color; 4809 Color color = Color;
4751 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); 4810 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A));
4752 } 4811 }
4812
4813 public void ResetOwnerChangeFlag()
4814 {
4815 List<UUID> inv = Inventory.GetInventoryList();
4816
4817 foreach (UUID itemID in inv)
4818 {
4819 TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
4820 item.OwnerChanged = false;
4821 Inventory.UpdateInventoryItem(item, false, false);
4822 }
4823 }
4753 } 4824 }
4754} 4825}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index f2d1915..ca85d10 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
@@ -123,38 +129,45 @@ namespace OpenSim.Region.Framework.Scenes
123 public void ResetInventoryIDs() 129 public void ResetInventoryIDs()
124 { 130 {
125 if (null == m_part) 131 if (null == m_part)
126 return; 132 m_items.LockItemsForWrite(true);
127 133
128 lock (m_items) 134 if (Items.Count == 0)
129 { 135 {
130 if (0 == m_items.Count) 136 m_items.LockItemsForWrite(false);
131 return; 137 return;
138 }
132 139
133 IList<TaskInventoryItem> items = GetInventoryItems(); 140 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
134 m_items.Clear(); 141 Items.Clear();
135 142
136 foreach (TaskInventoryItem item in items) 143 foreach (TaskInventoryItem item in items)
137 { 144 {
138 item.ResetIDs(m_part.UUID); 145 item.ResetIDs(m_part.UUID);
139 m_items.Add(item.ItemID, item); 146 Items.Add(item.ItemID, item);
140 }
141 } 147 }
148 m_items.LockItemsForWrite(false);
142 } 149 }
143 150
144 public void ResetObjectID() 151 public void ResetObjectID()
145 { 152 {
146 lock (Items) 153 m_items.LockItemsForWrite(true);
154
155 if (Items.Count == 0)
147 { 156 {
148 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); 157 m_items.LockItemsForWrite(false);
149 Items.Clear(); 158 return;
150
151 foreach (TaskInventoryItem item in items)
152 {
153 item.ParentPartID = m_part.UUID;
154 item.ParentID = m_part.UUID;
155 Items.Add(item.ItemID, item);
156 }
157 } 159 }
160
161 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
162 Items.Clear();
163
164 foreach (TaskInventoryItem item in items)
165 {
166 item.ParentPartID = m_part.UUID;
167 item.ParentID = m_part.UUID;
168 Items.Add(item.ItemID, item);
169 }
170 m_items.LockItemsForWrite(false);
158 } 171 }
159 172
160 /// <summary> 173 /// <summary>
@@ -163,12 +176,11 @@ namespace OpenSim.Region.Framework.Scenes
163 /// <param name="ownerId"></param> 176 /// <param name="ownerId"></param>
164 public void ChangeInventoryOwner(UUID ownerId) 177 public void ChangeInventoryOwner(UUID ownerId)
165 { 178 {
166 lock (Items) 179 m_items.LockItemsForWrite(true);
180 if (0 == Items.Count)
167 { 181 {
168 if (0 == Items.Count) 182 m_items.LockItemsForWrite(false);
169 { 183 return;
170 return;
171 }
172 } 184 }
173 185
174 HasInventoryChanged = true; 186 HasInventoryChanged = true;
@@ -184,6 +196,7 @@ namespace OpenSim.Region.Framework.Scenes
184 item.PermsGranter = UUID.Zero; 196 item.PermsGranter = UUID.Zero;
185 item.OwnerChanged = true; 197 item.OwnerChanged = true;
186 } 198 }
199 m_items.LockItemsForWrite(false);
187 } 200 }
188 201
189 /// <summary> 202 /// <summary>
@@ -192,12 +205,11 @@ namespace OpenSim.Region.Framework.Scenes
192 /// <param name="groupID"></param> 205 /// <param name="groupID"></param>
193 public void ChangeInventoryGroup(UUID groupID) 206 public void ChangeInventoryGroup(UUID groupID)
194 { 207 {
195 lock (Items) 208 m_items.LockItemsForWrite(true);
209 if (0 == Items.Count)
196 { 210 {
197 if (0 == Items.Count) 211 m_items.LockItemsForWrite(false);
198 { 212 return;
199 return;
200 }
201 } 213 }
202 214
203 // Don't let this set the HasGroupChanged flag for attachments 215 // Don't let this set the HasGroupChanged flag for attachments
@@ -209,12 +221,45 @@ namespace OpenSim.Region.Framework.Scenes
209 m_part.ParentGroup.HasGroupChanged = true; 221 m_part.ParentGroup.HasGroupChanged = true;
210 } 222 }
211 223
212 List<TaskInventoryItem> items = GetInventoryItems(); 224 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
213 foreach (TaskInventoryItem item in items) 225 foreach (TaskInventoryItem item in items)
214 { 226 {
215 if (groupID != item.GroupID) 227 if (groupID != item.GroupID)
228 {
216 item.GroupID = groupID; 229 item.GroupID = groupID;
230 }
217 } 231 }
232 m_items.LockItemsForWrite(false);
233 }
234
235 private void QueryScriptStates()
236 {
237 if (m_part == null || m_part.ParentGroup == null)
238 return;
239
240 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
241 if (engines == null) // No engine at all
242 return;
243
244 Items.LockItemsForRead(true);
245 foreach (TaskInventoryItem item in Items.Values)
246 {
247 if (item.InvType == (int)InventoryType.LSL)
248 {
249 foreach (IScriptModule e in engines)
250 {
251 bool running;
252
253 if (e.HasScript(item.ItemID, out running))
254 {
255 item.ScriptRunning = running;
256 break;
257 }
258 }
259 }
260 }
261
262 Items.LockItemsForRead(false);
218 } 263 }
219 264
220 /// <summary> 265 /// <summary>
@@ -222,9 +267,14 @@ namespace OpenSim.Region.Framework.Scenes
222 /// </summary> 267 /// </summary>
223 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) 268 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
224 { 269 {
225 List<TaskInventoryItem> scripts = GetInventoryScripts(); 270 Items.LockItemsForRead(true);
226 foreach (TaskInventoryItem item in scripts) 271 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
227 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 272 Items.LockItemsForRead(false);
273 foreach (TaskInventoryItem item in items)
274 {
275 if ((int)InventoryType.LSL == item.InvType)
276 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
277 }
228 } 278 }
229 279
230 public ArrayList GetScriptErrors(UUID itemID) 280 public ArrayList GetScriptErrors(UUID itemID)
@@ -255,9 +305,18 @@ namespace OpenSim.Region.Framework.Scenes
255 /// </param> 305 /// </param>
256 public void RemoveScriptInstances(bool sceneObjectBeingDeleted) 306 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
257 { 307 {
258 List<TaskInventoryItem> scripts = GetInventoryScripts(); 308 Items.LockItemsForRead(true);
259 foreach (TaskInventoryItem item in scripts) 309 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
260 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); 310 Items.LockItemsForRead(false);
311
312 foreach (TaskInventoryItem item in items)
313 {
314 if ((int)InventoryType.LSL == item.InvType)
315 {
316 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
317 m_part.RemoveScriptEvents(item.ItemID);
318 }
319 }
261 } 320 }
262 321
263 /// <summary> 322 /// <summary>
@@ -271,7 +330,10 @@ namespace OpenSim.Region.Framework.Scenes
271// item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName); 330// item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName);
272 331
273 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) 332 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
333 {
334 StoreScriptError(item.ItemID, "no permission");
274 return; 335 return;
336 }
275 337
276 m_part.AddFlag(PrimFlags.Scripted); 338 m_part.AddFlag(PrimFlags.Scripted);
277 339
@@ -280,14 +342,13 @@ namespace OpenSim.Region.Framework.Scenes
280 if (stateSource == 2 && // Prim crossing 342 if (stateSource == 2 && // Prim crossing
281 m_part.ParentGroup.Scene.m_trustBinaries) 343 m_part.ParentGroup.Scene.m_trustBinaries)
282 { 344 {
283 lock (m_items) 345 m_items.LockItemsForWrite(true);
284 { 346 m_items[item.ItemID].PermsMask = 0;
285 m_items[item.ItemID].PermsMask = 0; 347 m_items[item.ItemID].PermsGranter = UUID.Zero;
286 m_items[item.ItemID].PermsGranter = UUID.Zero; 348 m_items.LockItemsForWrite(false);
287 }
288
289 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 349 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
290 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); 350 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
351 StoreScriptErrors(item.ItemID, null);
291 m_part.ParentGroup.AddActiveScriptCount(1); 352 m_part.ParentGroup.AddActiveScriptCount(1);
292 m_part.ScheduleFullUpdate(); 353 m_part.ScheduleFullUpdate();
293 return; 354 return;
@@ -296,6 +357,8 @@ namespace OpenSim.Region.Framework.Scenes
296 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); 357 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
297 if (null == asset) 358 if (null == asset)
298 { 359 {
360 string msg = String.Format("asset ID {0} could not be found", item.AssetID);
361 StoreScriptError(item.ItemID, msg);
299 m_log.ErrorFormat( 362 m_log.ErrorFormat(
300 "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", 363 "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
301 item.Name, item.ItemID, m_part.AbsolutePosition, 364 item.Name, item.ItemID, m_part.AbsolutePosition,
@@ -306,16 +369,21 @@ namespace OpenSim.Region.Framework.Scenes
306 if (m_part.ParentGroup.m_savedScriptState != null) 369 if (m_part.ParentGroup.m_savedScriptState != null)
307 item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID); 370 item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID);
308 371
309 lock (m_items) 372 m_items.LockItemsForWrite(true);
310 {
311 m_items[item.ItemID].OldItemID = item.OldItemID;
312 m_items[item.ItemID].PermsMask = 0;
313 m_items[item.ItemID].PermsGranter = UUID.Zero;
314 }
315 373
374 m_items[item.ItemID].OldItemID = item.OldItemID;
375 m_items[item.ItemID].PermsMask = 0;
376 m_items[item.ItemID].PermsGranter = UUID.Zero;
377
378 m_items.LockItemsForWrite(false);
379
316 string script = Utils.BytesToString(asset.Data); 380 string script = Utils.BytesToString(asset.Data);
317 m_part.ParentGroup.Scene.EventManager.TriggerRezScript( 381 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
318 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); 382 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
383 StoreScriptErrors(item.ItemID, null);
384 if (!item.ScriptRunning)
385 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(
386 m_part.LocalId, item.ItemID);
319 m_part.ParentGroup.AddActiveScriptCount(1); 387 m_part.ParentGroup.AddActiveScriptCount(1);
320 m_part.ScheduleFullUpdate(); 388 m_part.ScheduleFullUpdate();
321 } 389 }
@@ -386,20 +454,146 @@ namespace OpenSim.Region.Framework.Scenes
386 454
387 /// <summary> 455 /// <summary>
388 /// Start a script which is in this prim's inventory. 456 /// Start a script which is in this prim's inventory.
457 /// Some processing may occur in the background, but this routine returns asap.
389 /// </summary> 458 /// </summary>
390 /// <param name="itemId"> 459 /// <param name="itemId">
391 /// A <see cref="UUID"/> 460 /// A <see cref="UUID"/>
392 /// </param> 461 /// </param>
393 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) 462 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
394 { 463 {
395 TaskInventoryItem item = GetInventoryItem(itemId); 464 lock (m_scriptErrors)
396 if (item != null) 465 {
397 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); 466 // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
467 m_scriptErrors.Remove(itemId);
468 }
469 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
470 }
471
472 private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
473 {
474 m_items.LockItemsForRead(true);
475 if (m_items.ContainsKey(itemId))
476 {
477 if (m_items.ContainsKey(itemId))
478 {
479 m_items.LockItemsForRead(false);
480 CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource);
481 }
482 else
483 {
484 m_items.LockItemsForRead(false);
485 string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID,
486 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
487 StoreScriptError(itemId, msg);
488 m_log.ErrorFormat(
489 "[PRIM INVENTORY]: " +
490 "Couldn't start script with ID {0} since it {1}", itemId, msg);
491 }
492 }
398 else 493 else
494 {
495 m_items.LockItemsForRead(false);
496 string msg = String.Format("couldn't be found for prim {0}, {1}", m_part.Name, m_part.UUID);
497 StoreScriptError(itemId, msg);
399 m_log.ErrorFormat( 498 m_log.ErrorFormat(
400 "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", 499 "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
401 itemId, m_part.Name, m_part.UUID, 500 itemId, m_part.Name, m_part.UUID,
402 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 501 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
502 }
503
504 }
505
506 /// <summary>
507 /// Start a script which is in this prim's inventory and return any compilation error messages.
508 /// </summary>
509 /// <param name="itemId">
510 /// A <see cref="UUID"/>
511 /// </param>
512 public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
513 {
514 ArrayList errors;
515
516 // Indicate to CreateScriptInstanceInternal() we want it to
517 // post any compilation/loading error messages
518 lock (m_scriptErrors)
519 {
520 m_scriptErrors[itemId] = null;
521 }
522
523 // Perform compilation/loading
524 CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
525
526 // Wait for and retrieve any errors
527 lock (m_scriptErrors)
528 {
529 while ((errors = m_scriptErrors[itemId]) == null)
530 {
531 if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
532 {
533 m_log.ErrorFormat(
534 "[PRIM INVENTORY]: " +
535 "timedout waiting for script {0} errors", itemId);
536 errors = m_scriptErrors[itemId];
537 if (errors == null)
538 {
539 errors = new ArrayList(1);
540 errors.Add("timedout waiting for errors");
541 }
542 break;
543 }
544 }
545 m_scriptErrors.Remove(itemId);
546 }
547 return errors;
548 }
549
550 // Signal to CreateScriptInstanceEr() that compilation/loading is complete
551 private void StoreScriptErrors(UUID itemId, ArrayList errors)
552 {
553 lock (m_scriptErrors)
554 {
555 // If compilation/loading initiated via CreateScriptInstance(),
556 // it does not want the errors, so just get out
557 if (!m_scriptErrors.ContainsKey(itemId))
558 {
559 return;
560 }
561
562 // Initiated via CreateScriptInstanceEr(), if we know what the
563 // errors are, save them and wake CreateScriptInstanceEr().
564 if (errors != null)
565 {
566 m_scriptErrors[itemId] = errors;
567 System.Threading.Monitor.PulseAll(m_scriptErrors);
568 return;
569 }
570 }
571
572 // Initiated via CreateScriptInstanceEr() but we don't know what
573 // the errors are yet, so retrieve them from the script engine.
574 // This may involve some waiting internal to GetScriptErrors().
575 errors = GetScriptErrors(itemId);
576
577 // Get a default non-null value to indicate success.
578 if (errors == null)
579 {
580 errors = new ArrayList();
581 }
582
583 // Post to CreateScriptInstanceEr() and wake it up
584 lock (m_scriptErrors)
585 {
586 m_scriptErrors[itemId] = errors;
587 System.Threading.Monitor.PulseAll(m_scriptErrors);
588 }
589 }
590
591 // Like StoreScriptErrors(), but just posts a single string message
592 private void StoreScriptError(UUID itemId, string message)
593 {
594 ArrayList errors = new ArrayList(1);
595 errors.Add(message);
596 StoreScriptErrors(itemId, errors);
403 } 597 }
404 598
405 /// <summary> 599 /// <summary>
@@ -412,15 +606,7 @@ namespace OpenSim.Region.Framework.Scenes
412 /// </param> 606 /// </param>
413 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) 607 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
414 { 608 {
415 bool scriptPresent = false; 609 if (m_items.ContainsKey(itemId))
416
417 lock (m_items)
418 {
419 if (m_items.ContainsKey(itemId))
420 scriptPresent = true;
421 }
422
423 if (scriptPresent)
424 { 610 {
425 if (!sceneObjectBeingDeleted) 611 if (!sceneObjectBeingDeleted)
426 m_part.RemoveScriptEvents(itemId); 612 m_part.RemoveScriptEvents(itemId);
@@ -445,14 +631,16 @@ namespace OpenSim.Region.Framework.Scenes
445 /// <returns></returns> 631 /// <returns></returns>
446 private bool InventoryContainsName(string name) 632 private bool InventoryContainsName(string name)
447 { 633 {
448 lock (m_items) 634 m_items.LockItemsForRead(true);
635 foreach (TaskInventoryItem item in m_items.Values)
449 { 636 {
450 foreach (TaskInventoryItem item in m_items.Values) 637 if (item.Name == name)
451 { 638 {
452 if (item.Name == name) 639 m_items.LockItemsForRead(false);
453 return true; 640 return true;
454 } 641 }
455 } 642 }
643 m_items.LockItemsForRead(false);
456 return false; 644 return false;
457 } 645 }
458 646
@@ -494,8 +682,9 @@ namespace OpenSim.Region.Framework.Scenes
494 /// <param name="item"></param> 682 /// <param name="item"></param>
495 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) 683 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
496 { 684 {
497 List<TaskInventoryItem> il = GetInventoryItems(); 685 m_items.LockItemsForRead(true);
498 686 List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
687 m_items.LockItemsForRead(false);
499 foreach (TaskInventoryItem i in il) 688 foreach (TaskInventoryItem i in il)
500 { 689 {
501 if (i.Name == item.Name) 690 if (i.Name == item.Name)
@@ -533,14 +722,14 @@ namespace OpenSim.Region.Framework.Scenes
533 item.Name = name; 722 item.Name = name;
534 item.GroupID = m_part.GroupID; 723 item.GroupID = m_part.GroupID;
535 724
536 lock (m_items) 725 m_items.LockItemsForWrite(true);
537 m_items.Add(item.ItemID, item); 726 m_items.Add(item.ItemID, item);
538 727 m_items.LockItemsForWrite(false);
539 if (allowedDrop) 728 if (allowedDrop)
540 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); 729 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
541 else 730 else
542 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 731 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
543 732
544 m_inventorySerial++; 733 m_inventorySerial++;
545 //m_inventorySerial += 2; 734 //m_inventorySerial += 2;
546 HasInventoryChanged = true; 735 HasInventoryChanged = true;
@@ -556,15 +745,15 @@ namespace OpenSim.Region.Framework.Scenes
556 /// <param name="items"></param> 745 /// <param name="items"></param>
557 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) 746 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
558 { 747 {
559 lock (m_items) 748 m_items.LockItemsForWrite(true);
749 foreach (TaskInventoryItem item in items)
560 { 750 {
561 foreach (TaskInventoryItem item in items) 751 m_items.Add(item.ItemID, item);
562 { 752// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
563 m_items.Add(item.ItemID, item);
564// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
565 }
566 m_inventorySerial++;
567 } 753 }
754 m_items.LockItemsForWrite(false);
755
756 m_inventorySerial++;
568 } 757 }
569 758
570 /// <summary> 759 /// <summary>
@@ -575,10 +764,9 @@ namespace OpenSim.Region.Framework.Scenes
575 public TaskInventoryItem GetInventoryItem(UUID itemId) 764 public TaskInventoryItem GetInventoryItem(UUID itemId)
576 { 765 {
577 TaskInventoryItem item; 766 TaskInventoryItem item;
578 767 m_items.LockItemsForRead(true);
579 lock (m_items) 768 m_items.TryGetValue(itemId, out item);
580 m_items.TryGetValue(itemId, out item); 769 m_items.LockItemsForRead(false);
581
582 return item; 770 return item;
583 } 771 }
584 772
@@ -594,15 +782,16 @@ namespace OpenSim.Region.Framework.Scenes
594 { 782 {
595 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(); 783 IList<TaskInventoryItem> items = new List<TaskInventoryItem>();
596 784
597 lock (m_items) 785 m_items.LockItemsForRead(true);
786
787 foreach (TaskInventoryItem item in m_items.Values)
598 { 788 {
599 foreach (TaskInventoryItem item in m_items.Values) 789 if (item.Name == name)
600 { 790 items.Add(item);
601 if (item.Name == name)
602 items.Add(item);
603 }
604 } 791 }
605 792
793 m_items.LockItemsForRead(false);
794
606 return items; 795 return items;
607 } 796 }
608 797
@@ -621,6 +810,9 @@ namespace OpenSim.Region.Framework.Scenes
621 string xmlData = Utils.BytesToString(rezAsset.Data); 810 string xmlData = Utils.BytesToString(rezAsset.Data);
622 SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); 811 SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
623 812
813 group.RootPart.AttachPoint = group.RootPart.Shape.State;
814 group.RootPart.AttachOffset = group.AbsolutePosition;
815
624 group.ResetIDs(); 816 group.ResetIDs();
625 817
626 SceneObjectPart rootPart = group.GetChildPart(group.UUID); 818 SceneObjectPart rootPart = group.GetChildPart(group.UUID);
@@ -695,8 +887,9 @@ namespace OpenSim.Region.Framework.Scenes
695 887
696 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) 888 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
697 { 889 {
698 TaskInventoryItem it = GetInventoryItem(item.ItemID); 890 m_items.LockItemsForWrite(true);
699 if (it != null) 891
892 if (m_items.ContainsKey(item.ItemID))
700 { 893 {
701// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name); 894// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
702 895
@@ -709,14 +902,10 @@ namespace OpenSim.Region.Framework.Scenes
709 item.GroupID = m_part.GroupID; 902 item.GroupID = m_part.GroupID;
710 903
711 if (item.AssetID == UUID.Zero) 904 if (item.AssetID == UUID.Zero)
712 item.AssetID = it.AssetID; 905 item.AssetID = m_items[item.ItemID].AssetID;
713 906
714 lock (m_items) 907 m_items[item.ItemID] = item;
715 { 908 m_inventorySerial++;
716 m_items[item.ItemID] = item;
717 m_inventorySerial++;
718 }
719
720 if (fireScriptEvents) 909 if (fireScriptEvents)
721 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 910 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
722 911
@@ -725,7 +914,7 @@ namespace OpenSim.Region.Framework.Scenes
725 HasInventoryChanged = true; 914 HasInventoryChanged = true;
726 m_part.ParentGroup.HasGroupChanged = true; 915 m_part.ParentGroup.HasGroupChanged = true;
727 } 916 }
728 917 m_items.LockItemsForWrite(false);
729 return true; 918 return true;
730 } 919 }
731 else 920 else
@@ -736,8 +925,9 @@ namespace OpenSim.Region.Framework.Scenes
736 item.ItemID, m_part.Name, m_part.UUID, 925 item.ItemID, m_part.Name, m_part.UUID,
737 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); 926 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
738 } 927 }
739 return false; 928 m_items.LockItemsForWrite(false);
740 929
930 return false;
741 } 931 }
742 932
743 /// <summary> 933 /// <summary>
@@ -748,43 +938,59 @@ namespace OpenSim.Region.Framework.Scenes
748 /// in this prim's inventory.</returns> 938 /// in this prim's inventory.</returns>
749 public int RemoveInventoryItem(UUID itemID) 939 public int RemoveInventoryItem(UUID itemID)
750 { 940 {
751 TaskInventoryItem item = GetInventoryItem(itemID); 941 m_items.LockItemsForRead(true);
752 if (item != null) 942
943 if (m_items.ContainsKey(itemID))
753 { 944 {
754 int type = m_items[itemID].InvType; 945 int type = m_items[itemID].InvType;
946 m_items.LockItemsForRead(false);
755 if (type == 10) // Script 947 if (type == 10) // Script
756 { 948 {
757 m_part.RemoveScriptEvents(itemID);
758 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); 949 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
759 } 950 }
951 m_items.LockItemsForWrite(true);
760 m_items.Remove(itemID); 952 m_items.Remove(itemID);
953 m_items.LockItemsForWrite(false);
761 m_inventorySerial++; 954 m_inventorySerial++;
762 m_part.TriggerScriptChangedEvent(Changed.INVENTORY); 955 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
763 956
764 HasInventoryChanged = true; 957 HasInventoryChanged = true;
765 m_part.ParentGroup.HasGroupChanged = true; 958 m_part.ParentGroup.HasGroupChanged = true;
766 959
767 if (!ContainsScripts()) 960 int scriptcount = 0;
961 m_items.LockItemsForRead(true);
962 foreach (TaskInventoryItem item in m_items.Values)
963 {
964 if (item.Type == 10)
965 {
966 scriptcount++;
967 }
968 }
969 m_items.LockItemsForRead(false);
970
971
972 if (scriptcount <= 0)
973 {
768 m_part.RemFlag(PrimFlags.Scripted); 974 m_part.RemFlag(PrimFlags.Scripted);
975 }
769 976
770 m_part.ScheduleFullUpdate(); 977 m_part.ScheduleFullUpdate();
771 978
772 return type; 979 return type;
773
774 } 980 }
775 else 981 else
776 { 982 {
983 m_items.LockItemsForRead(false);
777 m_log.ErrorFormat( 984 m_log.ErrorFormat(
778 "[PRIM INVENTORY]: " + 985 "[PRIM INVENTORY]: " +
779 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", 986 "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
780 itemID, m_part.Name, m_part.UUID, 987 itemID, m_part.Name, m_part.UUID);
781 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
782 } 988 }
783 989
784 return -1; 990 return -1;
785 } 991 }
786 992
787 private bool CreateInventoryFile() 993 private bool CreateInventoryFileName()
788 { 994 {
789// m_log.DebugFormat( 995// m_log.DebugFormat(
790// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}", 996// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}",
@@ -793,116 +999,125 @@ namespace OpenSim.Region.Framework.Scenes
793 if (m_inventoryFileName == String.Empty || 999 if (m_inventoryFileName == String.Empty ||
794 m_inventoryFileNameSerial < m_inventorySerial) 1000 m_inventoryFileNameSerial < m_inventorySerial)
795 { 1001 {
796 // Something changed, we need to create a new file
797 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; 1002 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
798 m_inventoryFileNameSerial = m_inventorySerial; 1003 m_inventoryFileNameSerial = m_inventorySerial;
799 1004
800 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); 1005 return true;
1006 }
1007
1008 return false;
1009 }
1010
1011 /// <summary>
1012 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
1013 /// </summary>
1014 /// <param name="xferManager"></param>
1015 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
1016 {
1017 bool changed = CreateInventoryFileName();
1018
1019 bool includeAssets = false;
1020 if (m_part.ParentGroup.Scene.Permissions.CanEditObjectInventory(m_part.UUID, client.AgentId))
1021 includeAssets = true;
1022
1023 if (m_inventoryPrivileged != includeAssets)
1024 changed = true;
1025
1026 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
1027
1028 Items.LockItemsForRead(true);
1029
1030 if (m_inventorySerial == 0) // No inventory
1031 {
1032 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
1033 Items.LockItemsForRead(false);
1034 return;
1035 }
801 1036
802 lock (m_items) 1037 if (m_items.Count == 0) // No inventory
1038 {
1039 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
1040 Items.LockItemsForRead(false);
1041 return;
1042 }
1043
1044 if (!changed)
1045 {
1046 if (m_inventoryFileData.Length > 2)
803 { 1047 {
804 foreach (TaskInventoryItem item in m_items.Values) 1048 xferManager.AddNewFile(m_inventoryFileName,
805 { 1049 m_inventoryFileData);
806// m_log.DebugFormat( 1050 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
807// "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}", 1051 Util.StringToBytes256(m_inventoryFileName));
808// item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId);
809 1052
810 UUID ownerID = item.OwnerID; 1053 Items.LockItemsForRead(false);
811 uint everyoneMask = 0; 1054 return;
812 uint baseMask = item.BasePermissions; 1055 }
813 uint ownerMask = item.CurrentPermissions; 1056 }
814 uint groupMask = item.GroupPermissions;
815 1057
816 invString.AddItemStart(); 1058 m_inventoryPrivileged = includeAssets;
817 invString.AddNameValueLine("item_id", item.ItemID.ToString());
818 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
819 1059
820 invString.AddPermissionsStart(); 1060 foreach (TaskInventoryItem item in m_items.Values)
1061 {
1062 UUID ownerID = item.OwnerID;
1063 uint everyoneMask = 0;
1064 uint baseMask = item.BasePermissions;
1065 uint ownerMask = item.CurrentPermissions;
1066 uint groupMask = item.GroupPermissions;
821 1067
822 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); 1068 invString.AddItemStart();
823 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); 1069 invString.AddNameValueLine("item_id", item.ItemID.ToString());
824 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask)); 1070 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
825 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
826 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
827 1071
828 invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); 1072 invString.AddPermissionsStart();
829 invString.AddNameValueLine("owner_id", ownerID.ToString());
830 1073
831 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); 1074 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
1075 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
1076 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
1077 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
1078 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
832 1079
833 invString.AddNameValueLine("group_id", item.GroupID.ToString()); 1080 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
834 invString.AddSectionEnd(); 1081 invString.AddNameValueLine("owner_id", ownerID.ToString());
835 1082
836 invString.AddNameValueLine("asset_id", item.AssetID.ToString()); 1083 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
837 invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
838 invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
839 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
840 1084
841 invString.AddSaleStart(); 1085 invString.AddNameValueLine("group_id", item.GroupID.ToString());
842 invString.AddNameValueLine("sale_type", "not"); 1086 invString.AddSectionEnd();
843 invString.AddNameValueLine("sale_price", "0");
844 invString.AddSectionEnd();
845 1087
846 invString.AddNameValueLine("name", item.Name + "|"); 1088 if (includeAssets)
847 invString.AddNameValueLine("desc", item.Description + "|"); 1089 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
1090 else
1091 invString.AddNameValueLine("asset_id", UUID.Zero.ToString());
1092 invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
1093 invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
1094 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
848 1095
849 invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); 1096 invString.AddSaleStart();
850 invString.AddSectionEnd(); 1097 invString.AddNameValueLine("sale_type", "not");
851 } 1098 invString.AddNameValueLine("sale_price", "0");
852 } 1099 invString.AddSectionEnd();
853 1100
854 m_inventoryFileData = Utils.StringToBytes(invString.BuildString); 1101 invString.AddNameValueLine("name", item.Name + "|");
1102 invString.AddNameValueLine("desc", item.Description + "|");
855 1103
856 return true; 1104 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
1105 invString.AddSectionEnd();
857 } 1106 }
858 1107
859 // No need to recreate, the existing file is fine 1108 Items.LockItemsForRead(false);
860 return false;
861 }
862
863 /// <summary>
864 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
865 /// </summary>
866 /// <param name="xferManager"></param>
867 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
868 {
869 lock (m_items)
870 {
871 // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing
872 // a new script if any previous deletion has left the prim inventory empty.
873 if (m_items.Count == 0) // No inventory
874 {
875// m_log.DebugFormat(
876// "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items",
877// m_part.Name, m_part.LocalId, m_part.UUID, client.Name);
878 1109
879 client.SendTaskInventory(m_part.UUID, 0, new byte[0]); 1110 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
880 return;
881 }
882 1111
883 CreateInventoryFile(); 1112 if (m_inventoryFileData.Length > 2)
884 1113 {
885 // In principle, we should only do the rest if the inventory changed; 1114 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
886 // by sending m_inventorySerial to the client, it ought to know 1115 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
887 // that nothing changed and that it doesn't need to request the file. 1116 Util.StringToBytes256(m_inventoryFileName));
888 // Unfortunately, it doesn't look like the client optimizes this; 1117 return;
889 // the client seems to always come back and request the Xfer,
890 // no matter what value m_inventorySerial has.
891 // FIXME: Could probably be > 0 here rather than > 2
892 if (m_inventoryFileData.Length > 2)
893 {
894 // Add the file for Xfer
895 // m_log.DebugFormat(
896 // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}",
897 // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId);
898
899 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
900 }
901
902 // Tell the client we're ready to Xfer the file
903 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
904 Util.StringToBytes256(m_inventoryFileName));
905 } 1118 }
1119
1120 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
906 } 1121 }
907 1122
908 /// <summary> 1123 /// <summary>
@@ -911,13 +1126,19 @@ namespace OpenSim.Region.Framework.Scenes
911 /// <param name="datastore"></param> 1126 /// <param name="datastore"></param>
912 public void ProcessInventoryBackup(ISimulationDataService datastore) 1127 public void ProcessInventoryBackup(ISimulationDataService datastore)
913 { 1128 {
914 if (HasInventoryChanged) 1129// Removed this because linking will cause an immediate delete of the new
915 { 1130// child prim from the database and the subsequent storing of the prim sees
916 HasInventoryChanged = false; 1131// the inventory of it as unchanged and doesn't store it at all. The overhead
917 List<TaskInventoryItem> items = GetInventoryItems(); 1132// of storing prim inventory needlessly is much less than the aggravation
918 datastore.StorePrimInventory(m_part.UUID, items); 1133// of prim inventory loss.
1134// if (HasInventoryChanged)
1135// {
1136 Items.LockItemsForRead(true);
1137 datastore.StorePrimInventory(m_part.UUID, Items.Values);
1138 Items.LockItemsForRead(false);
919 1139
920 } 1140 HasInventoryChanged = false;
1141// }
921 } 1142 }
922 1143
923 public class InventoryStringBuilder 1144 public class InventoryStringBuilder
@@ -983,82 +1204,63 @@ namespace OpenSim.Region.Framework.Scenes
983 { 1204 {
984 uint mask=0x7fffffff; 1205 uint mask=0x7fffffff;
985 1206
986 lock (m_items) 1207 foreach (TaskInventoryItem item in m_items.Values)
987 { 1208 {
988 foreach (TaskInventoryItem item in m_items.Values) 1209 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1210 mask &= ~((uint)PermissionMask.Copy >> 13);
1211 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1212 mask &= ~((uint)PermissionMask.Transfer >> 13);
1213 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1214 mask &= ~((uint)PermissionMask.Modify >> 13);
1215
1216 if (item.InvType == (int)InventoryType.Object)
989 { 1217 {
990 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) 1218 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
991 mask &= ~((uint)PermissionMask.Copy >> 13); 1219 mask &= ~((uint)PermissionMask.Copy >> 13);
992 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) 1220 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
993 mask &= ~((uint)PermissionMask.Transfer >> 13); 1221 mask &= ~((uint)PermissionMask.Transfer >> 13);
994 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) 1222 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
995 mask &= ~((uint)PermissionMask.Modify >> 13); 1223 mask &= ~((uint)PermissionMask.Modify >> 13);
996
997 if (item.InvType != (int)InventoryType.Object)
998 {
999 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1000 mask &= ~((uint)PermissionMask.Copy >> 13);
1001 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1002 mask &= ~((uint)PermissionMask.Transfer >> 13);
1003 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1004 mask &= ~((uint)PermissionMask.Modify >> 13);
1005 }
1006 else
1007 {
1008 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1009 mask &= ~((uint)PermissionMask.Copy >> 13);
1010 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1011 mask &= ~((uint)PermissionMask.Transfer >> 13);
1012 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1013 mask &= ~((uint)PermissionMask.Modify >> 13);
1014 }
1015
1016 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1017 mask &= ~(uint)PermissionMask.Copy;
1018 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1019 mask &= ~(uint)PermissionMask.Transfer;
1020 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1021 mask &= ~(uint)PermissionMask.Modify;
1022 } 1224 }
1225
1226 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1227 mask &= ~(uint)PermissionMask.Copy;
1228 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1229 mask &= ~(uint)PermissionMask.Transfer;
1230 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1231 mask &= ~(uint)PermissionMask.Modify;
1023 } 1232 }
1024
1025 return mask; 1233 return mask;
1026 } 1234 }
1027 1235
1028 public void ApplyNextOwnerPermissions() 1236 public void ApplyNextOwnerPermissions()
1029 { 1237 {
1030 lock (m_items) 1238 foreach (TaskInventoryItem item in m_items.Values)
1031 { 1239 {
1032 foreach (TaskInventoryItem item in m_items.Values) 1240 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
1033 { 1241 {
1034 if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0) 1242 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
1035 { 1243 item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
1036 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0) 1244 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
1037 item.CurrentPermissions &= ~(uint)PermissionMask.Copy; 1245 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
1038 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0) 1246 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1039 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer; 1247 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1040 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
1041 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
1042 }
1043 item.CurrentPermissions &= item.NextPermissions;
1044 item.BasePermissions &= item.NextPermissions;
1045 item.EveryonePermissions &= item.NextPermissions;
1046 item.OwnerChanged = true;
1047 item.PermsMask = 0;
1048 item.PermsGranter = UUID.Zero;
1049 } 1248 }
1249 item.OwnerChanged = true;
1250 item.CurrentPermissions &= item.NextPermissions;
1251 item.BasePermissions &= item.NextPermissions;
1252 item.EveryonePermissions &= item.NextPermissions;
1253 item.PermsMask = 0;
1254 item.PermsGranter = UUID.Zero;
1050 } 1255 }
1051 } 1256 }
1052 1257
1053 public void ApplyGodPermissions(uint perms) 1258 public void ApplyGodPermissions(uint perms)
1054 { 1259 {
1055 lock (m_items) 1260 foreach (TaskInventoryItem item in m_items.Values)
1056 { 1261 {
1057 foreach (TaskInventoryItem item in m_items.Values) 1262 item.CurrentPermissions = perms;
1058 { 1263 item.BasePermissions = perms;
1059 item.CurrentPermissions = perms;
1060 item.BasePermissions = perms;
1061 }
1062 } 1264 }
1063 1265
1064 m_inventorySerial++; 1266 m_inventorySerial++;
@@ -1071,17 +1273,13 @@ namespace OpenSim.Region.Framework.Scenes
1071 /// <returns></returns> 1273 /// <returns></returns>
1072 public bool ContainsScripts() 1274 public bool ContainsScripts()
1073 { 1275 {
1074 lock (m_items) 1276 foreach (TaskInventoryItem item in m_items.Values)
1075 { 1277 {
1076 foreach (TaskInventoryItem item in m_items.Values) 1278 if (item.InvType == (int)InventoryType.LSL)
1077 { 1279 {
1078 if (item.InvType == (int)InventoryType.LSL) 1280 return true;
1079 {
1080 return true;
1081 }
1082 } 1281 }
1083 } 1282 }
1084
1085 return false; 1283 return false;
1086 } 1284 }
1087 1285
@@ -1089,11 +1287,8 @@ namespace OpenSim.Region.Framework.Scenes
1089 { 1287 {
1090 List<UUID> ret = new List<UUID>(); 1288 List<UUID> ret = new List<UUID>();
1091 1289
1092 lock (m_items) 1290 foreach (TaskInventoryItem item in m_items.Values)
1093 { 1291 ret.Add(item.ItemID);
1094 foreach (TaskInventoryItem item in m_items.Values)
1095 ret.Add(item.ItemID);
1096 }
1097 1292
1098 return ret; 1293 return ret;
1099 } 1294 }
@@ -1124,6 +1319,11 @@ namespace OpenSim.Region.Framework.Scenes
1124 1319
1125 public Dictionary<UUID, string> GetScriptStates() 1320 public Dictionary<UUID, string> GetScriptStates()
1126 { 1321 {
1322 return GetScriptStates(false);
1323 }
1324
1325 public Dictionary<UUID, string> GetScriptStates(bool oldIDs)
1326 {
1127 Dictionary<UUID, string> ret = new Dictionary<UUID, string>(); 1327 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1128 1328
1129 if (m_part.ParentGroup.Scene == null) // Group not in a scene 1329 if (m_part.ParentGroup.Scene == null) // Group not in a scene
@@ -1134,25 +1334,35 @@ namespace OpenSim.Region.Framework.Scenes
1134 if (engines.Length == 0) // No engine at all 1334 if (engines.Length == 0) // No engine at all
1135 return ret; 1335 return ret;
1136 1336
1137 List<TaskInventoryItem> scripts = GetInventoryScripts(); 1337 Items.LockItemsForRead(true);
1138 1338 foreach (TaskInventoryItem item in m_items.Values)
1139 foreach (TaskInventoryItem item in scripts)
1140 { 1339 {
1141 foreach (IScriptModule e in engines) 1340 if (item.InvType == (int)InventoryType.LSL)
1142 { 1341 {
1143 if (e != null) 1342 foreach (IScriptModule e in engines)
1144 { 1343 {
1145 string n = e.GetXMLState(item.ItemID); 1344 if (e != null)
1146 if (n != String.Empty)
1147 { 1345 {
1148 if (!ret.ContainsKey(item.ItemID)) 1346 string n = e.GetXMLState(item.ItemID);
1149 ret[item.ItemID] = n; 1347 if (n != String.Empty)
1150 break; 1348 {
1349 if (oldIDs)
1350 {
1351 if (!ret.ContainsKey(item.OldItemID))
1352 ret[item.OldItemID] = n;
1353 }
1354 else
1355 {
1356 if (!ret.ContainsKey(item.ItemID))
1357 ret[item.ItemID] = n;
1358 }
1359 break;
1360 }
1151 } 1361 }
1152 } 1362 }
1153 } 1363 }
1154 } 1364 }
1155 1365 Items.LockItemsForRead(false);
1156 return ret; 1366 return ret;
1157 } 1367 }
1158 1368
@@ -1162,21 +1372,27 @@ namespace OpenSim.Region.Framework.Scenes
1162 if (engines.Length == 0) 1372 if (engines.Length == 0)
1163 return; 1373 return;
1164 1374
1165 List<TaskInventoryItem> scripts = GetInventoryScripts();
1166 1375
1167 foreach (TaskInventoryItem item in scripts) 1376 Items.LockItemsForRead(true);
1377
1378 foreach (TaskInventoryItem item in m_items.Values)
1168 { 1379 {
1169 foreach (IScriptModule engine in engines) 1380 if (item.InvType == (int)InventoryType.LSL)
1170 { 1381 {
1171 if (engine != null) 1382 foreach (IScriptModule engine in engines)
1172 { 1383 {
1173 if (item.OwnerChanged) 1384 if (engine != null)
1174 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); 1385 {
1175 item.OwnerChanged = false; 1386 if (item.OwnerChanged)
1176 engine.ResumeScript(item.ItemID); 1387 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
1388 item.OwnerChanged = false;
1389 engine.ResumeScript(item.ItemID);
1390 }
1177 } 1391 }
1178 } 1392 }
1179 } 1393 }
1394
1395 Items.LockItemsForRead(false);
1180 } 1396 }
1181 } 1397 }
1182} 1398}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 5c56150..c7c90da 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -168,6 +168,7 @@ namespace OpenSim.Region.Framework.Scenes
168// private int m_lastColCount = -1; //KF: Look for Collision chnages 168// private int m_lastColCount = -1; //KF: Look for Collision chnages
169// private int m_updateCount = 0; //KF: Update Anims for a while 169// private int m_updateCount = 0; //KF: Update Anims for a while
170// private static readonly int UPDATE_COUNT = 10; // how many frames to update for 170// private static readonly int UPDATE_COUNT = 10; // how many frames to update for
171 private List<uint> m_lastColliders = new List<uint>();
171 172
172 private TeleportFlags m_teleportFlags; 173 private TeleportFlags m_teleportFlags;
173 public TeleportFlags TeleportFlags 174 public TeleportFlags TeleportFlags
@@ -229,6 +230,9 @@ namespace OpenSim.Region.Framework.Scenes
229 //private int m_moveToPositionStateStatus; 230 //private int m_moveToPositionStateStatus;
230 //***************************************************** 231 //*****************************************************
231 232
233 private bool m_collisionEventFlag = false;
234 private object m_collisionEventLock = new Object();
235
232 protected AvatarAppearance m_appearance; 236 protected AvatarAppearance m_appearance;
233 237
234 public AvatarAppearance Appearance 238 public AvatarAppearance Appearance
@@ -1751,9 +1755,9 @@ namespace OpenSim.Region.Framework.Scenes
1751 if (pos.Z - terrainHeight < 0.2) 1755 if (pos.Z - terrainHeight < 0.2)
1752 pos.Z = terrainHeight; 1756 pos.Z = terrainHeight;
1753 1757
1754 m_log.DebugFormat( 1758// m_log.DebugFormat(
1755 "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}", 1759// "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}",
1756 Name, pos, terrainHeight, m_scene.RegionInfo.RegionName); 1760// Name, pos, terrainHeight, m_scene.RegionInfo.RegionName);
1757 1761
1758 if (noFly) 1762 if (noFly)
1759 Flying = false; 1763 Flying = false;
@@ -1837,6 +1841,7 @@ namespace OpenSim.Region.Framework.Scenes
1837 if (part.SitTargetAvatar == UUID) 1841 if (part.SitTargetAvatar == UUID)
1838 part.SitTargetAvatar = UUID.Zero; 1842 part.SitTargetAvatar = UUID.Zero;
1839 1843
1844 part.ParentGroup.DeleteAvatar(UUID);
1840 ParentPosition = part.GetWorldPosition(); 1845 ParentPosition = part.GetWorldPosition();
1841 ControllingClient.SendClearFollowCamProperties(part.ParentUUID); 1846 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
1842 } 1847 }
@@ -1975,7 +1980,7 @@ namespace OpenSim.Region.Framework.Scenes
1975 forceMouselook = part.GetForceMouselook(); 1980 forceMouselook = part.GetForceMouselook();
1976 1981
1977 ControllingClient.SendSitResponse( 1982 ControllingClient.SendSitResponse(
1978 targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); 1983 part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
1979 1984
1980 m_requestedSitTargetUUID = targetID; 1985 m_requestedSitTargetUUID = targetID;
1981 1986
@@ -2260,11 +2265,13 @@ namespace OpenSim.Region.Framework.Scenes
2260 m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT; 2265 m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT;
2261 Rotation = sitTargetOrient; 2266 Rotation = sitTargetOrient;
2262 ParentPosition = part.AbsolutePosition; 2267 ParentPosition = part.AbsolutePosition;
2268 part.ParentGroup.AddAvatar(UUID);
2263 } 2269 }
2264 else 2270 else
2265 { 2271 {
2266 m_pos -= part.AbsolutePosition; 2272 m_pos -= part.AbsolutePosition;
2267 ParentPosition = part.AbsolutePosition; 2273 ParentPosition = part.AbsolutePosition;
2274 part.ParentGroup.AddAvatar(UUID);
2268 2275
2269// m_log.DebugFormat( 2276// m_log.DebugFormat(
2270// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", 2277// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target",
@@ -3370,6 +3377,8 @@ namespace OpenSim.Region.Framework.Scenes
3370 } 3377 }
3371 } 3378 }
3372 3379
3380 RaiseCollisionScriptEvents(coldata);
3381
3373 if (Invulnerable) 3382 if (Invulnerable)
3374 return; 3383 return;
3375 3384
@@ -3881,6 +3890,12 @@ namespace OpenSim.Region.Framework.Scenes
3881 3890
3882 private void CheckAndAdjustLandingPoint(ref Vector3 pos) 3891 private void CheckAndAdjustLandingPoint(ref Vector3 pos)
3883 { 3892 {
3893 string reason;
3894
3895 // Honor bans
3896 if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y))
3897 return;
3898
3884 SceneObjectGroup telehub = null; 3899 SceneObjectGroup telehub = null;
3885 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) 3900 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null)
3886 { 3901 {
@@ -3920,11 +3935,173 @@ namespace OpenSim.Region.Framework.Scenes
3920 pos = land.LandData.UserLocation; 3935 pos = land.LandData.UserLocation;
3921 } 3936 }
3922 } 3937 }
3923 3938
3924 land.SendLandUpdateToClient(ControllingClient); 3939 land.SendLandUpdateToClient(ControllingClient);
3925 } 3940 }
3926 } 3941 }
3927 3942
3943 private void RaiseCollisionScriptEvents(Dictionary<uint, ContactPoint> coldata)
3944 {
3945 lock(m_collisionEventLock)
3946 {
3947 if (m_collisionEventFlag)
3948 return;
3949 m_collisionEventFlag = true;
3950 }
3951
3952 Util.FireAndForget(delegate(object x)
3953 {
3954 try
3955 {
3956 List<uint> thisHitColliders = new List<uint>();
3957 List<uint> endedColliders = new List<uint>();
3958 List<uint> startedColliders = new List<uint>();
3959
3960 foreach (uint localid in coldata.Keys)
3961 {
3962 thisHitColliders.Add(localid);
3963 if (!m_lastColliders.Contains(localid))
3964 {
3965 startedColliders.Add(localid);
3966 }
3967 //m_log.Debug("[SCENE PRESENCE]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
3968 }
3969
3970 // calculate things that ended colliding
3971 foreach (uint localID in m_lastColliders)
3972 {
3973 if (!thisHitColliders.Contains(localID))
3974 {
3975 endedColliders.Add(localID);
3976 }
3977 }
3978 //add the items that started colliding this time to the last colliders list.
3979 foreach (uint localID in startedColliders)
3980 {
3981 m_lastColliders.Add(localID);
3982 }
3983 // remove things that ended colliding from the last colliders list
3984 foreach (uint localID in endedColliders)
3985 {
3986 m_lastColliders.Remove(localID);
3987 }
3988
3989 // do event notification
3990 if (startedColliders.Count > 0)
3991 {
3992 ColliderArgs StartCollidingMessage = new ColliderArgs();
3993 List<DetectedObject> colliding = new List<DetectedObject>();
3994 foreach (uint localId in startedColliders)
3995 {
3996 if (localId == 0)
3997 continue;
3998
3999 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
4000 string data = "";
4001 if (obj != null)
4002 {
4003 DetectedObject detobj = new DetectedObject();
4004 detobj.keyUUID = obj.UUID;
4005 detobj.nameStr = obj.Name;
4006 detobj.ownerUUID = obj.OwnerID;
4007 detobj.posVector = obj.AbsolutePosition;
4008 detobj.rotQuat = obj.GetWorldRotation();
4009 detobj.velVector = obj.Velocity;
4010 detobj.colliderType = 0;
4011 detobj.groupUUID = obj.GroupID;
4012 colliding.Add(detobj);
4013 }
4014 }
4015
4016 if (colliding.Count > 0)
4017 {
4018 StartCollidingMessage.Colliders = colliding;
4019
4020 foreach (SceneObjectGroup att in GetAttachments())
4021 Scene.EventManager.TriggerScriptCollidingStart(att.LocalId, StartCollidingMessage);
4022 }
4023 }
4024
4025 if (endedColliders.Count > 0)
4026 {
4027 ColliderArgs EndCollidingMessage = new ColliderArgs();
4028 List<DetectedObject> colliding = new List<DetectedObject>();
4029 foreach (uint localId in endedColliders)
4030 {
4031 if (localId == 0)
4032 continue;
4033
4034 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
4035 string data = "";
4036 if (obj != null)
4037 {
4038 DetectedObject detobj = new DetectedObject();
4039 detobj.keyUUID = obj.UUID;
4040 detobj.nameStr = obj.Name;
4041 detobj.ownerUUID = obj.OwnerID;
4042 detobj.posVector = obj.AbsolutePosition;
4043 detobj.rotQuat = obj.GetWorldRotation();
4044 detobj.velVector = obj.Velocity;
4045 detobj.colliderType = 0;
4046 detobj.groupUUID = obj.GroupID;
4047 colliding.Add(detobj);
4048 }
4049 }
4050
4051 if (colliding.Count > 0)
4052 {
4053 EndCollidingMessage.Colliders = colliding;
4054
4055 foreach (SceneObjectGroup att in GetAttachments())
4056 Scene.EventManager.TriggerScriptCollidingEnd(att.LocalId, EndCollidingMessage);
4057 }
4058 }
4059
4060 if (thisHitColliders.Count > 0)
4061 {
4062 ColliderArgs CollidingMessage = new ColliderArgs();
4063 List<DetectedObject> colliding = new List<DetectedObject>();
4064 foreach (uint localId in thisHitColliders)
4065 {
4066 if (localId == 0)
4067 continue;
4068
4069 SceneObjectPart obj = Scene.GetSceneObjectPart(localId);
4070 string data = "";
4071 if (obj != null)
4072 {
4073 DetectedObject detobj = new DetectedObject();
4074 detobj.keyUUID = obj.UUID;
4075 detobj.nameStr = obj.Name;
4076 detobj.ownerUUID = obj.OwnerID;
4077 detobj.posVector = obj.AbsolutePosition;
4078 detobj.rotQuat = obj.GetWorldRotation();
4079 detobj.velVector = obj.Velocity;
4080 detobj.colliderType = 0;
4081 detobj.groupUUID = obj.GroupID;
4082 colliding.Add(detobj);
4083 }
4084 }
4085
4086 if (colliding.Count > 0)
4087 {
4088 CollidingMessage.Colliders = colliding;
4089
4090 lock (m_attachments)
4091 {
4092 foreach (SceneObjectGroup att in m_attachments)
4093 Scene.EventManager.TriggerScriptColliding(att.LocalId, CollidingMessage);
4094 }
4095 }
4096 }
4097 }
4098 finally
4099 {
4100 m_collisionEventFlag = false;
4101 }
4102 });
4103 }
4104
3928 private void TeleportFlagsDebug() { 4105 private void TeleportFlagsDebug() {
3929 4106
3930 // Some temporary debugging help to show all the TeleportFlags we have... 4107 // Some temporary debugging help to show all the TeleportFlags we have...
@@ -3949,6 +4126,5 @@ namespace OpenSim.Region.Framework.Scenes
3949 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); 4126 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
3950 4127
3951 } 4128 }
3952
3953 } 4129 }
3954} 4130}
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index ab02f92..ba33122 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -346,6 +346,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
346 m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2); 346 m_SOPXmlProcessors.Add("PayPrice2", ProcessPayPrice2);
347 m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3); 347 m_SOPXmlProcessors.Add("PayPrice3", ProcessPayPrice3);
348 m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4); 348 m_SOPXmlProcessors.Add("PayPrice4", ProcessPayPrice4);
349
350 m_SOPXmlProcessors.Add("Buoyancy", ProcessBuoyancy);
351 m_SOPXmlProcessors.Add("VolumeDetectActive", ProcessVolumeDetectActive);
349 #endregion 352 #endregion
350 353
351 #region TaskInventoryXmlProcessors initialization 354 #region TaskInventoryXmlProcessors initialization
@@ -730,6 +733,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
730 obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty); 733 obj.PayPrice[4] = (int)reader.ReadElementContentAsInt("PayPrice4", String.Empty);
731 } 734 }
732 735
736 private static void ProcessBuoyancy(SceneObjectPart obj, XmlTextReader reader)
737 {
738 obj.Buoyancy = (int)reader.ReadElementContentAsFloat("Buoyancy", String.Empty);
739 }
740
741 private static void ProcessVolumeDetectActive(SceneObjectPart obj, XmlTextReader reader)
742 {
743 obj.VolumeDetectActive = Util.ReadBoolean(reader);
744 }
745
733 #endregion 746 #endregion
734 747
735 #region TaskInventoryXmlProcessors 748 #region TaskInventoryXmlProcessors
@@ -1215,6 +1228,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1215 writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString()); 1228 writer.WriteElementString("PayPrice3", sop.PayPrice[3].ToString());
1216 writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString()); 1229 writer.WriteElementString("PayPrice4", sop.PayPrice[4].ToString());
1217 1230
1231 writer.WriteElementString("Buoyancy", sop.Buoyancy.ToString());
1232 writer.WriteElementString("VolumeDetectActive", sop.VolumeDetectActive.ToString().ToLower());
1233
1218 writer.WriteEndElement(); 1234 writer.WriteEndElement();
1219 } 1235 }
1220 1236
@@ -1484,12 +1500,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1484 { 1500 {
1485 TaskInventoryDictionary tinv = new TaskInventoryDictionary(); 1501 TaskInventoryDictionary tinv = new TaskInventoryDictionary();
1486 1502
1487 if (reader.IsEmptyElement)
1488 {
1489 reader.Read();
1490 return tinv;
1491 }
1492
1493 reader.ReadStartElement(name, String.Empty); 1503 reader.ReadStartElement(name, String.Empty);
1494 1504
1495 while (reader.Name == "TaskInventoryItem") 1505 while (reader.Name == "TaskInventoryItem")
@@ -1527,12 +1537,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1527 1537
1528 PrimitiveBaseShape shape = new PrimitiveBaseShape(); 1538 PrimitiveBaseShape shape = new PrimitiveBaseShape();
1529 1539
1530 if (reader.IsEmptyElement)
1531 {
1532 reader.Read();
1533 return shape;
1534 }
1535
1536 reader.ReadStartElement(name, String.Empty); // Shape 1540 reader.ReadStartElement(name, String.Empty); // Shape
1537 1541
1538 ExternalRepresentationUtils.ExecuteReadProcessors( 1542 ExternalRepresentationUtils.ExecuteReadProcessors(
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs
index 860172c..5ed3c79 100644
--- a/OpenSim/Region/Framework/Scenes/UndoState.cs
+++ b/OpenSim/Region/Framework/Scenes/UndoState.cs
@@ -30,12 +30,27 @@ using System.Reflection;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Region.Framework.Interfaces; 32using OpenSim.Region.Framework.Interfaces;
33using System;
33 34
34namespace OpenSim.Region.Framework.Scenes 35namespace OpenSim.Region.Framework.Scenes
35{ 36{
37 [Flags]
38 public enum UndoType
39 {
40 STATE_PRIM_POSITION = 1,
41 STATE_PRIM_ROTATION = 2,
42 STATE_PRIM_SCALE = 4,
43 STATE_PRIM_ALL = 7,
44 STATE_GROUP_POSITION = 8,
45 STATE_GROUP_ROTATION = 16,
46 STATE_GROUP_SCALE = 32,
47 STATE_GROUP_ALL = 56,
48 STATE_ALL = 63
49 }
50
36 public class UndoState 51 public class UndoState
37 { 52 {
38// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39 54
40 public Vector3 Position = Vector3.Zero; 55 public Vector3 Position = Vector3.Zero;
41 public Vector3 Scale = Vector3.Zero; 56 public Vector3 Scale = Vector3.Zero;
@@ -57,37 +72,37 @@ namespace OpenSim.Region.Framework.Scenes
57 { 72 {
58 ForGroup = forGroup; 73 ForGroup = forGroup;
59 74
60// if (ForGroup) 75 // if (ForGroup)
61 Position = part.ParentGroup.AbsolutePosition; 76 Position = part.ParentGroup.AbsolutePosition;
62// else 77 // else
63// Position = part.OffsetPosition; 78 // Position = part.OffsetPosition;
64 79
65// m_log.DebugFormat( 80 // m_log.DebugFormat(
66// "[UNDO STATE]: Storing undo position {0} for root part", Position); 81 // "[UNDO STATE]: Storing undo position {0} for root part", Position);
67 82
68 Rotation = part.RotationOffset; 83 Rotation = part.RotationOffset;
69 84
70// m_log.DebugFormat( 85 // m_log.DebugFormat(
71// "[UNDO STATE]: Storing undo rotation {0} for root part", Rotation); 86 // "[UNDO STATE]: Storing undo rotation {0} for root part", Rotation);
72 87
73 Scale = part.Shape.Scale; 88 Scale = part.Shape.Scale;
74 89
75// m_log.DebugFormat( 90 // m_log.DebugFormat(
76// "[UNDO STATE]: Storing undo scale {0} for root part", Scale); 91 // "[UNDO STATE]: Storing undo scale {0} for root part", Scale);
77 } 92 }
78 else 93 else
79 { 94 {
80 Position = part.OffsetPosition; 95 Position = part.OffsetPosition;
81// m_log.DebugFormat( 96 // m_log.DebugFormat(
82// "[UNDO STATE]: Storing undo position {0} for child part", Position); 97 // "[UNDO STATE]: Storing undo position {0} for child part", Position);
83 98
84 Rotation = part.RotationOffset; 99 Rotation = part.RotationOffset;
85// m_log.DebugFormat( 100 // m_log.DebugFormat(
86// "[UNDO STATE]: Storing undo rotation {0} for child part", Rotation); 101 // "[UNDO STATE]: Storing undo rotation {0} for child part", Rotation);
87 102
88 Scale = part.Shape.Scale; 103 Scale = part.Shape.Scale;
89// m_log.DebugFormat( 104 // m_log.DebugFormat(
90// "[UNDO STATE]: Storing undo scale {0} for child part", Scale); 105 // "[UNDO STATE]: Storing undo scale {0} for child part", Scale);
91 } 106 }
92 } 107 }
93 108
@@ -121,9 +136,9 @@ namespace OpenSim.Region.Framework.Scenes
121 136
122 if (part.ParentID == 0) 137 if (part.ParentID == 0)
123 { 138 {
124// m_log.DebugFormat( 139 // m_log.DebugFormat(
125// "[UNDO STATE]: Undoing position to {0} for root part {1} {2}", 140 // "[UNDO STATE]: Undoing position to {0} for root part {1} {2}",
126// Position, part.Name, part.LocalId); 141 // Position, part.Name, part.LocalId);
127 142
128 if (Position != Vector3.Zero) 143 if (Position != Vector3.Zero)
129 { 144 {
@@ -133,9 +148,9 @@ namespace OpenSim.Region.Framework.Scenes
133 part.ParentGroup.UpdateRootPosition(Position); 148 part.ParentGroup.UpdateRootPosition(Position);
134 } 149 }
135 150
136// m_log.DebugFormat( 151 // m_log.DebugFormat(
137// "[UNDO STATE]: Undoing rotation {0} to {1} for root part {2} {3}", 152 // "[UNDO STATE]: Undoing rotation {0} to {1} for root part {2} {3}",
138// part.RotationOffset, Rotation, part.Name, part.LocalId); 153 // part.RotationOffset, Rotation, part.Name, part.LocalId);
139 154
140 if (ForGroup) 155 if (ForGroup)
141 part.UpdateRotation(Rotation); 156 part.UpdateRotation(Rotation);
@@ -144,9 +159,9 @@ namespace OpenSim.Region.Framework.Scenes
144 159
145 if (Scale != Vector3.Zero) 160 if (Scale != Vector3.Zero)
146 { 161 {
147// m_log.DebugFormat( 162 // m_log.DebugFormat(
148// "[UNDO STATE]: Undoing scale {0} to {1} for root part {2} {3}", 163 // "[UNDO STATE]: Undoing scale {0} to {1} for root part {2} {3}",
149// part.Shape.Scale, Scale, part.Name, part.LocalId); 164 // part.Shape.Scale, Scale, part.Name, part.LocalId);
150 165
151 if (ForGroup) 166 if (ForGroup)
152 part.ParentGroup.GroupResize(Scale); 167 part.ParentGroup.GroupResize(Scale);
@@ -161,24 +176,24 @@ namespace OpenSim.Region.Framework.Scenes
161 // Note: Updating these properties on sop automatically schedules an update if needed 176 // Note: Updating these properties on sop automatically schedules an update if needed
162 if (Position != Vector3.Zero) 177 if (Position != Vector3.Zero)
163 { 178 {
164// m_log.DebugFormat( 179 // m_log.DebugFormat(
165// "[UNDO STATE]: Undoing position {0} to {1} for child part {2} {3}", 180 // "[UNDO STATE]: Undoing position {0} to {1} for child part {2} {3}",
166// part.OffsetPosition, Position, part.Name, part.LocalId); 181 // part.OffsetPosition, Position, part.Name, part.LocalId);
167 182
168 part.OffsetPosition = Position; 183 part.OffsetPosition = Position;
169 } 184 }
170 185
171// m_log.DebugFormat( 186 // m_log.DebugFormat(
172// "[UNDO STATE]: Undoing rotation {0} to {1} for child part {2} {3}", 187 // "[UNDO STATE]: Undoing rotation {0} to {1} for child part {2} {3}",
173// part.RotationOffset, Rotation, part.Name, part.LocalId); 188 // part.RotationOffset, Rotation, part.Name, part.LocalId);
174 189
175 part.UpdateRotation(Rotation); 190 part.UpdateRotation(Rotation);
176 191
177 if (Scale != Vector3.Zero) 192 if (Scale != Vector3.Zero)
178 { 193 {
179// m_log.DebugFormat( 194 // m_log.DebugFormat(
180// "[UNDO STATE]: Undoing scale {0} to {1} for child part {2} {3}", 195 // "[UNDO STATE]: Undoing scale {0} to {1} for child part {2} {3}",
181// part.Shape.Scale, Scale, part.Name, part.LocalId); 196 // part.Shape.Scale, Scale, part.Name, part.LocalId);
182 197
183 part.Resize(Scale); 198 part.Resize(Scale);
184 } 199 }
@@ -247,4 +262,4 @@ namespace OpenSim.Region.Framework.Scenes
247 m_terrainModule.UndoTerrain(m_terrainChannel); 262 m_terrainModule.UndoTerrain(m_terrainChannel);
248 } 263 }
249 } 264 }
250} \ No newline at end of file 265}
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
index efb68a2..411e421 100644
--- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
+++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs
@@ -87,10 +87,6 @@ namespace OpenSim.Region.Framework.Scenes
87 /// <param name="assetUuids">The assets gathered</param> 87 /// <param name="assetUuids">The assets gathered</param>
88 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids) 88 public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids)
89 { 89 {
90 // avoid infinite loops
91 if (assetUuids.ContainsKey(assetUuid))
92 return;
93
94 try 90 try
95 { 91 {
96 assetUuids[assetUuid] = assetType; 92 assetUuids[assetUuid] = assetType;
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index c928af7..7d7c5c5 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -818,6 +818,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
818 public event ObjectOwner OnObjectOwner; 818 public event ObjectOwner OnObjectOwner;
819 public event DirPlacesQuery OnDirPlacesQuery; 819 public event DirPlacesQuery OnDirPlacesQuery;
820 public event DirFindQuery OnDirFindQuery; 820 public event DirFindQuery OnDirFindQuery;
821 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
821 public event DirLandQuery OnDirLandQuery; 822 public event DirLandQuery OnDirLandQuery;
822 public event DirPopularQuery OnDirPopularQuery; 823 public event DirPopularQuery OnDirPopularQuery;
823 public event DirClassifiedQuery OnDirClassifiedQuery; 824 public event DirClassifiedQuery OnDirClassifiedQuery;
@@ -834,7 +835,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
834 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 835 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
835 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 836 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
836 public event ClassifiedDelete OnClassifiedDelete; 837 public event ClassifiedDelete OnClassifiedDelete;
837 public event ClassifiedDelete OnClassifiedGodDelete; 838 public event ClassifiedGodDelete OnClassifiedGodDelete;
838 public event EventNotificationAddRequest OnEventNotificationAddRequest; 839 public event EventNotificationAddRequest OnEventNotificationAddRequest;
839 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 840 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
840 public event EventGodDelete OnEventGodDelete; 841 public event EventGodDelete OnEventGodDelete;
@@ -864,6 +865,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
864 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 865 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
865 public event SimWideDeletesDelegate OnSimWideDeletes; 866 public event SimWideDeletesDelegate OnSimWideDeletes;
866 public event SendPostcard OnSendPostcard; 867 public event SendPostcard OnSendPostcard;
868 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
867 public event MuteListEntryUpdate OnUpdateMuteListEntry; 869 public event MuteListEntryUpdate OnUpdateMuteListEntry;
868 public event MuteListEntryRemove OnRemoveMuteListEntry; 870 public event MuteListEntryRemove OnRemoveMuteListEntry;
869 public event GodlikeMessage onGodlikeMessage; 871 public event GodlikeMessage onGodlikeMessage;
@@ -885,6 +887,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
885 887
886 public void Close() 888 public void Close()
887 { 889 {
890 Close(true);
891 }
892
893 public void Close(bool sendStop)
894 {
888 Disconnect(); 895 Disconnect();
889 } 896 }
890 897
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 5323a95..1b675a6 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -563,7 +563,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
563 563
564 public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request) 564 public Hashtable FreeSwitchSLVoiceGetPreloginHTTPHandler(Hashtable request)
565 { 565 {
566 m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceGetPreloginHTTPHandler called"); 566// m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceGetPreloginHTTPHandler called");
567 567
568 Hashtable response = new Hashtable(); 568 Hashtable response = new Hashtable();
569 response["content_type"] = "text/xml"; 569 response["content_type"] = "text/xml";
@@ -714,7 +714,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
714 714
715 public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request) 715 public Hashtable FreeSwitchSLVoiceSigninHTTPHandler(Hashtable request)
716 { 716 {
717 m_log.Debug("[FreeSwitchVoice]: FreeSwitchSLVoiceSigninHTTPHandler called"); 717 //m_log.Debug("[FreeSwitchVoice] FreeSwitchSLVoiceSigninHTTPHandler called");
718// string requestbody = (string)request["body"]; 718// string requestbody = (string)request["body"];
719// string uri = (string)request["uri"]; 719// string uri = (string)request["uri"];
720// string contenttype = (string)request["content-type"]; 720// 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 70e2f7e..0be0a19 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/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
index b60cd42..d39b847 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
@@ -874,7 +874,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
874 msg.dialog = dialog; 874 msg.dialog = dialog;
875 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice; 875 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
876 msg.fromGroup = true; 876 msg.fromGroup = true;
877 msg.offline = (byte)0; 877 msg.offline = (byte)1; // Allow this message to be stored for offline use
878 msg.ParentEstateID = 0; 878 msg.ParentEstateID = 0;
879 msg.Position = Vector3.Zero; 879 msg.Position = Vector3.Zero;
880 msg.RegionID = UUID.Zero.Guid; 880 msg.RegionID = UUID.Zero.Guid;
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 9c838d0..d206f69 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 be0d56e..03b52c0 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -171,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
171#pragma warning disable 67 171#pragma warning disable 67
172 public event Action<IClientAPI> OnLogout; 172 public event Action<IClientAPI> OnLogout;
173 public event ObjectPermissions OnObjectPermissions; 173 public event ObjectPermissions OnObjectPermissions;
174 174 public event MoveItemsAndLeaveCopy OnMoveItemsAndLeaveCopy;
175 public event MoneyTransferRequest OnMoneyTransferRequest; 175 public event MoneyTransferRequest OnMoneyTransferRequest;
176 public event ParcelBuy OnParcelBuy; 176 public event ParcelBuy OnParcelBuy;
177 public event Action<IClientAPI> OnConnectionClosed; 177 public event Action<IClientAPI> OnConnectionClosed;
@@ -377,7 +377,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
377 public event ClassifiedInfoRequest OnClassifiedInfoRequest; 377 public event ClassifiedInfoRequest OnClassifiedInfoRequest;
378 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate; 378 public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
379 public event ClassifiedDelete OnClassifiedDelete; 379 public event ClassifiedDelete OnClassifiedDelete;
380 public event ClassifiedDelete OnClassifiedGodDelete; 380 public event ClassifiedGodDelete OnClassifiedGodDelete;
381 381
382 public event EventNotificationAddRequest OnEventNotificationAddRequest; 382 public event EventNotificationAddRequest OnEventNotificationAddRequest;
383 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest; 383 public event EventNotificationRemoveRequest OnEventNotificationRemoveRequest;
@@ -416,6 +416,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
416 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest; 416 public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
417 public event SimWideDeletesDelegate OnSimWideDeletes; 417 public event SimWideDeletesDelegate OnSimWideDeletes;
418 public event SendPostcard OnSendPostcard; 418 public event SendPostcard OnSendPostcard;
419 public event ChangeInventoryItemFlags OnChangeInventoryItemFlags;
419 public event MuteListEntryUpdate OnUpdateMuteListEntry; 420 public event MuteListEntryUpdate OnUpdateMuteListEntry;
420 public event MuteListEntryRemove OnRemoveMuteListEntry; 421 public event MuteListEntryRemove OnRemoveMuteListEntry;
421 public event GodlikeMessage onGodlikeMessage; 422 public event GodlikeMessage onGodlikeMessage;
@@ -851,8 +852,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
851 852
852 public void Close() 853 public void Close()
853 { 854 {
854 // Remove ourselves from the scene 855 Close(true);
855 m_scene.RemoveClient(AgentId, false); 856 }
857
858 public void Close(bool sendStop)
859 {
856 } 860 }
857 861
858 public void Start() 862 public void Start()
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..2945199
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODECharacter.cs
@@ -0,0 +1,1438 @@
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 set { _acceleration = value; }
845 }
846
847 public void SetAcceleration(Vector3 accel)
848 {
849 m_pidControllerActive = true;
850 _acceleration = accel;
851 }
852
853 /// <summary>
854 /// Adds the force supplied to the Target Velocity
855 /// The PID controller takes this target velocity and tries to make it a reality
856 /// </summary>
857 /// <param name="force"></param>
858 public override void AddForce(Vector3 force, bool pushforce)
859 {
860 if (force.IsFinite())
861 {
862 if (pushforce)
863 {
864 m_pidControllerActive = false;
865 force *= 100f;
866//Console.WriteLine("DF 1"); // ##
867 if (!force.ApproxEquals(Vector3.Zero, 0.01f))
868 doForce(force);
869 // If uncommented, things get pushed off world
870 //
871 // m_log.Debug("Push!");
872 // _target_velocity.X += force.X;
873 // _target_velocity.Y += force.Y;
874 // _target_velocity.Z += force.Z;
875 }
876 else
877 {
878 m_pidControllerActive = true;
879 _target_velocity.X += force.X;
880 _target_velocity.Y += force.Y;
881 _target_velocity.Z += force.Z;
882 }
883 }
884 else
885 {
886 m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character");
887 }
888 //m_lastUpdateSent = false;
889 }
890
891 public override void AddAngularForce(Vector3 force, bool pushforce)
892 {
893
894 }
895
896 /// <summary>
897 /// After all of the forces add up with 'add force' we apply them with doForce
898 /// </summary>
899 /// <param name="force"></param>
900 public void doForce(Vector3 force)
901 {
902 if (!collidelock)
903 {
904 d.BodyAddForce(Body, force.X, force.Y, force.Z);
905 //d.BodySetRotation(Body, ref m_StandUpRotation);
906 //standupStraight();
907 d.Vector3 vel = d.BodyGetLinearVel(Body); //##
908//Console.WriteLine("AvVel <{0},{1},{2}>", vel.X, vel.Y, vel.Z); //##
909 }
910 }
911
912 public override void SetMomentum(Vector3 momentum)
913 {
914 }
915
916
917 /// <summary>
918 /// Called from Simulate
919 /// This is the avatar's movement control + PID Controller
920 /// </summary>
921 /// <param name="timeStep"></param>
922 public void Move(float timeStep, List<OdeCharacter> defects)
923 {
924 // no lock; for now it's only called from within Simulate()
925
926 // If the PID Controller isn't active then we set our force
927 // calculating base velocity to the current position
928
929 if (Body == IntPtr.Zero)
930 return;
931
932 if (m_pidControllerActive == false)
933 {
934 _zeroPosition = d.BodyGetPosition(Body);
935 }
936 //PidStatus = true;
937
938 d.Vector3 localpos = d.BodyGetPosition(Body);
939 Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
940
941 if (!localPos.IsFinite())
942 {
943
944 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
945 defects.Add(this);
946 // _parent_scene.RemoveCharacter(this);
947
948 // destroy avatar capsule and related ODE data
949 if (Amotor != IntPtr.Zero)
950 {
951 // Kill the Amotor
952 d.JointDestroy(Amotor);
953 Amotor = IntPtr.Zero;
954 }
955
956 //kill the Geometry
957 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
958
959 if (Body != IntPtr.Zero)
960 {
961 //kill the body
962 d.BodyDestroy(Body);
963
964 Body = IntPtr.Zero;
965 }
966
967 if(Shell != IntPtr.Zero)
968 {
969 try
970 {
971 d.GeomDestroy(Shell);
972 }
973 catch (System.AccessViolationException)
974 {
975 m_log.Error("[PHYSICS]: PrimGeom dead");
976 }
977 // Remove any old entries
978//string tShell;
979//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
980//Console.WriteLine("**** Remove {0}", tShell);
981
982 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
983 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
984 Shell = IntPtr.Zero;
985 }
986
987 return;
988 }
989
990 Vector3 vec = Vector3.Zero;
991 d.Vector3 vel = d.BodyGetLinearVel(Body);
992
993 float movementdivisor = 1f;
994
995 if (!m_alwaysRun)
996 {
997 movementdivisor = walkDivisor;
998 }
999 else
1000 {
1001 movementdivisor = runDivisor;
1002 }
1003
1004 // if velocity is zero, use position control; otherwise, velocity control
1005 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
1006 {
1007 // keep track of where we stopped. No more slippin' & slidin'
1008 if (!_zeroFlag)
1009 {
1010 _zeroFlag = true;
1011 _zeroPosition = d.BodyGetPosition(Body);
1012 }
1013 if (m_pidControllerActive)
1014 {
1015 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1016 // react to the physics scene by moving it's position.
1017 // Avatar to Avatar collisions
1018 // Prim to avatar collisions
1019
1020 d.Vector3 pos = d.BodyGetPosition(Body);
1021 float errX = _zeroPosition.X - pos.X;
1022 float errY = _zeroPosition.Y - pos.Y;
1023 if( (Math.Abs(errX) > 0.1f) || (Math.Abs(errY) > 0.1f) )
1024 {
1025 vec.X = (_target_velocity.X - vel.X) * (PID_D) + (errX) * (PID_P * 2);
1026 vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (errY) * (PID_P * 2);
1027 }
1028 else
1029 { // close, jump to lateral destination
1030 d.BodySetPosition(Body, _zeroPosition.X, _zeroPosition.Y, pos.Z);
1031 }
1032// if (flying)
1033 if (flying || jumping) // add for jumping
1034 {
1035 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1036 }
1037 }
1038 //PidStatus = true;
1039 }
1040 else
1041 {
1042 m_pidControllerActive = true;
1043 _zeroFlag = false;
1044 if (m_iscolliding && !flying)
1045 {
1046 // We're standing on something
1047 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
1048 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
1049 }
1050 else if (m_iscolliding && flying)
1051 {
1052 // We're flying and colliding with something
1053 vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*(PID_D / 16);
1054 vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*(PID_D / 16);
1055 }
1056 else if (!m_iscolliding && flying)
1057 {
1058 // we're in mid air suspended
1059 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D/6);
1060 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D/6);
1061 }
1062
1063 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f)
1064 {
1065 // We're colliding with something and we're not flying but we're moving
1066 // This means we're walking or running.
1067 d.Vector3 pos = d.BodyGetPosition(Body);
1068 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P;
1069 if (_target_velocity.X > 0)
1070 {
1071 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1072 }
1073 if (_target_velocity.Y > 0)
1074 {
1075 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1076 }
1077 }
1078 else if (!m_iscolliding && !flying)
1079 {
1080 // we're not colliding and we're not flying so that means we're falling!
1081 // m_iscolliding includes collisions with the ground.
1082
1083 // d.Vector3 pos = d.BodyGetPosition(Body);
1084 if (Math.Abs(_target_velocity.X) > 0)
1085 {
1086 vec.X = ((_target_velocity.X - vel.X)/1.2f)*PID_D;
1087 }
1088 if (Math.Abs(_target_velocity.Y) > 0)
1089 {
1090 vec.Y = ((_target_velocity.Y - vel.Y)/1.2f)*PID_D;
1091 }
1092 }
1093
1094 if (flying)
1095 {
1096 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
1097 }
1098 }
1099 if (flying)
1100 {
1101 vec.Z += ((-1 * _parent_scene.gravityz)*m_mass);
1102
1103 //Added for auto fly height. Kitto Flora
1104 //d.Vector3 pos = d.BodyGetPosition(Body);
1105 float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
1106
1107 if (_position.Z < target_altitude)
1108 {
1109 vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
1110 }
1111 // end add Kitto Flora
1112 }
1113 if (vec.IsFinite())
1114 {
1115 if (!vec.ApproxEquals(Vector3.Zero, 0.02f)) // 0.01 allows 0.002 !!
1116 {
1117//Console.WriteLine("DF 2"); // ##
1118
1119 doForce(vec);
1120 if (!_zeroFlag)
1121 {
1122// AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
1123 }
1124 }
1125 }
1126 else
1127 {
1128 m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()");
1129 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
1130 defects.Add(this);
1131 // _parent_scene.RemoveCharacter(this);
1132 // destroy avatar capsule and related ODE data
1133 if (Amotor != IntPtr.Zero)
1134 {
1135 // Kill the Amotor
1136 d.JointDestroy(Amotor);
1137 Amotor = IntPtr.Zero;
1138 }
1139 //kill the Geometry
1140 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1141
1142 if (Body != IntPtr.Zero)
1143 {
1144 //kill the body
1145 d.BodyDestroy(Body);
1146
1147 Body = IntPtr.Zero;
1148 }
1149
1150 if(Shell != IntPtr.Zero)
1151 {
1152 try
1153 {
1154 d.GeomDestroy(Shell);
1155 }
1156 catch (System.AccessViolationException)
1157 {
1158 m_log.Error("[PHYSICS]: PrimGeom dead");
1159 }
1160 // Remove any old entries
1161//string tShell;
1162//_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1163//Console.WriteLine("**** Remove {0}", tShell);
1164
1165 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1166 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1167 Shell = IntPtr.Zero;
1168 }
1169 }
1170 }
1171
1172 /// <summary>
1173 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
1174 /// </summary>
1175 public void UpdatePositionAndVelocity()
1176 {
1177 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
1178 d.Vector3 vec;
1179 try
1180 {
1181 vec = d.BodyGetPosition(Body);
1182 }
1183 catch (NullReferenceException)
1184 {
1185 bad = true;
1186 _parent_scene.BadCharacter(this);
1187 vec = new d.Vector3(_position.X, _position.Y, _position.Z);
1188 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1189 m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid);
1190 }
1191
1192
1193 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1194 if (vec.X < 0.0f) vec.X = 0.0f;
1195 if (vec.Y < 0.0f) vec.Y = 0.0f;
1196 if (vec.X > (int)_parent_scene.WorldExtents.X - 0.05f) vec.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1197 if (vec.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) vec.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1198
1199 _position.X = vec.X;
1200 _position.Y = vec.Y;
1201 _position.Z = vec.Z;
1202
1203 // Did we move last? = zeroflag
1204 // This helps keep us from sliding all over
1205
1206 if (_zeroFlag)
1207 {
1208 _velocity.X = 0.0f;
1209 _velocity.Y = 0.0f;
1210 _velocity.Z = 0.0f;
1211
1212 // Did we send out the 'stopped' message?
1213 if (!m_lastUpdateSent)
1214 {
1215 m_lastUpdateSent = true;
1216 //base.RequestPhysicsterseUpdate();
1217
1218 }
1219 }
1220 else
1221 {
1222 m_lastUpdateSent = false;
1223 try
1224 {
1225 vec = d.BodyGetLinearVel(Body);
1226 }
1227 catch (NullReferenceException)
1228 {
1229 vec.X = _velocity.X;
1230 vec.Y = _velocity.Y;
1231 vec.Z = _velocity.Z;
1232 }
1233 _velocity.X = (vec.X);
1234 _velocity.Y = (vec.Y);
1235
1236 _velocity.Z = (vec.Z);
1237
1238 if (_velocity.Z < -6 && !m_hackSentFall)
1239 {
1240 m_hackSentFall = true;
1241 m_pidControllerActive = false;
1242 }
1243 else if (flying && !m_hackSentFly)
1244 {
1245 //m_hackSentFly = true;
1246 //base.SendCollisionUpdate(new CollisionEventUpdate());
1247 }
1248 else
1249 {
1250 m_hackSentFly = false;
1251 m_hackSentFall = false;
1252 }
1253 }
1254 }
1255
1256 /// <summary>
1257 /// Cleanup the things we use in the scene.
1258 /// </summary>
1259 public void Destroy()
1260 {
1261 m_tainted_isPhysical = false;
1262 _parent_scene.AddPhysicsActorTaint(this);
1263 }
1264
1265 public override void CrossingFailure()
1266 {
1267 }
1268
1269 public override Vector3 PIDTarget { set { return; } }
1270 public override bool PIDActive { set { return; } }
1271 public override float PIDTau { set { return; } }
1272
1273 public override float PIDHoverHeight { set { return; } }
1274 public override bool PIDHoverActive { set { return; } }
1275 public override PIDHoverType PIDHoverType { set { return; } }
1276 public override float PIDHoverTau { set { return; } }
1277
1278 public override Quaternion APIDTarget{ set { return; } }
1279
1280 public override bool APIDActive{ set { return; } }
1281
1282 public override float APIDStrength{ set { return; } }
1283
1284 public override float APIDDamping{ set { return; } }
1285
1286
1287 public override void SubscribeEvents(int ms)
1288 {
1289 m_requestedUpdateFrequency = ms;
1290 m_eventsubscription = ms;
1291 _parent_scene.addCollisionEventReporting(this);
1292 }
1293 public override void UnSubscribeEvents()
1294 {
1295 _parent_scene.remCollisionEventReporting(this);
1296 m_requestedUpdateFrequency = 0;
1297 m_eventsubscription = 0;
1298 }
1299 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1300 {
1301 if (m_eventsubscription > 0)
1302 {
1303 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
1304 }
1305 }
1306
1307 public void SendCollisions()
1308 {
1309 if (m_eventsubscription > m_requestedUpdateFrequency)
1310 {
1311 if (CollisionEventsThisFrame != null)
1312 {
1313 base.SendCollisionUpdate(CollisionEventsThisFrame);
1314 }
1315 CollisionEventsThisFrame = new CollisionEventUpdate();
1316 m_eventsubscription = 0;
1317 }
1318 }
1319 public override bool SubscribedEvents()
1320 {
1321 if (m_eventsubscription > 0)
1322 return true;
1323 return false;
1324 }
1325
1326 public void ProcessTaints(float timestep)
1327 {
1328 lock (m_syncRoot)
1329 {
1330
1331 if (m_tainted_isPhysical != m_isPhysical)
1332 {
1333 if (m_tainted_isPhysical)
1334 {
1335 // Create avatar capsule and related ODE data
1336 if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1337 {
1338 m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
1339 + (Shell!=IntPtr.Zero ? "Shell ":"")
1340 + (Body!=IntPtr.Zero ? "Body ":"")
1341 + (Amotor!=IntPtr.Zero ? "Amotor ":""));
1342 }
1343 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor);
1344 _parent_scene.AddCharacter(this);
1345 }
1346 else
1347 {
1348 _parent_scene.RemoveCharacter(this);
1349 // destroy avatar capsule and related ODE data
1350 if (Amotor != IntPtr.Zero)
1351 {
1352 // Kill the Amotor
1353 d.JointDestroy(Amotor);
1354 Amotor = IntPtr.Zero;
1355 }
1356 //kill the Geometry
1357 _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1358
1359 if (Body != IntPtr.Zero)
1360 {
1361 //kill the body
1362 d.BodyDestroy(Body);
1363 Body = IntPtr.Zero;
1364 }
1365
1366 if(Shell != IntPtr.Zero)
1367 {
1368 try
1369 {
1370 d.GeomDestroy(Shell);
1371 }
1372 catch (System.AccessViolationException)
1373 {
1374 m_log.Error("[PHYSICS]: PrimGeom dead");
1375 }
1376 // Remove any old entries
1377 //string tShell;
1378 //_parent_scene.geom_name_map.TryGetValue(Shell, out tShell);
1379 //Console.WriteLine("**** Remove {0}", tShell);
1380
1381 if(_parent_scene.geom_name_map.ContainsKey(Shell)) _parent_scene.geom_name_map.Remove(Shell);
1382 if(_parent_scene.actor_name_map.ContainsKey(Shell)) _parent_scene.actor_name_map.Remove(Shell);
1383 Shell = IntPtr.Zero;
1384 }
1385 }
1386
1387 m_isPhysical = m_tainted_isPhysical;
1388 }
1389
1390 if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1391 {
1392 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1393 {
1394
1395 m_pidControllerActive = true;
1396 // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1397 d.JointDestroy(Amotor);
1398 float prevCapsule = CAPSULE_LENGTH;
1399 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1400 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
1401 d.BodyDestroy(Body);
1402 AvatarGeomAndBodyCreation(_position.X, _position.Y,
1403 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1404 Velocity = Vector3.Zero;
1405 }
1406 else
1407 {
1408 m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - "
1409 + (Shell==IntPtr.Zero ? "Shell ":"")
1410 + (Body==IntPtr.Zero ? "Body ":"")
1411 + (Amotor==IntPtr.Zero ? "Amotor ":""));
1412 }
1413 }
1414
1415 if (!m_taintPosition.ApproxEquals(_position, 0.05f))
1416 {
1417 if (Body != IntPtr.Zero)
1418 {
1419 d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1420
1421 _position.X = m_taintPosition.X;
1422 _position.Y = m_taintPosition.Y;
1423 _position.Z = m_taintPosition.Z;
1424 }
1425 }
1426
1427 }
1428 }
1429
1430 internal void AddCollisionFrameTime(int p)
1431 {
1432 // protect it from overflow crashing
1433 if (m_eventsubscription + p >= int.MaxValue)
1434 m_eventsubscription = 0;
1435 m_eventsubscription += p;
1436 }
1437 }
1438}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
new file mode 100644
index 0000000..42e22ff
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs
@@ -0,0 +1,3875 @@
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, uint localid)
260 {
261 m_localID = localid;
262 ode = dode;
263 if (!pos.IsFinite())
264 {
265 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
266 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
267 m_log.Warn("[PHYSICS]: Got nonFinite Object create Position");
268 }
269
270 _position = pos;
271 m_taintposition = pos;
272 PID_D = parent_scene.bodyPIDD;
273 PID_G = parent_scene.bodyPIDG;
274 m_density = parent_scene.geomDefaultDensity;
275 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
276 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
277
278
279 prim_geom = IntPtr.Zero;
280// prev_geom = IntPtr.Zero;
281
282 if (!pos.IsFinite())
283 {
284 size = new Vector3(0.5f, 0.5f, 0.5f);
285 m_log.Warn("[PHYSICS]: Got nonFinite Object create Size");
286 }
287
288 if (size.X <= 0) size.X = 0.01f;
289 if (size.Y <= 0) size.Y = 0.01f;
290 if (size.Z <= 0) size.Z = 0.01f;
291
292 _size = size;
293 m_taintsize = _size;
294
295 if (!QuaternionIsFinite(rotation))
296 {
297 rotation = Quaternion.Identity;
298 m_log.Warn("[PHYSICS]: Got nonFinite Object create Rotation");
299 }
300
301 _orientation = rotation;
302 m_taintrot = _orientation;
303 _mesh = mesh;
304 _pbs = pbs;
305
306 _parent_scene = parent_scene;
307 m_targetSpace = (IntPtr)0;
308
309// if (pos.Z < 0)
310 if (pos.Z < parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y))
311 m_isphysical = false;
312 else
313 {
314 m_isphysical = pisPhysical;
315 // If we're physical, we need to be in the master space for now.
316 // linksets *should* be in a space together.. but are not currently
317 if (m_isphysical)
318 m_targetSpace = _parent_scene.space;
319 }
320 m_primName = primName;
321 m_taintadd = true;
322 _parent_scene.AddPhysicsActorTaint(this);
323 // don't do .add() here; old geoms get recycled with the same hash
324 }
325
326 public override int PhysicsActorType
327 {
328 get { return (int) ActorTypes.Prim; }
329 set { return; }
330 }
331
332 public override bool SetAlwaysRun
333 {
334 get { return false; }
335 set { return; }
336 }
337
338 public override uint LocalID
339 {
340 set {
341 //m_log.Info("[PHYSICS]: Setting TrackerID: " + value);
342 m_localID = value; }
343 }
344
345 public override bool Grabbed
346 {
347 set { return; }
348 }
349
350 public override bool Selected
351 {
352 set {
353
354//Console.WriteLine("Sel {0} {1} {2}", m_primName, value, m_isphysical);
355 // This only makes the object not collidable if the object
356 // is physical or the object is modified somehow *IN THE FUTURE*
357 // without this, if an avatar selects prim, they can walk right
358 // through it while it's selected
359 m_collisionscore = 0;
360 if ((m_isphysical && !_zeroFlag) || !value)
361 {
362 m_taintselected = value;
363 _parent_scene.AddPhysicsActorTaint(this);
364 }
365 else
366 {
367 m_taintselected = value;
368 m_isSelected = value;
369 }
370 if(m_isSelected) disableBodySoft();
371 }
372 }
373
374 public override bool IsPhysical
375 {
376 get { return m_isphysical; }
377 set
378 {
379 m_isphysical = value;
380 if (!m_isphysical)
381 { // Zero the remembered last velocity
382 m_lastVelocity = Vector3.Zero;
383 if (m_type != Vehicle.TYPE_NONE) Halt();
384 }
385 }
386 }
387
388 public void setPrimForRemoval()
389 {
390 m_taintremove = true;
391 }
392
393 public override bool Flying
394 {
395 // no flying prims for you
396 get { return false; }
397 set { }
398 }
399
400 public override bool IsColliding
401 {
402 get { return iscolliding; }
403 set { iscolliding = value; }
404 }
405
406 public override bool CollidingGround
407 {
408 get { return false; }
409 set { return; }
410 }
411
412 public override bool CollidingObj
413 {
414 get { return false; }
415 set { return; }
416 }
417
418 public override bool ThrottleUpdates
419 {
420 get { return m_throttleUpdates; }
421 set { m_throttleUpdates = value; }
422 }
423
424 public override bool Stopped
425 {
426 get { return _zeroFlag; }
427 }
428
429 public override Vector3 Position
430 {
431 get { return _position; }
432
433 set { _position = value;
434 //m_log.Info("[PHYSICS]: " + _position.ToString());
435 }
436 }
437
438 public override Vector3 Size
439 {
440 get { return _size; }
441 set
442 {
443 if (value.IsFinite())
444 {
445 _size = value;
446 }
447 else
448 {
449 m_log.Warn("[PHYSICS]: Got NaN Size on object");
450 }
451 }
452 }
453
454 public override float Mass
455 {
456 get { return CalculateMass(); }
457 }
458
459 public override Vector3 Force
460 {
461 //get { return Vector3.Zero; }
462 get { return m_force; }
463 set
464 {
465 if (value.IsFinite())
466 {
467 m_force = value;
468 }
469 else
470 {
471 m_log.Warn("[PHYSICS]: NaN in Force Applied to an Object");
472 }
473 }
474 }
475
476 public override int VehicleType
477 {
478 get { return (int)m_type; }
479 set { ProcessTypeChange((Vehicle)value); }
480 }
481
482 public override void VehicleFloatParam(int param, float value)
483 {
484 ProcessFloatVehicleParam((Vehicle) param, value);
485 }
486
487 public override void VehicleVectorParam(int param, Vector3 value)
488 {
489 ProcessVectorVehicleParam((Vehicle) param, value);
490 }
491
492 public override void VehicleRotationParam(int param, Quaternion rotation)
493 {
494 ProcessRotationVehicleParam((Vehicle) param, rotation);
495 }
496
497 public override void VehicleFlags(int param, bool remove)
498 {
499 ProcessVehicleFlags(param, remove);
500 }
501
502 public override void SetVolumeDetect(int param)
503 {
504 lock (_parent_scene.OdeLock)
505 {
506 m_isVolumeDetect = (param!=0);
507 }
508 }
509
510 public override Vector3 CenterOfMass
511 {
512 get { return Vector3.Zero; }
513 }
514
515 public override Vector3 GeometricCenter
516 {
517 get { return Vector3.Zero; }
518 }
519
520 public override PrimitiveBaseShape Shape
521 {
522 set
523 {
524 _pbs = value;
525 m_taintshape = true;
526 }
527 }
528
529 public override Vector3 Velocity
530 {
531 get
532 {
533 // Averate previous velocity with the new one so
534 // client object interpolation works a 'little' better
535 if (_zeroFlag)
536 return Vector3.Zero;
537
538 Vector3 returnVelocity = Vector3.Zero;
539 returnVelocity.X = (m_lastVelocity.X + _velocity.X)/2;
540 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y)/2;
541 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z)/2;
542 return returnVelocity;
543 }
544 set
545 {
546 if (value.IsFinite())
547 {
548 _velocity = value;
549 if (_velocity.ApproxEquals(Vector3.Zero,0.001f))
550 _acceleration = Vector3.Zero;
551
552 m_taintVelocity = value;
553 _parent_scene.AddPhysicsActorTaint(this);
554 }
555 else
556 {
557 m_log.Warn("[PHYSICS]: Got NaN Velocity in Object");
558 }
559
560 }
561 }
562
563 public override Vector3 Torque
564 {
565 get
566 {
567 if (!m_isphysical || Body == IntPtr.Zero)
568 return Vector3.Zero;
569
570 return _torque;
571 }
572
573 set
574 {
575 if (value.IsFinite())
576 {
577 m_taintTorque = value;
578 _parent_scene.AddPhysicsActorTaint(this);
579 }
580 else
581 {
582 m_log.Warn("[PHYSICS]: Got NaN Torque in Object");
583 }
584 }
585 }
586
587 public override float CollisionScore
588 {
589 get { return m_collisionscore; }
590 set { m_collisionscore = value; }
591 }
592
593 public override bool Kinematic
594 {
595 get { return false; }
596 set { }
597 }
598
599 public override Quaternion Orientation
600 {
601 get { return _orientation; }
602 set
603 {
604 if (QuaternionIsFinite(value))
605 {
606 _orientation = value;
607 }
608 else
609 m_log.Warn("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object");
610
611 }
612 }
613
614
615 public override bool FloatOnWater
616 {
617 set {
618 m_taintCollidesWater = value;
619 _parent_scene.AddPhysicsActorTaint(this);
620 }
621 }
622
623 public override void SetMomentum(Vector3 momentum)
624 {
625 }
626
627 public override Vector3 PIDTarget
628 {
629 set
630 {
631 if (value.IsFinite())
632 {
633 m_PIDTarget = value;
634 }
635 else
636 m_log.Warn("[PHYSICS]: Got NaN PIDTarget from Scene on Object");
637 }
638 }
639 public override bool PIDActive { set { m_usePID = value; } }
640 public override float PIDTau { set { m_PIDTau = value; } }
641
642 // For RotLookAt
643 public override Quaternion APIDTarget { set { m_APIDTarget = value; } }
644 public override bool APIDActive { set { m_useAPID = value; } }
645 public override float APIDStrength { set { m_APIDStrength = value; } }
646 public override float APIDDamping { set { m_APIDDamping = value; } }
647
648 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
649 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
650 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
651 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
652
653 internal static bool QuaternionIsFinite(Quaternion q)
654 {
655 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
656 return false;
657 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
658 return false;
659 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
660 return false;
661 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
662 return false;
663 return true;
664 }
665
666 public override Vector3 Acceleration // client updates read data via here
667 {
668 get
669 {
670 if (_zeroFlag)
671 {
672 return Vector3.Zero;
673 }
674 return _acceleration;
675 }
676 set { _acceleration = value; }
677 }
678
679
680 public void SetAcceleration(Vector3 accel) // No one calls this, and it would not do anything.
681 {
682 _acceleration = accel;
683 }
684
685 public override void AddForce(Vector3 force, bool pushforce)
686 {
687 if (force.IsFinite())
688 {
689 lock (m_forcelist)
690 m_forcelist.Add(force);
691
692 m_taintforce = true;
693 }
694 else
695 {
696 m_log.Warn("[PHYSICS]: Got Invalid linear force vector from Scene in Object");
697 }
698 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
699 }
700
701 public override void AddAngularForce(Vector3 force, bool pushforce)
702 {
703 if (force.IsFinite())
704 {
705 m_angularforcelist.Add(force);
706 m_taintaddangularforce = true;
707 }
708 else
709 {
710 m_log.Warn("[PHYSICS]: Got Invalid Angular force vector from Scene in Object");
711 }
712 }
713
714 public override Vector3 RotationalVelocity
715 {
716 get
717 {
718 return m_rotationalVelocity;
719 }
720 set
721 {
722 if (value.IsFinite())
723 {
724 m_rotationalVelocity = value;
725 }
726 else
727 {
728 m_log.Warn("[PHYSICS]: Got NaN RotationalVelocity in Object");
729 }
730 }
731 }
732
733 public override void CrossingFailure()
734 {
735 m_crossingfailures++;
736 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
737 {
738 base.RaiseOutOfBounds(_position);
739 return;
740 }
741 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
742 {
743 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + m_primName);
744 }
745 }
746
747 public override float Buoyancy
748 {
749 get { return m_buoyancy; }
750 set { m_buoyancy = value; }
751 }
752
753 public override void link(PhysicsActor obj)
754 {
755 m_taintparent = obj;
756 }
757
758 public override void delink()
759 {
760 m_taintparent = null;
761 }
762
763 public override void LockAngularMotion(Vector3 axis)
764 {
765 // This is actually ROTATION ENABLE, not a lock.
766 // default is <1,1,1> which is all enabled.
767 // The lock value is updated inside Move(), no point in using the taint system.
768 // OS 'm_taintAngularLock' etc change to m_rotateEnable.
769 if (axis.IsFinite())
770 {
771 axis.X = (axis.X > 0) ? 1f : 0f;
772 axis.Y = (axis.Y > 0) ? 1f : 0f;
773 axis.Z = (axis.Z > 0) ? 1f : 0f;
774 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
775 m_rotateEnableRequest = axis;
776 m_rotateEnableUpdate = true;
777 }
778 else
779 {
780 m_log.Warn("[PHYSICS]: Got NaN locking axis from Scene on Object");
781 }
782 }
783
784
785 public void SetGeom(IntPtr geom)
786 {
787 if(prim_geom != IntPtr.Zero)
788 {
789 // Remove any old entries
790//string tPA;
791//_parent_scene.geom_name_map.TryGetValue(prim_geom, out tPA);
792//Console.WriteLine("**** Remove {0}", tPA);
793 if(_parent_scene.geom_name_map.ContainsKey(prim_geom)) _parent_scene.geom_name_map.Remove(prim_geom);
794 if(_parent_scene.actor_name_map.ContainsKey(prim_geom)) _parent_scene.actor_name_map.Remove(prim_geom);
795 d.GeomDestroy(prim_geom);
796 }
797
798 prim_geom = geom;
799//Console.WriteLine("SetGeom to " + prim_geom + " for " + m_primName);
800 if (prim_geom != IntPtr.Zero)
801 {
802 _parent_scene.geom_name_map[prim_geom] = this.m_primName;
803 _parent_scene.actor_name_map[prim_geom] = (PhysicsActor)this;
804 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
805 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
806//Console.WriteLine("**** Create {2} Dicts: actor={0} name={1}", _parent_scene.actor_name_map.Count, _parent_scene.geom_name_map.Count, this.m_primName);
807 }
808
809 if (childPrim)
810 {
811 if (_parent != null && _parent is OdePrim)
812 {
813 OdePrim parent = (OdePrim)_parent;
814//Console.WriteLine("SetGeom calls ChildSetGeom");
815 parent.ChildSetGeom(this);
816 }
817 }
818 //m_log.Warn("Setting Geom to: " + prim_geom);
819 }
820
821 public void enableBodySoft()
822 {
823 if (!childPrim)
824 {
825 if (m_isphysical && Body != IntPtr.Zero)
826 {
827 d.BodyEnable(Body);
828 if (m_type != Vehicle.TYPE_NONE)
829 Enable(Body, _parent_scene);
830 }
831
832 m_disabled = false;
833 }
834 }
835
836 public void disableBodySoft()
837 {
838 m_disabled = true;
839
840 if (m_isphysical && Body != IntPtr.Zero)
841 {
842 d.BodyDisable(Body);
843 Halt();
844 }
845 }
846
847 public void enableBody()
848 {
849 // Don't enable this body if we're a child prim
850 // this should be taken care of in the parent function not here
851 if (!childPrim)
852 {
853 // Sets the geom to a body
854 Body = d.BodyCreate(_parent_scene.world);
855
856 setMass();
857 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
858 d.Quaternion myrot = new d.Quaternion();
859 myrot.X = _orientation.X;
860 myrot.Y = _orientation.Y;
861 myrot.Z = _orientation.Z;
862 myrot.W = _orientation.W;
863 d.BodySetQuaternion(Body, ref myrot);
864 d.GeomSetBody(prim_geom, Body);
865 m_collisionCategories |= CollisionCategories.Body;
866 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
867
868 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
869 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
870
871 d.BodySetAutoDisableFlag(Body, true);
872 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
873
874 // disconnect from world gravity so we can apply buoyancy
875 d.BodySetGravityMode (Body, false);
876
877 m_interpenetrationcount = 0;
878 m_collisionscore = 0;
879 m_disabled = false;
880
881 if (m_type != Vehicle.TYPE_NONE)
882 {
883 Enable(Body, _parent_scene);
884 }
885
886 _parent_scene.addActivePrim(this);
887 }
888 }
889
890 #region Mass Calculation
891
892 private float CalculateMass()
893 {
894 float volume = _size.X * _size.Y * _size.Z; // default
895 float tmp;
896
897 float returnMass = 0;
898 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
899 float hollowVolume = hollowAmount * hollowAmount;
900
901 switch (_pbs.ProfileShape)
902 {
903 case ProfileShape.Square:
904 // default box
905
906 if (_pbs.PathCurve == (byte)Extrusion.Straight)
907 {
908 if (hollowAmount > 0.0)
909 {
910 switch (_pbs.HollowShape)
911 {
912 case HollowShape.Square:
913 case HollowShape.Same:
914 break;
915
916 case HollowShape.Circle:
917
918 hollowVolume *= 0.78539816339f;
919 break;
920
921 case HollowShape.Triangle:
922
923 hollowVolume *= (0.5f * .5f);
924 break;
925
926 default:
927 hollowVolume = 0;
928 break;
929 }
930 volume *= (1.0f - hollowVolume);
931 }
932 }
933
934 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
935 {
936 //a tube
937
938 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
939 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
940 volume -= volume*tmp*tmp;
941
942 if (hollowAmount > 0.0)
943 {
944 hollowVolume *= hollowAmount;
945
946 switch (_pbs.HollowShape)
947 {
948 case HollowShape.Square:
949 case HollowShape.Same:
950 break;
951
952 case HollowShape.Circle:
953 hollowVolume *= 0.78539816339f;;
954 break;
955
956 case HollowShape.Triangle:
957 hollowVolume *= 0.5f * 0.5f;
958 break;
959 default:
960 hollowVolume = 0;
961 break;
962 }
963 volume *= (1.0f - hollowVolume);
964 }
965 }
966
967 break;
968
969 case ProfileShape.Circle:
970
971 if (_pbs.PathCurve == (byte)Extrusion.Straight)
972 {
973 volume *= 0.78539816339f; // elipse base
974
975 if (hollowAmount > 0.0)
976 {
977 switch (_pbs.HollowShape)
978 {
979 case HollowShape.Same:
980 case HollowShape.Circle:
981 break;
982
983 case HollowShape.Square:
984 hollowVolume *= 0.5f * 2.5984480504799f;
985 break;
986
987 case HollowShape.Triangle:
988 hollowVolume *= .5f * 1.27323954473516f;
989 break;
990
991 default:
992 hollowVolume = 0;
993 break;
994 }
995 volume *= (1.0f - hollowVolume);
996 }
997 }
998
999 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1000 {
1001 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
1002 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1003 volume *= (1.0f - tmp * tmp);
1004
1005 if (hollowAmount > 0.0)
1006 {
1007
1008 // calculate the hollow volume by it's shape compared to the prim shape
1009 hollowVolume *= hollowAmount;
1010
1011 switch (_pbs.HollowShape)
1012 {
1013 case HollowShape.Same:
1014 case HollowShape.Circle:
1015 break;
1016
1017 case HollowShape.Square:
1018 hollowVolume *= 0.5f * 2.5984480504799f;
1019 break;
1020
1021 case HollowShape.Triangle:
1022 hollowVolume *= .5f * 1.27323954473516f;
1023 break;
1024
1025 default:
1026 hollowVolume = 0;
1027 break;
1028 }
1029 volume *= (1.0f - hollowVolume);
1030 }
1031 }
1032 break;
1033
1034 case ProfileShape.HalfCircle:
1035 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1036 {
1037 volume *= 0.52359877559829887307710723054658f;
1038 }
1039 break;
1040
1041 case ProfileShape.EquilateralTriangle:
1042
1043 if (_pbs.PathCurve == (byte)Extrusion.Straight)
1044 {
1045 volume *= 0.32475953f;
1046
1047 if (hollowAmount > 0.0)
1048 {
1049
1050 // calculate the hollow volume by it's shape compared to the prim shape
1051 switch (_pbs.HollowShape)
1052 {
1053 case HollowShape.Same:
1054 case HollowShape.Triangle:
1055 hollowVolume *= .25f;
1056 break;
1057
1058 case HollowShape.Square:
1059 hollowVolume *= 0.499849f * 3.07920140172638f;
1060 break;
1061
1062 case HollowShape.Circle:
1063 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1064 // Cyllinder hollow volume calculation
1065
1066 hollowVolume *= 0.1963495f * 3.07920140172638f;
1067 break;
1068
1069 default:
1070 hollowVolume = 0;
1071 break;
1072 }
1073 volume *= (1.0f - hollowVolume);
1074 }
1075 }
1076 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
1077 {
1078 volume *= 0.32475953f;
1079 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
1080 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
1081 volume *= (1.0f - tmp * tmp);
1082
1083 if (hollowAmount > 0.0)
1084 {
1085
1086 hollowVolume *= hollowAmount;
1087
1088 switch (_pbs.HollowShape)
1089 {
1090 case HollowShape.Same:
1091 case HollowShape.Triangle:
1092 hollowVolume *= .25f;
1093 break;
1094
1095 case HollowShape.Square:
1096 hollowVolume *= 0.499849f * 3.07920140172638f;
1097 break;
1098
1099 case HollowShape.Circle:
1100
1101 hollowVolume *= 0.1963495f * 3.07920140172638f;
1102 break;
1103
1104 default:
1105 hollowVolume = 0;
1106 break;
1107 }
1108 volume *= (1.0f - hollowVolume);
1109 }
1110 }
1111 break;
1112
1113 default:
1114 break;
1115 }
1116
1117
1118
1119 float taperX1;
1120 float taperY1;
1121 float taperX;
1122 float taperY;
1123 float pathBegin;
1124 float pathEnd;
1125 float profileBegin;
1126 float profileEnd;
1127
1128 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
1129 {
1130 taperX1 = _pbs.PathScaleX * 0.01f;
1131 if (taperX1 > 1.0f)
1132 taperX1 = 2.0f - taperX1;
1133 taperX = 1.0f - taperX1;
1134
1135 taperY1 = _pbs.PathScaleY * 0.01f;
1136 if (taperY1 > 1.0f)
1137 taperY1 = 2.0f - taperY1;
1138 taperY = 1.0f - taperY1;
1139 }
1140 else
1141 {
1142 taperX = _pbs.PathTaperX * 0.01f;
1143 if (taperX < 0.0f)
1144 taperX = -taperX;
1145 taperX1 = 1.0f - taperX;
1146
1147 taperY = _pbs.PathTaperY * 0.01f;
1148 if (taperY < 0.0f)
1149 taperY = -taperY;
1150 taperY1 = 1.0f - taperY;
1151
1152 }
1153
1154
1155 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1156
1157 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
1158 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
1159 volume *= (pathEnd - pathBegin);
1160
1161// this is crude aproximation
1162 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
1163 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
1164 volume *= (profileEnd - profileBegin);
1165
1166 returnMass = m_density * volume;
1167
1168 if (returnMass <= 0)
1169 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
1170// else if (returnMass > _parent_scene.maximumMassObject)
1171// returnMass = _parent_scene.maximumMassObject;
1172
1173
1174
1175
1176 // Recursively calculate mass
1177 bool HasChildPrim = false;
1178 lock (childrenPrim)
1179 {
1180 if (childrenPrim.Count > 0)
1181 {
1182 HasChildPrim = true;
1183 }
1184
1185 }
1186 if (HasChildPrim)
1187 {
1188 OdePrim[] childPrimArr = new OdePrim[0];
1189
1190 lock (childrenPrim)
1191 childPrimArr = childrenPrim.ToArray();
1192
1193 for (int i = 0; i < childPrimArr.Length; i++)
1194 {
1195 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
1196 returnMass += childPrimArr[i].CalculateMass();
1197 // failsafe, this shouldn't happen but with OpenSim, you never know :)
1198 if (i > 256)
1199 break;
1200 }
1201 }
1202 if (returnMass > _parent_scene.maximumMassObject)
1203 returnMass = _parent_scene.maximumMassObject;
1204 return returnMass;
1205 }// end CalculateMass
1206
1207 #endregion
1208
1209 public void setMass()
1210 {
1211 if (Body != (IntPtr) 0)
1212 {
1213 float newmass = CalculateMass();
1214
1215 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
1216
1217 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
1218 d.BodySetMass(Body, ref pMass);
1219 }
1220 }
1221
1222 public void disableBody()
1223 {
1224 //this kills the body so things like 'mesh' can re-create it.
1225 lock (this)
1226 {
1227 if (!childPrim)
1228 {
1229 if (Body != IntPtr.Zero)
1230 {
1231 _parent_scene.remActivePrim(this);
1232 m_collisionCategories &= ~CollisionCategories.Body;
1233 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1234
1235 if (prim_geom != IntPtr.Zero)
1236 {
1237 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1238 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1239 }
1240
1241
1242 d.BodyDestroy(Body);
1243 lock (childrenPrim)
1244 {
1245 if (childrenPrim.Count > 0)
1246 {
1247 foreach (OdePrim prm in childrenPrim)
1248 {
1249 _parent_scene.remActivePrim(prm);
1250 prm.Body = IntPtr.Zero;
1251 }
1252 }
1253 }
1254 Body = IntPtr.Zero;
1255 }
1256 }
1257 else
1258 {
1259 _parent_scene.remActivePrim(this);
1260
1261 m_collisionCategories &= ~CollisionCategories.Body;
1262 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
1263
1264 if (prim_geom != IntPtr.Zero)
1265 {
1266 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1267 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1268 }
1269
1270
1271 Body = IntPtr.Zero;
1272 }
1273 }
1274 m_disabled = true;
1275 m_collisionscore = 0;
1276 }
1277
1278 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
1279
1280 public void setMesh(OdeScene parent_scene, IMesh mesh)
1281 {
1282 // This sleeper is there to moderate how long it takes between
1283 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
1284
1285 //Thread.Sleep(10);
1286
1287 //Kill Body so that mesh can re-make the geom
1288 if (IsPhysical && Body != IntPtr.Zero)
1289 {
1290 if (childPrim)
1291 {
1292 if (_parent != null)
1293 {
1294 OdePrim parent = (OdePrim)_parent;
1295 parent.ChildDelink(this);
1296 }
1297 }
1298 else
1299 {
1300 disableBody();
1301 }
1302 }
1303 IntPtr vertices, indices;
1304 int vertexCount, indexCount;
1305 int vertexStride, triStride;
1306 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
1307 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
1308
1309 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
1310 if (m_MeshToTriMeshMap.ContainsKey(mesh))
1311 {
1312 _triMeshData = m_MeshToTriMeshMap[mesh];
1313 }
1314 else
1315 {
1316 _triMeshData = d.GeomTriMeshDataCreate();
1317
1318 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
1319 d.GeomTriMeshDataPreprocess(_triMeshData);
1320 m_MeshToTriMeshMap[mesh] = _triMeshData;
1321 }
1322
1323 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1324 try
1325 {
1326 // if (prim_geom == IntPtr.Zero) // setGeom takes care of phys engine recreate and prim_geom pointer
1327 // {
1328 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
1329 // }
1330 }
1331 catch (AccessViolationException)
1332 {
1333 m_log.Error("[PHYSICS]: MESH LOCKED");
1334 return;
1335 }
1336
1337
1338 // if (IsPhysical && Body == (IntPtr) 0)
1339 // {
1340 // Recreate the body
1341 // m_interpenetrationcount = 0;
1342 // m_collisionscore = 0;
1343
1344 // enableBody();
1345 // }
1346 }
1347
1348 public void ProcessTaints(float timestep) //=============================================================================
1349 {
1350 if (m_taintadd)
1351 {
1352 changeadd(timestep);
1353 }
1354
1355 if (prim_geom != IntPtr.Zero)
1356 {
1357 if (!_position.ApproxEquals(m_taintposition, 0f))
1358 {
1359 changemove(timestep);
1360 }
1361 if (m_taintrot != _orientation)
1362 {
1363 if(childPrim && IsPhysical) // For physical child prim...
1364 {
1365 rotate(timestep);
1366 // KF: ODE will also rotate the parent prim!
1367 // so rotate the root back to where it was
1368 OdePrim parent = (OdePrim)_parent;
1369 parent.rotate(timestep);
1370 }
1371 else
1372 {
1373 //Just rotate the prim
1374 rotate(timestep);
1375 }
1376 }
1377 //
1378
1379 if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent))
1380 {
1381 changePhysicsStatus(timestep);
1382 }//
1383
1384 if (!_size.ApproxEquals(m_taintsize,0f))
1385 changesize(timestep);
1386 //
1387
1388 if (m_taintshape)
1389 changeshape(timestep);
1390 //
1391
1392 if (m_taintforce)
1393 changeAddForce(timestep);
1394
1395 if (m_taintaddangularforce)
1396 changeAddAngularForce(timestep);
1397
1398 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
1399 changeSetTorque(timestep);
1400
1401 if (m_taintdisable)
1402 changedisable(timestep);
1403
1404 if (m_taintselected != m_isSelected)
1405 changeSelectedStatus(timestep);
1406
1407 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
1408 changevelocity(timestep);
1409
1410 if (m_taintparent != _parent)
1411 changelink(timestep);
1412
1413 if (m_taintCollidesWater != m_collidesWater)
1414 changefloatonwater(timestep);
1415/* obsolete
1416 if (!m_angularLock.ApproxEquals(m_taintAngularLock,0f))
1417 changeAngularLock(timestep);
1418 */
1419 }
1420 else
1421 {
1422 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.)");
1423 }
1424 }
1425
1426/* obsolete
1427 private void changeAngularLock(float timestep)
1428 {
1429 if (_parent == null)
1430 {
1431 m_angularLock = m_taintAngularLock;
1432 m_angularLockSet = true;
1433 }
1434 }
1435 */
1436 private void changelink(float timestep)
1437 {
1438 // If the newly set parent is not null
1439 // create link
1440 if (_parent == null && m_taintparent != null)
1441 {
1442 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1443 {
1444 OdePrim obj = (OdePrim)m_taintparent;
1445 //obj.disableBody();
1446 obj.ParentPrim(this);
1447
1448 /*
1449 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1450 {
1451 _linkJointGroup = d.JointGroupCreate(0);
1452 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1453 d.JointAttach(m_linkJoint, obj.Body, Body);
1454 d.JointSetFixed(m_linkJoint);
1455 }
1456 */
1457 }
1458 }
1459 // If the newly set parent is null
1460 // destroy link
1461 else if (_parent != null && m_taintparent == null)
1462 {
1463 if (_parent is OdePrim)
1464 {
1465 OdePrim obj = (OdePrim)_parent;
1466 obj.ChildDelink(this);
1467 childPrim = false;
1468 //_parent = null;
1469 }
1470
1471 /*
1472 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1473 d.JointGroupDestroy(_linkJointGroup);
1474
1475 _linkJointGroup = (IntPtr)0;
1476 m_linkJoint = (IntPtr)0;
1477 */
1478 }
1479
1480 _parent = m_taintparent;
1481 m_taintPhysics = m_isphysical;
1482 }
1483
1484 // I'm the parent
1485 // prim is the child
1486 public void ParentPrim(OdePrim prim)
1487 {
1488 if (this.m_localID != prim.m_localID)
1489 {
1490 if (Body == IntPtr.Zero)
1491 {
1492 Body = d.BodyCreate(_parent_scene.world);
1493 // disconnect from world gravity so we can apply buoyancy
1494 d.BodySetGravityMode (Body, false);
1495
1496 setMass();
1497 }
1498 if (Body != IntPtr.Zero)
1499 {
1500 lock (childrenPrim)
1501 {
1502 if (!childrenPrim.Contains(prim))
1503 {
1504 childrenPrim.Add(prim);
1505
1506 foreach (OdePrim prm in childrenPrim)
1507 {
1508 d.Mass m2;
1509 d.MassSetZero(out m2);
1510 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1511
1512
1513 d.Quaternion quat = new d.Quaternion();
1514 quat.W = prm._orientation.W;
1515 quat.X = prm._orientation.X;
1516 quat.Y = prm._orientation.Y;
1517 quat.Z = prm._orientation.Z;
1518
1519 d.Matrix3 mat = new d.Matrix3();
1520 d.RfromQ(out mat, ref quat);
1521 d.MassRotate(ref m2, ref mat);
1522 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1523 d.MassAdd(ref pMass, ref m2);
1524 }
1525 foreach (OdePrim prm in childrenPrim)
1526 {
1527
1528 prm.m_collisionCategories |= CollisionCategories.Body;
1529 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1530
1531 if (prm.prim_geom == IntPtr.Zero)
1532 {
1533 m_log.Warn("[PHYSICS]: Unable to link one of the linkset elements. No geom yet");
1534 continue;
1535 }
1536 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1537 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1538
1539
1540 d.Quaternion quat = new d.Quaternion();
1541 quat.W = prm._orientation.W;
1542 quat.X = prm._orientation.X;
1543 quat.Y = prm._orientation.Y;
1544 quat.Z = prm._orientation.Z;
1545
1546 d.Matrix3 mat = new d.Matrix3();
1547 d.RfromQ(out mat, ref quat);
1548 if (Body != IntPtr.Zero)
1549 {
1550 d.GeomSetBody(prm.prim_geom, Body);
1551 prm.childPrim = true;
1552 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1553 //d.GeomSetOffsetPosition(prim.prim_geom,
1554 // (Position.X - prm.Position.X) - pMass.c.X,
1555 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1556 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1557 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1558 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1559 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1560 d.BodySetMass(Body, ref pMass);
1561 }
1562 else
1563 {
1564 m_log.Debug("[PHYSICS]:I ain't got no boooooooooddy, no body");
1565 }
1566
1567
1568 prm.m_interpenetrationcount = 0;
1569 prm.m_collisionscore = 0;
1570 prm.m_disabled = false;
1571
1572 prm.Body = Body;
1573 _parent_scene.addActivePrim(prm);
1574 }
1575 m_collisionCategories |= CollisionCategories.Body;
1576 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1577
1578 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1579 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1580
1581
1582 d.Quaternion quat2 = new d.Quaternion();
1583 quat2.W = _orientation.W;
1584 quat2.X = _orientation.X;
1585 quat2.Y = _orientation.Y;
1586 quat2.Z = _orientation.Z;
1587
1588 d.Matrix3 mat2 = new d.Matrix3();
1589 d.RfromQ(out mat2, ref quat2);
1590 d.GeomSetBody(prim_geom, Body);
1591 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1592 //d.GeomSetOffsetPosition(prim.prim_geom,
1593 // (Position.X - prm.Position.X) - pMass.c.X,
1594 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1595 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1596 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1597 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1598 d.BodySetMass(Body, ref pMass);
1599
1600 d.BodySetAutoDisableFlag(Body, true);
1601 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1602
1603
1604 m_interpenetrationcount = 0;
1605 m_collisionscore = 0;
1606 m_disabled = false;
1607
1608 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1609 if (m_type != Vehicle.TYPE_NONE) Enable(Body, _parent_scene);
1610 _parent_scene.addActivePrim(this);
1611 }
1612 }
1613 }
1614 }
1615
1616 }
1617
1618 private void ChildSetGeom(OdePrim odePrim)
1619 {
1620 //if (m_isphysical && Body != IntPtr.Zero)
1621 lock (childrenPrim)
1622 {
1623 foreach (OdePrim prm in childrenPrim)
1624 {
1625 //prm.childPrim = true;
1626 prm.disableBody();
1627 //prm.m_taintparent = null;
1628 //prm._parent = null;
1629 //prm.m_taintPhysics = false;
1630 //prm.m_disabled = true;
1631 //prm.childPrim = false;
1632 }
1633 }
1634 disableBody();
1635
1636
1637 if (Body != IntPtr.Zero)
1638 {
1639 _parent_scene.remActivePrim(this);
1640 }
1641
1642 lock (childrenPrim)
1643 {
1644 foreach (OdePrim prm in childrenPrim)
1645 {
1646 ParentPrim(prm);
1647 }
1648 }
1649
1650 }
1651
1652 private void ChildDelink(OdePrim odePrim)
1653 {
1654 // Okay, we have a delinked child.. need to rebuild the body.
1655 lock (childrenPrim)
1656 {
1657 foreach (OdePrim prm in childrenPrim)
1658 {
1659 prm.childPrim = true;
1660 prm.disableBody();
1661 //prm.m_taintparent = null;
1662 //prm._parent = null;
1663 //prm.m_taintPhysics = false;
1664 //prm.m_disabled = true;
1665 //prm.childPrim = false;
1666 }
1667 }
1668 disableBody();
1669
1670 lock (childrenPrim)
1671 {
1672 childrenPrim.Remove(odePrim);
1673 }
1674
1675 if (Body != IntPtr.Zero)
1676 {
1677 _parent_scene.remActivePrim(this);
1678 }
1679
1680 lock (childrenPrim)
1681 {
1682 foreach (OdePrim prm in childrenPrim)
1683 {
1684 ParentPrim(prm);
1685 }
1686 }
1687 }
1688
1689 private void changeSelectedStatus(float timestep)
1690 {
1691 if (m_taintselected)
1692 {
1693 m_collisionCategories = CollisionCategories.Selected;
1694 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1695
1696 // We do the body disable soft twice because 'in theory' a collision could have happened
1697 // in between the disabling and the collision properties setting
1698 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1699 // through the ground.
1700
1701 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1702 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1703 // so that causes the selected part to wake up and continue moving.
1704
1705 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1706 // assembly will stop simulating during the selection, because of the lack of atomicity
1707 // of select operations (their processing could be interrupted by a thread switch, causing
1708 // simulation to continue before all of the selected object notifications trickle down to
1709 // the physics engine).
1710
1711 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1712 // selected and disabled. then, due to a thread switch, the selection processing is
1713 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1714 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1715 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1716 // up, start simulating again, which in turn wakes up the last 50.
1717
1718 if (m_isphysical)
1719 {
1720 disableBodySoft();
1721 }
1722
1723 if (prim_geom != IntPtr.Zero)
1724 {
1725 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1726 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1727 }
1728
1729 if (m_isphysical)
1730 {
1731 disableBodySoft();
1732 }
1733 if (Body != IntPtr.Zero)
1734 {
1735 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1736 d.BodySetForce(Body, 0f, 0f, 0f);
1737 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
1738 d.BodySetTorque (Body, 0.0f, 0.0f, 0.0f);
1739 }
1740
1741 }
1742 else
1743 {
1744 m_collisionCategories = CollisionCategories.Geom;
1745
1746 if (m_isphysical)
1747 m_collisionCategories |= CollisionCategories.Body;
1748
1749 m_collisionFlags = m_default_collisionFlags;
1750
1751 if (m_collidesLand)
1752 m_collisionFlags |= CollisionCategories.Land;
1753 if (m_collidesWater)
1754 m_collisionFlags |= CollisionCategories.Water;
1755
1756 if (prim_geom != IntPtr.Zero)
1757 {
1758 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1759 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1760 }
1761 if (Body != IntPtr.Zero)
1762 {
1763 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1764 d.BodySetForce(Body, 0f, 0f, 0f);
1765 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
1766 d.BodySetTorque (Body, 0.0f, 0.0f, 0.0f);
1767 }
1768
1769 if (m_isphysical)
1770 {
1771 if (Body != IntPtr.Zero)
1772 {
1773 enableBodySoft();
1774 }
1775 }
1776 }
1777
1778 resetCollisionAccounting();
1779 m_isSelected = m_taintselected;
1780 }//end changeSelectedStatus
1781
1782 public void ResetTaints()
1783 {
1784 m_taintposition = _position;
1785 m_taintrot = _orientation;
1786 m_taintPhysics = m_isphysical;
1787 m_taintselected = m_isSelected;
1788 m_taintsize = _size;
1789 m_taintshape = false;
1790 m_taintforce = false;
1791 m_taintdisable = false;
1792 m_taintVelocity = Vector3.Zero;
1793 }
1794
1795 public void CreateGeom(IntPtr m_targetSpace, IMesh _mesh)
1796 {
1797 if (_mesh != null) // Special - make mesh
1798 {
1799 setMesh(_parent_scene, _mesh);
1800 }
1801 else // not a mesh
1802 {
1803 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) // special profile??
1804 {
1805 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) // Equi-size
1806 {
1807 if (((_size.X / 2f) > 0f)) // Has size
1808 {
1809 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1810 try
1811 {
1812 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1813 }
1814 catch (AccessViolationException)
1815 {
1816 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1817 ode.dunlock(_parent_scene.world);
1818 return;
1819 }
1820 }
1821 else
1822 {
1823 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1824 try
1825 {
1826 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1827 }
1828 catch (AccessViolationException)
1829 {
1830 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1831 ode.dunlock(_parent_scene.world);
1832 return;
1833 }
1834 }
1835 }
1836 else // not equi-size
1837 {
1838 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1839 try
1840 {
1841 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1842 }
1843 catch (AccessViolationException)
1844 {
1845 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1846 ode.dunlock(_parent_scene.world);
1847 return;
1848 }
1849 }
1850 }
1851
1852 else // not special profile
1853 {
1854 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1855 try
1856 {
1857 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1858 }
1859 catch (AccessViolationException)
1860 {
1861 m_log.Warn("[PHYSICS]: Unable to create physics proxy for object");
1862 ode.dunlock(_parent_scene.world);
1863 return;
1864 }
1865 }
1866 }
1867 }
1868
1869 public void changeadd(float timestep)
1870 {
1871 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1872 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1873
1874 if (targetspace == IntPtr.Zero)
1875 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1876
1877 m_targetSpace = targetspace;
1878
1879 if (_mesh == null && m_meshfailed == false)
1880 {
1881 if (_parent_scene.needsMeshing(_pbs))
1882 {
1883 // Don't need to re-enable body.. it's done in SetMesh
1884 try
1885 {
1886 _mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1887 }
1888 catch
1889 {
1890 //Don't continuously try to mesh prims when meshing has failed
1891 m_meshfailed = true;
1892 }
1893 // createmesh returns null when it's a shape that isn't a cube.
1894 // m_log.Debug(m_localID);
1895 }
1896 }
1897
1898
1899 lock (_parent_scene.OdeLock)
1900 {
1901 CreateGeom(m_targetSpace, _mesh);
1902
1903 if (prim_geom != IntPtr.Zero)
1904 {
1905 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1906 d.Quaternion myrot = new d.Quaternion();
1907 myrot.X = _orientation.X;
1908 myrot.Y = _orientation.Y;
1909 myrot.Z = _orientation.Z;
1910 myrot.W = _orientation.W;
1911 d.GeomSetQuaternion(prim_geom, ref myrot);
1912 }
1913
1914 if (m_isphysical && Body == IntPtr.Zero)
1915 {
1916 enableBody();
1917 }
1918 }
1919
1920 changeSelectedStatus(timestep);
1921
1922 m_taintadd = false;
1923 }
1924
1925 public void changemove(float timestep)
1926 {
1927 if (m_isphysical)
1928 {
1929// if (!m_disabled && !m_taintremove && !childPrim) After one edit m_disabled is sometimes set, disabling further edits!
1930 if (!m_taintremove && !childPrim)
1931 {
1932 if (Body == IntPtr.Zero)
1933 enableBody();
1934 //Prim auto disable after 20 frames,
1935 //if you move it, re-enable the prim manually.
1936 if (_parent != null)
1937 {
1938 if (m_linkJoint != IntPtr.Zero)
1939 {
1940 d.JointDestroy(m_linkJoint);
1941 m_linkJoint = IntPtr.Zero;
1942 }
1943 }
1944 if (Body != IntPtr.Zero)
1945 {
1946 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1947
1948 if (_parent != null)
1949 {
1950 OdePrim odParent = (OdePrim)_parent;
1951 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1952 {
1953// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1954Console.WriteLine("ODEPrim JointCreateFixed !!!");
1955 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1956 d.JointAttach(m_linkJoint, Body, odParent.Body);
1957 d.JointSetFixed(m_linkJoint);
1958 }
1959 }
1960 d.BodyEnable(Body);
1961 if (m_type != Vehicle.TYPE_NONE)
1962 {
1963 Enable(Body, _parent_scene);
1964 }
1965 }
1966 else
1967 {
1968 m_log.Warn("[PHYSICS]: Body Still null after enableBody(). This is a crash scenario.");
1969 }
1970 }
1971 //else
1972 // {
1973 //m_log.Debug("[BUG]: race!");
1974 //}
1975 }
1976 else
1977 {
1978 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1979 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1980 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1981
1982 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1983 m_targetSpace = tempspace;
1984
1985 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1986 if (prim_geom != IntPtr.Zero)
1987 {
1988 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1989
1990 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1991 d.SpaceAdd(m_targetSpace, prim_geom);
1992 }
1993 }
1994
1995 changeSelectedStatus(timestep);
1996
1997 resetCollisionAccounting();
1998 m_taintposition = _position;
1999 }
2000
2001
2002
2003 public void rotate(float timestep)
2004 {
2005 d.Quaternion myrot = new d.Quaternion();
2006 myrot.X = _orientation.X;
2007 myrot.Y = _orientation.Y;
2008 myrot.Z = _orientation.Z;
2009 myrot.W = _orientation.W;
2010 if (Body != IntPtr.Zero)
2011 {
2012 // KF: If this is a root prim do BodySet
2013 d.BodySetQuaternion(Body, ref myrot);
2014 }
2015 else
2016 {
2017 // daughter prim, do Geom set
2018 d.GeomSetQuaternion(prim_geom, ref myrot);
2019 }
2020
2021 resetCollisionAccounting();
2022 m_taintrot = _orientation;
2023 }
2024
2025 private void resetCollisionAccounting()
2026 {
2027 m_collisionscore = 0;
2028 m_interpenetrationcount = 0;
2029 m_disabled = false;
2030 }
2031
2032 public void changedisable(float timestep)
2033 {
2034 m_disabled = true;
2035 if (Body != IntPtr.Zero)
2036 {
2037 d.BodyDisable(Body);
2038 Body = IntPtr.Zero;
2039 }
2040
2041 m_taintdisable = false;
2042 }
2043
2044 public void changePhysicsStatus(float timestep)
2045 {
2046 if (m_isphysical == true)
2047 {
2048 if (Body == IntPtr.Zero)
2049 {
2050 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2051 {
2052 changeshape(2f);
2053 }
2054 else
2055 {
2056 enableBody();
2057 }
2058 }
2059 }
2060 else
2061 {
2062 if (Body != IntPtr.Zero)
2063 {
2064 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2065 {
2066 _mesh = null;
2067 changeadd(2f);
2068 }
2069 if (childPrim)
2070 {
2071 if (_parent != null)
2072 {
2073 OdePrim parent = (OdePrim)_parent;
2074 parent.ChildDelink(this);
2075 }
2076 }
2077 else
2078 {
2079 disableBody();
2080 }
2081 }
2082 }
2083
2084 changeSelectedStatus(timestep);
2085
2086 resetCollisionAccounting();
2087 m_taintPhysics = m_isphysical;
2088 }
2089
2090 public void changesize(float timestamp)
2091 {
2092
2093 string oldname = _parent_scene.geom_name_map[prim_geom];
2094
2095 if (_size.X <= 0) _size.X = 0.01f;
2096 if (_size.Y <= 0) _size.Y = 0.01f;
2097 if (_size.Z <= 0) _size.Z = 0.01f;
2098
2099 // Cleanup of old prim geometry
2100 if (_mesh != null)
2101 {
2102 // Cleanup meshing here
2103 }
2104 //kill body to rebuild
2105 if (IsPhysical && Body != IntPtr.Zero)
2106 {
2107 if (childPrim)
2108 {
2109 if (_parent != null)
2110 {
2111 OdePrim parent = (OdePrim)_parent;
2112 parent.ChildDelink(this);
2113 }
2114 }
2115 else
2116 {
2117 disableBody();
2118 }
2119 }
2120 if (d.SpaceQuery(m_targetSpace, prim_geom))
2121 {
2122 _parent_scene.waitForSpaceUnlock(m_targetSpace);
2123 d.SpaceRemove(m_targetSpace, prim_geom);
2124 }
2125 // we don't need to do space calculation because the client sends a position update also.
2126
2127 // Construction of new prim
2128 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2129 {
2130 float meshlod = _parent_scene.meshSculptLOD;
2131
2132 if (IsPhysical)
2133 meshlod = _parent_scene.MeshSculptphysicalLOD;
2134 // Don't need to re-enable body.. it's done in SetMesh
2135
2136 IMesh mesh = null;
2137
2138 try
2139 {
2140 if (_parent_scene.needsMeshing(_pbs))
2141 mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2142 }
2143 catch
2144 {
2145 m_meshfailed = true;
2146 }
2147
2148 //IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2149 CreateGeom(m_targetSpace, mesh);
2150
2151
2152 }
2153 else
2154 {
2155 _mesh = null;
2156 CreateGeom(m_targetSpace, _mesh);
2157 }
2158
2159 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2160 d.Quaternion myrot = new d.Quaternion();
2161 myrot.X = _orientation.X;
2162 myrot.Y = _orientation.Y;
2163 myrot.Z = _orientation.Z;
2164 myrot.W = _orientation.W;
2165 d.GeomSetQuaternion(prim_geom, ref myrot);
2166
2167 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2168 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2169 {
2170 // Re creates body on size.
2171 // EnableBody also does setMass()
2172 enableBody();
2173 d.BodyEnable(Body);
2174 }
2175
2176 _parent_scene.geom_name_map[prim_geom] = oldname;
2177
2178 changeSelectedStatus(timestamp);
2179 if (childPrim)
2180 {
2181 if (_parent is OdePrim)
2182 {
2183 OdePrim parent = (OdePrim)_parent;
2184 parent.ChildSetGeom(this);
2185 }
2186 }
2187 resetCollisionAccounting();
2188 m_taintsize = _size;
2189 }
2190
2191
2192
2193 public void changefloatonwater(float timestep)
2194 {
2195 m_collidesWater = m_taintCollidesWater;
2196
2197 if (prim_geom != IntPtr.Zero)
2198 {
2199 if (m_collidesWater)
2200 {
2201 m_collisionFlags |= CollisionCategories.Water;
2202 }
2203 else
2204 {
2205 m_collisionFlags &= ~CollisionCategories.Water;
2206 }
2207 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2208 }
2209 }
2210
2211 public void changeshape(float timestamp)
2212 {
2213 string oldname = _parent_scene.geom_name_map[prim_geom];
2214
2215 // Cleanup of old prim geometry and Bodies
2216 if (IsPhysical && Body != IntPtr.Zero)
2217 {
2218 if (childPrim)
2219 {
2220 if (_parent != null)
2221 {
2222 OdePrim parent = (OdePrim)_parent;
2223 parent.ChildDelink(this);
2224 }
2225 }
2226 else
2227 {
2228 disableBody();
2229 }
2230 }
2231
2232
2233 // we don't need to do space calculation because the client sends a position update also.
2234 if (_size.X <= 0) _size.X = 0.01f;
2235 if (_size.Y <= 0) _size.Y = 0.01f;
2236 if (_size.Z <= 0) _size.Z = 0.01f;
2237 // Construction of new prim
2238
2239 if (_parent_scene.needsMeshing(_pbs) && m_meshfailed == false)
2240 {
2241 // Don't need to re-enable body.. it's done in SetMesh
2242 float meshlod = _parent_scene.meshSculptLOD;
2243
2244 if (IsPhysical)
2245 meshlod = _parent_scene.MeshSculptphysicalLOD;
2246 try
2247 {
2248 IMesh mesh = _parent_scene.mesher.CreateMesh(oldname, _pbs, _size, meshlod, IsPhysical);
2249 CreateGeom(m_targetSpace, mesh);
2250 }
2251 catch
2252 {
2253 m_meshfailed = true;
2254 }
2255 // createmesh returns null when it doesn't mesh.
2256 }
2257 else
2258 {
2259 _mesh = null;
2260 CreateGeom(m_targetSpace, null);
2261 }
2262
2263 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2264 d.Quaternion myrot = new d.Quaternion();
2265 //myrot.W = _orientation.w;
2266 myrot.W = _orientation.W;
2267 myrot.X = _orientation.X;
2268 myrot.Y = _orientation.Y;
2269 myrot.Z = _orientation.Z;
2270 d.GeomSetQuaternion(prim_geom, ref myrot);
2271
2272 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2273 if (IsPhysical && Body == IntPtr.Zero)
2274 {
2275 // Re creates body on size.
2276 // EnableBody also does setMass()
2277 enableBody();
2278 if (Body != IntPtr.Zero)
2279 {
2280 d.BodyEnable(Body);
2281 }
2282 }
2283 _parent_scene.geom_name_map[prim_geom] = oldname;
2284
2285 changeSelectedStatus(timestamp);
2286 if (childPrim)
2287 {
2288 if (_parent is OdePrim)
2289 {
2290 OdePrim parent = (OdePrim)_parent;
2291 parent.ChildSetGeom(this);
2292 }
2293 }
2294 resetCollisionAccounting();
2295 m_taintshape = false;
2296 }
2297
2298 public void changeAddForce(float timestamp)
2299 {
2300 if (!m_isSelected)
2301 {
2302 lock (m_forcelist)
2303 {
2304 //m_log.Info("[PHYSICS]: dequeing forcelist");
2305 if (IsPhysical)
2306 {
2307 Vector3 iforce = Vector3.Zero;
2308 int i = 0;
2309 try
2310 {
2311 for (i = 0; i < m_forcelist.Count; i++)
2312 {
2313
2314 iforce = iforce + (m_forcelist[i] * 100);
2315 }
2316 }
2317 catch (IndexOutOfRangeException)
2318 {
2319 m_forcelist = new List<Vector3>();
2320 m_collisionscore = 0;
2321 m_interpenetrationcount = 0;
2322 m_taintforce = false;
2323 return;
2324 }
2325 catch (ArgumentOutOfRangeException)
2326 {
2327 m_forcelist = new List<Vector3>();
2328 m_collisionscore = 0;
2329 m_interpenetrationcount = 0;
2330 m_taintforce = false;
2331 return;
2332 }
2333 d.BodyEnable(Body);
2334
2335 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2336 }
2337 m_forcelist.Clear();
2338 }
2339
2340 m_collisionscore = 0;
2341 m_interpenetrationcount = 0;
2342 }
2343
2344 m_taintforce = false;
2345
2346 }
2347
2348
2349
2350 public void changeSetTorque(float timestamp)
2351 {
2352 if (!m_isSelected)
2353 {
2354 if (IsPhysical && Body != IntPtr.Zero)
2355 {
2356 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2357 }
2358 }
2359
2360 m_taintTorque = Vector3.Zero;
2361 }
2362
2363 public void changeAddAngularForce(float timestamp)
2364 {
2365 if (!m_isSelected)
2366 {
2367 lock (m_angularforcelist)
2368 {
2369 //m_log.Info("[PHYSICS]: dequeing forcelist");
2370 if (IsPhysical)
2371 {
2372 Vector3 iforce = Vector3.Zero;
2373 for (int i = 0; i < m_angularforcelist.Count; i++)
2374 {
2375 iforce = iforce + (m_angularforcelist[i] * 100);
2376 }
2377 d.BodyEnable(Body);
2378 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2379
2380 }
2381 m_angularforcelist.Clear();
2382 }
2383
2384 m_collisionscore = 0;
2385 m_interpenetrationcount = 0;
2386 }
2387
2388 m_taintaddangularforce = false;
2389 }
2390
2391 private void changevelocity(float timestep)
2392 {
2393 if (!m_isSelected)
2394 {
2395 Thread.Sleep(20);
2396 if (IsPhysical)
2397 {
2398 if (Body != IntPtr.Zero)
2399 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2400 }
2401
2402 //resetCollisionAccounting();
2403 }
2404 m_taintVelocity = Vector3.Zero;
2405 }
2406
2407 public void UpdatePositionAndVelocity()
2408 {
2409 return; // moved to the Move () method
2410 }
2411
2412 public d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
2413 {
2414 obj.I.M00 = pMat[0, 0];
2415 obj.I.M01 = pMat[0, 1];
2416 obj.I.M02 = pMat[0, 2];
2417 obj.I.M10 = pMat[1, 0];
2418 obj.I.M11 = pMat[1, 1];
2419 obj.I.M12 = pMat[1, 2];
2420 obj.I.M20 = pMat[2, 0];
2421 obj.I.M21 = pMat[2, 1];
2422 obj.I.M22 = pMat[2, 2];
2423 return obj;
2424 }
2425
2426 public override void SubscribeEvents(int ms)
2427 {
2428 m_eventsubscription = ms;
2429 _parent_scene.addCollisionEventReporting(this);
2430 }
2431
2432 public override void UnSubscribeEvents()
2433 {
2434 _parent_scene.remCollisionEventReporting(this);
2435 m_eventsubscription = 0;
2436 }
2437
2438 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
2439 {
2440 if (CollisionEventsThisFrame == null)
2441 CollisionEventsThisFrame = new CollisionEventUpdate();
2442 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
2443 }
2444
2445 public void SendCollisions()
2446 {
2447 if (CollisionEventsThisFrame == null)
2448 return;
2449
2450 base.SendCollisionUpdate(CollisionEventsThisFrame);
2451
2452 if (CollisionEventsThisFrame.m_objCollisionList.Count == 0)
2453 CollisionEventsThisFrame = null;
2454 else
2455 CollisionEventsThisFrame = new CollisionEventUpdate();
2456 }
2457
2458 public override bool SubscribedEvents()
2459 {
2460 if (m_eventsubscription > 0)
2461 return true;
2462 return false;
2463 }
2464
2465 public static Matrix4 Inverse(Matrix4 pMat)
2466 {
2467 if (determinant3x3(pMat) == 0)
2468 {
2469 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
2470 }
2471
2472
2473
2474 return (Adjoint(pMat) / determinant3x3(pMat));
2475 }
2476
2477 public static Matrix4 Adjoint(Matrix4 pMat)
2478 {
2479 Matrix4 adjointMatrix = new Matrix4();
2480 for (int i=0; i<4; i++)
2481 {
2482 for (int j=0; j<4; j++)
2483 {
2484 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
2485 }
2486 }
2487
2488 adjointMatrix = Transpose(adjointMatrix);
2489 return adjointMatrix;
2490 }
2491
2492 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
2493 {
2494 Matrix4 minor = new Matrix4();
2495 int m = 0, n = 0;
2496 for (int i = 0; i < 4; i++)
2497 {
2498 if (i == iRow)
2499 continue;
2500 n = 0;
2501 for (int j = 0; j < 4; j++)
2502 {
2503 if (j == iCol)
2504 continue;
2505 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
2506 n++;
2507 }
2508 m++;
2509 }
2510 return minor;
2511 }
2512
2513 public static Matrix4 Transpose(Matrix4 pMat)
2514 {
2515 Matrix4 transposeMatrix = new Matrix4();
2516 for (int i = 0; i < 4; i++)
2517 for (int j = 0; j < 4; j++)
2518 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
2519 return transposeMatrix;
2520 }
2521
2522 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
2523 {
2524 switch (r)
2525 {
2526 case 0:
2527 switch (c)
2528 {
2529 case 0:
2530 pMat.M11 = val;
2531 break;
2532 case 1:
2533 pMat.M12 = val;
2534 break;
2535 case 2:
2536 pMat.M13 = val;
2537 break;
2538 case 3:
2539 pMat.M14 = val;
2540 break;
2541 }
2542
2543 break;
2544 case 1:
2545 switch (c)
2546 {
2547 case 0:
2548 pMat.M21 = val;
2549 break;
2550 case 1:
2551 pMat.M22 = val;
2552 break;
2553 case 2:
2554 pMat.M23 = val;
2555 break;
2556 case 3:
2557 pMat.M24 = val;
2558 break;
2559 }
2560
2561 break;
2562 case 2:
2563 switch (c)
2564 {
2565 case 0:
2566 pMat.M31 = val;
2567 break;
2568 case 1:
2569 pMat.M32 = val;
2570 break;
2571 case 2:
2572 pMat.M33 = val;
2573 break;
2574 case 3:
2575 pMat.M34 = val;
2576 break;
2577 }
2578
2579 break;
2580 case 3:
2581 switch (c)
2582 {
2583 case 0:
2584 pMat.M41 = val;
2585 break;
2586 case 1:
2587 pMat.M42 = val;
2588 break;
2589 case 2:
2590 pMat.M43 = val;
2591 break;
2592 case 3:
2593 pMat.M44 = val;
2594 break;
2595 }
2596
2597 break;
2598 }
2599 }
2600 private static float determinant3x3(Matrix4 pMat)
2601 {
2602 float det = 0;
2603 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
2604 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
2605 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
2606 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
2607 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
2608 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
2609
2610 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
2611 return det;
2612
2613 }
2614
2615 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
2616 {
2617 dst.c.W = src.c.W;
2618 dst.c.X = src.c.X;
2619 dst.c.Y = src.c.Y;
2620 dst.c.Z = src.c.Z;
2621 dst.mass = src.mass;
2622 dst.I.M00 = src.I.M00;
2623 dst.I.M01 = src.I.M01;
2624 dst.I.M02 = src.I.M02;
2625 dst.I.M10 = src.I.M10;
2626 dst.I.M11 = src.I.M11;
2627 dst.I.M12 = src.I.M12;
2628 dst.I.M20 = src.I.M20;
2629 dst.I.M21 = src.I.M21;
2630 dst.I.M22 = src.I.M22;
2631 }
2632
2633 public override void SetMaterial(int pMaterial)
2634 {
2635 m_material = pMaterial;
2636 }
2637
2638 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
2639 {
2640 switch (pParam)
2641 {
2642 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
2643 if (pValue < 0.01f) pValue = 0.01f;
2644 // m_angularDeflectionEfficiency = pValue;
2645 break;
2646 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
2647 if (pValue < 0.1f) pValue = 0.1f;
2648 // m_angularDeflectionTimescale = pValue;
2649 break;
2650 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
2651 if (pValue < 0.3f) pValue = 0.3f;
2652 m_angularMotorDecayTimescale = pValue;
2653 break;
2654 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
2655 if (pValue < 0.3f) pValue = 0.3f;
2656 m_angularMotorTimescale = pValue;
2657 break;
2658 case Vehicle.BANKING_EFFICIENCY:
2659 if (pValue < 0.01f) pValue = 0.01f;
2660 // m_bankingEfficiency = pValue;
2661 break;
2662 case Vehicle.BANKING_MIX:
2663 if (pValue < 0.01f) pValue = 0.01f;
2664 // m_bankingMix = pValue;
2665 break;
2666 case Vehicle.BANKING_TIMESCALE:
2667 if (pValue < 0.01f) pValue = 0.01f;
2668 // m_bankingTimescale = pValue;
2669 break;
2670 case Vehicle.BUOYANCY:
2671 if (pValue < -1f) pValue = -1f;
2672 if (pValue > 1f) pValue = 1f;
2673 m_VehicleBuoyancy = pValue;
2674 break;
2675// case Vehicle.HOVER_EFFICIENCY:
2676// if (pValue < 0f) pValue = 0f;
2677// if (pValue > 1f) pValue = 1f;
2678// m_VhoverEfficiency = pValue;
2679// break;
2680 case Vehicle.HOVER_HEIGHT:
2681 m_VhoverHeight = pValue;
2682 break;
2683 case Vehicle.HOVER_TIMESCALE:
2684 if (pValue < 0.1f) pValue = 0.1f;
2685 m_VhoverTimescale = pValue;
2686 break;
2687 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
2688 if (pValue < 0.01f) pValue = 0.01f;
2689 // m_linearDeflectionEfficiency = pValue;
2690 break;
2691 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
2692 if (pValue < 0.01f) pValue = 0.01f;
2693 // m_linearDeflectionTimescale = pValue;
2694 break;
2695 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
2696 if (pValue < 0.3f) pValue = 0.3f;
2697 m_linearMotorDecayTimescale = pValue;
2698 break;
2699 case Vehicle.LINEAR_MOTOR_TIMESCALE:
2700 if (pValue < 0.1f) pValue = 0.1f;
2701 m_linearMotorTimescale = pValue;
2702 break;
2703 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
2704 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
2705 if (pValue > 1.0f) pValue = 1.0f;
2706 m_verticalAttractionEfficiency = pValue;
2707 break;
2708 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
2709 if (pValue < 0.1f) pValue = 0.1f;
2710 m_verticalAttractionTimescale = pValue;
2711 break;
2712
2713 // These are vector properties but the engine lets you use a single float value to
2714 // set all of the components to the same value
2715 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2716 if (pValue > 30f) pValue = 30f;
2717 if (pValue < 0.1f) pValue = 0.1f;
2718 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
2719 break;
2720 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2721 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
2722 UpdateAngDecay();
2723 break;
2724 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2725 if (pValue < 0.1f) pValue = 0.1f;
2726 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
2727 break;
2728 case Vehicle.LINEAR_MOTOR_DIRECTION:
2729 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
2730 UpdateLinDecay();
2731 break;
2732 case Vehicle.LINEAR_MOTOR_OFFSET:
2733 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
2734 break;
2735
2736 }
2737
2738 }//end ProcessFloatVehicleParam
2739
2740 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
2741 {
2742 switch (pParam)
2743 {
2744 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
2745 if (pValue.X > 30f) pValue.X = 30f;
2746 if (pValue.X < 0.1f) pValue.X = 0.1f;
2747 if (pValue.Y > 30f) pValue.Y = 30f;
2748 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2749 if (pValue.Z > 30f) pValue.Z = 30f;
2750 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2751 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2752 break;
2753 case Vehicle.ANGULAR_MOTOR_DIRECTION:
2754 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
2755 // Limit requested angular speed to 2 rps= 4 pi rads/sec
2756 if(m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
2757 if(m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
2758 if(m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
2759 if(m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
2760 if(m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
2761 if(m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
2762 UpdateAngDecay();
2763 break;
2764 case Vehicle.LINEAR_FRICTION_TIMESCALE:
2765 if (pValue.X < 0.1f) pValue.X = 0.1f;
2766 if (pValue.Y < 0.1f) pValue.Y = 0.1f;
2767 if (pValue.Z < 0.1f) pValue.Z = 0.1f;
2768 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
2769 break;
2770 case Vehicle.LINEAR_MOTOR_DIRECTION:
2771 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting
2772 UpdateLinDecay();
2773 break;
2774 case Vehicle.LINEAR_MOTOR_OFFSET:
2775 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
2776 break;
2777 }
2778
2779 }//end ProcessVectorVehicleParam
2780
2781 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
2782 {
2783 switch (pParam)
2784 {
2785 case Vehicle.REFERENCE_FRAME:
2786 // m_referenceFrame = pValue;
2787 break;
2788 }
2789
2790 }//end ProcessRotationVehicleParam
2791
2792 internal void ProcessVehicleFlags(int pParam, bool remove)
2793 {
2794 if (remove)
2795 {
2796 m_flags &= ~((VehicleFlag)pParam);
2797 }
2798 else
2799 {
2800 m_flags |= (VehicleFlag)pParam;
2801 }
2802 }
2803
2804 internal void ProcessTypeChange(Vehicle pType)
2805 {
2806 // Set Defaults For Type
2807 m_type = pType;
2808 switch (pType)
2809 {
2810 case Vehicle.TYPE_SLED:
2811 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
2812 m_angularFrictionTimescale = new Vector3(30, 30, 30);
2813// m_lLinMotorVel = Vector3.Zero;
2814 m_linearMotorTimescale = 1000;
2815 m_linearMotorDecayTimescale = 120;
2816 m_angularMotorDirection = Vector3.Zero;
2817 m_angularMotorDVel = Vector3.Zero;
2818 m_angularMotorTimescale = 1000;
2819 m_angularMotorDecayTimescale = 120;
2820 m_VhoverHeight = 0;
2821// m_VhoverEfficiency = 1;
2822 m_VhoverTimescale = 10;
2823 m_VehicleBuoyancy = 0;
2824 // m_linearDeflectionEfficiency = 1;
2825 // m_linearDeflectionTimescale = 1;
2826 // m_angularDeflectionEfficiency = 1;
2827 // m_angularDeflectionTimescale = 1000;
2828 // m_bankingEfficiency = 0;
2829 // m_bankingMix = 1;
2830 // m_bankingTimescale = 10;
2831 // m_referenceFrame = Quaternion.Identity;
2832 m_flags &=
2833 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2834 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2835 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2836 break;
2837 case Vehicle.TYPE_CAR:
2838 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
2839 m_angularFrictionTimescale = new Vector3(30, 30, 30); // was 1000, but sl max frict time is 30.
2840// m_lLinMotorVel = Vector3.Zero;
2841 m_linearMotorTimescale = 1;
2842 m_linearMotorDecayTimescale = 60;
2843 m_angularMotorDirection = Vector3.Zero;
2844 m_angularMotorDVel = Vector3.Zero;
2845 m_angularMotorTimescale = 1;
2846 m_angularMotorDecayTimescale = 0.8f;
2847 m_VhoverHeight = 0;
2848// m_VhoverEfficiency = 0;
2849 m_VhoverTimescale = 1000;
2850 m_VehicleBuoyancy = 0;
2851 // // m_linearDeflectionEfficiency = 1;
2852 // // m_linearDeflectionTimescale = 2;
2853 // // m_angularDeflectionEfficiency = 0;
2854 // m_angularDeflectionTimescale = 10;
2855 m_verticalAttractionEfficiency = 1f;
2856 m_verticalAttractionTimescale = 10f;
2857 // m_bankingEfficiency = -0.2f;
2858 // m_bankingMix = 1;
2859 // m_bankingTimescale = 1;
2860 // m_referenceFrame = Quaternion.Identity;
2861 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2862 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY |
2863 VehicleFlag.LIMIT_MOTOR_UP);
2864 break;
2865 case Vehicle.TYPE_BOAT:
2866 m_linearFrictionTimescale = new Vector3(10, 3, 2);
2867 m_angularFrictionTimescale = new Vector3(10,10,10);
2868// m_lLinMotorVel = Vector3.Zero;
2869 m_linearMotorTimescale = 5;
2870 m_linearMotorDecayTimescale = 60;
2871 m_angularMotorDirection = Vector3.Zero;
2872 m_angularMotorDVel = Vector3.Zero;
2873 m_angularMotorTimescale = 4;
2874 m_angularMotorDecayTimescale = 4;
2875 m_VhoverHeight = 0;
2876// m_VhoverEfficiency = 0.5f;
2877 m_VhoverTimescale = 2;
2878 m_VehicleBuoyancy = 1;
2879 // m_linearDeflectionEfficiency = 0.5f;
2880 // m_linearDeflectionTimescale = 3;
2881 // m_angularDeflectionEfficiency = 0.5f;
2882 // m_angularDeflectionTimescale = 5;
2883 m_verticalAttractionEfficiency = 0.5f;
2884 m_verticalAttractionTimescale = 5f;
2885 // m_bankingEfficiency = -0.3f;
2886 // m_bankingMix = 0.8f;
2887 // m_bankingTimescale = 1;
2888 // m_referenceFrame = Quaternion.Identity;
2889 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY |
2890 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
2891 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY |
2892 VehicleFlag.LIMIT_MOTOR_UP);
2893 break;
2894 case Vehicle.TYPE_AIRPLANE:
2895 m_linearFrictionTimescale = new Vector3(200, 10, 5);
2896 m_angularFrictionTimescale = new Vector3(20, 20, 20);
2897// m_lLinMotorVel = Vector3.Zero;
2898 m_linearMotorTimescale = 2;
2899 m_linearMotorDecayTimescale = 60;
2900 m_angularMotorDirection = Vector3.Zero;
2901 m_angularMotorDVel = Vector3.Zero;
2902 m_angularMotorTimescale = 4;
2903 m_angularMotorDecayTimescale = 4;
2904 m_VhoverHeight = 0;
2905// m_VhoverEfficiency = 0.5f;
2906 m_VhoverTimescale = 1000;
2907 m_VehicleBuoyancy = 0;
2908 // m_linearDeflectionEfficiency = 0.5f;
2909 // m_linearDeflectionTimescale = 3;
2910 // m_angularDeflectionEfficiency = 1;
2911 // m_angularDeflectionTimescale = 2;
2912 m_verticalAttractionEfficiency = 0.9f;
2913 m_verticalAttractionTimescale = 2f;
2914 // m_bankingEfficiency = 1;
2915 // m_bankingMix = 0.7f;
2916 // m_bankingTimescale = 2;
2917 // m_referenceFrame = Quaternion.Identity;
2918 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2919 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2920 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
2921 break;
2922 case Vehicle.TYPE_BALLOON:
2923 m_linearFrictionTimescale = new Vector3(5, 5, 5);
2924 m_angularFrictionTimescale = new Vector3(10, 10, 10);
2925 m_linearMotorTimescale = 5;
2926 m_linearMotorDecayTimescale = 60;
2927 m_angularMotorDirection = Vector3.Zero;
2928 m_angularMotorDVel = Vector3.Zero;
2929 m_angularMotorTimescale = 6;
2930 m_angularMotorDecayTimescale = 10;
2931 m_VhoverHeight = 5;
2932// m_VhoverEfficiency = 0.8f;
2933 m_VhoverTimescale = 10;
2934 m_VehicleBuoyancy = 1;
2935 // m_linearDeflectionEfficiency = 0;
2936 // m_linearDeflectionTimescale = 5;
2937 // m_angularDeflectionEfficiency = 0;
2938 // m_angularDeflectionTimescale = 5;
2939 m_verticalAttractionEfficiency = 1f;
2940 m_verticalAttractionTimescale = 100f;
2941 // m_bankingEfficiency = 0;
2942 // m_bankingMix = 0.7f;
2943 // m_bankingTimescale = 5;
2944 // m_referenceFrame = Quaternion.Identity;
2945 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
2946 VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
2947 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
2948 break;
2949
2950 }
2951 }//end SetDefaultsForType
2952
2953 internal void Enable(IntPtr pBody, OdeScene pParentScene)
2954 {
2955 if (m_type == Vehicle.TYPE_NONE)
2956 return;
2957
2958 m_body = pBody;
2959 }
2960
2961
2962 internal void Halt()
2963 { // Kill all motions, when non-physical
2964 // m_linearMotorDirection = Vector3.Zero;
2965 m_lLinMotorDVel = Vector3.Zero;
2966 m_lLinObjectVel = Vector3.Zero;
2967 m_wLinObjectVel = Vector3.Zero;
2968 m_angularMotorDirection = Vector3.Zero;
2969 m_lastAngularVelocity = Vector3.Zero;
2970 m_angularMotorDVel = Vector3.Zero;
2971 _acceleration = Vector3.Zero;
2972 }
2973
2974 private void UpdateLinDecay()
2975 {
2976// if (Math.Abs(m_linearMotorDirection.X) > Math.Abs(m_lLinMotorDVel.X)) m_lLinMotorDVel.X = m_linearMotorDirection.X;
2977// if (Math.Abs(m_linearMotorDirection.Y) > Math.Abs(m_lLinMotorDVel.Y)) m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2978// if (Math.Abs(m_linearMotorDirection.Z) > Math.Abs(m_lLinMotorDVel.Z)) m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2979 m_lLinMotorDVel.X = m_linearMotorDirection.X;
2980 m_lLinMotorDVel.Y = m_linearMotorDirection.Y;
2981 m_lLinMotorDVel.Z = m_linearMotorDirection.Z;
2982 } // else let the motor decay on its own
2983
2984 private void UpdateAngDecay()
2985 {
2986// if (Math.Abs(m_angularMotorDirection.X) > Math.Abs(m_angularMotorDVel.X)) m_angularMotorDVel.X = m_angularMotorDirection.X;
2987// if (Math.Abs(m_angularMotorDirection.Y) > Math.Abs(m_angularMotorDVel.Y)) m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2988// if (Math.Abs(m_angularMotorDirection.Z) > Math.Abs(m_angularMotorDVel.Z)) m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2989 m_angularMotorDVel.X = m_angularMotorDirection.X;
2990 m_angularMotorDVel.Y = m_angularMotorDirection.Y;
2991 m_angularMotorDVel.Z = m_angularMotorDirection.Z;
2992 } // else let the motor decay on its own
2993
2994 public void Move(float timestep)
2995 {
2996 float fx = 0;
2997 float fy = 0;
2998 float fz = 0;
2999 Vector3 linvel; // velocity applied, including any reversal
3000 int outside = 0;
3001
3002 // If geomCrossingFailuresBeforeOutofbounds is set to 0 in OpenSim.ini then phys objects bounce off region borders.
3003 // This is a temp patch until proper region crossing is developed.
3004
3005 int failureLimit = _parent_scene.geomCrossingFailuresBeforeOutofbounds;
3006 float fence = _parent_scene.geomRegionFence;
3007
3008 frcount++; // used to limit debug comment output
3009 if (frcount > 50)
3010 frcount = 0;
3011
3012 if(revcount > 0) revcount--;
3013
3014 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // Only move root prims.
3015 {
3016 // Old public void UpdatePositionAndVelocity(), more accuratley calculated here
3017 bool lastZeroFlag = _zeroFlag; // was it stopped
3018
3019 d.Vector3 vec = d.BodyGetPosition(Body);
3020 Vector3 l_position = Vector3.Zero;
3021 l_position.X = vec.X;
3022 l_position.Y = vec.Y;
3023 l_position.Z = vec.Z;
3024 m_lastposition = _position;
3025 _position = l_position;
3026
3027 d.Quaternion ori = d.BodyGetQuaternion(Body);
3028 // Quaternion l_orientation = Quaternion.Identity;
3029 _orientation.X = ori.X;
3030 _orientation.Y = ori.Y;
3031 _orientation.Z = ori.Z;
3032 _orientation.W = ori.W;
3033 m_lastorientation = _orientation;
3034
3035 d.Vector3 vel = d.BodyGetLinearVel(Body);
3036 m_lastVelocity = _velocity;
3037 _velocity.X = vel.X;
3038 _velocity.Y = vel.Y;
3039 _velocity.Z = vel.Z;
3040 _acceleration = ((_velocity - m_lastVelocity) / timestep);
3041
3042 d.Vector3 torque = d.BodyGetTorque(Body);
3043 _torque = new Vector3(torque.X, torque.Y, torque.Z);
3044
3045 base.RequestPhysicsterseUpdate();
3046
3047//Console.WriteLine("Move {0} at {1}", m_primName, l_position);
3048
3049 // Check if outside region
3050 // In Scene.cs/CrossPrimGroupIntoNewRegion the object is checked for 0.1M from border!
3051 if (l_position.X > ((float)_parent_scene.WorldExtents.X - fence))
3052 {
3053 l_position.X = ((float)_parent_scene.WorldExtents.X - fence);
3054 outside = 1;
3055 }
3056
3057 if (l_position.X < fence)
3058 {
3059 l_position.X = fence;
3060 outside = 2;
3061 }
3062 if (l_position.Y > ((float)_parent_scene.WorldExtents.Y - fence))
3063 {
3064 l_position.Y = ((float)_parent_scene.WorldExtents.Y - fence);
3065 outside = 3;
3066 }
3067
3068 if (l_position.Y < fence)
3069 {
3070 l_position.Y = fence;
3071 outside = 4;
3072 }
3073
3074 if (outside > 0)
3075 {
3076
3077//Console.WriteLine("Border {0} fence={1}", l_position, fence);
3078 if (fence > 0.0f) // bounce object off boundary
3079 {
3080 if (revcount == 0)
3081 {
3082 if (outside < 3)
3083 {
3084 _velocity.X = -_velocity.X;
3085 }
3086 else
3087 {
3088 _velocity.Y = -_velocity.Y;
3089 }
3090 if (m_type != Vehicle.TYPE_NONE) Halt();
3091 _position = l_position;
3092 m_taintposition = _position;
3093 m_lastVelocity = _velocity;
3094 _acceleration = Vector3.Zero;
3095 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
3096 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
3097 base.RequestPhysicsterseUpdate();
3098
3099 revcount = 25; // wait for object to move away from border
3100 }
3101 } // else old crossing mode
3102 else if (m_crossingfailures < failureLimit)
3103 { // keep trying to cross?
3104 _position = l_position;
3105 //_parent_scene.remActivePrim(this);
3106 if (_parent == null) base.RequestPhysicsterseUpdate();
3107 return; // Dont process any other motion?
3108 }
3109 else
3110 { // Too many tries
3111 if (_parent == null) base.RaiseOutOfBounds(l_position);
3112 return; // Dont process any other motion?
3113 } // end various methods
3114 } // end outside region horizontally
3115
3116
3117 if (l_position.Z < 0)
3118 {
3119 // This is so prim that get lost underground don't fall forever and suck up
3120 //
3121 // Sim resources and memory.
3122 // Disables the prim's movement physics....
3123 // It's a hack and will generate a console message if it fails.
3124
3125 //IsPhysical = false;
3126 if (_parent == null) base.RaiseOutOfBounds(_position);
3127
3128
3129 _acceleration.X = 0; // This stuff may stop client display but it has no
3130 _acceleration.Y = 0; // effect on the object in phys engine!
3131 _acceleration.Z = 0;
3132
3133 _velocity.X = 0;
3134 _velocity.Y = 0;
3135 _velocity.Z = 0;
3136 m_lastVelocity = Vector3.Zero;
3137 m_rotationalVelocity.X = 0;
3138 m_rotationalVelocity.Y = 0;
3139 m_rotationalVelocity.Z = 0;
3140
3141 if (_parent == null) base.RequestPhysicsterseUpdate();
3142
3143 m_throttleUpdates = false;
3144 throttleCounter = 0;
3145 _zeroFlag = true;
3146 //outofBounds = true;
3147 } // end neg Z check
3148
3149 // Is it moving?
3150 /* if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
3151 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
3152 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02) */
3153 if ( (Vector3.Mag(_velocity) < 0.01) && // moving very slowly
3154 (Vector3.Mag(_velocity) < Vector3.Mag(m_lastVelocity)) && // decelerating
3155 (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, _orientation)) < 0.0001) ) // spinning very slowly
3156 {
3157 _zeroFlag = true;
3158 m_throttleUpdates = false;
3159 }
3160 else
3161 {
3162 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
3163 _zeroFlag = false;
3164 m_lastUpdateSent = false;
3165 //m_throttleUpdates = false;
3166 }
3167
3168 if (_zeroFlag)
3169 { // Its stopped
3170 _velocity.X = 0.0f;
3171 _velocity.Y = 0.0f;
3172 // _velocity.Z = 0.0f;
3173
3174 _acceleration.X = 0;
3175 _acceleration.Y = 0;
3176 // _acceleration.Z = 0;
3177
3178 m_rotationalVelocity.X = 0;
3179 m_rotationalVelocity.Y = 0;
3180 m_rotationalVelocity.Z = 0;
3181 // Stop it in the phys engine
3182 d.BodySetLinearVel(Body, 0.0f, 0.0f, _velocity.Z);
3183 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3184 d.BodySetForce(Body, 0f, 0f, 0f);
3185
3186 if (!m_lastUpdateSent)
3187 {
3188 m_throttleUpdates = false;
3189 throttleCounter = 0;
3190 if (_parent == null)
3191 {
3192 base.RequestPhysicsterseUpdate();
3193 }
3194
3195 m_lastUpdateSent = true;
3196 }
3197 }
3198 else
3199 { // Its moving
3200 if (lastZeroFlag != _zeroFlag)
3201 {
3202 if (_parent == null)
3203 {
3204 base.RequestPhysicsterseUpdate();
3205 }
3206 }
3207 m_lastUpdateSent = false;
3208 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
3209 {
3210 if (_parent == null)
3211 {
3212 base.RequestPhysicsterseUpdate();
3213 }
3214 }
3215 else
3216 {
3217 throttleCounter++;
3218 }
3219 }
3220 m_lastposition = l_position;
3221
3222 /// End UpdatePositionAndVelocity insert
3223
3224
3225 // Rotation lock =====================================
3226 if(m_rotateEnableUpdate)
3227 {
3228 // Snapshot current angles, set up Amotor(s)
3229 m_rotateEnableUpdate = false;
3230 m_rotateEnable = m_rotateEnableRequest;
3231//Console.WriteLine("RotEnable {0} = {1}",m_primName, m_rotateEnable);
3232
3233 if (Amotor != IntPtr.Zero)
3234 {
3235 d.JointDestroy(Amotor);
3236 Amotor = IntPtr.Zero;
3237//Console.WriteLine("Old Amotor Destroyed");
3238 }
3239
3240 if (!m_rotateEnable.ApproxEquals(Vector3.One, 0.003f))
3241 { // not all are enabled
3242 d.Quaternion r = d.BodyGetQuaternion(Body);
3243 Quaternion locrot = new Quaternion(r.X, r.Y, r.Z, r.W);
3244 // extract the axes vectors
3245 Vector3 vX = new Vector3(1f,0f,0f);
3246 Vector3 vY = new Vector3(0f,1f,0f);
3247 Vector3 vZ = new Vector3(0f,0f,1f);
3248 vX = vX * locrot;
3249 vY = vY * locrot;
3250 vZ = vZ * locrot;
3251 // snapshot the current angle vectors
3252 m_lockX = vX;
3253 m_lockY = vY;
3254 m_lockZ = vZ;
3255 // m_lockRot = locrot;
3256 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3257 d.JointAttach(Amotor, Body, IntPtr.Zero);
3258 d.JointSetAMotorMode(Amotor, 0); // User mode??
3259//Console.WriteLine("New Amotor Created for {0}", m_primName);
3260
3261 float axisnum = 3; // how many to lock
3262 axisnum = (axisnum - (m_rotateEnable.X + m_rotateEnable.Y + m_rotateEnable.Z));
3263 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3264//Console.WriteLine("AxisNum={0}",(int)axisnum);
3265
3266 int i = 0;
3267
3268 if (m_rotateEnable.X == 0)
3269 {
3270 d.JointSetAMotorAxis(Amotor, i, 0, m_lockX.X, m_lockX.Y, m_lockX.Z);
3271//Console.WriteLine("AxisX {0} set to {1}", i, m_lockX);
3272 i++;
3273 }
3274
3275 if (m_rotateEnable.Y == 0)
3276 {
3277 d.JointSetAMotorAxis(Amotor, i, 0, m_lockY.X, m_lockY.Y, m_lockY.Z);
3278//Console.WriteLine("AxisY {0} set to {1}", i, m_lockY);
3279 i++;
3280 }
3281
3282 if (m_rotateEnable.Z == 0)
3283 {
3284 d.JointSetAMotorAxis(Amotor, i, 0, m_lockZ.X, m_lockZ.Y, m_lockZ.Z);
3285//Console.WriteLine("AxisZ {0} set to {1}", i, m_lockZ);
3286 i++;
3287 }
3288
3289 // These lowstops and high stops are effectively (no wiggle room)
3290 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0f);
3291 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
3292 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0f);
3293 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3294 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3295 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3296 d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 0f);
3297 d.JointSetAMotorParam(Amotor, (int) dParam.Vel3, 0f);
3298 d.JointSetAMotorParam(Amotor, (int) dParam.Vel2, 0f);
3299 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f);
3300 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
3301 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
3302 } // else none are locked
3303 } // end Rotation Update
3304
3305
3306 // VEHICLE processing ==========================================
3307 if (m_type != Vehicle.TYPE_NONE)
3308 {
3309 // get body attitude
3310 d.Quaternion rot = d.BodyGetQuaternion(Body);
3311 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
3312 Quaternion irotq = Quaternion.Inverse(rotq);
3313
3314 // VEHICLE Linear Motion
3315 d.Vector3 velnow = d.BodyGetLinearVel(Body); // this is in world frame
3316 Vector3 vel_now = new Vector3(velnow.X, velnow.Y, velnow.Z);
3317 m_lLinObjectVel = vel_now * irotq;
3318 if (m_linearMotorDecayTimescale < 300.0f) //setting of 300 or more disables decay rate
3319 {
3320 if ( Vector3.Mag(m_lLinMotorDVel) < 1.0f)
3321 {
3322 float decayfactor = m_linearMotorDecayTimescale/timestep;
3323 Vector3 decayAmount = (m_lLinMotorDVel/decayfactor);
3324 m_lLinMotorDVel -= decayAmount;
3325 }
3326 else
3327 {
3328 float decayfactor = 3.0f - (0.57f * (float)Math.Log((double)(m_linearMotorDecayTimescale)));
3329 Vector3 decel = Vector3.Normalize(m_lLinMotorDVel) * decayfactor * timestep;
3330 m_lLinMotorDVel -= decel;
3331 }
3332 if (m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3333 {
3334 m_lLinMotorDVel = Vector3.Zero;
3335 }
3336
3337 /* else
3338 {
3339 if (Math.Abs(m_lLinMotorDVel.X) < Math.Abs(m_lLinObjectVel.X)) m_lLinObjectVel.X = m_lLinMotorDVel.X;
3340 if (Math.Abs(m_lLinMotorDVel.Y) < Math.Abs(m_lLinObjectVel.Y)) m_lLinObjectVel.Y = m_lLinMotorDVel.Y;
3341 if (Math.Abs(m_lLinMotorDVel.Z) < Math.Abs(m_lLinObjectVel.Z)) m_lLinObjectVel.Z = m_lLinMotorDVel.Z;
3342 } */
3343 } // end linear motor decay
3344
3345 if ( (! m_lLinMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! m_lLinObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3346 {
3347 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3348 if (m_linearMotorTimescale < 300.0f)
3349 {
3350 Vector3 attack_error = m_lLinMotorDVel - m_lLinObjectVel;
3351 float linfactor = m_linearMotorTimescale/timestep;
3352 Vector3 attackAmount = (attack_error/linfactor) * 1.3f;
3353 m_lLinObjectVel += attackAmount;
3354 }
3355 if (m_linearFrictionTimescale.X < 300.0f)
3356 {
3357 float fricfactor = m_linearFrictionTimescale.X / timestep;
3358 float fricX = m_lLinObjectVel.X / fricfactor;
3359 m_lLinObjectVel.X -= fricX;
3360 }
3361 if (m_linearFrictionTimescale.Y < 300.0f)
3362 {
3363 float fricfactor = m_linearFrictionTimescale.Y / timestep;
3364 float fricY = m_lLinObjectVel.Y / fricfactor;
3365 m_lLinObjectVel.Y -= fricY;
3366 }
3367 if (m_linearFrictionTimescale.Z < 300.0f)
3368 {
3369 float fricfactor = m_linearFrictionTimescale.Z / timestep;
3370 float fricZ = m_lLinObjectVel.Z / fricfactor;
3371 m_lLinObjectVel.Z -= fricZ;
3372 }
3373 }
3374 m_wLinObjectVel = m_lLinObjectVel * rotq;
3375
3376 // Gravity and Buoyancy
3377 Vector3 grav = Vector3.Zero;
3378 if(m_VehicleBuoyancy < 1.0f)
3379 {
3380 // There is some gravity, make a gravity force vector
3381 // that is applied after object velocity.
3382 d.Mass objMass;
3383 d.BodyGetMass(Body, out objMass);
3384 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
3385 grav.Z = _parent_scene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Applied later as a force
3386 } // else its 1.0, no gravity.
3387
3388 // Hovering
3389 if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
3390 {
3391 // We should hover, get the target height
3392 d.Vector3 pos = d.BodyGetPosition(Body);
3393 if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY)
3394 {
3395 m_VhoverTargetHeight = _parent_scene.GetWaterLevel() + m_VhoverHeight;
3396 }
3397 else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY)
3398 {
3399 m_VhoverTargetHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
3400 }
3401 else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT)
3402 {
3403 m_VhoverTargetHeight = m_VhoverHeight;
3404 }
3405
3406 if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY)
3407 {
3408 // If body is aready heigher, use its height as target height
3409 if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
3410 }
3411
3412// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
3413// m_VhoverTimescale = 0f; // time to acheive height
3414// timestep is time since last frame,in secs
3415 float herr0 = pos.Z - m_VhoverTargetHeight;
3416 // Replace Vertical speed with correction figure if significant
3417 if(Math.Abs(herr0) > 0.01f )
3418 {
3419 //? d.Mass objMass;
3420 //? d.BodyGetMass(Body, out objMass);
3421 m_wLinObjectVel.Z = - ( (herr0 * timestep * 50.0f) / m_VhoverTimescale);
3422 //KF: m_VhoverEfficiency is not yet implemented
3423 }
3424 else
3425 {
3426 m_wLinObjectVel.Z = 0f;
3427 }
3428 }
3429 else
3430 { // not hovering
3431 if (m_wLinObjectVel.Z == 0f)
3432 { // Gravity rules
3433 m_wLinObjectVel.Z = vel_now.Z;
3434 } // else the motor has it
3435 }
3436 linvel = m_wLinObjectVel;
3437
3438 // Vehicle Linear Motion done =======================================
3439 // Apply velocity
3440 d.BodySetLinearVel(Body, linvel.X, linvel.Y, linvel.Z);
3441 // apply gravity force
3442 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
3443//if(frcount == 0) Console.WriteLine("Vel={0} Force={1}",linvel , grav);
3444 // end MoveLinear()
3445
3446
3447 // MoveAngular
3448 /*
3449 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
3450
3451 private float m_angularMotorTimescale = 0; // motor angular Attack rate set by LSL
3452 private float m_angularMotorDecayTimescale = 0; // motor angular Decay rate set by LSL
3453 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular Friction set by LSL
3454
3455 private Vector3 m_angularMotorDVel = Vector3.Zero; // decayed angular motor
3456 private Vector3 m_angObjectVel = Vector3.Zero; // what was last applied to body
3457 */
3458//if(frcount == 0) Console.WriteLine("MoveAngular ");
3459
3460 d.Vector3 angularObjectVel = d.BodyGetAngularVel(Body);
3461 Vector3 angObjectVel = new Vector3(angularObjectVel.X, angularObjectVel.Y, angularObjectVel.Z);
3462 angObjectVel = angObjectVel * irotq; // ============ Converts to LOCAL rotation
3463
3464//if(frcount == 0) Console.WriteLine("V0 = {0}", angObjectVel);
3465
3466 // Decay Angular Motor 1. In SL this also depends on attack rate! decay ~= 23/Attack.
3467 float atk_decayfactor = 23.0f / (m_angularMotorTimescale * timestep);
3468 m_angularMotorDVel -= m_angularMotorDVel / atk_decayfactor;
3469 // Decay Angular Motor 2.
3470 if (m_angularMotorDecayTimescale < 300.0f)
3471 {
3472 if ( Vector3.Mag(m_angularMotorDVel) < 1.0f)
3473 {
3474 float decayfactor = (m_angularMotorDecayTimescale)/timestep;
3475 Vector3 decayAmount = (m_angularMotorDVel/decayfactor);
3476 m_angularMotorDVel -= decayAmount;
3477 }
3478 else
3479 {
3480 Vector3 decel = Vector3.Normalize(m_angularMotorDVel) * timestep / m_angularMotorDecayTimescale;
3481 m_angularMotorDVel -= decel;
3482 }
3483
3484 if (m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f))
3485 {
3486 m_angularMotorDVel = Vector3.Zero;
3487 }
3488 else
3489 {
3490 if (Math.Abs(m_angularMotorDVel.X) < Math.Abs(angObjectVel.X)) angObjectVel.X = m_angularMotorDVel.X;
3491 if (Math.Abs(m_angularMotorDVel.Y) < Math.Abs(angObjectVel.Y)) angObjectVel.Y = m_angularMotorDVel.Y;
3492 if (Math.Abs(m_angularMotorDVel.Z) < Math.Abs(angObjectVel.Z)) angObjectVel.Z = m_angularMotorDVel.Z;
3493 }
3494 } // end decay angular motor
3495//if(frcount == 0) Console.WriteLine("MotorDvel {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3496
3497//if(frcount == 0) Console.WriteLine("VA = {0}", angObjectVel);
3498
3499 if ( (! m_angularMotorDVel.ApproxEquals(Vector3.Zero, 0.01f)) || (! angObjectVel.ApproxEquals(Vector3.Zero, 0.01f)) )
3500 { // if motor or object have motion
3501 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
3502
3503 if (m_angularMotorTimescale < 300.0f)
3504 {
3505 Vector3 attack_error = m_angularMotorDVel - angObjectVel;
3506 float angfactor = m_angularMotorTimescale/timestep;
3507 Vector3 attackAmount = (attack_error/angfactor);
3508 angObjectVel += attackAmount;
3509//if(frcount == 0) Console.WriteLine("Accel {0} Attk {1}",FrAaccel, attackAmount);
3510//if(frcount == 0) Console.WriteLine("V2+= {0}", angObjectVel);
3511 }
3512
3513 angObjectVel.X -= angObjectVel.X / (m_angularFrictionTimescale.X * 0.7f / timestep);
3514 angObjectVel.Y -= angObjectVel.Y / (m_angularFrictionTimescale.Y * 0.7f / timestep);
3515 angObjectVel.Z -= angObjectVel.Z / (m_angularFrictionTimescale.Z * 0.7f / timestep);
3516 } // else no signif. motion
3517
3518//if(frcount == 0) Console.WriteLine("Dmotor {0} Obj {1}", m_angularMotorDVel, angObjectVel);
3519 // Bank section tba
3520 // Deflection section tba
3521//if(frcount == 0) Console.WriteLine("V3 = {0}", angObjectVel);
3522
3523
3524 /* // Rotation Axis Disables:
3525 if (!m_angularEnable.ApproxEquals(Vector3.One, 0.003f))
3526 {
3527 if (m_angularEnable.X == 0)
3528 angObjectVel.X = 0f;
3529 if (m_angularEnable.Y == 0)
3530 angObjectVel.Y = 0f;
3531 if (m_angularEnable.Z == 0)
3532 angObjectVel.Z = 0f;
3533 }
3534 */
3535 angObjectVel = angObjectVel * rotq; // ================ Converts to WORLD rotation
3536
3537 // Vertical attractor section
3538 Vector3 vertattr = Vector3.Zero;
3539
3540 if(m_verticalAttractionTimescale < 300)
3541 {
3542 float VAservo = 1.0f / (m_verticalAttractionTimescale * timestep);
3543 // make a vector pointing up
3544 Vector3 verterr = Vector3.Zero;
3545 verterr.Z = 1.0f;
3546 // rotate it to Body Angle
3547 verterr = verterr * rotq;
3548 // 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.
3549 // 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
3550 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
3551
3552 if (verterr.Z < 0.0f)
3553 { // Deflection from vertical exceeds 90-degrees. This method will ensure stable return to
3554 // vertical, BUT for some reason a z-rotation is imparted to the object. TBI.
3555//Console.WriteLine("InvertFlip");
3556 verterr.X = 2.0f - verterr.X;
3557 verterr.Y = 2.0f - verterr.Y;
3558 }
3559 verterr *= 0.5f;
3560 // verterror is 0 (no error) to +/- 1 (max error at 180-deg tilt)
3561 Vector3 xyav = angObjectVel;
3562 xyav.Z = 0.0f;
3563 if ((!xyav.ApproxEquals(Vector3.Zero, 0.001f)) || (verterr.Z < 0.49f))
3564 {
3565 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
3566 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
3567 vertattr.X = verterr.Y;
3568 vertattr.Y = - verterr.X;
3569 vertattr.Z = 0f;
3570//if(frcount == 0) Console.WriteLine("VAerr=" + verterr);
3571
3572 // scaling appears better usingsquare-law
3573 float damped = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
3574 float bounce = 1.0f - damped;
3575 // 0 = crit damp, 1 = bouncy
3576 float oavz = angObjectVel.Z; // retain z velocity
3577 // time-scaled correction, which sums, therefore is bouncy:
3578 angObjectVel = (angObjectVel + (vertattr * VAservo * 0.0333f)) * bounce;
3579 // damped, good @ < 90:
3580 angObjectVel = angObjectVel + (vertattr * VAservo * 0.0667f * damped);
3581 angObjectVel.Z = oavz;
3582//if(frcount == 0) Console.WriteLine("VA+");
3583//Console.WriteLine("VAttr {0} OAvel {1}", vertattr, angObjectVel);
3584 }
3585 else
3586 {
3587 // else error is very small
3588 angObjectVel.X = 0f;
3589 angObjectVel.Y = 0f;
3590//if(frcount == 0) Console.WriteLine("VA0");
3591 }
3592 } // else vertical attractor is off
3593//if(frcount == 0) Console.WriteLine("V1 = {0}", angObjectVel);
3594
3595
3596 m_lastAngularVelocity = angObjectVel;
3597 // apply Angular Velocity to body
3598 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
3599//if(frcount == 0) Console.WriteLine("V4 = {0}", m_lastAngularVelocity);
3600
3601 } // end VEHICLES
3602 else
3603 {
3604 // Dyamics (NON-'VEHICLES') are dealt with here ================================================================
3605
3606 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
3607
3608 /// Dynamics Buoyancy
3609 //KF: m_buoyancy is set by llSetBuoyancy() and is for non-vehicle.
3610 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
3611 // NB Prims in ODE are no subject to global gravity
3612 // This should only affect gravity operations
3613
3614 float m_mass = CalculateMass();
3615 // calculate z-force due togravity on object.
3616 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass; // force = acceleration * mass
3617 if ((m_usePID) && (m_PIDTau > 0.0f)) // Dynamics llMoveToTarget.
3618 {
3619 fz = 0; // llMoveToTarget ignores gravity.
3620 // it also ignores mass of object, and any physical resting on it.
3621 // Vector3 m_PIDTarget is where we are going
3622 // float m_PIDTau is time to get there
3623 fx = 0;
3624 fy = 0;
3625 d.Vector3 pos = d.BodyGetPosition(Body);
3626 Vector3 error = new Vector3(
3627 (m_PIDTarget.X - pos.X),
3628 (m_PIDTarget.Y - pos.Y),
3629 (m_PIDTarget.Z - pos.Z));
3630 if (error.ApproxEquals(Vector3.Zero,0.01f))
3631 { // Very close, Jump there and quit move
3632
3633 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
3634 _target_velocity = Vector3.Zero;
3635 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3636 d.BodySetForce(Body, 0f, 0f, 0f);
3637 }
3638 else
3639 {
3640 float scale = 50.0f * timestep / m_PIDTau;
3641 if ((error.ApproxEquals(Vector3.Zero,0.5f)) && (_target_velocity != Vector3.Zero))
3642 {
3643 // Nearby, quit update of velocity
3644 }
3645 else
3646 { // Far, calc damped velocity
3647 _target_velocity = error * scale;
3648 }
3649 d.BodySetLinearVel(Body, _target_velocity.X, _target_velocity.Y, _target_velocity.Z);
3650 }
3651 } // end PID MoveToTarget
3652
3653
3654 /// Dynamics Hover ===================================================================================
3655 // Hover PID Controller can only run if the PIDcontroller is not in use.
3656 if (m_useHoverPID && !m_usePID)
3657 {
3658//Console.WriteLine("Hover " + m_primName);
3659
3660 // If we're using the PID controller, then we have no gravity
3661 fz = (-1 * _parent_scene.gravityz) * m_mass;
3662
3663 // no lock; for now it's only called from within Simulate()
3664
3665 // If the PID Controller isn't active then we set our force
3666 // calculating base velocity to the current position
3667
3668 if ((m_PIDTau < 1))
3669 {
3670 PID_G = PID_G / m_PIDTau;
3671 }
3672
3673 if ((PID_G - m_PIDTau) <= 0)
3674 {
3675 PID_G = m_PIDTau + 1;
3676 }
3677
3678
3679 // Where are we, and where are we headed?
3680 d.Vector3 pos = d.BodyGetPosition(Body);
3681// d.Vector3 vel = d.BodyGetLinearVel(Body);
3682
3683
3684 // Non-Vehicles have a limited set of Hover options.
3685 // determine what our target height really is based on HoverType
3686 switch (m_PIDHoverType)
3687 {
3688 case PIDHoverType.Ground:
3689 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3690 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3691 break;
3692 case PIDHoverType.GroundAndWater:
3693 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
3694 m_waterHeight = _parent_scene.GetWaterLevel();
3695 if (m_groundHeight > m_waterHeight)
3696 {
3697 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
3698 }
3699 else
3700 {
3701 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
3702 }
3703 break;
3704
3705 } // end switch (m_PIDHoverType)
3706
3707
3708 _target_velocity =
3709 new Vector3(0.0f, 0.0f,
3710 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
3711 );
3712
3713 // if velocity is zero, use position control; otherwise, velocity control
3714
3715 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
3716 {
3717 // keep track of where we stopped. No more slippin' & slidin'
3718
3719 // We only want to deactivate the PID Controller if we think we want to have our surrogate
3720 // react to the physics scene by moving it's position.
3721 // Avatar to Avatar collisions
3722 // Prim to avatar collisions
3723 d.Vector3 dlinvel = vel;
3724 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
3725 d.BodySetLinearVel(Body, dlinvel.X, dlinvel.Y, dlinvel.Z);
3726 d.BodyAddForce(Body, 0, 0, fz);
3727 //KF this prevents furthur motions return;
3728 }
3729 else
3730 {
3731 _zeroFlag = false;
3732
3733 // We're flying and colliding with something
3734 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
3735 }
3736 } // end m_useHoverPID && !m_usePID
3737
3738
3739 /// Dynamics Apply Forces ===================================================================================
3740 fx *= m_mass;
3741 fy *= m_mass;
3742 //fz *= m_mass;
3743 fx += m_force.X;
3744 fy += m_force.Y;
3745 fz += m_force.Z;
3746
3747 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
3748 if (fx != 0 || fy != 0 || fz != 0)
3749 {
3750 //m_taintdisable = true;
3751 //base.RaiseOutOfBounds(Position);
3752 //d.BodySetLinearVel(Body, fx, fy, 0f);
3753 if (!d.BodyIsEnabled(Body))
3754 {
3755 // A physical body at rest on a surface will auto-disable after a while,
3756 // this appears to re-enable it incase the surface it is upon vanishes,
3757 // and the body should fall again.
3758 d.BodySetLinearVel(Body, 0f, 0f, 0f);
3759 d.BodySetForce(Body, 0f, 0f, 0f);
3760 enableBodySoft();
3761 }
3762
3763 // 35x10 = 350n times the mass per second applied maximum.
3764 float nmax = 35f * m_mass;
3765 float nmin = -35f * m_mass;
3766
3767
3768 if (fx > nmax)
3769 fx = nmax;
3770 if (fx < nmin)
3771 fx = nmin;
3772 if (fy > nmax)
3773 fy = nmax;
3774 if (fy < nmin)
3775 fy = nmin;
3776 d.BodyAddForce(Body, fx, fy, fz);
3777 } // end apply forces
3778 } // end Vehicle/Dynamics
3779
3780 /// RotLookAt / LookAt =================================================================================
3781 if (m_useAPID)
3782 {
3783 // RotLookAt, apparently overrides all other rotation sources. Inputs:
3784 // Quaternion m_APIDTarget
3785 // float m_APIDStrength // From SL experiments, this is the time to get there
3786 // float m_APIDDamping // From SL experiments, this is damping, 1.0 = damped, 0.1 = wobbly
3787 // Also in SL the mass of the object has no effect on time to get there.
3788 // Factors:
3789 // get present body rotation
3790 float limit = 1.0f;
3791 float rscaler = 50f; // adjusts rotation damping time
3792 float lscaler = 10f; // adjusts linear damping time in llLookAt
3793 float RLAservo = 0f;
3794 Vector3 diff_axis;
3795 float diff_angle;
3796 d.Quaternion rot = d.BodyGetQuaternion(Body); // prim present rotation
3797 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
3798 Quaternion rtarget = new Quaternion();
3799
3800 if(m_APIDTarget.W == -99.9f)
3801 {
3802 // this is really a llLookAt(), x,y,z is the target vector
3803 Vector3 target = new Vector3(m_APIDTarget.X, m_APIDTarget.Y, m_APIDTarget.Z);
3804 Vector3 ospin = new Vector3(1.0f, 0.0f, 0.0f) * rotq;
3805 Vector3 error = new Vector3(0.0f, 0.0f, 0.0f);
3806 float twopi = 2.0f * (float)Math.PI;
3807 Vector3 dir = target - _position;
3808 dir.Normalize();
3809 float tzrot = (float)Math.Atan2(dir.Y, dir.X);
3810 float txy = (float)Math.Sqrt((dir.X * dir.X) + (dir.Y * dir.Y));
3811 float terot = (float)Math.Atan2(dir.Z, txy);
3812 float ozrot = (float)Math.Atan2(ospin.Y, ospin.X);
3813 float oxy = (float)Math.Sqrt((ospin.X * ospin.X) + (ospin.Y * ospin.Y));
3814 float oerot = (float)Math.Atan2(ospin.Z, oxy);
3815 float ra = 2.0f * ((rotq.W * rotq.X) + (rotq.Y * rotq.Z));
3816 float rb = 1.0f - 2.0f * ((rotq.Y * rotq.Y)+(rotq.X * rotq.X));
3817 float roll = (float)Math.Atan2(ra, rb);
3818 float errorz = tzrot - ozrot;
3819 if(errorz > (float)Math.PI) errorz -= twopi;
3820 else if(errorz < -(float)Math.PI) errorz += twopi;
3821 float errory = oerot - terot;
3822 if(errory > (float)Math.PI) errory -= twopi;
3823 else if(errory < -(float)Math.PI) errory += twopi;
3824 diff_angle = Math.Abs(errorz) + Math.Abs(errory) + Math.Abs(roll);
3825 if(diff_angle > 0.01f * m_APIDdamper)
3826 {
3827 m_APIDdamper = 1.0f;
3828 RLAservo = timestep / m_APIDStrength * rscaler;
3829 errorz *= RLAservo;
3830 errory *= RLAservo;
3831 error.X = -roll * 8.0f;
3832 error.Y = errory;
3833 error.Z = errorz;
3834 error *= rotq;
3835 d.BodySetAngularVel (Body, error.X, error.Y, error.Z);
3836 }
3837 else
3838 {
3839 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3840 m_APIDdamper = 2.0f;
3841 }
3842 }
3843 else
3844 {
3845 // this is a llRotLookAt()
3846 rtarget = m_APIDTarget;
3847
3848 Quaternion rot_diff = Quaternion.Inverse(rotq) * rtarget; // difference to desired rot
3849 rot_diff.GetAxisAngle(out diff_axis, out diff_angle); // convert to axis to point at & error angle
3850//if(frcount == 0) Console.WriteLine("axis {0} angle {1}",diff_axis * 57.3f, diff_angle);
3851
3852 // diff_axis.Normalize(); it already is!
3853 if(diff_angle > 0.01f * m_APIDdamper) // diff_angle is always +ve // if there is enough error
3854 {
3855 m_APIDdamper = 1.0f;
3856 Vector3 rotforce = new Vector3(diff_axis.X, diff_axis.Y, diff_axis.Z);
3857 rotforce = rotforce * rotq;
3858 if(diff_angle > limit) diff_angle = limit; // cap the rotate rate
3859 RLAservo = timestep / m_APIDStrength * lscaler;
3860 rotforce = rotforce * RLAservo * diff_angle ;
3861 d.BodySetAngularVel (Body, rotforce.X, rotforce.Y, rotforce.Z);
3862//Console.WriteLine("axis= " + diff_axis + " angle= " + diff_angle + "servo= " + RLAservo);
3863 }
3864 else
3865 { // close enough
3866 d.BodySetAngularVel (Body, 0.0f, 0.0f, 0.0f);
3867 m_APIDdamper = 2.0f;
3868 }
3869 } // end llLookAt/llRotLookAt
3870//if(frcount == 0) Console.WriteLine("mass= " + m_mass + " servo= " + RLAservo + " angle= " + diff_angle);
3871 } // end m_useAPID
3872 } // end root prims
3873 } // end Move()
3874 } // end class
3875}
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..712029e
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/ODERayCastRequestManager.cs
@@ -0,0 +1,384 @@
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 try
113 {
114 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
115 RayCast(reqs[i]); // if there isn't anyone to send results
116 }
117 catch
118 {
119 //Fail silently
120 //This can genuinely happen because raycast requests are queued, and the actor may have
121 //been removed from the scene since it was queued
122 }
123 }
124 /*
125 foreach (ODERayCastRequest req in m_PendingRequests)
126 {
127 if (req.callbackMethod != null) // quick optimization here, don't raycast
128 RayCast(req); // if there isn't anyone to send results to
129
130 }
131 */
132 m_PendingRequests.Clear();
133 }
134 }
135
136 lock (m_contactResults)
137 m_contactResults.Clear();
138
139 return System.Environment.TickCount - time;
140 }
141
142 /// <summary>
143 /// Method that actually initiates the raycast
144 /// </summary>
145 /// <param name="req"></param>
146 private void RayCast(ODERayCastRequest req)
147 {
148 // Create the ray
149 IntPtr ray = d.CreateRay(m_scene.space, req.length);
150 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
151
152 // Collide test
153 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
154
155 // Remove Ray
156 d.GeomDestroy(ray);
157
158
159 // Define default results
160 bool hitYN = false;
161 uint hitConsumerID = 0;
162 float distance = 999999999999f;
163 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
164 Vector3 snormal = Vector3.Zero;
165
166 // Find closest contact and object.
167 lock (m_contactResults)
168 {
169 foreach (ContactResult cResult in m_contactResults)
170 {
171 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
172 {
173 closestcontact = cResult.Pos;
174 hitConsumerID = cResult.ConsumerID;
175 distance = cResult.Depth;
176 hitYN = true;
177 snormal = cResult.Normal;
178 }
179 }
180
181 m_contactResults.Clear();
182 }
183
184 // Return results
185 if (req.callbackMethod != null)
186 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
187 }
188
189 // This is the standard Near. Uses space AABBs to speed up detection.
190 private void near(IntPtr space, IntPtr g1, IntPtr g2)
191 {
192
193 //Don't test against heightfield Geom, or you'll be sorry!
194
195 /*
196 terminate called after throwing an instance of 'std::bad_alloc'
197 what(): std::bad_alloc
198 Stacktrace:
199
200 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
201 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
202 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
203 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
204 fffff>
205 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
206 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
207 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
208 0x00114>
209 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
210 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
211 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
212 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
213 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
214 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
215
216 Native stacktrace:
217
218 mono [0x80d2a42]
219 [0xb7f5840c]
220 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
221 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
222 /usr/lib/libstdc++.so.6 [0xb45fa865]
223 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
224 /usr/lib/libstdc++.so.6 [0xb45fa9da]
225 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
226 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
227 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
228 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
229 libode.so(dCollide+0x102) [0xb46571b2]
230 [0x95cfdec9]
231 [0x8ea07fe1]
232 [0xab260146]
233 libode.so [0xb465a5c4]
234 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
235 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
236 [0x95cf978e]
237 [0x8ea07945]
238 [0x95cf2bbc]
239 [0xab2787e7]
240 [0xab419fb3]
241 [0xab416657]
242 [0xab415bda]
243 [0xb609b08e]
244 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
245 mono [0x81a2f0f]
246 mono [0x81d28b6]
247 mono [0x81ea2c6]
248 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
249 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
250 */
251
252 // Exclude heightfield geom
253
254 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
255 return;
256 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
257 return;
258
259 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
260 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
261 {
262 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
263 return;
264
265 // Separating static prim geometry spaces.
266 // We'll be calling near recursivly if one
267 // of them is a space to find all of the
268 // contact points in the space
269 try
270 {
271 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
272 }
273 catch (AccessViolationException)
274 {
275 m_log.Warn("[PHYSICS]: Unable to collide test a space");
276 return;
277 }
278 //Colliding a space or a geom with a space or a geom. so drill down
279
280 //Collide all geoms in each space..
281 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
282 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
283 return;
284 }
285
286 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
287 return;
288
289 int count = 0;
290 try
291 {
292
293 if (g1 == g2)
294 return; // Can't collide with yourself
295
296 lock (contacts)
297 {
298 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
299 }
300 }
301 catch (SEHException)
302 {
303 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.");
304 }
305 catch (Exception e)
306 {
307 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
308 return;
309 }
310
311 PhysicsActor p1 = null;
312 PhysicsActor p2 = null;
313
314 if (g1 != IntPtr.Zero)
315 m_scene.actor_name_map.TryGetValue(g1, out p1);
316
317 if (g2 != IntPtr.Zero)
318 m_scene.actor_name_map.TryGetValue(g1, out p2);
319
320 // Loop over contacts, build results.
321 for (int i = 0; i < count; i++)
322 {
323 if (p1 != null) {
324 if (p1 is OdePrim)
325 {
326 ContactResult collisionresult = new ContactResult();
327
328 collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
329 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
330 collisionresult.Depth = contacts[i].depth;
331 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
332 contacts[i].normal.Z);
333 lock (m_contactResults)
334 m_contactResults.Add(collisionresult);
335 }
336 }
337
338 if (p2 != null)
339 {
340 if (p2 is OdePrim)
341 {
342 ContactResult collisionresult = new ContactResult();
343
344 collisionresult.ConsumerID = ((OdePrim)p2).m_localID;
345 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
346 collisionresult.Depth = contacts[i].depth;
347 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
348 contacts[i].normal.Z);
349
350 lock (m_contactResults)
351 m_contactResults.Add(collisionresult);
352 }
353 }
354
355
356 }
357
358 }
359
360 /// <summary>
361 /// Dereference the creator scene so that it can be garbage collected if needed.
362 /// </summary>
363 internal void Dispose()
364 {
365 m_scene = null;
366 }
367 }
368
369 public struct ODERayCastRequest
370 {
371 public Vector3 Origin;
372 public Vector3 Normal;
373 public float length;
374 public RaycastCallback callbackMethod;
375 }
376
377 public struct ContactResult
378 {
379 public Vector3 Pos;
380 public float Depth;
381 public uint ConsumerID;
382 public Vector3 Normal;
383 }
384}
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..353db44
--- /dev/null
+++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs
@@ -0,0 +1,3841 @@
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 /// Commented this because it triggers on every bullet
1557 //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!");
1558 }
1559 }
1560 }
1561 catch (AccessViolationException)
1562 {
1563 m_log.Warn("[PHYSICS]: Unable to space collide");
1564 }
1565 }
1566 }
1567 if (removeprims != null)
1568 {
1569 foreach (OdePrim chr in removeprims)
1570 {
1571 _activeprims.Remove(chr);
1572 }
1573 }
1574 }
1575
1576 _perloopContact.Clear();
1577 }
1578
1579 #endregion
1580
1581 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1582 {
1583 m_worldOffset = offset;
1584 WorldExtents = new Vector2(extents.X, extents.Y);
1585 m_parentScene = pScene;
1586
1587 }
1588
1589 // Recovered for use by fly height. Kitto Flora
1590 public float GetTerrainHeightAtXY(float x, float y)
1591 {
1592
1593 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1594 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1595
1596 IntPtr heightFieldGeom = IntPtr.Zero;
1597
1598 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1599 {
1600 if (heightFieldGeom != IntPtr.Zero)
1601 {
1602 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1603 {
1604
1605 int index;
1606
1607
1608 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1609 (int)x < 0.001f || (int)y < 0.001f)
1610 return 0;
1611
1612 x = x - offsetX;
1613 y = y - offsetY;
1614
1615 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1616
1617 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1618 {
1619 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1620 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1621 }
1622
1623 else
1624 return 0f;
1625 }
1626 else
1627 {
1628 return 0f;
1629 }
1630
1631 }
1632 else
1633 {
1634 return 0f;
1635 }
1636
1637 }
1638 else
1639 {
1640 return 0f;
1641 }
1642
1643
1644 }
1645// End recovered. Kitto Flora
1646
1647 public void addCollisionEventReporting(PhysicsActor obj)
1648 {
1649 lock (_collisionEventPrim)
1650 {
1651 if (!_collisionEventPrim.Contains(obj))
1652 _collisionEventPrim.Add(obj);
1653 }
1654 }
1655
1656 public void remCollisionEventReporting(PhysicsActor obj)
1657 {
1658 lock (_collisionEventPrim)
1659 {
1660 if (!_collisionEventPrim.Contains(obj))
1661 _collisionEventPrim.Remove(obj);
1662 }
1663 }
1664
1665 #region Add/Remove Entities
1666
1667 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1668 {
1669 Vector3 pos;
1670 pos.X = position.X;
1671 pos.Y = position.Y;
1672 pos.Z = position.Z;
1673 OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size, avPIDD, avPIDP, avCapRadius, avStandupTensor, avDensity, avHeightFudgeFactor, avMovementDivisorWalk, avMovementDivisorRun);
1674 newAv.Flying = isFlying;
1675 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1676
1677 return newAv;
1678 }
1679
1680 public void AddCharacter(OdeCharacter chr)
1681 {
1682 lock (_characters)
1683 {
1684 if (!_characters.Contains(chr))
1685 {
1686 _characters.Add(chr);
1687 if (chr.bad)
1688 m_log.DebugFormat("[PHYSICS] Added BAD actor {0} to characters list", chr.m_uuid);
1689 }
1690 }
1691 }
1692
1693 public void RemoveCharacter(OdeCharacter chr)
1694 {
1695 lock (_characters)
1696 {
1697 if (_characters.Contains(chr))
1698 {
1699 _characters.Remove(chr);
1700 }
1701 }
1702 }
1703 public void BadCharacter(OdeCharacter chr)
1704 {
1705 lock (_badCharacter)
1706 {
1707 if (!_badCharacter.Contains(chr))
1708 _badCharacter.Add(chr);
1709 }
1710 }
1711
1712 public override void RemoveAvatar(PhysicsActor actor)
1713 {
1714 //m_log.Debug("[PHYSICS]:ODELOCK");
1715 ((OdeCharacter) actor).Destroy();
1716
1717 }
1718
1719 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
1720 IMesh mesh, PrimitiveBaseShape pbs, bool isphysical, uint localid)
1721 {
1722
1723 Vector3 pos = position;
1724 Vector3 siz = size;
1725 Quaternion rot = rotation;
1726
1727 OdePrim newPrim;
1728 lock (OdeLock)
1729 {
1730 newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode, localid);
1731
1732 lock (_prims)
1733 _prims.Add(newPrim);
1734 }
1735
1736 return newPrim;
1737 }
1738
1739 public void addActivePrim(OdePrim activatePrim)
1740 {
1741 // adds active prim.. (ones that should be iterated over in collisions_optimized
1742 lock (_activeprims)
1743 {
1744 if (!_activeprims.Contains(activatePrim))
1745 _activeprims.Add(activatePrim);
1746 //else
1747 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
1748 }
1749 }
1750
1751 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
1752 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
1753 {
1754 PhysicsActor result;
1755 IMesh mesh = null;
1756
1757 if (needsMeshing(pbs))
1758 mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
1759
1760 result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical, localid);
1761
1762 return result;
1763 }
1764
1765 public override float TimeDilation
1766 {
1767 get { return m_timeDilation; }
1768 }
1769
1770 public override bool SupportsNINJAJoints
1771 {
1772 get { return m_NINJA_physics_joints_enabled; }
1773 }
1774
1775 // internal utility function: must be called within a lock (OdeLock)
1776 private void InternalAddActiveJoint(PhysicsJoint joint)
1777 {
1778 activeJoints.Add(joint);
1779 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
1780 }
1781
1782 // internal utility function: must be called within a lock (OdeLock)
1783 private void InternalAddPendingJoint(OdePhysicsJoint joint)
1784 {
1785 pendingJoints.Add(joint);
1786 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
1787 }
1788
1789 // internal utility function: must be called within a lock (OdeLock)
1790 private void InternalRemovePendingJoint(PhysicsJoint joint)
1791 {
1792 pendingJoints.Remove(joint);
1793 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
1794 }
1795
1796 // internal utility function: must be called within a lock (OdeLock)
1797 private void InternalRemoveActiveJoint(PhysicsJoint joint)
1798 {
1799 activeJoints.Remove(joint);
1800 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
1801 }
1802
1803 public override void DumpJointInfo()
1804 {
1805 string hdr = "[NINJA] JOINTINFO: ";
1806 foreach (PhysicsJoint j in pendingJoints)
1807 {
1808 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1809 }
1810 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
1811 foreach (string jointName in SOPName_to_pendingJoint.Keys)
1812 {
1813 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
1814 }
1815 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
1816 foreach (PhysicsJoint j in activeJoints)
1817 {
1818 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1819 }
1820 m_log.Debug(hdr + activeJoints.Count + " total active joints");
1821 foreach (string jointName in SOPName_to_activeJoint.Keys)
1822 {
1823 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
1824 }
1825 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
1826
1827 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
1828 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
1829 foreach (string actorName in joints_connecting_actor.Keys)
1830 {
1831 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
1832 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
1833 {
1834 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
1835 }
1836 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
1837 }
1838 }
1839
1840 public override void RequestJointDeletion(string ObjectNameInScene)
1841 {
1842 lock (externalJointRequestsLock)
1843 {
1844 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
1845 {
1846 requestedJointsToBeDeleted.Add(ObjectNameInScene);
1847 }
1848 }
1849 }
1850
1851 private void DeleteRequestedJoints()
1852 {
1853 List<string> myRequestedJointsToBeDeleted;
1854 lock (externalJointRequestsLock)
1855 {
1856 // make a local copy of the shared list for processing (threading issues)
1857 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
1858 }
1859
1860 foreach (string jointName in myRequestedJointsToBeDeleted)
1861 {
1862 lock (OdeLock)
1863 {
1864 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
1865 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
1866 {
1867 OdePhysicsJoint joint = null;
1868 if (SOPName_to_activeJoint.ContainsKey(jointName))
1869 {
1870 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
1871 InternalRemoveActiveJoint(joint);
1872 }
1873 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
1874 {
1875 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
1876 InternalRemovePendingJoint(joint);
1877 }
1878
1879 if (joint != null)
1880 {
1881 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
1882 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1883 {
1884 string bodyName = joint.BodyNames[iBodyName];
1885 if (bodyName != "NULL")
1886 {
1887 joints_connecting_actor[bodyName].Remove(joint);
1888 if (joints_connecting_actor[bodyName].Count == 0)
1889 {
1890 joints_connecting_actor.Remove(bodyName);
1891 }
1892 }
1893 }
1894
1895 DoJointDeactivated(joint);
1896 if (joint.jointID != IntPtr.Zero)
1897 {
1898 d.JointDestroy(joint.jointID);
1899 joint.jointID = IntPtr.Zero;
1900 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
1901 }
1902 else
1903 {
1904 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
1905 }
1906 }
1907 else
1908 {
1909 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
1910 }
1911 }
1912 else
1913 {
1914 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
1915 }
1916 }
1917 }
1918
1919 // remove processed joints from the shared list
1920 lock (externalJointRequestsLock)
1921 {
1922 foreach (string jointName in myRequestedJointsToBeDeleted)
1923 {
1924 requestedJointsToBeDeleted.Remove(jointName);
1925 }
1926 }
1927 }
1928
1929 // for pending joints we don't know if their associated bodies exist yet or not.
1930 // the joint is actually created during processing of the taints
1931 private void CreateRequestedJoints()
1932 {
1933 List<PhysicsJoint> myRequestedJointsToBeCreated;
1934 lock (externalJointRequestsLock)
1935 {
1936 // make a local copy of the shared list for processing (threading issues)
1937 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
1938 }
1939
1940 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1941 {
1942 lock (OdeLock)
1943 {
1944 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
1945 {
1946 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);
1947 continue;
1948 }
1949 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
1950 {
1951 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);
1952 continue;
1953 }
1954
1955 InternalAddPendingJoint(joint as OdePhysicsJoint);
1956
1957 if (joint.BodyNames.Count >= 2)
1958 {
1959 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1960 {
1961 string bodyName = joint.BodyNames[iBodyName];
1962 if (bodyName != "NULL")
1963 {
1964 if (!joints_connecting_actor.ContainsKey(bodyName))
1965 {
1966 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
1967 }
1968 joints_connecting_actor[bodyName].Add(joint);
1969 }
1970 }
1971 }
1972 }
1973 }
1974
1975 // remove processed joints from shared list
1976 lock (externalJointRequestsLock)
1977 {
1978 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
1979 {
1980 requestedJointsToBeCreated.Remove(joint);
1981 }
1982 }
1983
1984 }
1985
1986 // public function to add an request for joint creation
1987 // this joint will just be added to a waiting list that is NOT processed during the main
1988 // Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
1989
1990 public override PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
1991 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
1992
1993 {
1994
1995 OdePhysicsJoint joint = new OdePhysicsJoint();
1996 joint.ObjectNameInScene = objectNameInScene;
1997 joint.Type = jointType;
1998 joint.Position = position;
1999 joint.Rotation = rotation;
2000 joint.RawParams = parms;
2001 joint.BodyNames = new List<string>(bodyNames);
2002 joint.TrackedBodyName = trackedBodyName;
2003 joint.LocalRotation = localRotation;
2004 joint.jointID = IntPtr.Zero;
2005 joint.ErrorMessageCount = 0;
2006
2007 lock (externalJointRequestsLock)
2008 {
2009 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2010 {
2011 requestedJointsToBeCreated.Add(joint);
2012 }
2013 }
2014 return joint;
2015 }
2016
2017 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2018 {
2019 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2020 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2021 {
2022
2023 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2024 //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)
2025 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2026 {
2027 jointsToRemove.Add(j);
2028 }
2029 foreach (PhysicsJoint j in jointsToRemove)
2030 {
2031 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2032 RequestJointDeletion(j.ObjectNameInScene);
2033 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2034 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)
2035 }
2036 }
2037 }
2038
2039 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2040 {
2041 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2042 lock (OdeLock)
2043 {
2044 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2045 RemoveAllJointsConnectedToActor(actor);
2046 }
2047 }
2048
2049 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2050 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2051 {
2052 Debug.Assert(joint.IsInPhysicsEngine);
2053 d.Vector3 pos = new d.Vector3();
2054
2055 if (!(joint is OdePhysicsJoint))
2056 {
2057 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2058 }
2059 else
2060 {
2061 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2062 switch (odeJoint.Type)
2063 {
2064 case PhysicsJointType.Ball:
2065 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2066 break;
2067 case PhysicsJointType.Hinge:
2068 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2069 break;
2070 }
2071 }
2072 return new Vector3(pos.X, pos.Y, pos.Z);
2073 }
2074
2075 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2076 // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2077 // appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2078 // keeping track of the joint's original orientation relative to one of the involved bodies.
2079 public override Vector3 GetJointAxis(PhysicsJoint joint)
2080 {
2081 Debug.Assert(joint.IsInPhysicsEngine);
2082 d.Vector3 axis = new d.Vector3();
2083
2084 if (!(joint is OdePhysicsJoint))
2085 {
2086 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2087 }
2088 else
2089 {
2090 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2091 switch (odeJoint.Type)
2092 {
2093 case PhysicsJointType.Ball:
2094 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2095 break;
2096 case PhysicsJointType.Hinge:
2097 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2098 break;
2099 }
2100 }
2101 return new Vector3(axis.X, axis.Y, axis.Z);
2102 }
2103
2104
2105 public void remActivePrim(OdePrim deactivatePrim)
2106 {
2107 lock (_activeprims)
2108 {
2109 _activeprims.Remove(deactivatePrim);
2110 }
2111 }
2112
2113 public override void RemovePrim(PhysicsActor prim)
2114 {
2115 if (prim is OdePrim)
2116 {
2117 lock (OdeLock)
2118 {
2119 OdePrim p = (OdePrim) prim;
2120
2121 p.setPrimForRemoval();
2122 AddPhysicsActorTaint(prim);
2123 //RemovePrimThreadLocked(p);
2124 }
2125 }
2126 }
2127
2128 /// <summary>
2129 /// This is called from within simulate but outside the locked portion
2130 /// We need to do our own locking here
2131 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2132 ///
2133 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2134 /// that the space was using.
2135 /// </summary>
2136 /// <param name="prim"></param>
2137 public void RemovePrimThreadLocked(OdePrim prim)
2138 {
2139//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName);
2140 lock (prim)
2141 {
2142 remCollisionEventReporting(prim);
2143 lock (ode)
2144 {
2145 if (prim.prim_geom != IntPtr.Zero)
2146 {
2147 prim.ResetTaints();
2148
2149 if (prim.IsPhysical)
2150 {
2151 prim.disableBody();
2152 if (prim.childPrim)
2153 {
2154 prim.childPrim = false;
2155 prim.Body = IntPtr.Zero;
2156 prim.m_disabled = true;
2157 prim.IsPhysical = false;
2158 }
2159
2160
2161 }
2162 // we don't want to remove the main space
2163
2164 // If the geometry is in the targetspace, remove it from the target space
2165 //m_log.Warn(prim.m_targetSpace);
2166
2167 //if (prim.m_targetSpace != IntPtr.Zero)
2168 //{
2169 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2170 //{
2171
2172 //if (d.GeomIsSpace(prim.m_targetSpace))
2173 //{
2174 //waitForSpaceUnlock(prim.m_targetSpace);
2175 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2176 prim.m_targetSpace = IntPtr.Zero;
2177 //}
2178 //else
2179 //{
2180 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2181 //((OdePrim)prim).m_targetSpace.ToString());
2182 //}
2183
2184 //}
2185 //}
2186 //m_log.Warn(prim.prim_geom);
2187 try
2188 {
2189 if (prim.prim_geom != IntPtr.Zero)
2190 {
2191
2192//string tPA;
2193//geom_name_map.TryGetValue(prim.prim_geom, out tPA);
2194//Console.WriteLine("**** Remove {0}", tPA);
2195 if(geom_name_map.ContainsKey(prim.prim_geom)) geom_name_map.Remove(prim.prim_geom);
2196 if(actor_name_map.ContainsKey(prim.prim_geom)) actor_name_map.Remove(prim.prim_geom);
2197 d.GeomDestroy(prim.prim_geom);
2198 prim.prim_geom = IntPtr.Zero;
2199 }
2200 else
2201 {
2202 m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
2203 }
2204 }
2205 catch (AccessViolationException)
2206 {
2207 m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
2208 }
2209 lock (_prims)
2210 _prims.Remove(prim);
2211
2212 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2213 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2214 //{
2215 //if (prim.m_targetSpace != null)
2216 //{
2217 //if (d.GeomIsSpace(prim.m_targetSpace))
2218 //{
2219 //waitForSpaceUnlock(prim.m_targetSpace);
2220 //d.SpaceRemove(space, prim.m_targetSpace);
2221 // free up memory used by the space.
2222 //d.SpaceDestroy(prim.m_targetSpace);
2223 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2224 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2225 //}
2226 //else
2227 //{
2228 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2229 //((OdePrim) prim).m_targetSpace.ToString());
2230 //}
2231 //}
2232 //}
2233
2234 if (SupportsNINJAJoints)
2235 {
2236 RemoveAllJointsConnectedToActorThreadLocked(prim);
2237 }
2238 }
2239 }
2240 }
2241 }
2242
2243 #endregion
2244
2245 #region Space Separation Calculation
2246
2247 /// <summary>
2248 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2249 /// </summary>
2250 /// <param name="pSpace"></param>
2251 public void resetSpaceArrayItemToZero(IntPtr pSpace)
2252 {
2253 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2254 {
2255 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2256 {
2257 if (staticPrimspace[x, y] == pSpace)
2258 staticPrimspace[x, y] = IntPtr.Zero;
2259 }
2260 }
2261 }
2262
2263 public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2264 {
2265 staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2266 }
2267
2268 /// <summary>
2269 /// Called when a static prim moves. Allocates a space for the prim based on its position
2270 /// </summary>
2271 /// <param name="geom">the pointer to the geom that moved</param>
2272 /// <param name="pos">the position that the geom moved to</param>
2273 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2274 /// <returns>a pointer to the new space it's in</returns>
2275 public IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2276 {
2277 // Called from setting the Position and Size of an ODEPrim so
2278 // it's already in locked space.
2279
2280 // we don't want to remove the main space
2281 // we don't need to test physical here because this function should
2282 // never be called if the prim is physical(active)
2283
2284 // All physical prim end up in the root space
2285 //Thread.Sleep(20);
2286 if (currentspace != space)
2287 {
2288 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2289 //if (currentspace == IntPtr.Zero)
2290 //{
2291 //int adfadf = 0;
2292 //}
2293 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2294 {
2295 if (d.GeomIsSpace(currentspace))
2296 {
2297 waitForSpaceUnlock(currentspace);
2298 d.SpaceRemove(currentspace, geom);
2299 }
2300 else
2301 {
2302 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2303 " Geom:" + geom);
2304 }
2305 }
2306 else
2307 {
2308 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2309 if (sGeomIsIn != IntPtr.Zero)
2310 {
2311 if (d.GeomIsSpace(currentspace))
2312 {
2313 waitForSpaceUnlock(sGeomIsIn);
2314 d.SpaceRemove(sGeomIsIn, geom);
2315 }
2316 else
2317 {
2318 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2319 sGeomIsIn + " Geom:" + geom);
2320 }
2321 }
2322 }
2323
2324 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2325 if (d.SpaceGetNumGeoms(currentspace) == 0)
2326 {
2327 if (currentspace != IntPtr.Zero)
2328 {
2329 if (d.GeomIsSpace(currentspace))
2330 {
2331 waitForSpaceUnlock(currentspace);
2332 waitForSpaceUnlock(space);
2333 d.SpaceRemove(space, currentspace);
2334 // free up memory used by the space.
2335
2336 //d.SpaceDestroy(currentspace);
2337 resetSpaceArrayItemToZero(currentspace);
2338 }
2339 else
2340 {
2341 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2342 currentspace + " Geom:" + geom);
2343 }
2344 }
2345 }
2346 }
2347 else
2348 {
2349 // this is a physical object that got disabled. ;.;
2350 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2351 {
2352 if (d.SpaceQuery(currentspace, geom))
2353 {
2354 if (d.GeomIsSpace(currentspace))
2355 {
2356 waitForSpaceUnlock(currentspace);
2357 d.SpaceRemove(currentspace, geom);
2358 }
2359 else
2360 {
2361 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2362 currentspace + " Geom:" + geom);
2363 }
2364 }
2365 else
2366 {
2367 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2368 if (sGeomIsIn != IntPtr.Zero)
2369 {
2370 if (d.GeomIsSpace(sGeomIsIn))
2371 {
2372 waitForSpaceUnlock(sGeomIsIn);
2373 d.SpaceRemove(sGeomIsIn, geom);
2374 }
2375 else
2376 {
2377 m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
2378 sGeomIsIn + " Geom:" + geom);
2379 }
2380 }
2381 }
2382 }
2383 }
2384
2385 // The routines in the Position and Size sections do the 'inserting' into the space,
2386 // so all we have to do is make sure that the space that we're putting the prim into
2387 // is in the 'main' space.
2388 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2389 IntPtr newspace = calculateSpaceForGeom(pos);
2390
2391 if (newspace == IntPtr.Zero)
2392 {
2393 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2394 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2395 }
2396
2397 return newspace;
2398 }
2399
2400 /// <summary>
2401 /// Creates a new space at X Y
2402 /// </summary>
2403 /// <param name="iprimspaceArrItemX"></param>
2404 /// <param name="iprimspaceArrItemY"></param>
2405 /// <returns>A pointer to the created space</returns>
2406 public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2407 {
2408 // creating a new space for prim and inserting it into main space.
2409 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2410 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2411 waitForSpaceUnlock(space);
2412 d.SpaceSetSublevel(space, 1);
2413 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2414 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2415 }
2416
2417 /// <summary>
2418 /// Calculates the space the prim should be in by its position
2419 /// </summary>
2420 /// <param name="pos"></param>
2421 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2422 public IntPtr calculateSpaceForGeom(Vector3 pos)
2423 {
2424 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2425 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2426 return staticPrimspace[xyspace[0], xyspace[1]];
2427 }
2428
2429 /// <summary>
2430 /// Holds the space allocation logic
2431 /// </summary>
2432 /// <param name="pos"></param>
2433 /// <returns>an array item based on the position</returns>
2434 public int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2435 {
2436 int[] returnint = new int[2];
2437
2438 returnint[0] = (int) (pos.X/metersInSpace);
2439
2440 if (returnint[0] > ((int) (259f/metersInSpace)))
2441 returnint[0] = ((int) (259f/metersInSpace));
2442 if (returnint[0] < 0)
2443 returnint[0] = 0;
2444
2445 returnint[1] = (int) (pos.Y/metersInSpace);
2446 if (returnint[1] > ((int) (259f/metersInSpace)))
2447 returnint[1] = ((int) (259f/metersInSpace));
2448 if (returnint[1] < 0)
2449 returnint[1] = 0;
2450
2451 return returnint;
2452 }
2453
2454 #endregion
2455
2456 /// <summary>
2457 /// Routine to figure out if we need to mesh this prim with our mesher
2458 /// </summary>
2459 /// <param name="pbs"></param>
2460 /// <returns></returns>
2461 public bool needsMeshing(PrimitiveBaseShape pbs)
2462 {
2463 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2464 // but we still need to check for sculptie meshing being enabled so this is the most
2465 // convenient place to do it for now...
2466
2467 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2468 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2469 int iPropertiesNotSupportedDefault = 0;
2470
2471 if (pbs.SculptEntry && !meshSculptedPrim)
2472 {
2473#if SPAM
2474 m_log.Warn("NonMesh");
2475#endif
2476 return false;
2477 }
2478
2479 // 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
2480 if (!forceSimplePrimMeshing)
2481 {
2482 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2483 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2484 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2485 {
2486
2487 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2488 && pbs.ProfileHollow == 0
2489 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2490 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2491 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2492 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2493 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2494 {
2495#if SPAM
2496 m_log.Warn("NonMesh");
2497#endif
2498 return false;
2499 }
2500 }
2501 }
2502
2503 if (pbs.ProfileHollow != 0)
2504 iPropertiesNotSupportedDefault++;
2505
2506 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2507 iPropertiesNotSupportedDefault++;
2508
2509 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2510 iPropertiesNotSupportedDefault++;
2511
2512 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2513 iPropertiesNotSupportedDefault++;
2514
2515 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2516 iPropertiesNotSupportedDefault++;
2517
2518 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2519 iPropertiesNotSupportedDefault++;
2520
2521 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))
2522 iPropertiesNotSupportedDefault++;
2523
2524 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2525 iPropertiesNotSupportedDefault++;
2526
2527 // test for torus
2528 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2529 {
2530 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2531 {
2532 iPropertiesNotSupportedDefault++;
2533 }
2534 }
2535 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2536 {
2537 if (pbs.PathCurve == (byte)Extrusion.Straight)
2538 {
2539 iPropertiesNotSupportedDefault++;
2540 }
2541
2542 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2543 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2544 {
2545 iPropertiesNotSupportedDefault++;
2546 }
2547 }
2548 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2549 {
2550 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2551 {
2552 iPropertiesNotSupportedDefault++;
2553 }
2554 }
2555 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2556 {
2557 if (pbs.PathCurve == (byte)Extrusion.Straight)
2558 {
2559 iPropertiesNotSupportedDefault++;
2560 }
2561 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2562 {
2563 iPropertiesNotSupportedDefault++;
2564 }
2565 }
2566
2567
2568 if (iPropertiesNotSupportedDefault == 0)
2569 {
2570#if SPAM
2571 m_log.Warn("NonMesh");
2572#endif
2573 return false;
2574 }
2575#if SPAM
2576 m_log.Debug("Mesh");
2577#endif
2578 return true;
2579 }
2580
2581 /// <summary>
2582 /// Called after our prim properties are set Scale, position etc.
2583 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2584 /// This assures us that we have no race conditions
2585 /// </summary>
2586 /// <param name="prim"></param>
2587 public override void AddPhysicsActorTaint(PhysicsActor prim)
2588 {
2589
2590 if (prim is OdePrim)
2591 {
2592 OdePrim taintedprim = ((OdePrim) prim);
2593 lock (_taintedPrimLock)
2594 {
2595 if (!(_taintedPrimH.Contains(taintedprim)))
2596 {
2597//Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.m_primName);
2598 _taintedPrimH.Add(taintedprim); // HashSet for searching
2599 _taintedPrimL.Add(taintedprim); // List for ordered readout
2600 }
2601 }
2602 return;
2603 }
2604 else if (prim is OdeCharacter)
2605 {
2606 OdeCharacter taintedchar = ((OdeCharacter)prim);
2607 lock (_taintedActors)
2608 {
2609 if (!(_taintedActors.Contains(taintedchar)))
2610 {
2611 _taintedActors.Add(taintedchar);
2612 if (taintedchar.bad)
2613 m_log.DebugFormat("[PHYSICS]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2614 }
2615 }
2616 }
2617 }
2618
2619 /// <summary>
2620 /// This is our main simulate loop
2621 /// It's thread locked by a Mutex in the scene.
2622 /// It holds Collisions, it instructs ODE to step through the physical reactions
2623 /// It moves the objects around in memory
2624 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2625 /// </summary>
2626 /// <param name="timeStep"></param>
2627 /// <returns></returns>
2628 public override float Simulate(float timeStep)
2629 {
2630 if (framecount >= int.MaxValue)
2631 framecount = 0;
2632 //if (m_worldOffset != Vector3.Zero)
2633 // return 0;
2634
2635 framecount++;
2636
2637 DateTime now = DateTime.UtcNow;
2638 TimeSpan SinceLastFrame = now - m_lastframe;
2639 m_lastframe = now;
2640 float realtime = (float)SinceLastFrame.TotalSeconds;
2641// Console.WriteLine("ts={0} rt={1}", timeStep, realtime);
2642 timeStep = realtime;
2643
2644 // float fps = 1.0f / realtime;
2645 float fps = 0.0f; // number of ODE steps in this Simulate step
2646 //m_log.Info(timeStep.ToString());
2647 step_time += timeStep;
2648
2649 // If We're loaded down by something else,
2650 // or debugging with the Visual Studio project on pause
2651 // skip a few frames to catch up gracefully.
2652 // without shooting the physicsactors all over the place
2653
2654 if (step_time >= m_SkipFramesAtms)
2655 {
2656 // Instead of trying to catch up, it'll do 5 physics frames only
2657 step_time = ODE_STEPSIZE;
2658 m_physicsiterations = 5;
2659 }
2660 else
2661 {
2662 m_physicsiterations = 10;
2663 }
2664
2665 if (SupportsNINJAJoints)
2666 {
2667 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2668 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2669 }
2670
2671 lock (OdeLock)
2672 {
2673 // Process 10 frames if the sim is running normal..
2674 // process 5 frames if the sim is running slow
2675 //try
2676 //{
2677 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
2678 //}
2679 //catch (StackOverflowException)
2680 //{
2681 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
2682 // ode.drelease(world);
2683 //base.TriggerPhysicsBasedRestart();
2684 //}
2685
2686 int i = 0;
2687
2688 // Figure out the Frames Per Second we're going at.
2689 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
2690
2691 // fps = (step_time / ODE_STEPSIZE) * 1000;
2692 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
2693 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
2694
2695 // step_time = 0.09375f;
2696
2697 while (step_time > 0.0f)
2698 {
2699 //lock (ode)
2700 //{
2701 //if (!ode.lockquery())
2702 //{
2703 // ode.dlock(world);
2704 try
2705 {
2706 // Insert, remove Characters
2707 bool processedtaints = false;
2708
2709 lock (_taintedActors)
2710 {
2711 if (_taintedActors.Count > 0)
2712 {
2713 foreach (OdeCharacter character in _taintedActors)
2714 {
2715
2716 character.ProcessTaints(ODE_STEPSIZE);
2717
2718 processedtaints = true;
2719 //character.m_collisionscore = 0;
2720 }
2721
2722 if (processedtaints)
2723 _taintedActors.Clear();
2724 }
2725 } // end lock _taintedActors
2726
2727 // Modify other objects in the scene.
2728 processedtaints = false;
2729
2730 lock (_taintedPrimLock)
2731 {
2732 foreach (OdePrim prim in _taintedPrimL)
2733 {
2734 if (prim.m_taintremove)
2735 {
2736 //Console.WriteLine("Simulate calls RemovePrimThreadLocked");
2737 RemovePrimThreadLocked(prim);
2738 }
2739 else
2740 {
2741 //Console.WriteLine("Simulate calls ProcessTaints");
2742 prim.ProcessTaints(ODE_STEPSIZE);
2743 }
2744 processedtaints = true;
2745 prim.m_collisionscore = 0;
2746
2747 // This loop can block up the Heartbeat for a very long time on large regions.
2748 // We need to let the Watchdog know that the Heartbeat is not dead
2749 // NOTE: This is currently commented out, but if things like OAR loading are
2750 // timing the heartbeat out we will need to uncomment it
2751 //Watchdog.UpdateThread();
2752 }
2753
2754 if (SupportsNINJAJoints)
2755 {
2756 // Create pending joints, if possible
2757
2758 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
2759 // a joint requires specifying the body id of both involved bodies
2760 if (pendingJoints.Count > 0)
2761 {
2762 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
2763 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
2764 foreach (PhysicsJoint joint in pendingJoints)
2765 {
2766 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
2767 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(),
2768 System.StringSplitOptions.RemoveEmptyEntries);
2769 List<IntPtr> jointBodies = new List<IntPtr>();
2770 bool allJointBodiesAreReady = true;
2771 foreach (string jointParam in jointParams)
2772 {
2773 if (jointParam == "NULL")
2774 {
2775 //DoJointErrorMessage(joint, "attaching NULL joint to world");
2776 jointBodies.Add(IntPtr.Zero);
2777 }
2778 else
2779 {
2780 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
2781 bool foundPrim = false;
2782 lock (_prims)
2783 {
2784 foreach (OdePrim prim in _prims) // FIXME: inefficient
2785 {
2786 if (prim.SOPName == jointParam)
2787 {
2788 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
2789 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
2790 {
2791 jointBodies.Add(prim.Body);
2792 foundPrim = true;
2793 break;
2794 }
2795 else
2796 {
2797 DoJointErrorMessage(joint, "prim name " + jointParam +
2798 " exists but is not (yet) physical; deferring joint creation. " +
2799 "IsPhysical property is " + prim.IsPhysical +
2800 " and body is " + prim.Body);
2801 foundPrim = false;
2802 break;
2803 }
2804 }
2805 }
2806 }
2807 if (foundPrim)
2808 {
2809 // all is fine
2810 }
2811 else
2812 {
2813 allJointBodiesAreReady = false;
2814 break;
2815 }
2816 }
2817 }
2818 if (allJointBodiesAreReady)
2819 {
2820 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
2821 if (jointBodies[0] == jointBodies[1])
2822 {
2823 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
2824 }
2825 else
2826 {
2827 switch (joint.Type)
2828 {
2829 case PhysicsJointType.Ball:
2830 {
2831 IntPtr odeJoint;
2832 //DoJointErrorMessage(joint, "ODE creating ball joint ");
2833 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
2834 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2835 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2836 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
2837 d.JointSetBallAnchor(odeJoint,
2838 joint.Position.X,
2839 joint.Position.Y,
2840 joint.Position.Z);
2841 //DoJointErrorMessage(joint, "ODE joint setting OK");
2842 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
2843 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
2844 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
2845 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
2846
2847 if (joint is OdePhysicsJoint)
2848 {
2849 ((OdePhysicsJoint)joint).jointID = odeJoint;
2850 }
2851 else
2852 {
2853 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2854 }
2855 }
2856 break;
2857 case PhysicsJointType.Hinge:
2858 {
2859 IntPtr odeJoint;
2860 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
2861 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
2862 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
2863 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
2864 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
2865 d.JointSetHingeAnchor(odeJoint,
2866 joint.Position.X,
2867 joint.Position.Y,
2868 joint.Position.Z);
2869 // We use the orientation of the x-axis of the joint's coordinate frame
2870 // as the axis for the hinge.
2871
2872 // Therefore, we must get the joint's coordinate frame based on the
2873 // joint.Rotation field, which originates from the orientation of the
2874 // joint's proxy object in the scene.
2875
2876 // The joint's coordinate frame is defined as the transformation matrix
2877 // that converts a vector from joint-local coordinates into world coordinates.
2878 // World coordinates are defined as the XYZ coordinate system of the sim,
2879 // as shown in the top status-bar of the viewer.
2880
2881 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
2882 // and use that as the hinge axis.
2883
2884 //joint.Rotation.Normalize();
2885 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
2886
2887 // Now extract the X axis of the joint's coordinate frame.
2888
2889 // Do not try to use proxyFrame.AtAxis or you will become mired in the
2890 // tar pit of transposed, inverted, and generally messed-up orientations.
2891 // (In other words, Matrix4.AtAxis() is borked.)
2892 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
2893
2894 // Instead, compute the X axis of the coordinate frame by transforming
2895 // the (1,0,0) vector. At least that works.
2896
2897 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
2898 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
2899 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
2900 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
2901 d.JointSetHingeAxis(odeJoint,
2902 jointAxis.X,
2903 jointAxis.Y,
2904 jointAxis.Z);
2905 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
2906 if (joint is OdePhysicsJoint)
2907 {
2908 ((OdePhysicsJoint)joint).jointID = odeJoint;
2909 }
2910 else
2911 {
2912 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
2913 }
2914 }
2915 break;
2916 }
2917 successfullyProcessedPendingJoints.Add(joint);
2918 }
2919 }
2920 else
2921 {
2922 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
2923 }
2924 }
2925 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
2926 {
2927 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
2928 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
2929 InternalRemovePendingJoint(successfullyProcessedJoint);
2930 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
2931 InternalAddActiveJoint(successfullyProcessedJoint);
2932 //DoJointErrorMessage(successfullyProcessedJoint, "done");
2933 }
2934 }
2935 } // end SupportsNINJAJoints
2936
2937 if (processedtaints)
2938//Console.WriteLine("Simulate calls Clear of _taintedPrim list");
2939 _taintedPrimH.Clear(); // ??? if this only ???
2940 _taintedPrimL.Clear();
2941 } // end lock _taintedPrimLock
2942
2943 // Move characters
2944 lock (_characters)
2945 {
2946 List<OdeCharacter> defects = new List<OdeCharacter>();
2947 foreach (OdeCharacter actor in _characters)
2948 {
2949 if (actor != null)
2950 actor.Move(ODE_STEPSIZE, defects);
2951 }
2952 if (0 != defects.Count)
2953 {
2954 foreach (OdeCharacter defect in defects)
2955 {
2956 RemoveCharacter(defect);
2957 }
2958 }
2959 } // end lock _characters
2960
2961 // Move other active objects
2962 lock (_activeprims)
2963 {
2964 foreach (OdePrim prim in _activeprims)
2965 {
2966 prim.m_collisionscore = 0;
2967 prim.Move(ODE_STEPSIZE);
2968 }
2969 } // end lock _activeprims
2970
2971 //if ((framecount % m_randomizeWater) == 0)
2972 // randomizeWater(waterlevel);
2973
2974 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
2975 m_rayCastManager.ProcessQueuedRequests();
2976
2977 collision_optimized(ODE_STEPSIZE);
2978
2979 lock (_collisionEventPrim)
2980 {
2981 foreach (PhysicsActor obj in _collisionEventPrim)
2982 {
2983 if (obj == null)
2984 continue;
2985
2986 switch ((ActorTypes)obj.PhysicsActorType)
2987 {
2988 case ActorTypes.Agent:
2989 OdeCharacter cobj = (OdeCharacter)obj;
2990 cobj.AddCollisionFrameTime(100);
2991 cobj.SendCollisions();
2992 break;
2993 case ActorTypes.Prim:
2994 OdePrim pobj = (OdePrim)obj;
2995 pobj.SendCollisions();
2996 break;
2997 }
2998 }
2999 } // end lock _collisionEventPrim
3000
3001 //if (m_global_contactcount > 5)
3002 //{
3003 // m_log.DebugFormat("[PHYSICS]: Contacts:{0}", m_global_contactcount);
3004 //}
3005
3006 m_global_contactcount = 0;
3007
3008 d.WorldQuickStep(world, ODE_STEPSIZE);
3009 d.JointGroupEmpty(contactgroup);
3010 fps++;
3011 //ode.dunlock(world);
3012 } // end try
3013 catch (Exception e)
3014 {
3015 m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3016 ode.dunlock(world);
3017 }
3018
3019 step_time -= ODE_STEPSIZE;
3020 i++;
3021 //}
3022 //else
3023 //{
3024 //fps = 0;
3025 //}
3026 //}
3027 } // end while (step_time > 0.0f)
3028
3029 lock (_characters)
3030 {
3031 foreach (OdeCharacter actor in _characters)
3032 {
3033 if (actor != null)
3034 {
3035 if (actor.bad)
3036 m_log.WarnFormat("[PHYSICS]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3037 actor.UpdatePositionAndVelocity();
3038 }
3039 }
3040 }
3041
3042 lock (_badCharacter)
3043 {
3044 if (_badCharacter.Count > 0)
3045 {
3046 foreach (OdeCharacter chr in _badCharacter)
3047 {
3048 RemoveCharacter(chr);
3049 }
3050 _badCharacter.Clear();
3051 }
3052 }
3053
3054 lock (_activeprims)
3055 {
3056 //if (timeStep < 0.2f)
3057 {
3058 foreach (OdePrim actor in _activeprims)
3059 {
3060 if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
3061 {
3062 actor.UpdatePositionAndVelocity();
3063
3064 if (SupportsNINJAJoints)
3065 {
3066 // If an actor moved, move its joint proxy objects as well.
3067 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3068 // for this purpose but it is never called! So we just do the joint
3069 // movement code here.
3070
3071 if (actor.SOPName != null &&
3072 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3073 joints_connecting_actor[actor.SOPName] != null &&
3074 joints_connecting_actor[actor.SOPName].Count > 0)
3075 {
3076 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3077 {
3078 if (affectedJoint.IsInPhysicsEngine)
3079 {
3080 DoJointMoved(affectedJoint);
3081 }
3082 else
3083 {
3084 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);
3085 }
3086 }
3087 }
3088 }
3089 }
3090 }
3091 }
3092 } // end lock _activeprims
3093
3094 //DumpJointInfo();
3095
3096 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3097 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3098 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3099 if (physics_logging && (physics_logging_interval>0) && (framecount % physics_logging_interval == 0))
3100 {
3101 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3102 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3103
3104 if (physics_logging_append_existing_logfile)
3105 {
3106 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3107 TextWriter fwriter = File.AppendText(fname);
3108 fwriter.WriteLine(header);
3109 fwriter.Close();
3110 }
3111 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3112 }
3113 } // end lock OdeLock
3114
3115 return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter!
3116 } // end Simulate
3117
3118 public override void GetResults()
3119 {
3120 }
3121
3122 public override bool IsThreaded
3123 {
3124 // for now we won't be multithreaded
3125 get { return (false); }
3126 }
3127
3128 #region ODE Specific Terrain Fixes
3129 public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3130 {
3131 float[] returnarr = new float[262144];
3132 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3133
3134 // Filling out the array into its multi-dimensional components
3135 for (int y = 0; y < WorldExtents.Y; y++)
3136 {
3137 for (int x = 0; x < WorldExtents.X; x++)
3138 {
3139 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3140 }
3141 }
3142
3143 // Resize using Nearest Neighbour
3144
3145 // This particular way is quick but it only works on a multiple of the original
3146
3147 // The idea behind this method can be described with the following diagrams
3148 // second pass and third pass happen in the same loop really.. just separated
3149 // them to show what this does.
3150
3151 // First Pass
3152 // ResultArr:
3153 // 1,1,1,1,1,1
3154 // 1,1,1,1,1,1
3155 // 1,1,1,1,1,1
3156 // 1,1,1,1,1,1
3157 // 1,1,1,1,1,1
3158 // 1,1,1,1,1,1
3159
3160 // Second Pass
3161 // ResultArr2:
3162 // 1,,1,,1,,1,,1,,1,
3163 // ,,,,,,,,,,
3164 // 1,,1,,1,,1,,1,,1,
3165 // ,,,,,,,,,,
3166 // 1,,1,,1,,1,,1,,1,
3167 // ,,,,,,,,,,
3168 // 1,,1,,1,,1,,1,,1,
3169 // ,,,,,,,,,,
3170 // 1,,1,,1,,1,,1,,1,
3171 // ,,,,,,,,,,
3172 // 1,,1,,1,,1,,1,,1,
3173
3174 // Third pass fills in the blanks
3175 // ResultArr2:
3176 // 1,1,1,1,1,1,1,1,1,1,1,1
3177 // 1,1,1,1,1,1,1,1,1,1,1,1
3178 // 1,1,1,1,1,1,1,1,1,1,1,1
3179 // 1,1,1,1,1,1,1,1,1,1,1,1
3180 // 1,1,1,1,1,1,1,1,1,1,1,1
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
3188 // X,Y = .
3189 // X+1,y = ^
3190 // X,Y+1 = *
3191 // X+1,Y+1 = #
3192
3193 // Filling in like this;
3194 // .*
3195 // ^#
3196 // 1st .
3197 // 2nd *
3198 // 3rd ^
3199 // 4th #
3200 // on single loop.
3201
3202 float[,] resultarr2 = new float[512, 512];
3203 for (int y = 0; y < WorldExtents.Y; y++)
3204 {
3205 for (int x = 0; x < WorldExtents.X; x++)
3206 {
3207 resultarr2[y * 2, x * 2] = resultarr[y, x];
3208
3209 if (y < WorldExtents.Y)
3210 {
3211 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3212 }
3213 if (x < WorldExtents.X)
3214 {
3215 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3216 }
3217 if (x < WorldExtents.X && y < WorldExtents.Y)
3218 {
3219 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3220 }
3221 }
3222 }
3223
3224 //Flatten out the array
3225 int i = 0;
3226 for (int y = 0; y < 512; y++)
3227 {
3228 for (int x = 0; x < 512; x++)
3229 {
3230 if (resultarr2[y, x] <= 0)
3231 returnarr[i] = 0.0000001f;
3232 else
3233 returnarr[i] = resultarr2[y, x];
3234
3235 i++;
3236 }
3237 }
3238
3239 return returnarr;
3240 }
3241
3242 public float[] ResizeTerrain512Interpolation(float[] heightMap)
3243 {
3244 float[] returnarr = new float[262144];
3245 float[,] resultarr = new float[512,512];
3246
3247 // Filling out the array into its multi-dimensional components
3248 for (int y = 0; y < 256; y++)
3249 {
3250 for (int x = 0; x < 256; x++)
3251 {
3252 resultarr[y, x] = heightMap[y * 256 + x];
3253 }
3254 }
3255
3256 // Resize using interpolation
3257
3258 // This particular way is quick but it only works on a multiple of the original
3259
3260 // The idea behind this method can be described with the following diagrams
3261 // second pass and third pass happen in the same loop really.. just separated
3262 // them to show what this does.
3263
3264 // First Pass
3265 // ResultArr:
3266 // 1,1,1,1,1,1
3267 // 1,1,1,1,1,1
3268 // 1,1,1,1,1,1
3269 // 1,1,1,1,1,1
3270 // 1,1,1,1,1,1
3271 // 1,1,1,1,1,1
3272
3273 // Second Pass
3274 // ResultArr2:
3275 // 1,,1,,1,,1,,1,,1,
3276 // ,,,,,,,,,,
3277 // 1,,1,,1,,1,,1,,1,
3278 // ,,,,,,,,,,
3279 // 1,,1,,1,,1,,1,,1,
3280 // ,,,,,,,,,,
3281 // 1,,1,,1,,1,,1,,1,
3282 // ,,,,,,,,,,
3283 // 1,,1,,1,,1,,1,,1,
3284 // ,,,,,,,,,,
3285 // 1,,1,,1,,1,,1,,1,
3286
3287 // Third pass fills in the blanks
3288 // ResultArr2:
3289 // 1,1,1,1,1,1,1,1,1,1,1,1
3290 // 1,1,1,1,1,1,1,1,1,1,1,1
3291 // 1,1,1,1,1,1,1,1,1,1,1,1
3292 // 1,1,1,1,1,1,1,1,1,1,1,1
3293 // 1,1,1,1,1,1,1,1,1,1,1,1
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
3301 // X,Y = .
3302 // X+1,y = ^
3303 // X,Y+1 = *
3304 // X+1,Y+1 = #
3305
3306 // Filling in like this;
3307 // .*
3308 // ^#
3309 // 1st .
3310 // 2nd *
3311 // 3rd ^
3312 // 4th #
3313 // on single loop.
3314
3315 float[,] resultarr2 = new float[512,512];
3316 for (int y = 0; y < (int)Constants.RegionSize; y++)
3317 {
3318 for (int x = 0; x < (int)Constants.RegionSize; x++)
3319 {
3320 resultarr2[y*2, x*2] = resultarr[y, x];
3321
3322 if (y < (int)Constants.RegionSize)
3323 {
3324 if (y + 1 < (int)Constants.RegionSize)
3325 {
3326 if (x + 1 < (int)Constants.RegionSize)
3327 {
3328 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3329 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3330 }
3331 else
3332 {
3333 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3334 }
3335 }
3336 else
3337 {
3338 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3339 }
3340 }
3341 if (x < (int)Constants.RegionSize)
3342 {
3343 if (x + 1 < (int)Constants.RegionSize)
3344 {
3345 if (y + 1 < (int)Constants.RegionSize)
3346 {
3347 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3348 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3349 }
3350 else
3351 {
3352 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3353 }
3354 }
3355 else
3356 {
3357 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3358 }
3359 }
3360 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3361 {
3362 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3363 {
3364 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3365 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3366 }
3367 else
3368 {
3369 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3370 }
3371 }
3372 }
3373 }
3374 //Flatten out the array
3375 int i = 0;
3376 for (int y = 0; y < 512; y++)
3377 {
3378 for (int x = 0; x < 512; x++)
3379 {
3380 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3381 {
3382 m_log.Warn("[PHYSICS]: Non finite heightfield element detected. Setting it to 0");
3383 resultarr2[y, x] = 0;
3384 }
3385 returnarr[i] = resultarr2[y, x];
3386 i++;
3387 }
3388 }
3389
3390 return returnarr;
3391 }
3392
3393 #endregion
3394
3395 public override void SetTerrain(float[] heightMap)
3396 {
3397 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3398 {
3399 if (m_parentScene is OdeScene)
3400 {
3401 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3402 }
3403 }
3404 else
3405 {
3406 SetTerrain(heightMap, m_worldOffset);
3407 }
3408 }
3409
3410 public void SetTerrain(float[] heightMap, Vector3 pOffset)
3411 {
3412
3413 uint regionsize = (uint) Constants.RegionSize; // visible region size eg. 256(M)
3414
3415 uint heightmapWidth = regionsize + 1; // ODE map size 257 x 257 (Meters) (1 extra
3416 uint heightmapHeight = regionsize + 1;
3417
3418 uint heightmapWidthSamples = (uint)regionsize + 2; // Sample file size, 258 x 258 samples
3419 uint heightmapHeightSamples = (uint)regionsize + 2;
3420
3421 // Array of height samples for ODE
3422 float[] _heightmap;
3423 _heightmap = new float[(heightmapWidthSamples * heightmapHeightSamples)]; // loaded samples 258 x 258
3424
3425 // Other ODE parameters
3426 const float scale = 1.0f;
3427 const float offset = 0.0f;
3428 const float thickness = 2.0f; // Was 0.2f, Larger appears to prevent Av fall-through
3429 const int wrap = 0;
3430
3431 float hfmin = 2000f;
3432 float hfmax = -2000f;
3433 float minele = 0.0f; // Dont allow -ve heights
3434
3435 uint x = 0;
3436 uint y = 0;
3437 uint xx = 0;
3438 uint yy = 0;
3439
3440 // load the height samples array from the heightMap
3441 for ( x = 0; x < heightmapWidthSamples; x++) // 0 to 257
3442 {
3443 for ( y = 0; y < heightmapHeightSamples; y++) // 0 to 257
3444 {
3445 xx = x - 1;
3446 if (xx < 0) xx = 0;
3447 if (xx > (regionsize - 1)) xx = regionsize - 1;
3448
3449 yy = y - 1;
3450 if (yy < 0) yy = 0;
3451 if (yy > (regionsize - 1)) yy = regionsize - 1;
3452 // Input xx = 0 0 1 2 ..... 254 255 255 256 total in
3453 // Output x = 0 1 2 3 ..... 255 256 257 258 total out
3454 float val= heightMap[(yy * regionsize) + xx]; // input from heightMap, <0-255 * 256> <0-255>
3455 if (val < minele) val = minele;
3456 _heightmap[x * (regionsize + 2) + y] = val; // samples output to _heightmap, <0-257 * 258> <0-257>
3457 hfmin = (val < hfmin) ? val : hfmin;
3458 hfmax = (val > hfmax) ? val : hfmax;
3459 }
3460 }
3461
3462 lock (OdeLock)
3463 {
3464 IntPtr GroundGeom = IntPtr.Zero;
3465 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3466 {
3467 RegionTerrain.Remove(pOffset);
3468 if (GroundGeom != IntPtr.Zero)
3469 {
3470 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3471 {
3472 TerrainHeightFieldHeights.Remove(GroundGeom);
3473 }
3474 d.SpaceRemove(space, GroundGeom);
3475 d.GeomDestroy(GroundGeom);
3476 }
3477 }
3478 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3479 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3480 heightmapWidth, heightmapHeight, (int)heightmapWidthSamples,
3481 (int)heightmapHeightSamples, scale, offset, thickness, wrap);
3482 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3483 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3484 if (GroundGeom != IntPtr.Zero)
3485 {
3486 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3487 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3488 }
3489 geom_name_map[GroundGeom] = "Terrain";
3490
3491 d.Matrix3 R = new d.Matrix3();
3492
3493 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3494 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3495 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3496
3497 q1 = q1 * q2;
3498 //q1 = q1 * q3;
3499 Vector3 v3;
3500 float angle;
3501 q1.GetAxisAngle(out v3, out angle);
3502
3503 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3504 d.GeomSetRotation(GroundGeom, ref R);
3505 d.GeomSetPosition(GroundGeom, (pOffset.X + (regionsize * 0.5f)) - 0.5f, (pOffset.Y + (regionsize * 0.5f)) - 0.5f, 0);
3506 IntPtr testGround = IntPtr.Zero;
3507 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3508 {
3509 RegionTerrain.Remove(pOffset);
3510 }
3511 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3512 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3513 }
3514 }
3515
3516 public override void DeleteTerrain()
3517 {
3518 }
3519
3520 public float GetWaterLevel()
3521 {
3522 return waterlevel;
3523 }
3524
3525 public override bool SupportsCombining()
3526 {
3527 return true;
3528 }
3529
3530 public override void UnCombine(PhysicsScene pScene)
3531 {
3532 IntPtr localGround = IntPtr.Zero;
3533// float[] localHeightfield;
3534 bool proceed = false;
3535 List<IntPtr> geomDestroyList = new List<IntPtr>();
3536
3537 lock (OdeLock)
3538 {
3539 if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3540 {
3541 foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3542 {
3543 if (geom == localGround)
3544 {
3545// localHeightfield = TerrainHeightFieldHeights[geom];
3546 proceed = true;
3547 }
3548 else
3549 {
3550 geomDestroyList.Add(geom);
3551 }
3552 }
3553
3554 if (proceed)
3555 {
3556 m_worldOffset = Vector3.Zero;
3557 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3558 m_parentScene = null;
3559
3560 foreach (IntPtr g in geomDestroyList)
3561 {
3562 // removingHeightField needs to be done or the garbage collector will
3563 // collect the terrain data before we tell ODE to destroy it causing
3564 // memory corruption
3565 if (TerrainHeightFieldHeights.ContainsKey(g))
3566 {
3567// float[] removingHeightField = TerrainHeightFieldHeights[g];
3568 TerrainHeightFieldHeights.Remove(g);
3569
3570 if (RegionTerrain.ContainsKey(g))
3571 {
3572 RegionTerrain.Remove(g);
3573 }
3574
3575 d.GeomDestroy(g);
3576 //removingHeightField = new float[0];
3577 }
3578 }
3579
3580 }
3581 else
3582 {
3583 m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3584
3585 }
3586 }
3587 }
3588 }
3589
3590 public override void SetWaterLevel(float baseheight)
3591 {
3592 waterlevel = baseheight;
3593 randomizeWater(waterlevel);
3594 }
3595
3596 public void randomizeWater(float baseheight)
3597 {
3598 const uint heightmapWidth = m_regionWidth + 2;
3599 const uint heightmapHeight = m_regionHeight + 2;
3600 const uint heightmapWidthSamples = m_regionWidth + 2;
3601 const uint heightmapHeightSamples = m_regionHeight + 2;
3602 const float scale = 1.0f;
3603 const float offset = 0.0f;
3604 const float thickness = 2.9f;
3605 const int wrap = 0;
3606
3607 for (int i = 0; i < (258 * 258); i++)
3608 {
3609 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3610 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3611 }
3612
3613 lock (OdeLock)
3614 {
3615 if (WaterGeom != IntPtr.Zero)
3616 {
3617 d.SpaceRemove(space, WaterGeom);
3618 }
3619 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3620 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3621 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3622 offset, thickness, wrap);
3623 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3624 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3625 if (WaterGeom != IntPtr.Zero)
3626 {
3627 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3628 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3629
3630 }
3631 geom_name_map[WaterGeom] = "Water";
3632
3633 d.Matrix3 R = new d.Matrix3();
3634
3635 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3636 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3637 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3638
3639 q1 = q1 * q2;
3640 //q1 = q1 * q3;
3641 Vector3 v3;
3642 float angle;
3643 q1.GetAxisAngle(out v3, out angle);
3644
3645 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3646 d.GeomSetRotation(WaterGeom, ref R);
3647 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3648
3649 }
3650
3651 }
3652
3653 public override void Dispose()
3654 {
3655 m_rayCastManager.Dispose();
3656 m_rayCastManager = null;
3657
3658 lock (OdeLock)
3659 {
3660 lock (_prims)
3661 {
3662 foreach (OdePrim prm in _prims)
3663 {
3664 RemovePrim(prm);
3665 }
3666 }
3667
3668 //foreach (OdeCharacter act in _characters)
3669 //{
3670 //RemoveAvatar(act);
3671 //}
3672 d.WorldDestroy(world);
3673 //d.CloseODE();
3674 }
3675 }
3676 public override Dictionary<uint, float> GetTopColliders()
3677 {
3678 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
3679 int cnt = 0;
3680 lock (_prims)
3681 {
3682 foreach (OdePrim prm in _prims)
3683 {
3684 if (prm.CollisionScore > 0)
3685 {
3686 returncolliders.Add(prm.m_localID, prm.CollisionScore);
3687 cnt++;
3688 prm.CollisionScore = 0f;
3689 if (cnt > 25)
3690 {
3691 break;
3692 }
3693 }
3694 }
3695 }
3696 return returncolliders;
3697 }
3698
3699 public override bool SupportsRayCast()
3700 {
3701 return true;
3702 }
3703
3704 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3705 {
3706 if (retMethod != null)
3707 {
3708 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3709 }
3710 }
3711
3712#if USE_DRAWSTUFF
3713 // Keyboard callback
3714 public void command(int cmd)
3715 {
3716 IntPtr geom;
3717 d.Mass mass;
3718 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3719
3720
3721
3722 Char ch = Char.ToLower((Char)cmd);
3723 switch ((Char)ch)
3724 {
3725 case 'w':
3726 try
3727 {
3728 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));
3729
3730 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3731 ds.SetViewpoint(ref xyz, ref hpr);
3732 }
3733 catch (ArgumentException)
3734 { hpr.X = 0; }
3735 break;
3736
3737 case 'a':
3738 hpr.X++;
3739 ds.SetViewpoint(ref xyz, ref hpr);
3740 break;
3741
3742 case 's':
3743 try
3744 {
3745 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));
3746
3747 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3748 ds.SetViewpoint(ref xyz, ref hpr);
3749 }
3750 catch (ArgumentException)
3751 { hpr.X = 0; }
3752 break;
3753 case 'd':
3754 hpr.X--;
3755 ds.SetViewpoint(ref xyz, ref hpr);
3756 break;
3757 case 'r':
3758 xyz.Z++;
3759 ds.SetViewpoint(ref xyz, ref hpr);
3760 break;
3761 case 'f':
3762 xyz.Z--;
3763 ds.SetViewpoint(ref xyz, ref hpr);
3764 break;
3765 case 'e':
3766 xyz.Y++;
3767 ds.SetViewpoint(ref xyz, ref hpr);
3768 break;
3769 case 'q':
3770 xyz.Y--;
3771 ds.SetViewpoint(ref xyz, ref hpr);
3772 break;
3773 }
3774 }
3775
3776 public void step(int pause)
3777 {
3778
3779 ds.SetColor(1.0f, 1.0f, 0.0f);
3780 ds.SetTexture(ds.Texture.Wood);
3781 lock (_prims)
3782 {
3783 foreach (OdePrim prm in _prims)
3784 {
3785 //IntPtr body = d.GeomGetBody(prm.prim_geom);
3786 if (prm.prim_geom != IntPtr.Zero)
3787 {
3788 d.Vector3 pos;
3789 d.GeomCopyPosition(prm.prim_geom, out pos);
3790 //d.BodyCopyPosition(body, out pos);
3791
3792 d.Matrix3 R;
3793 d.GeomCopyRotation(prm.prim_geom, out R);
3794 //d.BodyCopyRotation(body, out R);
3795
3796
3797 d.Vector3 sides = new d.Vector3();
3798 sides.X = prm.Size.X;
3799 sides.Y = prm.Size.Y;
3800 sides.Z = prm.Size.Z;
3801
3802 ds.DrawBox(ref pos, ref R, ref sides);
3803 }
3804 }
3805 }
3806 ds.SetColor(1.0f, 0.0f, 0.0f);
3807 lock (_characters)
3808 {
3809 foreach (OdeCharacter chr in _characters)
3810 {
3811 if (chr.Shell != IntPtr.Zero)
3812 {
3813 IntPtr body = d.GeomGetBody(chr.Shell);
3814
3815 d.Vector3 pos;
3816 d.GeomCopyPosition(chr.Shell, out pos);
3817 //d.BodyCopyPosition(body, out pos);
3818
3819 d.Matrix3 R;
3820 d.GeomCopyRotation(chr.Shell, out R);
3821 //d.BodyCopyRotation(body, out R);
3822
3823 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
3824 d.Vector3 sides = new d.Vector3();
3825 sides.X = 0.5f;
3826 sides.Y = 0.5f;
3827 sides.Z = 0.5f;
3828
3829 ds.DrawBox(ref pos, ref R, ref sides);
3830 }
3831 }
3832 }
3833 }
3834
3835 public void start(int unused)
3836 {
3837 ds.SetViewpoint(ref xyz, ref hpr);
3838 }
3839#endif
3840 }
3841}
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/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 2a6163c..514d9ad 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -122,6 +122,9 @@ namespace OpenSim.Region.Physics.Manager
122 /// <param name="prim"></param> 122 /// <param name="prim"></param>
123 public abstract void RemovePrim(PhysicsActor prim); 123 public abstract void RemovePrim(PhysicsActor prim);
124 124
125 //public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
126 // Vector3 size, Quaternion rotation); //To be removed - Actually removed!
127
125 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, 128 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
126 Vector3 size, Quaternion rotation, bool isPhysical, uint localid); 129 Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
127 130
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index 75364b7..62e3763 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -595,8 +595,8 @@ namespace OpenSim.Region.Physics.OdePlugin
595 break; 595 break;
596 596
597 case HollowShape.Circle: 597 case HollowShape.Circle:
598 // Hollow shape is a perfect cyllinder in respect to the cube's scale 598 // Hollow shape is a perfect cylinder in respect to the cube's scale
599 // Cyllinder hollow volume calculation 599 // Cylinder hollow volume calculation
600 600
601 hollowVolume *= 0.1963495f * 3.07920140172638f; 601 hollowVolume *= 0.1963495f * 3.07920140172638f;
602 break; 602 break;
@@ -2837,7 +2837,7 @@ Console.WriteLine(" JointCreateFixed");
2837 } 2837 }
2838 public override bool PIDActive { set { m_usePID = value; } } 2838 public override bool PIDActive { set { m_usePID = value; } }
2839 public override float PIDTau { set { m_PIDTau = value; } } 2839 public override float PIDTau { set { m_PIDTau = value; } }
2840 2840
2841 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } } 2841 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
2842 public override bool PIDHoverActive { set { m_useHoverPID = value; } } 2842 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
2843 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } } 2843 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
index 8d7d3b3..7e3ec63 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
@@ -137,8 +137,15 @@ namespace OpenSim.Region.Physics.OdePlugin
137 ODERayCastRequest[] reqs = m_PendingRequests.ToArray(); 137 ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
138 for (int i = 0; i < reqs.Length; i++) 138 for (int i = 0; i < reqs.Length; i++)
139 { 139 {
140 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast 140 try
141 RayCast(reqs[i]); // if there isn't anyone to send results 141 {
142 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
143 RayCast(reqs[i]); // if there isn't anyone to send results
144 }
145 catch
146 {
147 //Fail silently
148 }
142 } 149 }
143 150
144 m_PendingRequests.Clear(); 151 m_PendingRequests.Clear();
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
index e4fd7eb..2ea8bfc 100644
--- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
+++ b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
@@ -297,7 +297,7 @@ namespace OpenSim.Region.Physics.POSPlugin
297 { 297 {
298 set { return; } 298 set { return; }
299 } 299 }
300 300
301 public override Quaternion APIDTarget 301 public override Quaternion APIDTarget
302 { 302 {
303 set { return; } 303 set { return; }
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 09da97a..3c36943 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -89,89 +89,7 @@ namespace OpenSim.Region.RegionCombinerModule
89 public void RegionLoaded(Scene scene) 89 public void RegionLoaded(Scene scene)
90 { 90 {
91 if (enabledYN) 91 if (enabledYN)
92 {
93 RegionLoadedDoWork(scene); 92 RegionLoadedDoWork(scene);
94
95 scene.EventManager.OnNewPresence += NewPresence;
96 }
97 }
98
99 private void NewPresence(ScenePresence presence)
100 {
101 if (presence.IsChildAgent)
102 {
103 byte[] throttleData;
104
105 try
106 {
107 throttleData = presence.ControllingClient.GetThrottlesPacked(1);
108 }
109 catch (NotImplementedException)
110 {
111 return;
112 }
113
114 if (throttleData == null)
115 return;
116
117 if (throttleData.Length == 0)
118 return;
119
120 if (throttleData.Length != 28)
121 return;
122
123 byte[] adjData;
124 int pos = 0;
125
126 if (!BitConverter.IsLittleEndian)
127 {
128 byte[] newData = new byte[7 * 4];
129 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
130
131 for (int i = 0; i < 7; i++)
132 Array.Reverse(newData, i * 4, 4);
133
134 adjData = newData;
135 }
136 else
137 {
138 adjData = throttleData;
139 }
140
141 // 0.125f converts from bits to bytes
142 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
143 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
144 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
145 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
146 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
147 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
148 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
149 // State is a subcategory of task that we allocate a percentage to
150
151
152 //int total = resend + land + wind + cloud + task + texture + asset;
153
154 byte[] data = new byte[7 * 4];
155 int ii = 0;
156
157 Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4;
158 Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4;
159 Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4;
160 Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4;
161 Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4;
162 Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4;
163 Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4);
164
165 try
166 {
167 presence.ControllingClient.SetChildAgentThrottle(data);
168 }
169 catch (NotImplementedException)
170 {
171 return;
172 }
173
174 }
175 } 93 }
176 94
177 private void RegionLoadedDoWork(Scene scene) 95 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 0bdd84a..b0b1b16 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -28,10 +28,12 @@
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;
34using System.Text.RegularExpressions; 35using System.Text.RegularExpressions;
36using System.Timers;
35using Nini.Config; 37using Nini.Config;
36using log4net; 38using log4net;
37using OpenMetaverse; 39using OpenMetaverse;
@@ -44,6 +46,7 @@ using OpenSim.Region.CoreModules.World.Land;
44using OpenSim.Region.CoreModules.World.Terrain; 46using OpenSim.Region.CoreModules.World.Terrain;
45using OpenSim.Region.Framework.Interfaces; 47using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Region.Framework.Scenes; 48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Framework.Scenes.Serialization;
47using OpenSim.Region.Framework.Scenes.Animation; 50using OpenSim.Region.Framework.Scenes.Animation;
48using OpenSim.Region.Physics.Manager; 51using OpenSim.Region.Physics.Manager;
49using OpenSim.Region.ScriptEngine.Shared; 52using OpenSim.Region.ScriptEngine.Shared;
@@ -65,6 +68,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
65using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; 68using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
66using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; 69using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
67using System.Reflection; 70using System.Reflection;
71using Timer = System.Timers.Timer;
68 72
69namespace OpenSim.Region.ScriptEngine.Shared.Api 73namespace OpenSim.Region.ScriptEngine.Shared.Api
70{ 74{
@@ -99,16 +103,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
99 protected int m_notecardLineReadCharsMax = 255; 103 protected int m_notecardLineReadCharsMax = 255;
100 protected int m_scriptConsoleChannel = 0; 104 protected int m_scriptConsoleChannel = 0;
101 protected bool m_scriptConsoleChannelEnabled = false; 105 protected bool m_scriptConsoleChannelEnabled = false;
106 protected bool m_debuggerSafe = false;
102 protected IUrlModule m_UrlModule = null; 107 protected IUrlModule m_UrlModule = null;
103 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache = 108 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache =
104 new Dictionary<UUID, UserInfoCacheEntry>(); 109 new Dictionary<UUID, UserInfoCacheEntry>();
105 110
111 protected Timer m_ShoutSayTimer;
112 protected int m_SayShoutCount = 0;
113
106 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) 114 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
107 { 115 {
116 m_ShoutSayTimer = new Timer(1000);
117 m_ShoutSayTimer.Elapsed += SayShoutTimerElapsed;
118 m_ShoutSayTimer.AutoReset = true;
119 m_ShoutSayTimer.Start();
120
108 m_ScriptEngine = ScriptEngine; 121 m_ScriptEngine = ScriptEngine;
109 m_host = host; 122 m_host = host;
110 m_localID = localID; 123 m_localID = localID;
111 m_itemID = itemID; 124 m_itemID = itemID;
125 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
112 126
113 m_ScriptDelayFactor = 127 m_ScriptDelayFactor =
114 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); 128 m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f);
@@ -156,6 +170,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
156 get { return m_ScriptEngine.World; } 170 get { return m_ScriptEngine.World; }
157 } 171 }
158 172
173 [DebuggerNonUserCode]
159 public void state(string newState) 174 public void state(string newState)
160 { 175 {
161 m_ScriptEngine.SetState(m_itemID, newState); 176 m_ScriptEngine.SetState(m_itemID, newState);
@@ -165,6 +180,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
165 /// Reset the named script. The script must be present 180 /// Reset the named script. The script must be present
166 /// in the same prim. 181 /// in the same prim.
167 /// </summary> 182 /// </summary>
183 [DebuggerNonUserCode]
168 public void llResetScript() 184 public void llResetScript()
169 { 185 {
170 m_host.AddScriptLPS(1); 186 m_host.AddScriptLPS(1);
@@ -221,9 +237,62 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
221 } 237 }
222 } 238 }
223 239
240 public List<ScenePresence> GetLinkAvatars(int linkType)
241 {
242 List<ScenePresence> ret = new List<ScenePresence>();
243 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
244 return ret;
245
246 List<ScenePresence> avs = m_host.ParentGroup.GetLinkedAvatars();
247
248 switch (linkType)
249 {
250 case ScriptBaseClass.LINK_SET:
251 return avs;
252
253 case ScriptBaseClass.LINK_ROOT:
254 return ret;
255
256 case ScriptBaseClass.LINK_ALL_OTHERS:
257 return avs;
258
259 case ScriptBaseClass.LINK_ALL_CHILDREN:
260 return avs;
261
262 case ScriptBaseClass.LINK_THIS:
263 return ret;
264
265 default:
266 if (linkType < 0)
267 return ret;
268
269 int partCount = m_host.ParentGroup.GetPartCount();
270
271 if (linkType <= partCount)
272 {
273 return ret;
274 }
275 else
276 {
277 linkType = linkType - partCount;
278 if (linkType > avs.Count)
279 {
280 return ret;
281 }
282 else
283 {
284 ret.Add(avs[linkType-1]);
285 return ret;
286 }
287 }
288 }
289 }
290
224 public List<SceneObjectPart> GetLinkParts(int linkType) 291 public List<SceneObjectPart> GetLinkParts(int linkType)
225 { 292 {
226 List<SceneObjectPart> ret = new List<SceneObjectPart>(); 293 List<SceneObjectPart> ret = new List<SceneObjectPart>();
294 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
295 return ret;
227 ret.Add(m_host); 296 ret.Add(m_host);
228 297
229 switch (linkType) 298 switch (linkType)
@@ -270,40 +339,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
270 protected UUID InventorySelf() 339 protected UUID InventorySelf()
271 { 340 {
272 UUID invItemID = new UUID(); 341 UUID invItemID = new UUID();
273 342 bool unlock = false;
274 lock (m_host.TaskInventory) 343 if (!m_host.TaskInventory.IsReadLockedByMe())
275 { 344 {
276 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 345 m_host.TaskInventory.LockItemsForRead(true);
346 unlock = true;
347 }
348 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
349 {
350 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
277 { 351 {
278 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID) 352 invItemID = inv.Key;
279 { 353 break;
280 invItemID = inv.Key;
281 break;
282 }
283 } 354 }
284 } 355 }
285 356 if (unlock)
357 {
358 m_host.TaskInventory.LockItemsForRead(false);
359 }
286 return invItemID; 360 return invItemID;
287 } 361 }
288 362
289 protected UUID InventoryKey(string name, int type) 363 protected UUID InventoryKey(string name, int type)
290 { 364 {
291 m_host.AddScriptLPS(1); 365 m_host.AddScriptLPS(1);
292 366 m_host.TaskInventory.LockItemsForRead(true);
293 lock (m_host.TaskInventory) 367
368 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
294 { 369 {
295 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 370 if (inv.Value.Name == name)
296 { 371 {
297 if (inv.Value.Name == name) 372 m_host.TaskInventory.LockItemsForRead(false);
373
374 if (inv.Value.Type != type)
298 { 375 {
299 if (inv.Value.Type != type) 376 return UUID.Zero;
300 return UUID.Zero;
301
302 return inv.Value.AssetID;
303 } 377 }
378
379 return inv.Value.AssetID;
304 } 380 }
305 } 381 }
306 382
383 m_host.TaskInventory.LockItemsForRead(false);
307 return UUID.Zero; 384 return UUID.Zero;
308 } 385 }
309 386
@@ -311,17 +388,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
311 { 388 {
312 m_host.AddScriptLPS(1); 389 m_host.AddScriptLPS(1);
313 390
314 lock (m_host.TaskInventory) 391
392 m_host.TaskInventory.LockItemsForRead(true);
393
394 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
315 { 395 {
316 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 396 if (inv.Value.Name == name)
317 { 397 {
318 if (inv.Value.Name == name) 398 m_host.TaskInventory.LockItemsForRead(false);
319 { 399 return inv.Value.AssetID;
320 return inv.Value.AssetID;
321 }
322 } 400 }
323 } 401 }
324 402
403 m_host.TaskInventory.LockItemsForRead(false);
404
405
325 return UUID.Zero; 406 return UUID.Zero;
326 } 407 }
327 408
@@ -463,31 +544,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
463 544
464 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke 545 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
465 546
466 /// <summary> 547 // Utility function for llRot2Euler
467 /// Convert an LSL rotation to a Euler vector. 548
468 /// </summary> 549 // normalize an angle between -PI and PI (-180 to +180 degrees)
469 /// <remarks> 550 protected double NormalizeAngle(double angle)
470 /// Using algorithm based off http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/quat_2_euler_paper_ver2-1.pdf
471 /// to avoid issues with singularity and rounding with Y rotation of +/- PI/2
472 /// </remarks>
473 /// <param name="r"></param>
474 /// <returns></returns>
475 public LSL_Vector llRot2Euler(LSL_Rotation r)
476 { 551 {
477 m_host.AddScriptLPS(1); 552 if (angle > -Math.PI && angle < Math.PI)
553 return angle;
554
555 int numPis = (int)(Math.PI / angle);
556 double remainder = angle - Math.PI * numPis;
557 if (numPis % 2 == 1)
558 return Math.PI - angle;
559 return remainder;
560 }
478 561
479 LSL_Vector v = new LSL_Vector(0.0, 0.0, 1.0) * r; // Z axis unit vector unaffected by Z rotation component of r. 562 public LSL_Vector llRot2Euler(LSL_Rotation q1)
480 double m = LSL_Vector.Mag(v); // Just in case v isn't normalized, need magnitude for Asin() operation later. 563 {
481 if (m == 0.0) return new LSL_Vector(); 564 m_host.AddScriptLPS(1);
482 double x = Math.Atan2(-v.y, v.z); 565 LSL_Vector eul = new LSL_Vector();
483 double sin = v.x / m;
484 if (sin < -0.999999 || sin > 0.999999) x = 0.0; // Force X rotation to 0 at the singularities.
485 double y = Math.Asin(sin);
486 // Rotate X axis unit vector by r and unwind the X and Y rotations leaving only the Z rotation
487 v = new LSL_Vector(1.0, 0.0, 0.0) * ((r * new LSL_Rotation(Math.Sin(-x / 2.0), 0.0, 0.0, Math.Cos(-x / 2.0))) * new LSL_Rotation(0.0, Math.Sin(-y / 2.0), 0.0, Math.Cos(-y / 2.0)));
488 double z = Math.Atan2(v.y, v.x);
489 566
490 return new LSL_Vector(x, y, z); 567 double sqw = q1.s*q1.s;
568 double sqx = q1.x*q1.x;
569 double sqy = q1.z*q1.z;
570 double sqz = q1.y*q1.y;
571 double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
572 double test = q1.x*q1.z + q1.y*q1.s;
573 if (test > 0.4999*unit) { // singularity at north pole
574 eul.z = 2 * Math.Atan2(q1.x,q1.s);
575 eul.y = Math.PI/2;
576 eul.x = 0;
577 return eul;
578 }
579 if (test < -0.4999*unit) { // singularity at south pole
580 eul.z = -2 * Math.Atan2(q1.x,q1.s);
581 eul.y = -Math.PI/2;
582 eul.x = 0;
583 return eul;
584 }
585 eul.z = Math.Atan2(2*q1.z*q1.s-2*q1.x*q1.y , sqx - sqy - sqz + sqw);
586 eul.y = Math.Asin(2*test/unit);
587 eul.x = Math.Atan2(2*q1.x*q1.s-2*q1.z*q1.y , -sqx + sqy - sqz + sqw);
588 return eul;
491 } 589 }
492 590
493 /* From wiki: 591 /* From wiki:
@@ -689,77 +787,76 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
689 { 787 {
690 //A and B should both be normalized 788 //A and B should both be normalized
691 m_host.AddScriptLPS(1); 789 m_host.AddScriptLPS(1);
692 LSL_Rotation rotBetween; 790 /* This method is more accurate than the SL one, and thus causes problems
693 // Check for zero vectors. If either is zero, return zero rotation. Otherwise, 791 for scripts that deal with the SL inaccuracy around 180-degrees -.- .._.
694 // continue calculation. 792
695 if (a == new LSL_Vector(0.0f, 0.0f, 0.0f) || b == new LSL_Vector(0.0f, 0.0f, 0.0f)) 793 double dotProduct = LSL_Vector.Dot(a, b);
794 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
795 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
796 double angle = Math.Acos(dotProduct / magProduct);
797 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
798 double s = Math.Sin(angle / 2);
799
800 double x = axis.x * s;
801 double y = axis.y * s;
802 double z = axis.z * s;
803 double w = Math.Cos(angle / 2);
804
805 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
806 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
807
808 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
809 */
810
811 // This method mimics the 180 errors found in SL
812 // See www.euclideanspace.com... angleBetween
813 LSL_Vector vec_a = a;
814 LSL_Vector vec_b = b;
815
816 // Eliminate zero length
817 LSL_Float vec_a_mag = LSL_Vector.Mag(vec_a);
818 LSL_Float vec_b_mag = LSL_Vector.Mag(vec_b);
819 if (vec_a_mag < 0.00001 ||
820 vec_b_mag < 0.00001)
696 { 821 {
697 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f); 822 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
698 } 823 }
699 else 824
825 // Normalize
826 vec_a = llVecNorm(vec_a);
827 vec_b = llVecNorm(vec_b);
828
829 // Calculate axis and rotation angle
830 LSL_Vector axis = vec_a % vec_b;
831 LSL_Float cos_theta = vec_a * vec_b;
832
833 // Check if parallel
834 if (cos_theta > 0.99999)
700 { 835 {
701 a = LSL_Vector.Norm(a); 836 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
702 b = LSL_Vector.Norm(b); 837 }
703 double dotProduct = LSL_Vector.Dot(a, b); 838
704 // There are two degenerate cases possible. These are for vectors 180 or 839 // Check if anti-parallel
705 // 0 degrees apart. These have to be detected and handled individually. 840 else if (cos_theta < -0.99999)
706 // 841 {
707 // Check for vectors 180 degrees apart. 842 LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (vec_a.x / (vec_a * vec_a) * vec_a);
708 // A dot product of -1 would mean the angle between vectors is 180 degrees. 843 if (LSL_Vector.Mag(orthog_axis) < 0.000001) orthog_axis = new LSL_Vector(0.0, 0.0, 1.0);
709 if (dotProduct < -0.9999999f) 844 return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0);
710 { 845 }
711 // First assume X axis is orthogonal to the vectors. 846 else // other rotation
712 LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f); 847 {
713 orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a)); 848 LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f;
714 // Check for near zero vector. A very small non-zero number here will create 849 axis = llVecNorm(axis);
715 // a rotation in an undesired direction. 850 double x, y, z, s, t;
716 if (LSL_Vector.Mag(orthoVector) > 0.0001) 851 s = Math.Cos(theta);
717 { 852 t = Math.Sin(theta);
718 rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f); 853 x = axis.x * t;
719 } 854 y = axis.y * t;
720 // If the magnitude of the vector was near zero, then assume the X axis is not 855 z = axis.z * t;
721 // orthogonal and use the Z axis instead. 856 return new LSL_Rotation(x,y,z,s);
722 else
723 {
724 // Set 180 z rotation.
725 rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f);
726 }
727 }
728 // Check for parallel vectors.
729 // A dot product of 1 would mean the angle between vectors is 0 degrees.
730 else if (dotProduct > 0.9999999f)
731 {
732 // Set zero rotation.
733 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
734 }
735 else
736 {
737 // All special checks have been performed so get the axis of rotation.
738 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
739 // Quarternion s value is the length of the unit vector + dot product.
740 double qs = 1.0 + dotProduct;
741 rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs);
742 // Normalize the rotation.
743 double mag = LSL_Rotation.Mag(rotBetween);
744 // We shouldn't have to worry about a divide by zero here. The qs value will be
745 // non-zero because we already know if we're here, then the dotProduct is not -1 so
746 // qs will not be zero. Also, we've already handled the input vectors being zero so the
747 // crossProduct vector should also not be zero.
748 rotBetween.x = rotBetween.x / mag;
749 rotBetween.y = rotBetween.y / mag;
750 rotBetween.z = rotBetween.z / mag;
751 rotBetween.s = rotBetween.s / mag;
752 // Check for undefined values and set zero rotation if any found. This code might not actually be required
753 // any longer since zero vectors are checked for at the top.
754 if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s))
755 {
756 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
757 }
758 }
759 } 857 }
760 return rotBetween;
761 } 858 }
762 859
763 public void llWhisper(int channelID, string text) 860 public void llWhisper(int channelID, string text)
764 { 861 {
765 m_host.AddScriptLPS(1); 862 m_host.AddScriptLPS(1);
@@ -779,6 +876,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
779 { 876 {
780 m_host.AddScriptLPS(1); 877 m_host.AddScriptLPS(1);
781 878
879 if (channelID == 0)
880 m_SayShoutCount++;
881
882 if (m_SayShoutCount >= 11)
883 ScriptSleep(2000);
884
782 if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel)) 885 if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel))
783 { 886 {
784 Console.WriteLine(text); 887 Console.WriteLine(text);
@@ -801,6 +904,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
801 { 904 {
802 m_host.AddScriptLPS(1); 905 m_host.AddScriptLPS(1);
803 906
907 if (channelID == 0)
908 m_SayShoutCount++;
909
910 if (m_SayShoutCount >= 11)
911 ScriptSleep(2000);
912
804 if (text.Length > 1023) 913 if (text.Length > 1023)
805 text = text.Substring(0, 1023); 914 text = text.Substring(0, 1023);
806 915
@@ -1101,10 +1210,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1101 return detectedParams.TouchUV; 1210 return detectedParams.TouchUV;
1102 } 1211 }
1103 1212
1213 [DebuggerNonUserCode]
1104 public virtual void llDie() 1214 public virtual void llDie()
1105 { 1215 {
1106 m_host.AddScriptLPS(1); 1216 m_host.AddScriptLPS(1);
1107 throw new SelfDeleteException(); 1217 if (!m_host.ParentGroup.IsAttachment) throw new SelfDeleteException();
1108 } 1218 }
1109 1219
1110 public LSL_Float llGround(LSL_Vector offset) 1220 public LSL_Float llGround(LSL_Vector offset)
@@ -1177,6 +1287,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1177 1287
1178 public void llSetStatus(int status, int value) 1288 public void llSetStatus(int status, int value)
1179 { 1289 {
1290 if (m_host == null || m_host.ParentGroup == null || m_host.ParentGroup.IsDeleted)
1291 return;
1180 m_host.AddScriptLPS(1); 1292 m_host.AddScriptLPS(1);
1181 1293
1182 int statusrotationaxis = 0; 1294 int statusrotationaxis = 0;
@@ -1406,6 +1518,48 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1406 { 1518 {
1407 m_host.AddScriptLPS(1); 1519 m_host.AddScriptLPS(1);
1408 1520
1521 SetColor(m_host, color, face);
1522 }
1523
1524 protected void SetColor(SceneObjectPart part, LSL_Vector color, int face)
1525 {
1526 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1527 return;
1528
1529 Primitive.TextureEntry tex = part.Shape.Textures;
1530 Color4 texcolor;
1531 if (face >= 0 && face < GetNumberOfSides(part))
1532 {
1533 texcolor = tex.CreateFace((uint)face).RGBA;
1534 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1535 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1536 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1537 tex.FaceTextures[face].RGBA = texcolor;
1538 part.UpdateTextureEntry(tex.GetBytes());
1539 return;
1540 }
1541 else if (face == ScriptBaseClass.ALL_SIDES)
1542 {
1543 for (uint i = 0; i < GetNumberOfSides(part); i++)
1544 {
1545 if (tex.FaceTextures[i] != null)
1546 {
1547 texcolor = tex.FaceTextures[i].RGBA;
1548 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1549 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1550 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1551 tex.FaceTextures[i].RGBA = texcolor;
1552 }
1553 texcolor = tex.DefaultTexture.RGBA;
1554 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1555 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1556 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1557 tex.DefaultTexture.RGBA = texcolor;
1558 }
1559 part.UpdateTextureEntry(tex.GetBytes());
1560 return;
1561 }
1562
1409 if (face == ScriptBaseClass.ALL_SIDES) 1563 if (face == ScriptBaseClass.ALL_SIDES)
1410 face = SceneObjectPart.ALL_SIDES; 1564 face = SceneObjectPart.ALL_SIDES;
1411 1565
@@ -1414,6 +1568,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1414 1568
1415 public void SetTexGen(SceneObjectPart part, int face,int style) 1569 public void SetTexGen(SceneObjectPart part, int face,int style)
1416 { 1570 {
1571 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1572 return;
1573
1417 Primitive.TextureEntry tex = part.Shape.Textures; 1574 Primitive.TextureEntry tex = part.Shape.Textures;
1418 MappingType textype; 1575 MappingType textype;
1419 textype = MappingType.Default; 1576 textype = MappingType.Default;
@@ -1444,6 +1601,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1444 1601
1445 public void SetGlow(SceneObjectPart part, int face, float glow) 1602 public void SetGlow(SceneObjectPart part, int face, float glow)
1446 { 1603 {
1604 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1605 return;
1606
1447 Primitive.TextureEntry tex = part.Shape.Textures; 1607 Primitive.TextureEntry tex = part.Shape.Textures;
1448 if (face >= 0 && face < GetNumberOfSides(part)) 1608 if (face >= 0 && face < GetNumberOfSides(part))
1449 { 1609 {
@@ -1469,6 +1629,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1469 1629
1470 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump) 1630 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1471 { 1631 {
1632 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1633 return;
1472 1634
1473 Shininess sval = new Shininess(); 1635 Shininess sval = new Shininess();
1474 1636
@@ -1519,6 +1681,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1519 1681
1520 public void SetFullBright(SceneObjectPart part, int face, bool bright) 1682 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1521 { 1683 {
1684 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1685 return;
1686
1522 Primitive.TextureEntry tex = part.Shape.Textures; 1687 Primitive.TextureEntry tex = part.Shape.Textures;
1523 if (face >= 0 && face < GetNumberOfSides(part)) 1688 if (face >= 0 && face < GetNumberOfSides(part))
1524 { 1689 {
@@ -1579,13 +1744,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1579 m_host.AddScriptLPS(1); 1744 m_host.AddScriptLPS(1);
1580 1745
1581 List<SceneObjectPart> parts = GetLinkParts(linknumber); 1746 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1582 1747 if (parts.Count > 0)
1583 foreach (SceneObjectPart part in parts) 1748 {
1584 SetAlpha(part, alpha, face); 1749 try
1750 {
1751 parts[0].ParentGroup.areUpdatesSuspended = true;
1752 foreach (SceneObjectPart part in parts)
1753 SetAlpha(part, alpha, face);
1754 }
1755 finally
1756 {
1757 parts[0].ParentGroup.areUpdatesSuspended = false;
1758 }
1759 }
1585 } 1760 }
1586 1761
1587 protected void SetAlpha(SceneObjectPart part, double alpha, int face) 1762 protected void SetAlpha(SceneObjectPart part, double alpha, int face)
1588 { 1763 {
1764 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1765 return;
1766
1589 Primitive.TextureEntry tex = part.Shape.Textures; 1767 Primitive.TextureEntry tex = part.Shape.Textures;
1590 Color4 texcolor; 1768 Color4 texcolor;
1591 if (face >= 0 && face < GetNumberOfSides(part)) 1769 if (face >= 0 && face < GetNumberOfSides(part))
@@ -1638,7 +1816,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1638 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction, 1816 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1639 float wind, float tension, LSL_Vector Force) 1817 float wind, float tension, LSL_Vector Force)
1640 { 1818 {
1641 if (part == null) 1819 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1642 return; 1820 return;
1643 1821
1644 if (flexi) 1822 if (flexi)
@@ -1672,7 +1850,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1672 /// <param name="falloff"></param> 1850 /// <param name="falloff"></param>
1673 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff) 1851 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1674 { 1852 {
1675 if (part == null) 1853 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1676 return; 1854 return;
1677 1855
1678 if (light) 1856 if (light)
@@ -1749,15 +1927,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1749 m_host.AddScriptLPS(1); 1927 m_host.AddScriptLPS(1);
1750 1928
1751 List<SceneObjectPart> parts = GetLinkParts(linknumber); 1929 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1752 1930 if (parts.Count > 0)
1753 foreach (SceneObjectPart part in parts) 1931 {
1754 SetTexture(part, texture, face); 1932 try
1755 1933 {
1934 parts[0].ParentGroup.areUpdatesSuspended = true;
1935 foreach (SceneObjectPart part in parts)
1936 SetTexture(part, texture, face);
1937 }
1938 finally
1939 {
1940 parts[0].ParentGroup.areUpdatesSuspended = false;
1941 }
1942 }
1756 ScriptSleep(200); 1943 ScriptSleep(200);
1757 } 1944 }
1758 1945
1759 protected void SetTexture(SceneObjectPart part, string texture, int face) 1946 protected void SetTexture(SceneObjectPart part, string texture, int face)
1760 { 1947 {
1948 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1949 return;
1950
1761 UUID textureID = new UUID(); 1951 UUID textureID = new UUID();
1762 1952
1763 textureID = InventoryKey(texture, (int)AssetType.Texture); 1953 textureID = InventoryKey(texture, (int)AssetType.Texture);
@@ -1802,6 +1992,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1802 1992
1803 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face) 1993 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1804 { 1994 {
1995 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1996 return;
1997
1805 Primitive.TextureEntry tex = part.Shape.Textures; 1998 Primitive.TextureEntry tex = part.Shape.Textures;
1806 if (face >= 0 && face < GetNumberOfSides(part)) 1999 if (face >= 0 && face < GetNumberOfSides(part))
1807 { 2000 {
@@ -1838,6 +2031,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1838 2031
1839 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face) 2032 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1840 { 2033 {
2034 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2035 return;
2036
1841 Primitive.TextureEntry tex = part.Shape.Textures; 2037 Primitive.TextureEntry tex = part.Shape.Textures;
1842 if (face >= 0 && face < GetNumberOfSides(part)) 2038 if (face >= 0 && face < GetNumberOfSides(part))
1843 { 2039 {
@@ -1874,6 +2070,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1874 2070
1875 protected void RotateTexture(SceneObjectPart part, double rotation, int face) 2071 protected void RotateTexture(SceneObjectPart part, double rotation, int face)
1876 { 2072 {
2073 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2074 return;
2075
1877 Primitive.TextureEntry tex = part.Shape.Textures; 2076 Primitive.TextureEntry tex = part.Shape.Textures;
1878 if (face >= 0 && face < GetNumberOfSides(part)) 2077 if (face >= 0 && face < GetNumberOfSides(part))
1879 { 2078 {
@@ -1980,24 +2179,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1980 2179
1981 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) 2180 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos)
1982 { 2181 {
1983 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) 2182 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
1984 LSL_Vector currentPos = GetPartLocalPos(part); 2183 return;
1985 2184
1986 float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y); 2185 LSL_Vector currentPos = GetPartLocalPos(part);
1987 bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true); 2186 LSL_Vector toPos = GetSetPosTarget(part, targetPos, currentPos);
1988 2187
1989 if (part.ParentGroup.RootPart == part) 2188 if (part.ParentGroup.RootPart == part)
1990 { 2189 {
1991 if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
1992 targetPos.z = ground;
1993 SceneObjectGroup parent = part.ParentGroup; 2190 SceneObjectGroup parent = part.ParentGroup;
1994 LSL_Vector real_vec = SetPosAdjust(currentPos, targetPos); 2191 parent.UpdateGroupPosition(new Vector3((float)toPos.x, (float)toPos.y, (float)toPos.z));
1995 parent.UpdateGroupPosition(new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z));
1996 } 2192 }
1997 else 2193 else
1998 { 2194 {
1999 LSL_Vector rel_vec = SetPosAdjust(currentPos, targetPos); 2195 part.OffsetPosition = new Vector3((float)toPos.x, (float)toPos.y, (float)toPos.z);
2000 part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z);
2001 SceneObjectGroup parent = part.ParentGroup; 2196 SceneObjectGroup parent = part.ParentGroup;
2002 parent.HasGroupChanged = true; 2197 parent.HasGroupChanged = true;
2003 parent.ScheduleGroupForTerseUpdate(); 2198 parent.ScheduleGroupForTerseUpdate();
@@ -2028,11 +2223,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2028 } 2223 }
2029 else 2224 else
2030 { 2225 {
2031 if (m_host.IsRoot) 2226 if (part.IsRoot)
2032 { 2227 {
2033 return new LSL_Vector(m_host.AttachedPos.X, 2228 return new LSL_Vector(part.AttachedPos.X,
2034 m_host.AttachedPos.Y, 2229 part.AttachedPos.Y,
2035 m_host.AttachedPos.Z); 2230 part.AttachedPos.Z);
2036 } 2231 }
2037 else 2232 else
2038 { 2233 {
@@ -2048,9 +2243,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2048 m_host.AddScriptLPS(1); 2243 m_host.AddScriptLPS(1);
2049 2244
2050 // try to let this work as in SL... 2245 // try to let this work as in SL...
2051 if (m_host.ParentID == 0) 2246 if (m_host.LinkNum < 2)
2052 { 2247 {
2053 // special case: If we are root, rotate complete SOG to new rotation 2248 // Special case: If we are root, rotate complete SOG to new
2249 // rotation.
2250 // We are root if the link number is 0 (single prim) or 1
2251 // (root prim). ParentID may be nonzero in attachments and
2252 // using it would cause attachments and HUDs to rotate
2253 // to the wrong positions.
2054 SetRot(m_host, Rot2Quaternion(rot)); 2254 SetRot(m_host, Rot2Quaternion(rot));
2055 } 2255 }
2056 else 2256 else
@@ -2075,6 +2275,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2075 2275
2076 protected void SetRot(SceneObjectPart part, Quaternion rot) 2276 protected void SetRot(SceneObjectPart part, Quaternion rot)
2077 { 2277 {
2278 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2279 return;
2280
2078 part.UpdateRotation(rot); 2281 part.UpdateRotation(rot);
2079 // Update rotation does not move the object in the physics scene if it's a linkset. 2282 // Update rotation does not move the object in the physics scene if it's a linkset.
2080 2283
@@ -2698,12 +2901,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2698 2901
2699 m_host.AddScriptLPS(1); 2902 m_host.AddScriptLPS(1);
2700 2903
2904 m_host.TaskInventory.LockItemsForRead(true);
2701 TaskInventoryItem item = m_host.TaskInventory[invItemID]; 2905 TaskInventoryItem item = m_host.TaskInventory[invItemID];
2702 2906 m_host.TaskInventory.LockItemsForRead(false);
2703 lock (m_host.TaskInventory)
2704 {
2705 item = m_host.TaskInventory[invItemID];
2706 }
2707 2907
2708 if (item.PermsGranter == UUID.Zero) 2908 if (item.PermsGranter == UUID.Zero)
2709 return 0; 2909 return 0;
@@ -2771,64 +2971,69 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2771 { 2971 {
2772 m_host.AddScriptLPS(1); 2972 m_host.AddScriptLPS(1);
2773 2973
2774 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s)) 2974 Util.FireAndForget(delegate (object x)
2775 return; 2975 {
2776 float dist = (float)llVecDist(llGetPos(), pos); 2976 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
2977 return;
2978 float dist = (float)llVecDist(llGetPos(), pos);
2777 2979
2778 if (dist > m_ScriptDistanceFactor * 10.0f) 2980 if (dist > m_ScriptDistanceFactor * 10.0f)
2779 return; 2981 return;
2780 2982
2781 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 2983 //Clone is thread-safe
2984 TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
2782 2985
2783 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory) 2986 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in partInventory)
2784 {
2785 if (inv.Value.Name == inventory)
2786 { 2987 {
2787 // make sure we're an object. 2988 if (inv.Value.Name == inventory)
2788 if (inv.Value.InvType != (int)InventoryType.Object)
2789 { 2989 {
2790 llSay(0, "Unable to create requested object. Object is missing from database."); 2990 // make sure we're an object.
2791 return; 2991 if (inv.Value.InvType != (int)InventoryType.Object)
2792 } 2992 {
2993 llSay(0, "Unable to create requested object. Object is missing from database.");
2994 return;
2995 }
2793 2996
2794 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); 2997 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
2795 Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z); 2998 Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z);
2796 2999
2797 // need the magnitude later 3000 // need the magnitude later
2798 float velmag = (float)Util.GetMagnitude(llvel); 3001 // float velmag = (float)Util.GetMagnitude(llvel);
2799 3002
2800 SceneObjectGroup new_group = World.RezObject(m_host, inv.Value, llpos, Rot2Quaternion(rot), llvel, param); 3003 SceneObjectGroup new_group = World.RezObject(m_host, inv.Value, llpos, Rot2Quaternion(rot), llvel, param);
2801 3004
2802 // If either of these are null, then there was an unknown error. 3005 // If either of these are null, then there was an unknown error.
2803 if (new_group == null) 3006 if (new_group == null)
2804 continue; 3007 continue;
2805 3008
2806 // objects rezzed with this method are die_at_edge by default. 3009 // objects rezzed with this method are die_at_edge by default.
2807 new_group.RootPart.SetDieAtEdge(true); 3010 new_group.RootPart.SetDieAtEdge(true);
2808 3011
2809 new_group.ResumeScripts(); 3012 new_group.ResumeScripts();
2810 3013
2811 m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( 3014 m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
2812 "object_rez", new Object[] { 3015 "object_rez", new Object[] {
2813 new LSL_String( 3016 new LSL_String(
2814 new_group.RootPart.UUID.ToString()) }, 3017 new_group.RootPart.UUID.ToString()) },
2815 new DetectParams[0])); 3018 new DetectParams[0]));
2816 3019
2817 float groupmass = new_group.GetMass(); 3020 float groupmass = new_group.GetMass();
2818 3021
2819 if (new_group.RootPart.PhysActor != null && new_group.RootPart.PhysActor.IsPhysical && llvel != Vector3.Zero) 3022 if (new_group.RootPart.PhysActor != null && new_group.RootPart.PhysActor.IsPhysical && llvel != Vector3.Zero)
2820 { 3023 {
2821 //Recoil. 3024 //Recoil.
2822 llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0); 3025 llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0);
3026 }
3027 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
3028 return;
2823 } 3029 }
2824 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
2825 ScriptSleep((int)((groupmass * velmag) / 10));
2826 ScriptSleep(100);
2827 return;
2828 } 3030 }
2829 }
2830 3031
2831 llSay(0, "Could not find object " + inventory); 3032 llSay(0, "Could not find object " + inventory);
3033 });
3034
3035 //ScriptSleep((int)((groupmass * velmag) / 10));
3036 ScriptSleep(100);
2832 } 3037 }
2833 3038
2834 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param) 3039 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
@@ -2839,34 +3044,39 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2839 public void llLookAt(LSL_Vector target, double strength, double damping) 3044 public void llLookAt(LSL_Vector target, double strength, double damping)
2840 { 3045 {
2841 m_host.AddScriptLPS(1); 3046 m_host.AddScriptLPS(1);
2842 // Determine where we are looking from
2843 LSL_Vector from = llGetPos();
2844 3047
2845 // Work out the normalised vector from the source to the target 3048 // Get the normalized vector to the target
2846 LSL_Vector delta = llVecNorm(target - from); 3049 LSL_Vector d1 = llVecNorm(target - llGetPos());
2847 LSL_Vector angle = new LSL_Vector(0,0,0);
2848 3050
2849 // Calculate the yaw 3051 // Get the bearing (yaw)
2850 // subtracting PI_BY_TWO is required to compensate for the odd SL co-ordinate system 3052 LSL_Vector a1 = new LSL_Vector(0,0,0);
2851 angle.x = llAtan2(delta.z, delta.y) - ScriptBaseClass.PI_BY_TWO; 3053 a1.z = llAtan2(d1.y, d1.x);
2852 3054
2853 // Calculate pitch 3055 // Get the elevation (pitch)
2854 angle.y = llAtan2(delta.x, llSqrt((delta.y * delta.y) + (delta.z * delta.z))); 3056 LSL_Vector a2 = new LSL_Vector(0,0,0);
3057 a2.y= -llAtan2(d1.z, llSqrt((d1.x * d1.x) + (d1.y * d1.y)));
2855 3058
2856 // we need to convert from a vector describing 3059 LSL_Rotation r1 = llEuler2Rot(a1);
2857 // the angles of rotation in radians into rotation value 3060 LSL_Rotation r2 = llEuler2Rot(a2);
3061 LSL_Rotation r3 = new LSL_Rotation(0.000000, 0.707107, 0.000000, 0.707107);
2858 3062
2859 LSL_Rotation rot = llEuler2Rot(angle); 3063 if (m_host.PhysActor == null || !m_host.PhysActor.IsPhysical)
2860
2861 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
2862 // set the rotation of the object, copy that behavior
2863 if (strength == 0 || m_host.PhysActor == null || !m_host.PhysActor.IsPhysical)
2864 { 3064 {
2865 llSetRot(rot); 3065 // Do nothing if either value is 0 (this has been checked in SL)
3066 if (strength <= 0.0 || damping <= 0.0)
3067 return;
3068
3069 llSetRot(r3 * r2 * r1);
2866 } 3070 }
2867 else 3071 else
2868 { 3072 {
2869 m_host.StartLookAt(Rot2Quaternion(rot), (float)strength, (float)damping); 3073 if (strength == 0)
3074 {
3075 llSetRot(r3 * r2 * r1);
3076 return;
3077 }
3078
3079 m_host.StartLookAt(Rot2Quaternion(r3 * r2 * r1), (float)strength, (float)damping);
2870 } 3080 }
2871 } 3081 }
2872 3082
@@ -2916,13 +3126,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2916 { 3126 {
2917 TaskInventoryItem item; 3127 TaskInventoryItem item;
2918 3128
2919 lock (m_host.TaskInventory) 3129 m_host.TaskInventory.LockItemsForRead(true);
3130 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2920 { 3131 {
2921 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3132 m_host.TaskInventory.LockItemsForRead(false);
2922 return; 3133 return;
2923 else 3134 }
2924 item = m_host.TaskInventory[InventorySelf()]; 3135 else
3136 {
3137 item = m_host.TaskInventory[InventorySelf()];
2925 } 3138 }
3139 m_host.TaskInventory.LockItemsForRead(false);
2926 3140
2927 if (item.PermsGranter != UUID.Zero) 3141 if (item.PermsGranter != UUID.Zero)
2928 { 3142 {
@@ -2944,13 +3158,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2944 { 3158 {
2945 TaskInventoryItem item; 3159 TaskInventoryItem item;
2946 3160
3161 m_host.TaskInventory.LockItemsForRead(true);
2947 lock (m_host.TaskInventory) 3162 lock (m_host.TaskInventory)
2948 { 3163 {
3164
2949 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3165 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3166 {
3167 m_host.TaskInventory.LockItemsForRead(false);
2950 return; 3168 return;
3169 }
2951 else 3170 else
3171 {
2952 item = m_host.TaskInventory[InventorySelf()]; 3172 item = m_host.TaskInventory[InventorySelf()];
3173 }
2953 } 3174 }
3175 m_host.TaskInventory.LockItemsForRead(false);
2954 3176
2955 m_host.AddScriptLPS(1); 3177 m_host.AddScriptLPS(1);
2956 3178
@@ -2982,19 +3204,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2982 { 3204 {
2983 m_host.AddScriptLPS(1); 3205 m_host.AddScriptLPS(1);
2984 3206
2985// if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
2986// return;
2987
2988 TaskInventoryItem item; 3207 TaskInventoryItem item;
2989 3208
2990 lock (m_host.TaskInventory) 3209 m_host.TaskInventory.LockItemsForRead(true);
3210
3211 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2991 { 3212 {
2992 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3213 m_host.TaskInventory.LockItemsForRead(false);
2993 return; 3214 return;
2994 else 3215 }
2995 item = m_host.TaskInventory[InventorySelf()]; 3216 else
3217 {
3218 item = m_host.TaskInventory[InventorySelf()];
2996 } 3219 }
2997 3220
3221 m_host.TaskInventory.LockItemsForRead(false);
3222
2998 if (item.PermsGranter != m_host.OwnerID) 3223 if (item.PermsGranter != m_host.OwnerID)
2999 return; 3224 return;
3000 3225
@@ -3019,13 +3244,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3019 3244
3020 TaskInventoryItem item; 3245 TaskInventoryItem item;
3021 3246
3022 lock (m_host.TaskInventory) 3247 m_host.TaskInventory.LockItemsForRead(true);
3248
3249 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3023 { 3250 {
3024 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3251 m_host.TaskInventory.LockItemsForRead(false);
3025 return; 3252 return;
3026 else
3027 item = m_host.TaskInventory[InventorySelf()];
3028 } 3253 }
3254 else
3255 {
3256 item = m_host.TaskInventory[InventorySelf()];
3257 }
3258 m_host.TaskInventory.LockItemsForRead(false);
3259
3029 3260
3030 if (item.PermsGranter != m_host.OwnerID) 3261 if (item.PermsGranter != m_host.OwnerID)
3031 return; 3262 return;
@@ -3072,6 +3303,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3072 3303
3073 public void llInstantMessage(string user, string message) 3304 public void llInstantMessage(string user, string message)
3074 { 3305 {
3306 UUID result;
3307 if (!UUID.TryParse(user, out result))
3308 {
3309 ShoutError("An invalid key was passed to llInstantMessage");
3310 ScriptSleep(2000);
3311 return;
3312 }
3313
3314
3075 m_host.AddScriptLPS(1); 3315 m_host.AddScriptLPS(1);
3076 3316
3077 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance. 3317 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
@@ -3086,14 +3326,34 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3086 UUID friendTransactionID = UUID.Random(); 3326 UUID friendTransactionID = UUID.Random();
3087 3327
3088 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID); 3328 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
3089 3329
3090 GridInstantMessage msg = new GridInstantMessage(); 3330 GridInstantMessage msg = new GridInstantMessage();
3091 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid; 3331 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
3092 msg.toAgentID = new Guid(user); // toAgentID.Guid; 3332 msg.toAgentID = new Guid(user); // toAgentID.Guid;
3093 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here 3333 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
3094// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message); 3334// m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
3095// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString()); 3335// m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
3096 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp; 3336// DateTime dt = DateTime.UtcNow;
3337//
3338// // Ticks from UtcNow, but make it look like local. Evil, huh?
3339// dt = DateTime.SpecifyKind(dt, DateTimeKind.Local);
3340//
3341// try
3342// {
3343// // Convert that to the PST timezone
3344// TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
3345// dt = TimeZoneInfo.ConvertTime(dt, timeZoneInfo);
3346// }
3347// catch
3348// {
3349// // No logging here, as it could be VERY spammy
3350// }
3351//
3352// // And make it look local again to fool the unix time util
3353// dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc);
3354
3355 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
3356
3097 //if (client != null) 3357 //if (client != null)
3098 //{ 3358 //{
3099 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName; 3359 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
@@ -3107,12 +3367,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3107 msg.message = message.Substring(0, 1024); 3367 msg.message = message.Substring(0, 1024);
3108 else 3368 else
3109 msg.message = message; 3369 msg.message = message;
3110 msg.dialog = (byte)19; // messgage from script ??? // dialog; 3370 msg.dialog = (byte)19; // MessageFromObject
3111 msg.fromGroup = false;// fromGroup; 3371 msg.fromGroup = false;// fromGroup;
3112 msg.offline = (byte)0; //offline; 3372 msg.offline = (byte)0; //offline;
3113 msg.ParentEstateID = 0; //ParentEstateID; 3373 msg.ParentEstateID = World.RegionInfo.EstateSettings.EstateID;
3114 msg.Position = new Vector3(m_host.AbsolutePosition); 3374 msg.Position = new Vector3(m_host.AbsolutePosition);
3115 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid; 3375 msg.RegionID = World.RegionInfo.RegionID.Guid;
3116 msg.binaryBucket 3376 msg.binaryBucket
3117 = Util.StringToBytes256( 3377 = Util.StringToBytes256(
3118 "{0}/{1}/{2}/{3}", 3378 "{0}/{1}/{2}/{3}",
@@ -3140,7 +3400,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3140 } 3400 }
3141 3401
3142 emailModule.SendEmail(m_host.UUID, address, subject, message); 3402 emailModule.SendEmail(m_host.UUID, address, subject, message);
3143 ScriptSleep(20000); 3403 ScriptSleep(15000);
3144 } 3404 }
3145 3405
3146 public void llGetNextEmail(string address, string subject) 3406 public void llGetNextEmail(string address, string subject)
@@ -3279,14 +3539,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3279 3539
3280 TaskInventoryItem item; 3540 TaskInventoryItem item;
3281 3541
3282 lock (m_host.TaskInventory) 3542 m_host.TaskInventory.LockItemsForRead(true);
3543 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3283 { 3544 {
3284 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3545 m_host.TaskInventory.LockItemsForRead(false);
3285 return; 3546 return;
3286 else
3287 item = m_host.TaskInventory[InventorySelf()];
3288 } 3547 }
3289 3548 else
3549 {
3550 item = m_host.TaskInventory[InventorySelf()];
3551 }
3552 m_host.TaskInventory.LockItemsForRead(false);
3290 if (item.PermsGranter == UUID.Zero) 3553 if (item.PermsGranter == UUID.Zero)
3291 return; 3554 return;
3292 3555
@@ -3316,13 +3579,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3316 3579
3317 TaskInventoryItem item; 3580 TaskInventoryItem item;
3318 3581
3319 lock (m_host.TaskInventory) 3582 m_host.TaskInventory.LockItemsForRead(true);
3583 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
3320 { 3584 {
3321 if (!m_host.TaskInventory.ContainsKey(InventorySelf())) 3585 m_host.TaskInventory.LockItemsForRead(false);
3322 return; 3586 return;
3323 else 3587 }
3324 item = m_host.TaskInventory[InventorySelf()]; 3588 else
3589 {
3590 item = m_host.TaskInventory[InventorySelf()];
3325 } 3591 }
3592 m_host.TaskInventory.LockItemsForRead(false);
3593
3326 3594
3327 if (item.PermsGranter == UUID.Zero) 3595 if (item.PermsGranter == UUID.Zero)
3328 return; 3596 return;
@@ -3389,10 +3657,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3389 3657
3390 TaskInventoryItem item; 3658 TaskInventoryItem item;
3391 3659
3392 lock (m_host.TaskInventory) 3660
3661 m_host.TaskInventory.LockItemsForRead(true);
3662 if (!m_host.TaskInventory.ContainsKey(invItemID))
3663 {
3664 m_host.TaskInventory.LockItemsForRead(false);
3665 return;
3666 }
3667 else
3393 { 3668 {
3394 item = m_host.TaskInventory[invItemID]; 3669 item = m_host.TaskInventory[invItemID];
3395 } 3670 }
3671 m_host.TaskInventory.LockItemsForRead(false);
3396 3672
3397 if (agentID == UUID.Zero || perm == 0) // Releasing permissions 3673 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
3398 { 3674 {
@@ -3420,15 +3696,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3420 int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS | 3696 int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
3421 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | 3697 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
3422 ScriptBaseClass.PERMISSION_CONTROL_CAMERA | 3698 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
3699 ScriptBaseClass.PERMISSION_TRACK_CAMERA |
3423 ScriptBaseClass.PERMISSION_ATTACH; 3700 ScriptBaseClass.PERMISSION_ATTACH;
3424 3701
3425 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3702 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3426 { 3703 {
3427 lock (m_host.TaskInventory) 3704 m_host.TaskInventory.LockItemsForWrite(true);
3428 { 3705 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3429 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3706 m_host.TaskInventory[invItemID].PermsMask = perm;
3430 m_host.TaskInventory[invItemID].PermsMask = perm; 3707 m_host.TaskInventory.LockItemsForWrite(false);
3431 }
3432 3708
3433 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3709 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3434 "run_time_permissions", new Object[] { 3710 "run_time_permissions", new Object[] {
@@ -3438,28 +3714,44 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3438 return; 3714 return;
3439 } 3715 }
3440 } 3716 }
3441 else if (m_host.SitTargetAvatar == agentID) // Sitting avatar 3717 else
3442 { 3718 {
3443 // When agent is sitting, certain permissions are implicit if requested from sitting agent 3719 bool sitting = false;
3444 int implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION | 3720 if (m_host.SitTargetAvatar == agentID)
3445 ScriptBaseClass.PERMISSION_CONTROL_CAMERA | 3721 {
3446 ScriptBaseClass.PERMISSION_TRACK_CAMERA | 3722 sitting = true;
3447 ScriptBaseClass.PERMISSION_TAKE_CONTROLS; 3723 }
3724 else
3725 {
3726 foreach (SceneObjectPart p in m_host.ParentGroup.Parts)
3727 {
3728 if (p.SitTargetAvatar == agentID)
3729 sitting = true;
3730 }
3731 }
3448 3732
3449 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms 3733 if (sitting)
3450 { 3734 {
3451 lock (m_host.TaskInventory) 3735 // When agent is sitting, certain permissions are implicit if requested from sitting agent
3736 int implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
3737 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
3738 ScriptBaseClass.PERMISSION_TRACK_CAMERA |
3739 ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
3740
3741 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3452 { 3742 {
3743 m_host.TaskInventory.LockItemsForWrite(true);
3453 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3744 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3454 m_host.TaskInventory[invItemID].PermsMask = perm; 3745 m_host.TaskInventory[invItemID].PermsMask = perm;
3455 } 3746 m_host.TaskInventory.LockItemsForWrite(false);
3456 3747
3457 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3748 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3458 "run_time_permissions", new Object[] { 3749 "run_time_permissions", new Object[] {
3459 new LSL_Integer(perm) }, 3750 new LSL_Integer(perm) },
3460 new DetectParams[0])); 3751 new DetectParams[0]));
3461 3752
3462 return; 3753 return;
3754 }
3463 } 3755 }
3464 } 3756 }
3465 3757
@@ -3473,11 +3765,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3473 3765
3474 if (!m_waitingForScriptAnswer) 3766 if (!m_waitingForScriptAnswer)
3475 { 3767 {
3476 lock (m_host.TaskInventory) 3768 m_host.TaskInventory.LockItemsForWrite(true);
3477 { 3769 m_host.TaskInventory[invItemID].PermsGranter = agentID;
3478 m_host.TaskInventory[invItemID].PermsGranter = agentID; 3770 m_host.TaskInventory[invItemID].PermsMask = 0;
3479 m_host.TaskInventory[invItemID].PermsMask = 0; 3771 m_host.TaskInventory.LockItemsForWrite(false);
3480 }
3481 3772
3482 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; 3773 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
3483 m_waitingForScriptAnswer=true; 3774 m_waitingForScriptAnswer=true;
@@ -3512,10 +3803,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3512 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) 3803 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3513 llReleaseControls(); 3804 llReleaseControls();
3514 3805
3515 lock (m_host.TaskInventory) 3806
3516 { 3807 m_host.TaskInventory.LockItemsForWrite(true);
3517 m_host.TaskInventory[invItemID].PermsMask = answer; 3808 m_host.TaskInventory[invItemID].PermsMask = answer;
3518 } 3809 m_host.TaskInventory.LockItemsForWrite(false);
3810
3519 3811
3520 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( 3812 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
3521 "run_time_permissions", new Object[] { 3813 "run_time_permissions", new Object[] {
@@ -3527,16 +3819,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3527 { 3819 {
3528 m_host.AddScriptLPS(1); 3820 m_host.AddScriptLPS(1);
3529 3821
3530 lock (m_host.TaskInventory) 3822 m_host.TaskInventory.LockItemsForRead(true);
3823
3824 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3531 { 3825 {
3532 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3826 if (item.Type == 10 && item.ItemID == m_itemID)
3533 { 3827 {
3534 if (item.Type == 10 && item.ItemID == m_itemID) 3828 m_host.TaskInventory.LockItemsForRead(false);
3535 { 3829 return item.PermsGranter.ToString();
3536 return item.PermsGranter.ToString();
3537 }
3538 } 3830 }
3539 } 3831 }
3832 m_host.TaskInventory.LockItemsForRead(false);
3540 3833
3541 return UUID.Zero.ToString(); 3834 return UUID.Zero.ToString();
3542 } 3835 }
@@ -3545,19 +3838,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3545 { 3838 {
3546 m_host.AddScriptLPS(1); 3839 m_host.AddScriptLPS(1);
3547 3840
3548 lock (m_host.TaskInventory) 3841 m_host.TaskInventory.LockItemsForRead(true);
3842
3843 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3549 { 3844 {
3550 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 3845 if (item.Type == 10 && item.ItemID == m_itemID)
3551 { 3846 {
3552 if (item.Type == 10 && item.ItemID == m_itemID) 3847 int perms = item.PermsMask;
3553 { 3848 if (m_automaticLinkPermission)
3554 int perms = item.PermsMask; 3849 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
3555 if (m_automaticLinkPermission) 3850 m_host.TaskInventory.LockItemsForRead(false);
3556 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; 3851 return perms;
3557 return perms;
3558 }
3559 } 3852 }
3560 } 3853 }
3854 m_host.TaskInventory.LockItemsForRead(false);
3561 3855
3562 return 0; 3856 return 0;
3563 } 3857 }
@@ -3579,9 +3873,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3579 public void llSetLinkColor(int linknumber, LSL_Vector color, int face) 3873 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
3580 { 3874 {
3581 List<SceneObjectPart> parts = GetLinkParts(linknumber); 3875 List<SceneObjectPart> parts = GetLinkParts(linknumber);
3582 3876 if (parts.Count > 0)
3583 foreach (SceneObjectPart part in parts) 3877 {
3584 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face); 3878 try
3879 {
3880 parts[0].ParentGroup.areUpdatesSuspended = true;
3881 foreach (SceneObjectPart part in parts)
3882 part.SetFaceColor(new Vector3((float)color.x, (float)color.y, (float)color.z), face);
3883 }
3884 finally
3885 {
3886 parts[0].ParentGroup.areUpdatesSuspended = false;
3887 }
3888 }
3585 } 3889 }
3586 3890
3587 public void llCreateLink(string target, int parent) 3891 public void llCreateLink(string target, int parent)
@@ -3594,11 +3898,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3594 return; 3898 return;
3595 3899
3596 TaskInventoryItem item; 3900 TaskInventoryItem item;
3597 lock (m_host.TaskInventory) 3901 m_host.TaskInventory.LockItemsForRead(true);
3598 { 3902 item = m_host.TaskInventory[invItemID];
3599 item = m_host.TaskInventory[invItemID]; 3903 m_host.TaskInventory.LockItemsForRead(false);
3600 } 3904
3601
3602 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3905 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3603 && !m_automaticLinkPermission) 3906 && !m_automaticLinkPermission)
3604 { 3907 {
@@ -3615,11 +3918,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3615 3918
3616 if (targetPart.ParentGroup.AttachmentPoint != 0) 3919 if (targetPart.ParentGroup.AttachmentPoint != 0)
3617 return; // Fail silently if attached 3920 return; // Fail silently if attached
3921
3922 if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID)
3923 return;
3924
3618 SceneObjectGroup parentPrim = null, childPrim = null; 3925 SceneObjectGroup parentPrim = null, childPrim = null;
3619 3926
3620 if (targetPart != null) 3927 if (targetPart != null)
3621 { 3928 {
3622 if (parent != 0) { 3929 if (parent != 0)
3930 {
3623 parentPrim = m_host.ParentGroup; 3931 parentPrim = m_host.ParentGroup;
3624 childPrim = targetPart.ParentGroup; 3932 childPrim = targetPart.ParentGroup;
3625 } 3933 }
@@ -3631,7 +3939,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3631 3939
3632 // Required for linking 3940 // Required for linking
3633 childPrim.RootPart.ClearUpdateSchedule(); 3941 childPrim.RootPart.ClearUpdateSchedule();
3634 parentPrim.LinkToGroup(childPrim); 3942 parentPrim.LinkToGroup(childPrim, true);
3635 } 3943 }
3636 3944
3637 parentPrim.TriggerScriptChangedEvent(Changed.LINK); 3945 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
@@ -3650,16 +3958,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3650 m_host.AddScriptLPS(1); 3958 m_host.AddScriptLPS(1);
3651 UUID invItemID = InventorySelf(); 3959 UUID invItemID = InventorySelf();
3652 3960
3653 lock (m_host.TaskInventory) 3961 m_host.TaskInventory.LockItemsForRead(true);
3654 {
3655 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 3962 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3656 && !m_automaticLinkPermission) 3963 && !m_automaticLinkPermission)
3657 { 3964 {
3658 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); 3965 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
3966 m_host.TaskInventory.LockItemsForRead(false);
3659 return; 3967 return;
3660 } 3968 }
3661 } 3969 m_host.TaskInventory.LockItemsForRead(false);
3662 3970
3663 if (linknum < ScriptBaseClass.LINK_THIS) 3971 if (linknum < ScriptBaseClass.LINK_THIS)
3664 return; 3972 return;
3665 3973
@@ -3698,10 +4006,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3698 // Restructuring Multiple Prims. 4006 // Restructuring Multiple Prims.
3699 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts); 4007 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3700 parts.Remove(parentPrim.RootPart); 4008 parts.Remove(parentPrim.RootPart);
3701 foreach (SceneObjectPart part in parts) 4009 if (parts.Count > 0)
3702 { 4010 {
3703 parentPrim.DelinkFromGroup(part.LocalId, true); 4011 try
4012 {
4013 parts[0].ParentGroup.areUpdatesSuspended = true;
4014 foreach (SceneObjectPart part in parts)
4015 {
4016 parentPrim.DelinkFromGroup(part.LocalId, true);
4017 }
4018 }
4019 finally
4020 {
4021 parts[0].ParentGroup.areUpdatesSuspended = false;
4022 }
3704 } 4023 }
4024
3705 parentPrim.HasGroupChanged = true; 4025 parentPrim.HasGroupChanged = true;
3706 parentPrim.ScheduleGroupForFullUpdate(); 4026 parentPrim.ScheduleGroupForFullUpdate();
3707 parentPrim.TriggerScriptChangedEvent(Changed.LINK); 4027 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
@@ -3710,12 +4030,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3710 { 4030 {
3711 SceneObjectPart newRoot = parts[0]; 4031 SceneObjectPart newRoot = parts[0];
3712 parts.Remove(newRoot); 4032 parts.Remove(newRoot);
3713 foreach (SceneObjectPart part in parts) 4033
4034 try
3714 { 4035 {
3715 // Required for linking 4036 parts[0].ParentGroup.areUpdatesSuspended = true;
3716 part.ClearUpdateSchedule(); 4037 foreach (SceneObjectPart part in parts)
3717 newRoot.ParentGroup.LinkToGroup(part.ParentGroup); 4038 {
4039 part.ClearUpdateSchedule();
4040 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
4041 }
3718 } 4042 }
4043 finally
4044 {
4045 parts[0].ParentGroup.areUpdatesSuspended = false;
4046 }
4047
4048
3719 newRoot.ParentGroup.HasGroupChanged = true; 4049 newRoot.ParentGroup.HasGroupChanged = true;
3720 newRoot.ParentGroup.ScheduleGroupForFullUpdate(); 4050 newRoot.ParentGroup.ScheduleGroupForFullUpdate();
3721 } 4051 }
@@ -3735,6 +4065,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3735 public void llBreakAllLinks() 4065 public void llBreakAllLinks()
3736 { 4066 {
3737 m_host.AddScriptLPS(1); 4067 m_host.AddScriptLPS(1);
4068
4069 UUID invItemID = InventorySelf();
4070
4071 TaskInventoryItem item;
4072 m_host.TaskInventory.LockItemsForRead(true);
4073 item = m_host.TaskInventory[invItemID];
4074 m_host.TaskInventory.LockItemsForRead(false);
4075
4076 if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
4077 && !m_automaticLinkPermission)
4078 {
4079 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
4080 return;
4081 }
4082
3738 SceneObjectGroup parentPrim = m_host.ParentGroup; 4083 SceneObjectGroup parentPrim = m_host.ParentGroup;
3739 if (parentPrim.AttachmentPoint != 0) 4084 if (parentPrim.AttachmentPoint != 0)
3740 return; // Fail silently if attached 4085 return; // Fail silently if attached
@@ -3754,25 +4099,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3754 public LSL_String llGetLinkKey(int linknum) 4099 public LSL_String llGetLinkKey(int linknum)
3755 { 4100 {
3756 m_host.AddScriptLPS(1); 4101 m_host.AddScriptLPS(1);
3757 List<UUID> keytable = new List<UUID>();
3758 // parse for sitting avatare-uuids
3759 World.ForEachRootScenePresence(delegate(ScenePresence presence)
3760 {
3761 if (presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID))
3762 keytable.Add(presence.UUID);
3763 });
3764
3765 int totalprims = m_host.ParentGroup.PrimCount + keytable.Count;
3766 if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims)
3767 {
3768 return keytable[totalprims - linknum].ToString();
3769 }
3770
3771 if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && keytable.Count == 1)
3772 {
3773 return m_host.UUID.ToString();
3774 }
3775
3776 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum); 4102 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
3777 if (part != null) 4103 if (part != null)
3778 { 4104 {
@@ -3780,6 +4106,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3780 } 4106 }
3781 else 4107 else
3782 { 4108 {
4109 if (linknum > m_host.ParentGroup.PrimCount || (linknum == 1 && m_host.ParentGroup.PrimCount == 1))
4110 {
4111 linknum -= (m_host.ParentGroup.PrimCount) + 1;
4112
4113 if (linknum < 0)
4114 return UUID.Zero.ToString();
4115
4116 List<ScenePresence> avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET);
4117 if (avatars.Count > linknum)
4118 {
4119 return avatars[linknum].UUID.ToString();
4120 }
4121 }
3783 return UUID.Zero.ToString(); 4122 return UUID.Zero.ToString();
3784 } 4123 }
3785 } 4124 }
@@ -3878,17 +4217,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3878 m_host.AddScriptLPS(1); 4217 m_host.AddScriptLPS(1);
3879 int count = 0; 4218 int count = 0;
3880 4219
3881 lock (m_host.TaskInventory) 4220 m_host.TaskInventory.LockItemsForRead(true);
4221 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3882 { 4222 {
3883 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4223 if (inv.Value.Type == type || type == -1)
3884 { 4224 {
3885 if (inv.Value.Type == type || type == -1) 4225 count = count + 1;
3886 {
3887 count = count + 1;
3888 }
3889 } 4226 }
3890 } 4227 }
3891 4228
4229 m_host.TaskInventory.LockItemsForRead(false);
3892 return count; 4230 return count;
3893 } 4231 }
3894 4232
@@ -3897,16 +4235,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3897 m_host.AddScriptLPS(1); 4235 m_host.AddScriptLPS(1);
3898 ArrayList keys = new ArrayList(); 4236 ArrayList keys = new ArrayList();
3899 4237
3900 lock (m_host.TaskInventory) 4238 m_host.TaskInventory.LockItemsForRead(true);
4239 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3901 { 4240 {
3902 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4241 if (inv.Value.Type == type || type == -1)
3903 { 4242 {
3904 if (inv.Value.Type == type || type == -1) 4243 keys.Add(inv.Value.Name);
3905 {
3906 keys.Add(inv.Value.Name);
3907 }
3908 } 4244 }
3909 } 4245 }
4246 m_host.TaskInventory.LockItemsForRead(false);
3910 4247
3911 if (keys.Count == 0) 4248 if (keys.Count == 0)
3912 { 4249 {
@@ -3943,25 +4280,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3943 } 4280 }
3944 4281
3945 // move the first object found with this inventory name 4282 // move the first object found with this inventory name
3946 lock (m_host.TaskInventory) 4283 m_host.TaskInventory.LockItemsForRead(true);
4284 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3947 { 4285 {
3948 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 4286 if (inv.Value.Name == inventory)
3949 { 4287 {
3950 if (inv.Value.Name == inventory) 4288 found = true;
3951 { 4289 objId = inv.Key;
3952 found = true; 4290 assetType = inv.Value.Type;
3953 objId = inv.Key; 4291 objName = inv.Value.Name;
3954 assetType = inv.Value.Type; 4292 break;
3955 objName = inv.Value.Name;
3956 break;
3957 }
3958 } 4293 }
3959 } 4294 }
4295 m_host.TaskInventory.LockItemsForRead(false);
3960 4296
3961 if (!found) 4297 if (!found)
3962 { 4298 {
3963 llSay(0, String.Format("Could not find object '{0}'", inventory)); 4299 llSay(0, String.Format("Could not find object '{0}'", inventory));
3964 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); 4300 return;
4301// throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3965 } 4302 }
3966 4303
3967 // check if destination is an object 4304 // check if destination is an object
@@ -3987,48 +4324,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3987 return; 4324 return;
3988 } 4325 }
3989 } 4326 }
4327
3990 // destination is an avatar 4328 // destination is an avatar
3991 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId); 4329 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
3992 4330
3993 if (agentItem == null) 4331 if (agentItem == null)
3994 return; 4332 return;
3995 4333
3996 byte[] bucket = new byte[17]; 4334 byte[] bucket = new byte[1];
3997 bucket[0] = (byte)assetType; 4335 bucket[0] = (byte)assetType;
3998 byte[] objBytes = agentItem.ID.GetBytes(); 4336 //byte[] objBytes = agentItem.ID.GetBytes();
3999 Array.Copy(objBytes, 0, bucket, 1, 16); 4337 //Array.Copy(objBytes, 0, bucket, 1, 16);
4000 4338
4001 GridInstantMessage msg = new GridInstantMessage(World, 4339 GridInstantMessage msg = new GridInstantMessage(World,
4002 m_host.UUID, m_host.Name+", an object owned by "+ 4340 m_host.OwnerID, m_host.Name, destId,
4003 resolveName(m_host.OwnerID)+",", destId,
4004 (byte)InstantMessageDialog.TaskInventoryOffered, 4341 (byte)InstantMessageDialog.TaskInventoryOffered,
4005 false, objName+"\n"+m_host.Name+" is located at "+ 4342 false, objName+". "+m_host.Name+" is located at "+
4006 World.RegionInfo.RegionName+" "+ 4343 World.RegionInfo.RegionName+" "+
4007 m_host.AbsolutePosition.ToString(), 4344 m_host.AbsolutePosition.ToString(),
4008 agentItem.ID, true, m_host.AbsolutePosition, 4345 agentItem.ID, true, m_host.AbsolutePosition,
4009 bucket); 4346 bucket);
4010 if (m_TransferModule != null) 4347
4011 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {}); 4348 ScenePresence sp;
4349
4350 if (World.TryGetScenePresence(destId, out sp))
4351 {
4352 sp.ControllingClient.SendInstantMessage(msg);
4353 }
4354 else
4355 {
4356 if (m_TransferModule != null)
4357 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
4358 }
4359
4360 //This delay should only occur when giving inventory to avatars.
4012 ScriptSleep(3000); 4361 ScriptSleep(3000);
4013 } 4362 }
4014 } 4363 }
4015 4364
4365 [DebuggerNonUserCode]
4016 public void llRemoveInventory(string name) 4366 public void llRemoveInventory(string name)
4017 { 4367 {
4018 m_host.AddScriptLPS(1); 4368 m_host.AddScriptLPS(1);
4019 4369
4020 lock (m_host.TaskInventory) 4370 List<TaskInventoryItem> inv;
4371 try
4021 { 4372 {
4022 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4373 m_host.TaskInventory.LockItemsForRead(true);
4374 inv = new List<TaskInventoryItem>(m_host.TaskInventory.Values);
4375 }
4376 finally
4377 {
4378 m_host.TaskInventory.LockItemsForRead(false);
4379 }
4380 foreach (TaskInventoryItem item in inv)
4381 {
4382 if (item.Name == name)
4023 { 4383 {
4024 if (item.Name == name) 4384 if (item.ItemID == m_itemID)
4025 { 4385 throw new ScriptDeleteException();
4026 if (item.ItemID == m_itemID) 4386 else
4027 throw new ScriptDeleteException(); 4387 m_host.Inventory.RemoveInventoryItem(item.ItemID);
4028 else 4388 return;
4029 m_host.Inventory.RemoveInventoryItem(item.ItemID);
4030 return;
4031 }
4032 } 4389 }
4033 } 4390 }
4034 } 4391 }
@@ -4063,112 +4420,122 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4063 { 4420 {
4064 m_host.AddScriptLPS(1); 4421 m_host.AddScriptLPS(1);
4065 4422
4066 UUID uuid = (UUID)id; 4423 UUID uuid;
4067 PresenceInfo pinfo = null; 4424 if (UUID.TryParse(id, out uuid))
4068 UserAccount account;
4069
4070 UserInfoCacheEntry ce;
4071 if (!m_userInfoCache.TryGetValue(uuid, out ce))
4072 { 4425 {
4073 account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid); 4426 PresenceInfo pinfo = null;
4074 if (account == null) 4427 UserAccount account;
4428
4429 UserInfoCacheEntry ce;
4430 if (!m_userInfoCache.TryGetValue(uuid, out ce))
4075 { 4431 {
4076 m_userInfoCache[uuid] = null; // Cache negative 4432 account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
4077 return UUID.Zero.ToString(); 4433 if (account == null)
4078 } 4434 {
4435 m_userInfoCache[uuid] = null; // Cache negative
4436 return UUID.Zero.ToString();
4437 }
4079 4438
4080 4439
4081 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() }); 4440 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4082 if (pinfos != null && pinfos.Length > 0) 4441 if (pinfos != null && pinfos.Length > 0)
4083 {
4084 foreach (PresenceInfo p in pinfos)
4085 { 4442 {
4086 if (p.RegionID != UUID.Zero) 4443 foreach (PresenceInfo p in pinfos)
4087 { 4444 {
4088 pinfo = p; 4445 if (p.RegionID != UUID.Zero)
4446 {
4447 pinfo = p;
4448 }
4089 } 4449 }
4090 } 4450 }
4091 }
4092 4451
4093 ce = new UserInfoCacheEntry(); 4452 ce = new UserInfoCacheEntry();
4094 ce.time = Util.EnvironmentTickCount(); 4453 ce.time = Util.EnvironmentTickCount();
4095 ce.account = account; 4454 ce.account = account;
4096 ce.pinfo = pinfo; 4455 ce.pinfo = pinfo;
4097 } 4456 m_userInfoCache[uuid] = ce;
4098 else 4457 }
4099 { 4458 else
4100 if (ce == null) 4459 {
4101 return UUID.Zero.ToString(); 4460 if (ce == null)
4461 return UUID.Zero.ToString();
4102 4462
4103 account = ce.account; 4463 account = ce.account;
4104 pinfo = ce.pinfo; 4464 pinfo = ce.pinfo;
4105 } 4465 }
4106 4466
4107 if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000) 4467 if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000)
4108 {
4109 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4110 if (pinfos != null && pinfos.Length > 0)
4111 { 4468 {
4112 foreach (PresenceInfo p in pinfos) 4469 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4470 if (pinfos != null && pinfos.Length > 0)
4113 { 4471 {
4114 if (p.RegionID != UUID.Zero) 4472 foreach (PresenceInfo p in pinfos)
4115 { 4473 {
4116 pinfo = p; 4474 if (p.RegionID != UUID.Zero)
4475 {
4476 pinfo = p;
4477 }
4117 } 4478 }
4118 } 4479 }
4119 } 4480 else
4120 else 4481 pinfo = null;
4121 pinfo = null;
4122 4482
4123 ce.time = Util.EnvironmentTickCount(); 4483 ce.time = Util.EnvironmentTickCount();
4124 ce.pinfo = pinfo; 4484 ce.pinfo = pinfo;
4125 } 4485 }
4126 4486
4127 string reply = String.Empty; 4487 string reply = String.Empty;
4128 4488
4129 switch (data) 4489 switch (data)
4130 { 4490 {
4131 case 1: // DATA_ONLINE (0|1) 4491 case 1: // DATA_ONLINE (0|1)
4132 if (pinfo != null && pinfo.RegionID != UUID.Zero) 4492 if (pinfo != null && pinfo.RegionID != UUID.Zero)
4133 reply = "1"; 4493 reply = "1";
4134 else 4494 else
4135 reply = "0"; 4495 reply = "0";
4136 break; 4496 break;
4137 case 2: // DATA_NAME (First Last) 4497 case 2: // DATA_NAME (First Last)
4138 reply = account.FirstName + " " + account.LastName; 4498 reply = account.FirstName + " " + account.LastName;
4139 break; 4499 break;
4140 case 3: // DATA_BORN (YYYY-MM-DD) 4500 case 3: // DATA_BORN (YYYY-MM-DD)
4141 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0); 4501 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
4142 born = born.AddSeconds(account.Created); 4502 born = born.AddSeconds(account.Created);
4143 reply = born.ToString("yyyy-MM-dd"); 4503 reply = born.ToString("yyyy-MM-dd");
4144 break; 4504 break;
4145 case 4: // DATA_RATING (0,0,0,0,0,0) 4505 case 4: // DATA_RATING (0,0,0,0,0,0)
4146 reply = "0,0,0,0,0,0"; 4506 reply = "0,0,0,0,0,0";
4147 break; 4507 break;
4148 case 8: // DATA_PAYINFO (0|1|2|3) 4508 case 8: // DATA_PAYINFO (0|1|2|3)
4149 reply = "0"; 4509 reply = "0";
4150 break; 4510 break;
4151 default: 4511 default:
4152 return UUID.Zero.ToString(); // Raise no event 4512 return UUID.Zero.ToString(); // Raise no event
4153 } 4513 }
4154 4514
4155 UUID rq = UUID.Random(); 4515 UUID rq = UUID.Random();
4156 4516
4157 UUID tid = AsyncCommands. 4517 UUID tid = AsyncCommands.
4158 DataserverPlugin.RegisterRequest(m_localID, 4518 DataserverPlugin.RegisterRequest(m_localID,
4159 m_itemID, rq.ToString()); 4519 m_itemID, rq.ToString());
4160 4520
4161 AsyncCommands. 4521 AsyncCommands.
4162 DataserverPlugin.DataserverReply(rq.ToString(), reply); 4522 DataserverPlugin.DataserverReply(rq.ToString(), reply);
4163 4523
4164 ScriptSleep(100); 4524 ScriptSleep(100);
4165 return tid.ToString(); 4525 return tid.ToString();
4526 }
4527 else
4528 {
4529 ShoutError("Invalid UUID passed to llRequestAgentData.");
4530 }
4531 return "";
4166 } 4532 }
4167 4533
4168 public LSL_String llRequestInventoryData(string name) 4534 public LSL_String llRequestInventoryData(string name)
4169 { 4535 {
4170 m_host.AddScriptLPS(1); 4536 m_host.AddScriptLPS(1);
4171 4537
4538 //Clone is thread safe
4172 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 4539 TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
4173 4540
4174 foreach (TaskInventoryItem item in itemDictionary.Values) 4541 foreach (TaskInventoryItem item in itemDictionary.Values)
@@ -4222,6 +4589,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4222 ScenePresence presence = World.GetScenePresence(agentId); 4589 ScenePresence presence = World.GetScenePresence(agentId);
4223 if (presence != null) 4590 if (presence != null)
4224 { 4591 {
4592 // agent must not be a god
4593 if (presence.UserLevel >= 200) return;
4594
4225 // agent must be over the owners land 4595 // agent must be over the owners land
4226 if (m_host.OwnerID == World.LandChannel.GetLandObject( 4596 if (m_host.OwnerID == World.LandChannel.GetLandObject(
4227 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) 4597 presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
@@ -4244,7 +4614,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4244 UUID av = new UUID(); 4614 UUID av = new UUID();
4245 if (!UUID.TryParse(agent,out av)) 4615 if (!UUID.TryParse(agent,out av))
4246 { 4616 {
4247 LSLError("First parameter to llDialog needs to be a key"); 4617 //LSLError("First parameter to llDialog needs to be a key");
4248 return; 4618 return;
4249 } 4619 }
4250 4620
@@ -4281,17 +4651,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4281 UUID soundId = UUID.Zero; 4651 UUID soundId = UUID.Zero;
4282 if (!UUID.TryParse(impact_sound, out soundId)) 4652 if (!UUID.TryParse(impact_sound, out soundId))
4283 { 4653 {
4284 lock (m_host.TaskInventory) 4654 m_host.TaskInventory.LockItemsForRead(true);
4655 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4285 { 4656 {
4286 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4657 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound)
4287 { 4658 {
4288 if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) 4659 soundId = item.AssetID;
4289 { 4660 break;
4290 soundId = item.AssetID;
4291 break;
4292 }
4293 } 4661 }
4294 } 4662 }
4663 m_host.TaskInventory.LockItemsForRead(false);
4295 } 4664 }
4296 m_host.CollisionSound = soundId; 4665 m_host.CollisionSound = soundId;
4297 m_host.CollisionSoundVolume = (float)impact_volume; 4666 m_host.CollisionSoundVolume = (float)impact_volume;
@@ -4331,6 +4700,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4331 UUID partItemID; 4700 UUID partItemID;
4332 foreach (SceneObjectPart part in parts) 4701 foreach (SceneObjectPart part in parts)
4333 { 4702 {
4703 //Clone is thread safe
4334 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); 4704 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
4335 4705
4336 foreach (TaskInventoryItem item in itemsDictionary.Values) 4706 foreach (TaskInventoryItem item in itemsDictionary.Values)
@@ -4545,17 +4915,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4545 4915
4546 m_host.AddScriptLPS(1); 4916 m_host.AddScriptLPS(1);
4547 4917
4548 lock (m_host.TaskInventory) 4918 m_host.TaskInventory.LockItemsForRead(true);
4919 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
4549 { 4920 {
4550 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 4921 if (item.Type == 10 && item.ItemID == m_itemID)
4551 { 4922 {
4552 if (item.Type == 10 && item.ItemID == m_itemID) 4923 result = item.Name!=null?item.Name:String.Empty;
4553 { 4924 break;
4554 result = item.Name != null ? item.Name : String.Empty;
4555 break;
4556 }
4557 } 4925 }
4558 } 4926 }
4927 m_host.TaskInventory.LockItemsForRead(false);
4559 4928
4560 return result; 4929 return result;
4561 } 4930 }
@@ -4728,23 +5097,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4728 { 5097 {
4729 m_host.AddScriptLPS(1); 5098 m_host.AddScriptLPS(1);
4730 5099
4731 lock (m_host.TaskInventory) 5100 m_host.TaskInventory.LockItemsForRead(true);
5101 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4732 { 5102 {
4733 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 5103 if (inv.Value.Name == name)
4734 { 5104 {
4735 if (inv.Value.Name == name) 5105 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4736 { 5106 {
4737 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) 5107 m_host.TaskInventory.LockItemsForRead(false);
4738 { 5108 return inv.Value.AssetID.ToString();
4739 return inv.Value.AssetID.ToString(); 5109 }
4740 } 5110 else
4741 else 5111 {
4742 { 5112 m_host.TaskInventory.LockItemsForRead(false);
4743 return UUID.Zero.ToString(); 5113 return UUID.Zero.ToString();
4744 }
4745 } 5114 }
4746 } 5115 }
4747 } 5116 }
5117 m_host.TaskInventory.LockItemsForRead(false);
4748 5118
4749 return UUID.Zero.ToString(); 5119 return UUID.Zero.ToString();
4750 } 5120 }
@@ -4897,14 +5267,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4897 { 5267 {
4898 m_host.AddScriptLPS(1); 5268 m_host.AddScriptLPS(1);
4899 5269
4900 if (src == null) 5270 return src.Length;
4901 {
4902 return 0;
4903 }
4904 else
4905 {
4906 return src.Length;
4907 }
4908 } 5271 }
4909 5272
4910 public LSL_Integer llList2Integer(LSL_List src, int index) 5273 public LSL_Integer llList2Integer(LSL_List src, int index)
@@ -4950,7 +5313,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4950 else if (src.Data[index] is LSL_Float) 5313 else if (src.Data[index] is LSL_Float)
4951 return Convert.ToDouble(((LSL_Float) src.Data[index]).value); 5314 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
4952 else if (src.Data[index] is LSL_String) 5315 else if (src.Data[index] is LSL_String)
4953 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string); 5316 {
5317 string str = ((LSL_String) src.Data[index]).m_string;
5318 Match m = Regex.Match(str, "^\\s*(-?\\+?[,0-9]+\\.?[0-9]*)");
5319 if (m != Match.Empty)
5320 {
5321 str = m.Value;
5322 double d = 0.0;
5323 if (!Double.TryParse(str, out d))
5324 return 0.0;
5325
5326 return d;
5327 }
5328 return 0.0;
5329 }
4954 return Convert.ToDouble(src.Data[index]); 5330 return Convert.ToDouble(src.Data[index]);
4955 } 5331 }
4956 catch (FormatException) 5332 catch (FormatException)
@@ -5223,7 +5599,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5223 } 5599 }
5224 } 5600 }
5225 } 5601 }
5226 else { 5602 else
5603 {
5227 object[] array = new object[src.Length]; 5604 object[] array = new object[src.Length];
5228 Array.Copy(src.Data, 0, array, 0, src.Length); 5605 Array.Copy(src.Data, 0, array, 0, src.Length);
5229 result = new LSL_List(array); 5606 result = new LSL_List(array);
@@ -5672,10 +6049,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5672 m_host.AddScriptLPS(1); 6049 m_host.AddScriptLPS(1);
5673 6050
5674 List<SceneObjectPart> parts = GetLinkParts(linknumber); 6051 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5675 6052 if (parts.Count > 0)
5676 foreach (var part in parts)
5677 { 6053 {
5678 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate); 6054 try
6055 {
6056 parts[0].ParentGroup.areUpdatesSuspended = true;
6057 foreach (var part in parts)
6058 {
6059 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
6060 }
6061 }
6062 finally
6063 {
6064 parts[0].ParentGroup.areUpdatesSuspended = false;
6065 }
5679 } 6066 }
5680 } 6067 }
5681 6068
@@ -5727,13 +6114,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5727 6114
5728 if (m_host.OwnerID == land.LandData.OwnerID) 6115 if (m_host.OwnerID == land.LandData.OwnerID)
5729 { 6116 {
5730 World.TeleportClientHome(agentID, presence.ControllingClient); 6117 Vector3 pos = World.GetNearestAllowedPosition(presence, land);
6118 presence.TeleportWithMomentum(pos);
6119 presence.ControllingClient.SendAlertMessage("You have been ejected from this land");
5731 } 6120 }
5732 } 6121 }
5733 } 6122 }
5734 ScriptSleep(5000); 6123 ScriptSleep(5000);
5735 } 6124 }
5736 6125
6126 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers)
6127 {
6128 return ParseString2List(str, separators, in_spacers, false);
6129 }
6130
5737 public LSL_Integer llOverMyLand(string id) 6131 public LSL_Integer llOverMyLand(string id)
5738 { 6132 {
5739 m_host.AddScriptLPS(1); 6133 m_host.AddScriptLPS(1);
@@ -5798,8 +6192,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5798 UUID agentId = new UUID(); 6192 UUID agentId = new UUID();
5799 if (!UUID.TryParse(agent, out agentId)) 6193 if (!UUID.TryParse(agent, out agentId))
5800 return new LSL_Integer(0); 6194 return new LSL_Integer(0);
6195 if (agentId == m_host.GroupID)
6196 return new LSL_Integer(1);
5801 ScenePresence presence = World.GetScenePresence(agentId); 6197 ScenePresence presence = World.GetScenePresence(agentId);
5802 if (presence == null || presence.IsChildAgent) // Return flase for child agents 6198 if (presence == null || presence.IsChildAgent) // Return false for child agents
5803 return new LSL_Integer(0); 6199 return new LSL_Integer(0);
5804 IClientAPI client = presence.ControllingClient; 6200 IClientAPI client = presence.ControllingClient;
5805 if (m_host.GroupID == client.ActiveGroupId) 6201 if (m_host.GroupID == client.ActiveGroupId)
@@ -5934,7 +6330,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5934 return m_host.ParentGroup.AttachmentPoint; 6330 return m_host.ParentGroup.AttachmentPoint;
5935 } 6331 }
5936 6332
5937 public LSL_Integer llGetFreeMemory() 6333 public virtual LSL_Integer llGetFreeMemory()
5938 { 6334 {
5939 m_host.AddScriptLPS(1); 6335 m_host.AddScriptLPS(1);
5940 // Make scripts designed for LSO happy 6336 // Make scripts designed for LSO happy
@@ -6051,7 +6447,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6051 SetParticleSystem(m_host, rules); 6447 SetParticleSystem(m_host, rules);
6052 } 6448 }
6053 6449
6054 private void SetParticleSystem(SceneObjectPart part, LSL_List rules) { 6450 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6451 {
6055 6452
6056 6453
6057 if (rules.Length == 0) 6454 if (rules.Length == 0)
@@ -6245,14 +6642,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6245 6642
6246 protected UUID GetTaskInventoryItem(string name) 6643 protected UUID GetTaskInventoryItem(string name)
6247 { 6644 {
6248 lock (m_host.TaskInventory) 6645 m_host.TaskInventory.LockItemsForRead(true);
6646 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6249 { 6647 {
6250 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 6648 if (inv.Value.Name == name)
6251 { 6649 {
6252 if (inv.Value.Name == name) 6650 m_host.TaskInventory.LockItemsForRead(false);
6253 return inv.Key; 6651 return inv.Key;
6254 } 6652 }
6255 } 6653 }
6654 m_host.TaskInventory.LockItemsForRead(false);
6256 6655
6257 return UUID.Zero; 6656 return UUID.Zero;
6258 } 6657 }
@@ -6290,16 +6689,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6290 if (folderID == UUID.Zero) 6689 if (folderID == UUID.Zero)
6291 return; 6690 return;
6292 6691
6293 byte[] bucket = new byte[17]; 6692 byte[] bucket = new byte[1];
6294 bucket[0] = (byte)AssetType.Folder; 6693 bucket[0] = (byte)AssetType.Folder;
6295 byte[] objBytes = folderID.GetBytes(); 6694 //byte[] objBytes = folderID.GetBytes();
6296 Array.Copy(objBytes, 0, bucket, 1, 16); 6695 //Array.Copy(objBytes, 0, bucket, 1, 16);
6297 6696
6298 GridInstantMessage msg = new GridInstantMessage(World, 6697 GridInstantMessage msg = new GridInstantMessage(World,
6299 m_host.UUID, m_host.Name+", an object owned by "+ 6698 m_host.OwnerID, m_host.Name, destID,
6300 resolveName(m_host.OwnerID)+",", destID, 6699 (byte)InstantMessageDialog.TaskInventoryOffered,
6301 (byte)InstantMessageDialog.InventoryOffered, 6700 false, category+". "+m_host.Name+" is located at "+
6302 false, category+"\n"+m_host.Name+" is located at "+
6303 World.RegionInfo.RegionName+" "+ 6701 World.RegionInfo.RegionName+" "+
6304 m_host.AbsolutePosition.ToString(), 6702 m_host.AbsolutePosition.ToString(),
6305 folderID, true, m_host.AbsolutePosition, 6703 folderID, true, m_host.AbsolutePosition,
@@ -6515,13 +6913,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6515 UUID av = new UUID(); 6913 UUID av = new UUID();
6516 if (!UUID.TryParse(avatar,out av)) 6914 if (!UUID.TryParse(avatar,out av))
6517 { 6915 {
6518 LSLError("First parameter to llDialog needs to be a key"); 6916 //LSLError("First parameter to llDialog needs to be a key");
6519 return; 6917 return;
6520 } 6918 }
6521 if (buttons.Length < 1) 6919 if (buttons.Length < 1)
6522 { 6920 {
6523 LSLError("No less than 1 button can be shown"); 6921 buttons.Add("OK");
6524 return;
6525 } 6922 }
6526 if (buttons.Length > 12) 6923 if (buttons.Length > 12)
6527 { 6924 {
@@ -6538,7 +6935,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6538 } 6935 }
6539 if (buttons.Data[i].ToString().Length > 24) 6936 if (buttons.Data[i].ToString().Length > 24)
6540 { 6937 {
6541 LSLError("button label cannot be longer than 24 characters"); 6938 llWhisper(ScriptBaseClass.DEBUG_CHANNEL, "button label cannot be longer than 24 characters");
6542 return; 6939 return;
6543 } 6940 }
6544 buts[i] = buttons.Data[i].ToString(); 6941 buts[i] = buttons.Data[i].ToString();
@@ -6597,22 +6994,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6597 } 6994 }
6598 6995
6599 // copy the first script found with this inventory name 6996 // copy the first script found with this inventory name
6600 lock (m_host.TaskInventory) 6997 TaskInventoryItem scriptItem = null;
6998 m_host.TaskInventory.LockItemsForRead(true);
6999 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6601 { 7000 {
6602 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 7001 if (inv.Value.Name == name)
6603 { 7002 {
6604 if (inv.Value.Name == name) 7003 // make sure the object is a script
7004 if (10 == inv.Value.Type)
6605 { 7005 {
6606 // make sure the object is a script 7006 found = true;
6607 if (10 == inv.Value.Type) 7007 srcId = inv.Key;
6608 { 7008 scriptItem = inv.Value;
6609 found = true; 7009 break;
6610 srcId = inv.Key;
6611 break;
6612 }
6613 } 7010 }
6614 } 7011 }
6615 } 7012 }
7013 m_host.TaskInventory.LockItemsForRead(false);
6616 7014
6617 if (!found) 7015 if (!found)
6618 { 7016 {
@@ -6620,9 +7018,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6620 return; 7018 return;
6621 } 7019 }
6622 7020
6623 // the rest of the permission checks are done in RezScript, so check the pin there as well 7021 SceneObjectPart dest = World.GetSceneObjectPart(destId);
6624 World.RezScriptFromPrim(srcId, m_host, destId, pin, running, start_param); 7022 if (dest != null)
7023 {
7024 if ((scriptItem.BasePermissions & (uint)PermissionMask.Transfer) != 0 || dest.ParentGroup.RootPart.OwnerID == m_host.ParentGroup.RootPart.OwnerID)
7025 {
7026 // the rest of the permission checks are done in RezScript, so check the pin there as well
7027 World.RezScriptFromPrim(srcId, m_host, destId, pin, running, start_param);
6625 7028
7029 if ((scriptItem.BasePermissions & (uint)PermissionMask.Copy) == 0)
7030 m_host.Inventory.RemoveInventoryItem(srcId);
7031 }
7032 }
6626 // this will cause the delay even if the script pin or permissions were wrong - seems ok 7033 // this will cause the delay even if the script pin or permissions were wrong - seems ok
6627 ScriptSleep(3000); 7034 ScriptSleep(3000);
6628 } 7035 }
@@ -6685,19 +7092,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6685 public LSL_String llMD5String(string src, int nonce) 7092 public LSL_String llMD5String(string src, int nonce)
6686 { 7093 {
6687 m_host.AddScriptLPS(1); 7094 m_host.AddScriptLPS(1);
6688 return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString())); 7095 return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()), Encoding.UTF8);
6689 } 7096 }
6690 7097
6691 public LSL_String llSHA1String(string src) 7098 public LSL_String llSHA1String(string src)
6692 { 7099 {
6693 m_host.AddScriptLPS(1); 7100 m_host.AddScriptLPS(1);
6694 return Util.SHA1Hash(src).ToLower(); 7101 return Util.SHA1Hash(src, Encoding.UTF8).ToLower();
6695 } 7102 }
6696 7103
6697 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve) 7104 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve)
6698 { 7105 {
6699 float tempFloat; // Use in float expressions below to avoid byte cast precision issues. 7106 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
6700 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 7107 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
7108 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7109 return shapeBlock;
6701 7110
6702 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && 7111 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
6703 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE && 7112 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
@@ -6802,6 +7211,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6802 // Prim type box, cylinder and prism. 7211 // Prim type box, cylinder and prism.
6803 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve) 7212 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve)
6804 { 7213 {
7214 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7215 return;
7216
6805 float tempFloat; // Use in float expressions below to avoid byte cast precision issues. 7217 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
6806 ObjectShapePacket.ObjectDataBlock shapeBlock; 7218 ObjectShapePacket.ObjectDataBlock shapeBlock;
6807 7219
@@ -6855,6 +7267,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6855 // Prim type sphere. 7267 // Prim type sphere.
6856 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve) 7268 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve)
6857 { 7269 {
7270 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7271 return;
7272
6858 ObjectShapePacket.ObjectDataBlock shapeBlock; 7273 ObjectShapePacket.ObjectDataBlock shapeBlock;
6859 7274
6860 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); 7275 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
@@ -6896,6 +7311,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6896 // Prim type torus, tube and ring. 7311 // Prim type torus, tube and ring.
6897 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 profileshape, byte pathcurve) 7312 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 profileshape, byte pathcurve)
6898 { 7313 {
7314 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7315 return;
7316
6899 float tempFloat; // Use in float expressions below to avoid byte cast precision issues. 7317 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
6900 ObjectShapePacket.ObjectDataBlock shapeBlock; 7318 ObjectShapePacket.ObjectDataBlock shapeBlock;
6901 7319
@@ -7031,6 +7449,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7031 // Prim type sculpt. 7449 // Prim type sculpt.
7032 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve) 7450 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve)
7033 { 7451 {
7452 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7453 return;
7454
7034 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); 7455 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
7035 UUID sculptId; 7456 UUID sculptId;
7036 7457
@@ -7047,13 +7468,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7047 shapeBlock.PathScaleX = 100; 7468 shapeBlock.PathScaleX = 100;
7048 shapeBlock.PathScaleY = 150; 7469 shapeBlock.PathScaleY = 150;
7049 7470
7050 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER && 7471 if ((type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER) == 0 &&
7051 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE && 7472 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE) == 0 &&
7052 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE && 7473 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE) == 0 &&
7053 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) 7474 (type & (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS) == 0)
7054 { 7475 {
7055 // default 7476 // default
7056 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE; 7477 type = type | (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
7057 } 7478 }
7058 7479
7059 part.Shape.SetSculptProperties((byte)type, sculptId); 7480 part.Shape.SetSculptProperties((byte)type, sculptId);
@@ -7069,32 +7490,87 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7069 ScriptSleep(200); 7490 ScriptSleep(200);
7070 } 7491 }
7071 7492
7072 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules) 7493 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
7073 { 7494 {
7074 m_host.AddScriptLPS(1); 7495 m_host.AddScriptLPS(1);
7075 7496
7076 setLinkPrimParams(linknumber, rules); 7497 setLinkPrimParams(linknumber, rules);
7077
7078 ScriptSleep(200);
7079 } 7498 }
7080 7499
7081 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules) 7500 private void setLinkPrimParams(int linknumber, LSL_List rules)
7082 { 7501 {
7083 m_host.AddScriptLPS(1); 7502 List<SceneObjectPart> parts = GetLinkParts(linknumber);
7503 List<ScenePresence> avatars = GetLinkAvatars(linknumber);
7504 if (parts.Count>0)
7505 {
7506 try
7507 {
7508 parts[0].ParentGroup.areUpdatesSuspended = true;
7509 foreach (SceneObjectPart part in parts)
7510 SetPrimParams(part, rules);
7511 }
7512 finally
7513 {
7514 parts[0].ParentGroup.areUpdatesSuspended = false;
7515 }
7516 }
7517 if (avatars.Count > 0)
7518 {
7519 foreach (ScenePresence avatar in avatars)
7520 SetPrimParams(avatar, rules);
7521 }
7522 }
7084 7523
7085 setLinkPrimParams(linknumber, rules); 7524 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
7525 {
7526 llSetLinkPrimitiveParamsFast(linknumber, rules);
7527 ScriptSleep(200);
7086 } 7528 }
7087 7529
7088 protected void setLinkPrimParams(int linknumber, LSL_List rules) 7530 protected void SetPrimParams(ScenePresence av, LSL_List rules)
7089 { 7531 {
7090 List<SceneObjectPart> parts = GetLinkParts(linknumber); 7532 //This is a special version of SetPrimParams to deal with avatars which are sat on the linkset.
7533 //We only support PRIM_POSITION and PRIM_ROTATION
7091 7534
7092 foreach (SceneObjectPart part in parts) 7535 int idx = 0;
7093 SetPrimParams(part, rules); 7536
7537 while (idx < rules.Length)
7538 {
7539 int code = rules.GetLSLIntegerItem(idx++);
7540
7541 int remain = rules.Length - idx;
7542
7543
7544
7545 switch (code)
7546 {
7547 case (int)ScriptBaseClass.PRIM_POSITION:
7548 if (remain < 1)
7549 return;
7550 LSL_Vector v;
7551 v = rules.GetVector3Item(idx++);
7552 av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
7553 av.SendAvatarDataToAllAgents();
7554
7555 break;
7556
7557 case (int)ScriptBaseClass.PRIM_ROTATION:
7558 if (remain < 1)
7559 return;
7560 LSL_Rotation r;
7561 r = rules.GetQuaternionItem(idx++);
7562 av.Rotation = new Quaternion((float)r.x, (float)r.y, (float)r.z, (float)r.s);
7563 av.SendAvatarDataToAllAgents();
7564 break;
7565 }
7566 }
7094 } 7567 }
7095 7568
7096 protected void SetPrimParams(SceneObjectPart part, LSL_List rules) 7569 protected void SetPrimParams(SceneObjectPart part, LSL_List rules)
7097 { 7570 {
7571 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
7572 return;
7573
7098 int idx = 0; 7574 int idx = 0;
7099 7575
7100 bool positionChanged = false; 7576 bool positionChanged = false;
@@ -7122,6 +7598,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7122 currentPosition = GetSetPosTarget(part, v, currentPosition); 7598 currentPosition = GetSetPosTarget(part, v, currentPosition);
7123 7599
7124 break; 7600 break;
7601 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
7602 if (remain < 1)
7603 return;
7604
7605 v=rules.GetVector3Item(idx++);
7606 positionChanged = true;
7607 currentPosition = GetSetPosTarget(part, v, currentPosition);
7608
7609 break;
7125 case (int)ScriptBaseClass.PRIM_SIZE: 7610 case (int)ScriptBaseClass.PRIM_SIZE:
7126 if (remain < 1) 7611 if (remain < 1)
7127 return; 7612 return;
@@ -7499,6 +7984,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7499 } 7984 }
7500 } 7985 }
7501 } 7986 }
7987
7988 if (positionChanged)
7989 {
7990 if (part.ParentGroup.RootPart == part)
7991 {
7992 SceneObjectGroup parent = part.ParentGroup;
7993 parent.UpdateGroupPosition(new Vector3((float)currentPosition.x, (float)currentPosition.y, (float)currentPosition.z));
7994 }
7995 else
7996 {
7997 part.OffsetPosition = new Vector3((float)currentPosition.x, (float)currentPosition.y, (float)currentPosition.z);
7998 SceneObjectGroup parent = part.ParentGroup;
7999 parent.HasGroupChanged = true;
8000 parent.ScheduleGroupForTerseUpdate();
8001 }
8002 }
7502 } 8003 }
7503 8004
7504 public LSL_String llStringToBase64(string str) 8005 public LSL_String llStringToBase64(string str)
@@ -7659,13 +8160,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7659 public LSL_Integer llGetNumberOfPrims() 8160 public LSL_Integer llGetNumberOfPrims()
7660 { 8161 {
7661 m_host.AddScriptLPS(1); 8162 m_host.AddScriptLPS(1);
7662 int avatarCount = 0; 8163 int avatarCount = m_host.ParentGroup.GetLinkedAvatars().Count;
7663 World.ForEachRootScenePresence(delegate(ScenePresence presence) 8164
7664 {
7665 if (presence.ParentID != 0 && m_host.ParentGroup.HasChildPrim(presence.ParentID))
7666 avatarCount++;
7667 });
7668
7669 return m_host.ParentGroup.PrimCount + avatarCount; 8165 return m_host.ParentGroup.PrimCount + avatarCount;
7670 } 8166 }
7671 8167
@@ -7681,55 +8177,98 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7681 m_host.AddScriptLPS(1); 8177 m_host.AddScriptLPS(1);
7682 UUID objID = UUID.Zero; 8178 UUID objID = UUID.Zero;
7683 LSL_List result = new LSL_List(); 8179 LSL_List result = new LSL_List();
8180
8181 // If the ID is not valid, return null result
7684 if (!UUID.TryParse(obj, out objID)) 8182 if (!UUID.TryParse(obj, out objID))
7685 { 8183 {
7686 result.Add(new LSL_Vector()); 8184 result.Add(new LSL_Vector());
7687 result.Add(new LSL_Vector()); 8185 result.Add(new LSL_Vector());
7688 return result; 8186 return result;
7689 } 8187 }
8188
8189 // Check if this is an attached prim. If so, replace
8190 // the UUID with the avatar UUID and report it's bounding box
8191 SceneObjectPart part = World.GetSceneObjectPart(objID);
8192 if (part != null && part.ParentGroup.IsAttachment)
8193 objID = part.ParentGroup.AttachedAvatar;
8194
8195 // Find out if this is an avatar ID. If so, return it's box
7690 ScenePresence presence = World.GetScenePresence(objID); 8196 ScenePresence presence = World.GetScenePresence(objID);
7691 if (presence != null) 8197 if (presence != null)
7692 { 8198 {
7693 if (presence.ParentID == 0) // not sat on an object 8199 // As per LSL Wiki, there is no difference between sitting
8200 // and standing avatar since server 1.36
8201 LSL_Vector lower;
8202 LSL_Vector upper;
8203 if (presence.Animator.Animations.DefaultAnimation.AnimID
8204 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
7694 { 8205 {
7695 LSL_Vector lower; 8206 // This is for ground sitting avatars
7696 LSL_Vector upper; 8207 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7697 if (presence.Animator.Animations.DefaultAnimation.AnimID 8208 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7698 == AnimationSet.Animations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) 8209 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7699 {
7700 // This is for ground sitting avatars
7701 float height = presence.Appearance.AvatarHeight / 2.66666667f;
7702 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
7703 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
7704 }
7705 else
7706 {
7707 // This is for standing/flying avatars
7708 float height = presence.Appearance.AvatarHeight / 2.0f;
7709 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7710 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7711 }
7712 result.Add(lower);
7713 result.Add(upper);
7714 return result;
7715 } 8210 }
7716 else 8211 else
7717 { 8212 {
7718 // sitting on an object so we need the bounding box of that 8213 // This is for standing/flying avatars
7719 // which should include the avatar so set the UUID to the 8214 float height = presence.Appearance.AvatarHeight / 2.0f;
7720 // UUID of the object the avatar is sat on and allow it to fall through 8215 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
7721 // to processing an object 8216 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
7722 SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
7723 objID = p.UUID;
7724 } 8217 }
8218
8219 // Adjust to the documented error offsets (see LSL Wiki)
8220 lower += new LSL_Vector(0.05f, 0.05f, 0.05f);
8221 upper -= new LSL_Vector(0.05f, 0.05f, 0.05f);
8222
8223 if (lower.x > upper.x)
8224 lower.x = upper.x;
8225 if (lower.y > upper.y)
8226 lower.y = upper.y;
8227 if (lower.z > upper.z)
8228 lower.z = upper.z;
8229
8230 result.Add(lower);
8231 result.Add(upper);
8232 return result;
7725 } 8233 }
7726 SceneObjectPart part = World.GetSceneObjectPart(objID); 8234
8235 part = World.GetSceneObjectPart(objID);
7727 // Currently only works for single prims without a sitting avatar 8236 // Currently only works for single prims without a sitting avatar
7728 if (part != null) 8237 if (part != null)
7729 { 8238 {
7730 Vector3 halfSize = part.Scale / 2.0f; 8239 float minX;
7731 LSL_Vector lower = new LSL_Vector(halfSize.X * -1.0f, halfSize.Y * -1.0f, halfSize.Z * -1.0f); 8240 float maxX;
7732 LSL_Vector upper = new LSL_Vector(halfSize.X, halfSize.Y, halfSize.Z); 8241 float minY;
8242 float maxY;
8243 float minZ;
8244 float maxZ;
8245
8246 // This BBox is in sim coordinates, with the offset being
8247 // a contained point.
8248 Vector3[] offsets = Scene.GetCombinedBoundingBox(new List<SceneObjectGroup> { part.ParentGroup },
8249 out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
8250
8251 minX -= offsets[0].X;
8252 maxX -= offsets[0].X;
8253 minY -= offsets[0].Y;
8254 maxY -= offsets[0].Y;
8255 minZ -= offsets[0].Z;
8256 maxZ -= offsets[0].Z;
8257
8258 LSL_Vector lower;
8259 LSL_Vector upper;
8260
8261 // Adjust to the documented error offsets (see LSL Wiki)
8262 lower = new LSL_Vector(minX + 0.05f, minY + 0.05f, minZ + 0.05f);
8263 upper = new LSL_Vector(maxX - 0.05f, maxY - 0.05f, maxZ - 0.05f);
8264
8265 if (lower.x > upper.x)
8266 lower.x = upper.x;
8267 if (lower.y > upper.y)
8268 lower.y = upper.y;
8269 if (lower.z > upper.z)
8270 lower.z = upper.z;
8271
7733 result.Add(lower); 8272 result.Add(lower);
7734 result.Add(upper); 8273 result.Add(upper);
7735 return result; 8274 return result;
@@ -7809,13 +8348,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7809 LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X, 8348 LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
7810 part.AbsolutePosition.Y, 8349 part.AbsolutePosition.Y,
7811 part.AbsolutePosition.Z); 8350 part.AbsolutePosition.Z);
7812 // For some reason, the part.AbsolutePosition.* values do not change if the
7813 // linkset is rotated; they always reflect the child prim's world position
7814 // as though the linkset is unrotated. This is incompatible behavior with SL's
7815 // implementation, so will break scripts imported from there (not to mention it
7816 // makes it more difficult to determine a child prim's actual inworld position).
7817 if (part.ParentID != 0)
7818 v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
7819 res.Add(v); 8351 res.Add(v);
7820 break; 8352 break;
7821 8353
@@ -7986,56 +8518,92 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
7986 case (int)ScriptBaseClass.PRIM_BUMP_SHINY: 8518 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
7987 if (remain < 1) 8519 if (remain < 1)
7988 return res; 8520 return res;
7989 8521 face = (int)rules.GetLSLIntegerItem(idx++);
7990 face=(int)rules.GetLSLIntegerItem(idx++);
7991 8522
7992 tex = part.Shape.Textures; 8523 tex = part.Shape.Textures;
8524 int shiny;
7993 if (face == ScriptBaseClass.ALL_SIDES) 8525 if (face == ScriptBaseClass.ALL_SIDES)
7994 { 8526 {
7995 for (face = 0; face < GetNumberOfSides(part); face++) 8527 for (face = 0; face < GetNumberOfSides(part); face++)
7996 { 8528 {
7997 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8529 Shininess shinyness = tex.GetFace((uint)face).Shiny;
7998 // Convert Shininess to PRIM_SHINY_* 8530 if (shinyness == Shininess.High)
7999 res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); 8531 {
8000 // PRIM_BUMP_* 8532 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
8001 res.Add(new LSL_Integer((int)texface.Bump)); 8533 }
8534 else if (shinyness == Shininess.Medium)
8535 {
8536 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
8537 }
8538 else if (shinyness == Shininess.Low)
8539 {
8540 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8541 }
8542 else
8543 {
8544 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8545 }
8546 res.Add(new LSL_Integer(shiny));
8547 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
8002 } 8548 }
8003 } 8549 }
8004 else 8550 else
8005 { 8551 {
8006 if (face >= 0 && face < GetNumberOfSides(part)) 8552 Shininess shinyness = tex.GetFace((uint)face).Shiny;
8553 if (shinyness == Shininess.High)
8007 { 8554 {
8008 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8555 shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
8009 // Convert Shininess to PRIM_SHINY_* 8556 }
8010 res.Add(new LSL_Integer((uint)texface.Shiny >> 6)); 8557 else if (shinyness == Shininess.Medium)
8011 // PRIM_BUMP_* 8558 {
8012 res.Add(new LSL_Integer((int)texface.Bump)); 8559 shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
8560 }
8561 else if (shinyness == Shininess.Low)
8562 {
8563 shiny = ScriptBaseClass.PRIM_SHINY_LOW;
8013 } 8564 }
8565 else
8566 {
8567 shiny = ScriptBaseClass.PRIM_SHINY_NONE;
8568 }
8569 res.Add(new LSL_Integer(shiny));
8570 res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
8014 } 8571 }
8015 break; 8572 break;
8016 8573
8017 case (int)ScriptBaseClass.PRIM_FULLBRIGHT: 8574 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
8018 if (remain < 1) 8575 if (remain < 1)
8019 return res; 8576 return res;
8020 8577 face = (int)rules.GetLSLIntegerItem(idx++);
8021 face=(int)rules.GetLSLIntegerItem(idx++);
8022 8578
8023 tex = part.Shape.Textures; 8579 tex = part.Shape.Textures;
8580 int fullbright;
8024 if (face == ScriptBaseClass.ALL_SIDES) 8581 if (face == ScriptBaseClass.ALL_SIDES)
8025 { 8582 {
8026 for (face = 0; face < GetNumberOfSides(part); face++) 8583 for (face = 0; face < GetNumberOfSides(part); face++)
8027 { 8584 {
8028 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8585 if (tex.GetFace((uint)face).Fullbright == true)
8029 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0)); 8586 {
8587 fullbright = ScriptBaseClass.TRUE;
8588 }
8589 else
8590 {
8591 fullbright = ScriptBaseClass.FALSE;
8592 }
8593 res.Add(new LSL_Integer(fullbright));
8030 } 8594 }
8031 } 8595 }
8032 else 8596 else
8033 { 8597 {
8034 if (face >= 0 && face < GetNumberOfSides(part)) 8598 if (tex.GetFace((uint)face).Fullbright == true)
8035 { 8599 {
8036 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8600 fullbright = ScriptBaseClass.TRUE;
8037 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
8038 } 8601 }
8602 else
8603 {
8604 fullbright = ScriptBaseClass.FALSE;
8605 }
8606 res.Add(new LSL_Integer(fullbright));
8039 } 8607 }
8040 break; 8608 break;
8041 8609
@@ -8057,27 +8625,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8057 break; 8625 break;
8058 8626
8059 case (int)ScriptBaseClass.PRIM_TEXGEN: 8627 case (int)ScriptBaseClass.PRIM_TEXGEN:
8628 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
8060 if (remain < 1) 8629 if (remain < 1)
8061 return res; 8630 return res;
8062 8631 face = (int)rules.GetLSLIntegerItem(idx++);
8063 face=(int)rules.GetLSLIntegerItem(idx++);
8064 8632
8065 tex = part.Shape.Textures; 8633 tex = part.Shape.Textures;
8066 if (face == ScriptBaseClass.ALL_SIDES) 8634 if (face == ScriptBaseClass.ALL_SIDES)
8067 { 8635 {
8068 for (face = 0; face < GetNumberOfSides(part); face++) 8636 for (face = 0; face < GetNumberOfSides(part); face++)
8069 { 8637 {
8070 MappingType texgen = tex.GetFace((uint)face).TexMapType; 8638 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
8071 // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc. 8639 {
8072 res.Add(new LSL_Integer((uint)texgen >> 1)); 8640 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
8641 }
8642 else
8643 {
8644 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
8645 }
8073 } 8646 }
8074 } 8647 }
8075 else 8648 else
8076 { 8649 {
8077 if (face >= 0 && face < GetNumberOfSides(part)) 8650 if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
8078 { 8651 {
8079 MappingType texgen = tex.GetFace((uint)face).TexMapType; 8652 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
8080 res.Add(new LSL_Integer((uint)texgen >> 1)); 8653 }
8654 else
8655 {
8656 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
8081 } 8657 }
8082 } 8658 }
8083 break; 8659 break;
@@ -8100,28 +8676,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8100 case (int)ScriptBaseClass.PRIM_GLOW: 8676 case (int)ScriptBaseClass.PRIM_GLOW:
8101 if (remain < 1) 8677 if (remain < 1)
8102 return res; 8678 return res;
8103 8679 face = (int)rules.GetLSLIntegerItem(idx++);
8104 face=(int)rules.GetLSLIntegerItem(idx++);
8105 8680
8106 tex = part.Shape.Textures; 8681 tex = part.Shape.Textures;
8682 float primglow;
8107 if (face == ScriptBaseClass.ALL_SIDES) 8683 if (face == ScriptBaseClass.ALL_SIDES)
8108 { 8684 {
8109 for (face = 0; face < GetNumberOfSides(part); face++) 8685 for (face = 0; face < GetNumberOfSides(part); face++)
8110 { 8686 {
8111 Primitive.TextureEntryFace texface = tex.GetFace((uint)face); 8687 primglow = tex.GetFace((uint)face).Glow;
8112 res.Add(new LSL_Float(texface.Glow)); 8688 res.Add(new LSL_Float(primglow));
8113 } 8689 }
8114 } 8690 }
8115 else 8691 else
8116 { 8692 {
8117 if (face >= 0 && face < GetNumberOfSides(part)) 8693 primglow = tex.GetFace((uint)face).Glow;
8118 { 8694 res.Add(new LSL_Float(primglow));
8119 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8120 res.Add(new LSL_Float(texface.Glow));
8121 }
8122 } 8695 }
8123 break; 8696 break;
8124
8125 case (int)ScriptBaseClass.PRIM_TEXT: 8697 case (int)ScriptBaseClass.PRIM_TEXT:
8126 Color4 textColor = part.GetTextColor(); 8698 Color4 textColor = part.GetTextColor();
8127 res.Add(new LSL_String(part.Text)); 8699 res.Add(new LSL_String(part.Text));
@@ -8673,8 +9245,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8673 // The function returns an ordered list 9245 // The function returns an ordered list
8674 // representing the tokens found in the supplied 9246 // representing the tokens found in the supplied
8675 // sources string. If two successive tokenizers 9247 // sources string. If two successive tokenizers
8676 // are encountered, then a NULL entry is added 9248 // are encountered, then a null-string entry is
8677 // to the list. 9249 // added to the list.
8678 // 9250 //
8679 // It is a precondition that the source and 9251 // It is a precondition that the source and
8680 // toekizer lisst are non-null. If they are null, 9252 // toekizer lisst are non-null. If they are null,
@@ -8682,7 +9254,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8682 // while their lengths are being determined. 9254 // while their lengths are being determined.
8683 // 9255 //
8684 // A small amount of working memoryis required 9256 // A small amount of working memoryis required
8685 // of approximately 8*#tokenizers. 9257 // of approximately 8*#tokenizers + 8*srcstrlen.
8686 // 9258 //
8687 // There are many ways in which this function 9259 // There are many ways in which this function
8688 // can be implemented, this implementation is 9260 // can be implemented, this implementation is
@@ -8698,155 +9270,124 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8698 // and eliminates redundant tokenizers as soon 9270 // and eliminates redundant tokenizers as soon
8699 // as is possible. 9271 // as is possible.
8700 // 9272 //
8701 // The implementation tries to avoid any copying 9273 // The implementation tries to minimize temporary
8702 // of arrays or other objects. 9274 // garbage generation.
8703 // </remarks> 9275 // </remarks>
8704 9276
8705 private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls) 9277 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8706 { 9278 {
8707 int beginning = 0; 9279 return ParseString2List(src, separators, spacers, true);
8708 int srclen = src.Length; 9280 }
8709 int seplen = separators.Length;
8710 object[] separray = separators.Data;
8711 int spclen = spacers.Length;
8712 object[] spcarray = spacers.Data;
8713 int mlen = seplen+spclen;
8714
8715 int[] offset = new int[mlen+1];
8716 bool[] active = new bool[mlen];
8717
8718 int best;
8719 int j;
8720
8721 // Initial capacity reduces resize cost
8722 9281
8723 LSL_List tokens = new LSL_List(); 9282 private LSL_List ParseString2List(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
9283 {
9284 int srclen = src.Length;
9285 int seplen = separators.Length;
9286 object[] separray = separators.Data;
9287 int spclen = spacers.Length;
9288 object[] spcarray = spacers.Data;
9289 int dellen = 0;
9290 string[] delarray = new string[seplen+spclen];
8724 9291
8725 // All entries are initially valid 9292 int outlen = 0;
9293 string[] outarray = new string[srclen*2+1];
8726 9294
8727 for (int i = 0; i < mlen; i++) 9295 int i, j;
8728 active[i] = true; 9296 string d;
8729 9297
8730 offset[mlen] = srclen; 9298 m_host.AddScriptLPS(1);
8731 9299
8732 while (beginning < srclen) 9300 /*
9301 * Convert separator and spacer lists to C# strings.
9302 * Also filter out null strings so we don't hang.
9303 */
9304 for (i = 0; i < seplen; i ++)
8733 { 9305 {
9306 d = separray[i].ToString();
9307 if (d.Length > 0)
9308 {
9309 delarray[dellen++] = d;
9310 }
9311 }
9312 seplen = dellen;
8734 9313
8735 best = mlen; // as bad as it gets 9314 for (i = 0; i < spclen; i ++)
9315 {
9316 d = spcarray[i].ToString();
9317 if (d.Length > 0)
9318 {
9319 delarray[dellen++] = d;
9320 }
9321 }
8736 9322
8737 // Scan for separators 9323 /*
9324 * Scan through source string from beginning to end.
9325 */
9326 for (i = 0;;)
9327 {
8738 9328
8739 for (j = 0; j < seplen; j++) 9329 /*
9330 * Find earliest delimeter in src starting at i (if any).
9331 */
9332 int earliestDel = -1;
9333 int earliestSrc = srclen;
9334 string earliestStr = null;
9335 for (j = 0; j < dellen; j ++)
8740 { 9336 {
8741 if (separray[j].ToString() == String.Empty) 9337 d = delarray[j];
8742 active[j] = false; 9338 if (d != null)
8743
8744 if (active[j])
8745 { 9339 {
8746 // scan all of the markers 9340 int index = src.IndexOf(d, i);
8747 if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1) 9341 if (index < 0)
8748 { 9342 {
8749 // not present at all 9343 delarray[j] = null; // delim nowhere in src, don't check it anymore
8750 active[j] = false;
8751 } 9344 }
8752 else 9345 else if (index < earliestSrc)
8753 { 9346 {
8754 // present and correct 9347 earliestSrc = index; // where delimeter starts in source string
8755 if (offset[j] < offset[best]) 9348 earliestDel = j; // where delimeter is in delarray[]
8756 { 9349 earliestStr = d; // the delimeter string from delarray[]
8757 // closest so far 9350 if (index == i) break; // can't do any better than found at beg of string
8758 best = j;
8759 if (offset[best] == beginning)
8760 break;
8761 }
8762 } 9351 }
8763 } 9352 }
8764 } 9353 }
8765 9354
8766 // Scan for spacers 9355 /*
8767 9356 * Output source string starting at i through start of earliest delimeter.
8768 if (offset[best] != beginning) 9357 */
9358 if (keepNulls || (earliestSrc > i))
8769 { 9359 {
8770 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++) 9360 outarray[outlen++] = src.Substring(i, earliestSrc - i);
8771 {
8772 if (spcarray[j-seplen].ToString() == String.Empty)
8773 active[j] = false;
8774
8775 if (active[j])
8776 {
8777 // scan all of the markers
8778 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
8779 {
8780 // not present at all
8781 active[j] = false;
8782 }
8783 else
8784 {
8785 // present and correct
8786 if (offset[j] < offset[best])
8787 {
8788 // closest so far
8789 best = j;
8790 }
8791 }
8792 }
8793 }
8794 } 9361 }
8795 9362
8796 // This is the normal exit from the scanning loop 9363 /*
9364 * If no delimeter found at or after i, we're done scanning.
9365 */
9366 if (earliestDel < 0) break;
8797 9367
8798 if (best == mlen) 9368 /*
9369 * If delimeter was a spacer, output the spacer.
9370 */
9371 if (earliestDel >= seplen)
8799 { 9372 {
8800 // no markers were found on this pass 9373 outarray[outlen++] = earliestStr;
8801 // so we're pretty much done
8802 if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
8803 tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
8804 break;
8805 } 9374 }
8806 9375
8807 // Otherwise we just add the newly delimited token 9376 /*
8808 // and recalculate where the search should continue. 9377 * Look at rest of src string following delimeter.
8809 if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0)) 9378 */
8810 tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning))); 9379 i = earliestSrc + earliestStr.Length;
8811
8812 if (best < seplen)
8813 {
8814 beginning = offset[best] + (separray[best].ToString()).Length;
8815 }
8816 else
8817 {
8818 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
8819 string str = spcarray[best - seplen].ToString();
8820 if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
8821 tokens.Add(new LSL_String(str));
8822 }
8823 } 9380 }
8824 9381
8825 // This an awkward an not very intuitive boundary case. If the 9382 /*
8826 // last substring is a tokenizer, then there is an implied trailing 9383 * Make up an exact-sized output array suitable for an LSL_List object.
8827 // null list entry. Hopefully the single comparison will not be too 9384 */
8828 // arduous. Alternatively the 'break' could be replced with a return 9385 object[] outlist = new object[outlen];
8829 // but that's shabby programming. 9386 for (i = 0; i < outlen; i ++)
8830
8831 if ((beginning == srclen) && (keepNulls))
8832 { 9387 {
8833 if (srclen != 0) 9388 outlist[i] = new LSL_String(outarray[i]);
8834 tokens.Add(new LSL_String(""));
8835 } 9389 }
8836 9390 return new LSL_List(outlist);
8837 return tokens;
8838 }
8839
8840 public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers)
8841 {
8842 m_host.AddScriptLPS(1);
8843 return this.ParseString(src, separators, spacers, false);
8844 }
8845
8846 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
8847 {
8848 m_host.AddScriptLPS(1);
8849 return this.ParseString(src, separators, spacers, true);
8850 } 9391 }
8851 9392
8852 public LSL_Integer llGetObjectPermMask(int mask) 9393 public LSL_Integer llGetObjectPermMask(int mask)
@@ -8923,28 +9464,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8923 { 9464 {
8924 m_host.AddScriptLPS(1); 9465 m_host.AddScriptLPS(1);
8925 9466
8926 lock (m_host.TaskInventory) 9467 m_host.TaskInventory.LockItemsForRead(true);
9468 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8927 { 9469 {
8928 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9470 if (inv.Value.Name == item)
8929 { 9471 {
8930 if (inv.Value.Name == item) 9472 m_host.TaskInventory.LockItemsForRead(false);
9473 switch (mask)
8931 { 9474 {
8932 switch (mask) 9475 case 0:
8933 { 9476 return (int)inv.Value.BasePermissions;
8934 case 0: 9477 case 1:
8935 return (int)inv.Value.BasePermissions; 9478 return (int)inv.Value.CurrentPermissions;
8936 case 1: 9479 case 2:
8937 return (int)inv.Value.CurrentPermissions; 9480 return (int)inv.Value.GroupPermissions;
8938 case 2: 9481 case 3:
8939 return (int)inv.Value.GroupPermissions; 9482 return (int)inv.Value.EveryonePermissions;
8940 case 3: 9483 case 4:
8941 return (int)inv.Value.EveryonePermissions; 9484 return (int)inv.Value.NextPermissions;
8942 case 4:
8943 return (int)inv.Value.NextPermissions;
8944 }
8945 } 9485 }
8946 } 9486 }
8947 } 9487 }
9488 m_host.TaskInventory.LockItemsForRead(false);
8948 9489
8949 return -1; 9490 return -1;
8950 } 9491 }
@@ -8991,16 +9532,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
8991 { 9532 {
8992 m_host.AddScriptLPS(1); 9533 m_host.AddScriptLPS(1);
8993 9534
8994 lock (m_host.TaskInventory) 9535 m_host.TaskInventory.LockItemsForRead(true);
9536 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
8995 { 9537 {
8996 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 9538 if (inv.Value.Name == item)
8997 { 9539 {
8998 if (inv.Value.Name == item) 9540 m_host.TaskInventory.LockItemsForRead(false);
8999 { 9541 return inv.Value.CreatorID.ToString();
9000 return inv.Value.CreatorID.ToString();
9001 }
9002 } 9542 }
9003 } 9543 }
9544 m_host.TaskInventory.LockItemsForRead(false);
9004 9545
9005 llSay(0, "No item name '" + item + "'"); 9546 llSay(0, "No item name '" + item + "'");
9006 9547
@@ -9148,7 +9689,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9148 } 9689 }
9149 9690
9150 /// <summary> 9691 /// <summary>
9151 /// illListReplaceList removes the sub-list defined by the inclusive indices 9692 /// llListReplaceList removes the sub-list defined by the inclusive indices
9152 /// start and end and inserts the src list in its place. The inclusive 9693 /// start and end and inserts the src list in its place. The inclusive
9153 /// nature of the indices means that at least one element must be deleted 9694 /// nature of the indices means that at least one element must be deleted
9154 /// if the indices are within the bounds of the existing list. I.e. 2,2 9695 /// if the indices are within the bounds of the existing list. I.e. 2,2
@@ -9205,16 +9746,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9205 // based upon end. Note that if end exceeds the upper 9746 // based upon end. Note that if end exceeds the upper
9206 // bound in this case, the entire destination list 9747 // bound in this case, the entire destination list
9207 // is removed. 9748 // is removed.
9208 else 9749 else if (start == 0)
9209 { 9750 {
9210 if (end + 1 < dest.Length) 9751 if (end + 1 < dest.Length)
9211 {
9212 return src + dest.GetSublist(end + 1, -1); 9752 return src + dest.GetSublist(end + 1, -1);
9213 }
9214 else 9753 else
9215 {
9216 return src; 9754 return src;
9217 } 9755 }
9756 else // Start < 0
9757 {
9758 if (end + 1 < dest.Length)
9759 return dest.GetSublist(end + 1, -1);
9760 else
9761 return new LSL_List();
9218 } 9762 }
9219 } 9763 }
9220 // Finally, if start > end, we strip away a prefix and 9764 // Finally, if start > end, we strip away a prefix and
@@ -9265,17 +9809,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9265 int width = 0; 9809 int width = 0;
9266 int height = 0; 9810 int height = 0;
9267 9811
9268 ParcelMediaCommandEnum? commandToSend = null; 9812 uint commandToSend = 0;
9269 float time = 0.0f; // default is from start 9813 float time = 0.0f; // default is from start
9270 9814
9271 ScenePresence presence = null; 9815 ScenePresence presence = null;
9272 9816
9273 for (int i = 0; i < commandList.Data.Length; i++) 9817 for (int i = 0; i < commandList.Data.Length; i++)
9274 { 9818 {
9275 ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i]; 9819 uint command = (uint)(commandList.GetLSLIntegerItem(i));
9276 switch (command) 9820 switch (command)
9277 { 9821 {
9278 case ParcelMediaCommandEnum.Agent: 9822 case (uint)ParcelMediaCommandEnum.Agent:
9279 // we send only to one agent 9823 // we send only to one agent
9280 if ((i + 1) < commandList.Length) 9824 if ((i + 1) < commandList.Length)
9281 { 9825 {
@@ -9292,25 +9836,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9292 } 9836 }
9293 break; 9837 break;
9294 9838
9295 case ParcelMediaCommandEnum.Loop: 9839 case (uint)ParcelMediaCommandEnum.Loop:
9296 loop = 1; 9840 loop = 1;
9297 commandToSend = command; 9841 commandToSend = command;
9298 update = true; //need to send the media update packet to set looping 9842 update = true; //need to send the media update packet to set looping
9299 break; 9843 break;
9300 9844
9301 case ParcelMediaCommandEnum.Play: 9845 case (uint)ParcelMediaCommandEnum.Play:
9302 loop = 0; 9846 loop = 0;
9303 commandToSend = command; 9847 commandToSend = command;
9304 update = true; //need to send the media update packet to make sure it doesn't loop 9848 update = true; //need to send the media update packet to make sure it doesn't loop
9305 break; 9849 break;
9306 9850
9307 case ParcelMediaCommandEnum.Pause: 9851 case (uint)ParcelMediaCommandEnum.Pause:
9308 case ParcelMediaCommandEnum.Stop: 9852 case (uint)ParcelMediaCommandEnum.Stop:
9309 case ParcelMediaCommandEnum.Unload: 9853 case (uint)ParcelMediaCommandEnum.Unload:
9310 commandToSend = command; 9854 commandToSend = command;
9311 break; 9855 break;
9312 9856
9313 case ParcelMediaCommandEnum.Url: 9857 case (uint)ParcelMediaCommandEnum.Url:
9314 if ((i + 1) < commandList.Length) 9858 if ((i + 1) < commandList.Length)
9315 { 9859 {
9316 if (commandList.Data[i + 1] is LSL_String) 9860 if (commandList.Data[i + 1] is LSL_String)
@@ -9323,7 +9867,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9323 } 9867 }
9324 break; 9868 break;
9325 9869
9326 case ParcelMediaCommandEnum.Texture: 9870 case (uint)ParcelMediaCommandEnum.Texture:
9327 if ((i + 1) < commandList.Length) 9871 if ((i + 1) < commandList.Length)
9328 { 9872 {
9329 if (commandList.Data[i + 1] is LSL_String) 9873 if (commandList.Data[i + 1] is LSL_String)
@@ -9336,7 +9880,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9336 } 9880 }
9337 break; 9881 break;
9338 9882
9339 case ParcelMediaCommandEnum.Time: 9883 case (uint)ParcelMediaCommandEnum.Time:
9340 if ((i + 1) < commandList.Length) 9884 if ((i + 1) < commandList.Length)
9341 { 9885 {
9342 if (commandList.Data[i + 1] is LSL_Float) 9886 if (commandList.Data[i + 1] is LSL_Float)
@@ -9348,7 +9892,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9348 } 9892 }
9349 break; 9893 break;
9350 9894
9351 case ParcelMediaCommandEnum.AutoAlign: 9895 case (uint)ParcelMediaCommandEnum.AutoAlign:
9352 if ((i + 1) < commandList.Length) 9896 if ((i + 1) < commandList.Length)
9353 { 9897 {
9354 if (commandList.Data[i + 1] is LSL_Integer) 9898 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9362,7 +9906,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9362 } 9906 }
9363 break; 9907 break;
9364 9908
9365 case ParcelMediaCommandEnum.Type: 9909 case (uint)ParcelMediaCommandEnum.Type:
9366 if ((i + 1) < commandList.Length) 9910 if ((i + 1) < commandList.Length)
9367 { 9911 {
9368 if (commandList.Data[i + 1] is LSL_String) 9912 if (commandList.Data[i + 1] is LSL_String)
@@ -9375,7 +9919,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9375 } 9919 }
9376 break; 9920 break;
9377 9921
9378 case ParcelMediaCommandEnum.Desc: 9922 case (uint)ParcelMediaCommandEnum.Desc:
9379 if ((i + 1) < commandList.Length) 9923 if ((i + 1) < commandList.Length)
9380 { 9924 {
9381 if (commandList.Data[i + 1] is LSL_String) 9925 if (commandList.Data[i + 1] is LSL_String)
@@ -9388,7 +9932,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9388 } 9932 }
9389 break; 9933 break;
9390 9934
9391 case ParcelMediaCommandEnum.Size: 9935 case (uint)ParcelMediaCommandEnum.Size:
9392 if ((i + 2) < commandList.Length) 9936 if ((i + 2) < commandList.Length)
9393 { 9937 {
9394 if (commandList.Data[i + 1] is LSL_Integer) 9938 if (commandList.Data[i + 1] is LSL_Integer)
@@ -9458,7 +10002,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9458 } 10002 }
9459 } 10003 }
9460 10004
9461 if (commandToSend != null) 10005 if (commandToSend != 0)
9462 { 10006 {
9463 // the commandList contained a start/stop/... command, too 10007 // the commandList contained a start/stop/... command, too
9464 if (presence == null) 10008 if (presence == null)
@@ -9495,7 +10039,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9495 10039
9496 if (aList.Data[i] != null) 10040 if (aList.Data[i] != null)
9497 { 10041 {
9498 switch ((ParcelMediaCommandEnum) aList.Data[i]) 10042 switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString()))
9499 { 10043 {
9500 case ParcelMediaCommandEnum.Url: 10044 case ParcelMediaCommandEnum.Url:
9501 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL)); 10045 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
@@ -9538,16 +10082,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9538 { 10082 {
9539 m_host.AddScriptLPS(1); 10083 m_host.AddScriptLPS(1);
9540 10084
9541 lock (m_host.TaskInventory) 10085 m_host.TaskInventory.LockItemsForRead(true);
10086 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
9542 { 10087 {
9543 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 10088 if (inv.Value.Name == name)
9544 { 10089 {
9545 if (inv.Value.Name == name) 10090 m_host.TaskInventory.LockItemsForRead(false);
9546 { 10091 return inv.Value.Type;
9547 return inv.Value.Type;
9548 }
9549 } 10092 }
9550 } 10093 }
10094 m_host.TaskInventory.LockItemsForRead(false);
9551 10095
9552 return -1; 10096 return -1;
9553 } 10097 }
@@ -9558,15 +10102,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9558 10102
9559 if (quick_pay_buttons.Data.Length < 4) 10103 if (quick_pay_buttons.Data.Length < 4)
9560 { 10104 {
9561 LSLError("List must have at least 4 elements"); 10105 int x;
9562 return; 10106 for (x=quick_pay_buttons.Data.Length; x<= 4; x++)
10107 {
10108 quick_pay_buttons.Add(ScriptBaseClass.PAY_HIDE);
10109 }
9563 } 10110 }
9564 m_host.ParentGroup.RootPart.PayPrice[0]=price; 10111 int[] nPrice = new int[5];
9565 10112 nPrice[0] = price;
9566 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0]; 10113 nPrice[1] = quick_pay_buttons.GetLSLIntegerItem(0);
9567 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1]; 10114 nPrice[2] = quick_pay_buttons.GetLSLIntegerItem(1);
9568 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2]; 10115 nPrice[3] = quick_pay_buttons.GetLSLIntegerItem(2);
9569 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3]; 10116 nPrice[4] = quick_pay_buttons.GetLSLIntegerItem(3);
10117 m_host.ParentGroup.RootPart.PayPrice = nPrice;
9570 m_host.ParentGroup.HasGroupChanged = true; 10118 m_host.ParentGroup.HasGroupChanged = true;
9571 } 10119 }
9572 10120
@@ -9578,17 +10126,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9578 if (invItemID == UUID.Zero) 10126 if (invItemID == UUID.Zero)
9579 return new LSL_Vector(); 10127 return new LSL_Vector();
9580 10128
9581 lock (m_host.TaskInventory) 10129 m_host.TaskInventory.LockItemsForRead(true);
10130 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9582 { 10131 {
9583 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 10132 m_host.TaskInventory.LockItemsForRead(false);
9584 return new LSL_Vector(); 10133 return new LSL_Vector();
10134 }
9585 10135
9586 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) 10136 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9587 { 10137 {
9588 ShoutError("No permissions to track the camera"); 10138 ShoutError("No permissions to track the camera");
9589 return new LSL_Vector(); 10139 m_host.TaskInventory.LockItemsForRead(false);
9590 } 10140 return new LSL_Vector();
9591 } 10141 }
10142 m_host.TaskInventory.LockItemsForRead(false);
9592 10143
9593 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 10144 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9594 if (presence != null) 10145 if (presence != null)
@@ -9606,17 +10157,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9606 if (invItemID == UUID.Zero) 10157 if (invItemID == UUID.Zero)
9607 return new LSL_Rotation(); 10158 return new LSL_Rotation();
9608 10159
9609 lock (m_host.TaskInventory) 10160 m_host.TaskInventory.LockItemsForRead(true);
10161 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
9610 { 10162 {
9611 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) 10163 m_host.TaskInventory.LockItemsForRead(false);
9612 return new LSL_Rotation(); 10164 return new LSL_Rotation();
9613
9614 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
9615 {
9616 ShoutError("No permissions to track the camera");
9617 return new LSL_Rotation();
9618 }
9619 } 10165 }
10166 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10167 {
10168 ShoutError("No permissions to track the camera");
10169 m_host.TaskInventory.LockItemsForRead(false);
10170 return new LSL_Rotation();
10171 }
10172 m_host.TaskInventory.LockItemsForRead(false);
9620 10173
9621 ScenePresence presence = World.GetScenePresence(m_host.OwnerID); 10174 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
9622 if (presence != null) 10175 if (presence != null)
@@ -9678,8 +10231,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9678 { 10231 {
9679 m_host.AddScriptLPS(1); 10232 m_host.AddScriptLPS(1);
9680 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0); 10233 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0);
9681 if (detectedParams == null) return; // only works on the first detected avatar 10234 if (detectedParams == null)
9682 10235 {
10236 if (m_host.ParentGroup.IsAttachment == true)
10237 {
10238 detectedParams = new DetectParams();
10239 detectedParams.Key = m_host.OwnerID;
10240 }
10241 else
10242 {
10243 return;
10244 }
10245 }
10246
9683 ScenePresence avatar = World.GetScenePresence(detectedParams.Key); 10247 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
9684 if (avatar != null) 10248 if (avatar != null)
9685 { 10249 {
@@ -9687,6 +10251,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9687 new Vector3((float)pos.x, (float)pos.y, (float)pos.z), 10251 new Vector3((float)pos.x, (float)pos.y, (float)pos.z),
9688 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z)); 10252 new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z));
9689 } 10253 }
10254
9690 ScriptSleep(1000); 10255 ScriptSleep(1000);
9691 } 10256 }
9692 10257
@@ -9798,14 +10363,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9798 if (objectID == UUID.Zero) return; 10363 if (objectID == UUID.Zero) return;
9799 10364
9800 UUID agentID; 10365 UUID agentID;
9801 lock (m_host.TaskInventory) 10366 m_host.TaskInventory.LockItemsForRead(true);
9802 { 10367 // we need the permission first, to know which avatar we want to set the camera for
9803 // we need the permission first, to know which avatar we want to set the camera for 10368 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9804 agentID = m_host.TaskInventory[invItemID].PermsGranter;
9805 10369
9806 if (agentID == UUID.Zero) return; 10370 if (agentID == UUID.Zero)
9807 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; 10371 {
10372 m_host.TaskInventory.LockItemsForRead(false);
10373 return;
10374 }
10375 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10376 {
10377 m_host.TaskInventory.LockItemsForRead(false);
10378 return;
9808 } 10379 }
10380 m_host.TaskInventory.LockItemsForRead(false);
9809 10381
9810 ScenePresence presence = World.GetScenePresence(agentID); 10382 ScenePresence presence = World.GetScenePresence(agentID);
9811 10383
@@ -9814,12 +10386,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9814 10386
9815 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>(); 10387 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
9816 object[] data = rules.Data; 10388 object[] data = rules.Data;
9817 for (int i = 0; i < data.Length; ++i) { 10389 for (int i = 0; i < data.Length; ++i)
10390 {
9818 int type = Convert.ToInt32(data[i++].ToString()); 10391 int type = Convert.ToInt32(data[i++].ToString());
9819 if (i >= data.Length) break; // odd number of entries => ignore the last 10392 if (i >= data.Length) break; // odd number of entries => ignore the last
9820 10393
9821 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3) 10394 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
9822 switch (type) { 10395 switch (type)
10396 {
9823 case ScriptBaseClass.CAMERA_FOCUS: 10397 case ScriptBaseClass.CAMERA_FOCUS:
9824 case ScriptBaseClass.CAMERA_FOCUS_OFFSET: 10398 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
9825 case ScriptBaseClass.CAMERA_POSITION: 10399 case ScriptBaseClass.CAMERA_POSITION:
@@ -9855,12 +10429,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9855 10429
9856 // we need the permission first, to know which avatar we want to clear the camera for 10430 // we need the permission first, to know which avatar we want to clear the camera for
9857 UUID agentID; 10431 UUID agentID;
9858 lock (m_host.TaskInventory) 10432 m_host.TaskInventory.LockItemsForRead(true);
10433 agentID = m_host.TaskInventory[invItemID].PermsGranter;
10434 if (agentID == UUID.Zero)
9859 { 10435 {
9860 agentID = m_host.TaskInventory[invItemID].PermsGranter; 10436 m_host.TaskInventory.LockItemsForRead(false);
9861 if (agentID == UUID.Zero) return; 10437 return;
9862 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
9863 } 10438 }
10439 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10440 {
10441 m_host.TaskInventory.LockItemsForRead(false);
10442 return;
10443 }
10444 m_host.TaskInventory.LockItemsForRead(false);
9864 10445
9865 ScenePresence presence = World.GetScenePresence(agentID); 10446 ScenePresence presence = World.GetScenePresence(agentID);
9866 10447
@@ -9927,19 +10508,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9927 public LSL_String llXorBase64StringsCorrect(string str1, string str2) 10508 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
9928 { 10509 {
9929 m_host.AddScriptLPS(1); 10510 m_host.AddScriptLPS(1);
9930 string ret = String.Empty; 10511
9931 string src1 = llBase64ToString(str1); 10512 if (str1 == String.Empty)
9932 string src2 = llBase64ToString(str2); 10513 return String.Empty;
9933 int c = 0; 10514 if (str2 == String.Empty)
9934 for (int i = 0; i < src1.Length; i++) 10515 return str1;
10516
10517 int len = str2.Length;
10518 if ((len % 4) != 0) // LL is EVIL!!!!
9935 { 10519 {
9936 ret += (char) (src1[i] ^ src2[c]); 10520 while (str2.EndsWith("="))
10521 str2 = str2.Substring(0, str2.Length - 1);
10522
10523 len = str2.Length;
10524 int mod = len % 4;
10525
10526 if (mod == 1)
10527 str2 = str2.Substring(0, str2.Length - 1);
10528 else if (mod == 2)
10529 str2 += "==";
10530 else if (mod == 3)
10531 str2 += "=";
10532 }
9937 10533
9938 c++; 10534 byte[] data1;
9939 if (c >= src2.Length) 10535 byte[] data2;
9940 c = 0; 10536 try
10537 {
10538 data1 = Convert.FromBase64String(str1);
10539 data2 = Convert.FromBase64String(str2);
10540 }
10541 catch (Exception)
10542 {
10543 return new LSL_String(String.Empty);
9941 } 10544 }
9942 return llStringToBase64(ret); 10545
10546 byte[] d2 = new Byte[data1.Length];
10547 int pos = 0;
10548
10549 if (data1.Length <= data2.Length)
10550 {
10551 Array.Copy(data2, 0, d2, 0, data1.Length);
10552 }
10553 else
10554 {
10555 while (pos < data1.Length)
10556 {
10557 len = data1.Length - pos;
10558 if (len > data2.Length)
10559 len = data2.Length;
10560
10561 Array.Copy(data2, 0, d2, pos, len);
10562 pos += len;
10563 }
10564 }
10565
10566 for (pos = 0 ; pos < data1.Length ; pos++ )
10567 data1[pos] ^= d2[pos];
10568
10569 return Convert.ToBase64String(data1);
9943 } 10570 }
9944 10571
9945 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body) 10572 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
@@ -9996,12 +10623,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
9996 Regex r = new Regex(authregex); 10623 Regex r = new Regex(authregex);
9997 int[] gnums = r.GetGroupNumbers(); 10624 int[] gnums = r.GetGroupNumbers();
9998 Match m = r.Match(url); 10625 Match m = r.Match(url);
9999 if (m.Success) { 10626 if (m.Success)
10000 for (int i = 1; i < gnums.Length; i++) { 10627 {
10628 for (int i = 1; i < gnums.Length; i++)
10629 {
10001 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]]; 10630 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
10002 //CaptureCollection cc = g.Captures; 10631 //CaptureCollection cc = g.Captures;
10003 } 10632 }
10004 if (m.Groups.Count == 5) { 10633 if (m.Groups.Count == 5)
10634 {
10005 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString()))); 10635 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
10006 url = m.Groups[1].ToString() + m.Groups[4].ToString(); 10636 url = m.Groups[1].ToString() + m.Groups[4].ToString();
10007 } 10637 }
@@ -10287,15 +10917,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10287 10917
10288 internal UUID ScriptByName(string name) 10918 internal UUID ScriptByName(string name)
10289 { 10919 {
10290 lock (m_host.TaskInventory) 10920 m_host.TaskInventory.LockItemsForRead(true);
10921
10922 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
10291 { 10923 {
10292 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 10924 if (item.Type == 10 && item.Name == name)
10293 { 10925 {
10294 if (item.Type == 10 && item.Name == name) 10926 m_host.TaskInventory.LockItemsForRead(false);
10295 return item.ItemID; 10927 return item.ItemID;
10296 } 10928 }
10297 } 10929 }
10298 10930
10931 m_host.TaskInventory.LockItemsForRead(false);
10932
10299 return UUID.Zero; 10933 return UUID.Zero;
10300 } 10934 }
10301 10935
@@ -10336,6 +10970,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10336 { 10970 {
10337 m_host.AddScriptLPS(1); 10971 m_host.AddScriptLPS(1);
10338 10972
10973 //Clone is thread safe
10339 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 10974 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10340 10975
10341 UUID assetID = UUID.Zero; 10976 UUID assetID = UUID.Zero;
@@ -10398,6 +11033,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10398 { 11033 {
10399 m_host.AddScriptLPS(1); 11034 m_host.AddScriptLPS(1);
10400 11035
11036 //Clone is thread safe
10401 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); 11037 TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone();
10402 11038
10403 UUID assetID = UUID.Zero; 11039 UUID assetID = UUID.Zero;
@@ -10478,15 +11114,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10478 return GetLinkPrimitiveParams(obj, rules); 11114 return GetLinkPrimitiveParams(obj, rules);
10479 } 11115 }
10480 11116
10481 public void print(string str) 11117 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
10482 { 11118 {
10483 // yes, this is a real LSL function. See: http://wiki.secondlife.com/wiki/Print 11119 List<SceneObjectPart> parts = GetLinkParts(link);
10484 IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_itemID, "OSSL"); 11120 if (parts.Count < 1)
10485 if (ossl != null) 11121 return 0;
10486 { 11122
10487 ossl.CheckThreatLevel(ThreatLevel.High, "print"); 11123 return GetNumberOfSides(parts[0]);
10488 m_log.Info("LSL print():" + str);
10489 }
10490 } 11124 }
10491 11125
10492 private string Name2Username(string name) 11126 private string Name2Username(string name)
@@ -10532,153 +11166,392 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10532 return rq.ToString(); 11166 return rq.ToString();
10533 } 11167 }
10534 11168
11169 private void SayShoutTimerElapsed(Object sender, ElapsedEventArgs args)
11170 {
11171 m_SayShoutCount = 0;
11172 }
11173
11174 private struct Tri
11175 {
11176 public Vector3 p1;
11177 public Vector3 p2;
11178 public Vector3 p3;
11179 }
11180
11181 private bool InBoundingBox(ScenePresence avatar, Vector3 point)
11182 {
11183 float height = avatar.Appearance.AvatarHeight;
11184 Vector3 b1 = avatar.AbsolutePosition + new Vector3(-0.22f, -0.22f, -height/2);
11185 Vector3 b2 = avatar.AbsolutePosition + new Vector3(0.22f, 0.22f, height/2);
11186
11187 if (point.X > b1.X && point.X < b2.X &&
11188 point.Y > b1.Y && point.Y < b2.Y &&
11189 point.Z > b1.Z && point.Z < b2.Z)
11190 return true;
11191 return false;
11192 }
11193
11194 private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd)
11195 {
11196 List<ContactResult> contacts = new List<ContactResult>();
11197
11198 Vector3 ab = rayEnd - rayStart;
11199
11200 World.ForEachScenePresence(delegate(ScenePresence sp)
11201 {
11202 Vector3 ac = sp.AbsolutePosition - rayStart;
11203 Vector3 bc = sp.AbsolutePosition - rayEnd;
11204
11205 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11206
11207 if (d > 1.5)
11208 return;
11209
11210 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
11211
11212 if (d2 > 0)
11213 return;
11214
11215 double dp = Math.Sqrt(Vector3.Mag(ac) * Vector3.Mag(ac) - d * d);
11216 Vector3 p = rayStart + Vector3.Divide(Vector3.Multiply(ab, (float)dp), (float)Vector3.Mag(ab));
11217
11218 if (!InBoundingBox(sp, p))
11219 return;
11220
11221 ContactResult result = new ContactResult ();
11222 result.ConsumerID = sp.LocalId;
11223 result.Depth = Vector3.Distance(rayStart, p);
11224 result.Normal = Vector3.Zero;
11225 result.Pos = p;
11226
11227 contacts.Add(result);
11228 });
11229
11230 return contacts.ToArray();
11231 }
11232
11233 private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom)
11234 {
11235 Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
11236 List<ContactResult> contacts = new List<ContactResult>();
11237
11238 Vector3 ab = rayEnd - rayStart;
11239
11240 World.ForEachSOG(delegate(SceneObjectGroup group)
11241 {
11242 if (m_host.ParentGroup == group)
11243 return;
11244
11245 if (group.IsAttachment)
11246 return;
11247
11248 if (group.RootPart.PhysActor == null)
11249 {
11250 if (!includePhantom)
11251 return;
11252 }
11253 else
11254 {
11255 if (group.RootPart.PhysActor.IsPhysical)
11256 {
11257 if (!includePhysical)
11258 return;
11259 }
11260 else
11261 {
11262 if (!includeNonPhysical)
11263 return;
11264 }
11265 }
11266
11267 // Find the radius ouside of which we don't even need to hit test
11268 float minX;
11269 float maxX;
11270 float minY;
11271 float maxY;
11272 float minZ;
11273 float maxZ;
11274
11275 float radius = 0.0f;
11276
11277 group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
11278
11279 if (Math.Abs(minX) > radius)
11280 radius = Math.Abs(minX);
11281 if (Math.Abs(minY) > radius)
11282 radius = Math.Abs(minY);
11283 if (Math.Abs(minZ) > radius)
11284 radius = Math.Abs(minZ);
11285 if (Math.Abs(maxX) > radius)
11286 radius = Math.Abs(maxX);
11287 if (Math.Abs(maxY) > radius)
11288 radius = Math.Abs(maxY);
11289 if (Math.Abs(maxZ) > radius)
11290 radius = Math.Abs(maxZ);
11291
11292 Vector3 ac = group.AbsolutePosition - rayStart;
11293 Vector3 bc = group.AbsolutePosition - rayEnd;
11294
11295 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11296
11297 // Too far off ray, don't bother
11298 if (d > radius)
11299 return;
11300
11301 // Behind ray, drop
11302 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
11303 if (d2 > 0)
11304 return;
11305
11306 EntityIntersection intersection = group.TestIntersection(ray, true, false);
11307 // Miss.
11308 if (!intersection.HitTF)
11309 return;
11310
11311 ContactResult result = new ContactResult ();
11312 result.ConsumerID = group.LocalId;
11313 result.Depth = intersection.distance;
11314 result.Normal = intersection.normal;
11315 result.Pos = intersection.ipoint;
11316
11317 contacts.Add(result);
11318 });
11319
11320 return contacts.ToArray();
11321 }
11322
11323 private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd)
11324 {
11325 double[,] heightfield = World.Heightmap.GetDoubles();
11326 List<ContactResult> contacts = new List<ContactResult>();
11327
11328 double min = 2048.0;
11329 double max = 0.0;
11330
11331 // Find the min and max of the heightfield
11332 for (int x = 0 ; x < World.Heightmap.Width ; x++)
11333 {
11334 for (int y = 0 ; y < World.Heightmap.Height ; y++)
11335 {
11336 if (heightfield[x, y] > max)
11337 max = heightfield[x, y];
11338 if (heightfield[x, y] < min)
11339 min = heightfield[x, y];
11340 }
11341 }
11342
11343
11344 // A ray extends past rayEnd, but doesn't go back before
11345 // rayStart. If the start is above the highest point of the ground
11346 // and the ray goes up, we can't hit the ground. Ever.
11347 if (rayStart.Z > max && rayEnd.Z >= rayStart.Z)
11348 return null;
11349
11350 // Same for going down
11351 if (rayStart.Z < min && rayEnd.Z <= rayStart.Z)
11352 return null;
11353
11354 List<Tri> trilist = new List<Tri>();
11355
11356 // Create our triangle list
11357 for (int x = 1 ; x < World.Heightmap.Width ; x++)
11358 {
11359 for (int y = 1 ; y < World.Heightmap.Height ; y++)
11360 {
11361 Tri t1 = new Tri();
11362 Tri t2 = new Tri();
11363
11364 Vector3 p1 = new Vector3(x-1, y-1, (float)heightfield[x-1, y-1]);
11365 Vector3 p2 = new Vector3(x, y-1, (float)heightfield[x, y-1]);
11366 Vector3 p3 = new Vector3(x, y, (float)heightfield[x, y]);
11367 Vector3 p4 = new Vector3(x-1, y, (float)heightfield[x-1, y]);
11368
11369 t1.p1 = p1;
11370 t1.p2 = p2;
11371 t1.p3 = p3;
11372
11373 t2.p1 = p3;
11374 t2.p2 = p4;
11375 t2.p3 = p1;
11376
11377 trilist.Add(t1);
11378 trilist.Add(t2);
11379 }
11380 }
11381
11382 // Ray direction
11383 Vector3 rayDirection = rayEnd - rayStart;
11384
11385 foreach (Tri t in trilist)
11386 {
11387 // Compute triangle plane normal and edges
11388 Vector3 u = t.p2 - t.p1;
11389 Vector3 v = t.p3 - t.p1;
11390 Vector3 n = Vector3.Cross(u, v);
11391
11392 if (n == Vector3.Zero)
11393 continue;
11394
11395 Vector3 w0 = rayStart - t.p1;
11396 double a = -Vector3.Dot(n, w0);
11397 double b = Vector3.Dot(n, rayDirection);
11398
11399 // Not intersecting the plane, or in plane (same thing)
11400 // Ignoring this MAY cause the ground to not be detected
11401 // sometimes
11402 if (Math.Abs(b) < 0.000001)
11403 continue;
11404
11405 double r = a / b;
11406
11407 // ray points away from plane
11408 if (r < 0.0)
11409 continue;
11410
11411 Vector3 ip = rayStart + Vector3.Multiply(rayDirection, (float)r);
11412
11413 float uu = Vector3.Dot(u, u);
11414 float uv = Vector3.Dot(u, v);
11415 float vv = Vector3.Dot(v, v);
11416 Vector3 w = ip - t.p1;
11417 float wu = Vector3.Dot(w, u);
11418 float wv = Vector3.Dot(w, v);
11419 float d = uv * uv - uu * vv;
11420
11421 float cs = (uv * wv - vv * wu) / d;
11422 if (cs < 0 || cs > 1.0)
11423 continue;
11424 float ct = (uv * wu - uu * wv) / d;
11425 if (ct < 0 || (cs + ct) > 1.0)
11426 continue;
11427
11428 // Add contact point
11429 ContactResult result = new ContactResult ();
11430 result.ConsumerID = 0;
11431 result.Depth = Vector3.Distance(rayStart, ip);
11432 result.Normal = n;
11433 result.Pos = ip;
11434
11435 contacts.Add(result);
11436 }
11437
11438 if (contacts.Count == 0)
11439 return null;
11440
11441 contacts.Sort(delegate(ContactResult a, ContactResult b)
11442 {
11443 return (int)(a.Depth - b.Depth);
11444 });
11445
11446 return contacts[0];
11447 }
11448
10535 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) 11449 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
10536 { 11450 {
11451 LSL_List list = new LSL_List();
11452
10537 m_host.AddScriptLPS(1); 11453 m_host.AddScriptLPS(1);
10538 11454
10539 Vector3 dir = new Vector3((float)(end-start).x, (float)(end-start).y, (float)(end-start).z); 11455 Vector3 rayStart = new Vector3((float)start.x, (float)start.y, (float)start.z);
10540 Vector3 startvector = new Vector3((float)start.x, (float)start.y, (float)start.z); 11456 Vector3 rayEnd = new Vector3((float)end.x, (float)end.y, (float)end.z);
10541 Vector3 endvector = new Vector3((float)end.x, (float)end.y, (float)end.z); 11457 Vector3 dir = rayEnd - rayStart;
10542 11458
10543 int count = 0; 11459 int count = 1;
10544// int detectPhantom = 0; 11460 bool detectPhantom = false;
10545 int dataFlags = 0; 11461 int dataFlags = 0;
10546 int rejectTypes = 0; 11462 int rejectTypes = 0;
10547 11463
10548 for (int i = 0; i < options.Length; i += 2) 11464 for (int i = 0; i < options.Length; i += 2)
10549 { 11465 {
10550 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) 11466 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
10551 {
10552 count = options.GetLSLIntegerItem(i + 1); 11467 count = options.GetLSLIntegerItem(i + 1);
10553 } 11468 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
10554// else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) 11469 detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0);
10555// {
10556// detectPhantom = options.GetLSLIntegerItem(i + 1);
10557// }
10558 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) 11470 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
10559 {
10560 dataFlags = options.GetLSLIntegerItem(i + 1); 11471 dataFlags = options.GetLSLIntegerItem(i + 1);
10561 }
10562 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) 11472 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
10563 {
10564 rejectTypes = options.GetLSLIntegerItem(i + 1); 11473 rejectTypes = options.GetLSLIntegerItem(i + 1);
10565 }
10566 } 11474 }
10567 11475
10568 LSL_List list = new LSL_List(); 11476 if (count > 16)
10569 List<ContactResult> results = World.PhysicsScene.RaycastWorld(startvector, dir, dir.Length(), count); 11477 count = 16;
10570
10571 double distance = Util.GetDistanceTo(startvector, endvector);
10572 11478
10573 if (distance == 0) 11479 List<ContactResult> results = new List<ContactResult>();
10574 distance = 0.001;
10575
10576 Vector3 posToCheck = startvector;
10577 ITerrainChannel channel = World.RequestModuleInterface<ITerrainChannel>();
10578 11480
10579 bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND); 11481 bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND);
10580 bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS); 11482 bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS);
10581 bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); 11483 bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL);
10582 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); 11484 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
10583 11485
10584 for (float i = 0; i <= distance; i += 0.1f) 11486 if (checkTerrain)
10585 { 11487 {
10586 posToCheck = startvector + (dir * (i / (float)distance)); 11488 ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
11489 if (groundContact != null)
11490 results.Add((ContactResult)groundContact);
11491 }
10587 11492
10588 if (checkTerrain && channel[(int)(posToCheck.X + startvector.X), (int)(posToCheck.Y + startvector.Y)] < posToCheck.Z) 11493 if (checkAgents)
10589 { 11494 {
10590 ContactResult result = new ContactResult(); 11495 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
10591 result.ConsumerID = 0; 11496 foreach (ContactResult r in agentHits)
10592 result.Depth = 0; 11497 results.Add(r);
10593 result.Normal = Vector3.Zero; 11498 }
10594 result.Pos = posToCheck;
10595 results.Add(result);
10596 checkTerrain = false;
10597 }
10598 11499
10599 if (checkAgents) 11500 if (checkPhysical || checkNonPhysical)
10600 { 11501 {
10601 World.ForEachRootScenePresence(delegate(ScenePresence sp) 11502 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
10602 { 11503 foreach (ContactResult r in objectHits)
10603 if (sp.AbsolutePosition.ApproxEquals(posToCheck, sp.PhysicsActor.Size.X)) 11504 results.Add(r);
10604 {
10605 ContactResult result = new ContactResult ();
10606 result.ConsumerID = sp.LocalId;
10607 result.Depth = 0;
10608 result.Normal = Vector3.Zero;
10609 result.Pos = posToCheck;
10610 results.Add(result);
10611 }
10612 });
10613 }
10614 } 11505 }
10615 11506
10616 int refcount = 0; 11507 results.Sort(delegate(ContactResult a, ContactResult b)
11508 {
11509 return (int)(a.Depth - b.Depth);
11510 });
11511
11512 int values = 0;
10617 foreach (ContactResult result in results) 11513 foreach (ContactResult result in results)
10618 { 11514 {
10619 if ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) 11515 UUID itemID = UUID.Zero;
10620 == ScriptBaseClass.RC_REJECT_LAND && result.ConsumerID == 0) 11516 int linkNum = 0;
10621 continue;
10622
10623 ISceneEntity entity = World.GetSceneObjectPart(result.ConsumerID);
10624
10625 if (entity == null && (rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != ScriptBaseClass.RC_REJECT_AGENTS)
10626 entity = World.GetScenePresence(result.ConsumerID); //Only check if we should be looking for agents
10627 11517
10628 if (entity == null) 11518 SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID);
11519 // It's a prim!
11520 if (part != null)
10629 { 11521 {
10630 list.Add(UUID.Zero); 11522 if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY)
10631 11523 itemID = part.ParentGroup.UUID;
10632 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) 11524 else
10633 list.Add(0); 11525 itemID = part.UUID;
10634
10635 list.Add(result.Pos);
10636
10637 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
10638 list.Add(result.Normal);
10639 11526
10640 continue; //Can't find it, so add UUID.Zero 11527 linkNum = part.LinkNum;
10641 } 11528 }
10642 11529 else
10643 /*if (detectPhantom == 0 && intersection.obj is ISceneChildEntity &&
10644 ((ISceneChildEntity)intersection.obj).PhysActor == null)
10645 continue;*/ //Can't do this ATM, physics engine knows only of non phantom objects
10646
10647 if (entity is SceneObjectPart)
10648 { 11530 {
10649 if (((SceneObjectPart)entity).PhysActor != null && ((SceneObjectPart)entity).PhysActor.IsPhysical) 11531 ScenePresence sp = World.GetScenePresence(result.ConsumerID);
10650 { 11532 /// It it a boy? a girl?
10651 if (!checkPhysical) 11533 if (sp != null)
10652 continue; 11534 itemID = sp.UUID;
10653 }
10654 else
10655 {
10656 if (!checkNonPhysical)
10657 continue;
10658 }
10659 } 11535 }
10660 11536
10661 refcount++; 11537 list.Add(new LSL_String(itemID.ToString()));
10662 if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY && entity is SceneObjectPart) 11538 list.Add(new LSL_String(result.Pos.ToString()));
10663 list.Add(((SceneObjectPart)entity).ParentGroup.UUID);
10664 else
10665 list.Add(entity.UUID);
10666 11539
10667 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) 11540 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM)
10668 { 11541 list.Add(new LSL_Integer(linkNum));
10669 if (entity is SceneObjectPart)
10670 list.Add(((SceneObjectPart)entity).LinkNum);
10671 else
10672 list.Add(0);
10673 }
10674 11542
10675 list.Add(result.Pos);
10676 11543
10677 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) 11544 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
10678 list.Add(result.Normal); 11545 list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z));
11546
11547 values++;
11548 count--;
11549
11550 if (count == 0)
11551 break;
10679 } 11552 }
10680 11553
10681 list.Add(refcount); //The status code, either the # of contacts, RCERR_SIM_PERF_LOW, or RCERR_CAST_TIME_EXCEEDED 11554 list.Add(new LSL_Integer(values));
10682 11555
10683 return list; 11556 return list;
10684 } 11557 }
@@ -10718,7 +11591,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10718 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD: 11591 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD:
10719 if (!isAccount) return 0; 11592 if (!isAccount) return 0;
10720 if (estate.HasAccess(id)) return 1; 11593 if (estate.HasAccess(id)) return 1;
10721 if (estate.IsBanned(id)) 11594 if (estate.IsBanned(id, World.GetUserFlags(id)))
10722 estate.RemoveBan(id); 11595 estate.RemoveBan(id);
10723 estate.AddEstateUser(id); 11596 estate.AddEstateUser(id);
10724 break; 11597 break;
@@ -10737,14 +11610,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10737 break; 11610 break;
10738 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD: 11611 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD:
10739 if (!isAccount) return 0; 11612 if (!isAccount) return 0;
10740 if (estate.IsBanned(id)) return 1; 11613 if (estate.IsBanned(id, World.GetUserFlags(id))) return 1;
10741 EstateBan ban = new EstateBan(); 11614 EstateBan ban = new EstateBan();
10742 ban.EstateID = estate.EstateID; 11615 ban.EstateID = estate.EstateID;
10743 ban.BannedUserID = id; 11616 ban.BannedUserID = id;
10744 estate.AddBan(ban); 11617 estate.AddBan(ban);
10745 break; 11618 break;
10746 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE: 11619 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE:
10747 if (!isAccount || !estate.IsBanned(id)) return 0; 11620 if (!isAccount || !estate.IsBanned(id, World.GetUserFlags(id))) return 0;
10748 estate.RemoveBan(id); 11621 estate.RemoveBan(id);
10749 break; 11622 break;
10750 default: return 0; 11623 default: return 0;
@@ -10770,22 +11643,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10770 NotImplemented("llGetSPMaxMemory"); 11643 NotImplemented("llGetSPMaxMemory");
10771 } 11644 }
10772 11645
10773 public void llGetUsedMemory() 11646 public virtual LSL_Integer llGetUsedMemory()
10774 { 11647 {
10775 m_host.AddScriptLPS(1); 11648 m_host.AddScriptLPS(1);
10776 NotImplemented("llGetUsedMemory"); 11649 NotImplemented("llGetUsedMemory");
11650 return 0;
10777 } 11651 }
10778 11652
10779 public void llScriptProfiler(LSL_Integer flags) 11653 public void llScriptProfiler(LSL_Integer flags)
10780 { 11654 {
10781 m_host.AddScriptLPS(1); 11655 m_host.AddScriptLPS(1);
10782 NotImplemented("llScriptProfiler"); 11656 //NotImplemented("llScriptProfiler");
10783 } 11657 }
10784 11658
10785 public void llSetSoundQueueing(int queue) 11659 public void llSetSoundQueueing(int queue)
10786 { 11660 {
10787 m_host.AddScriptLPS(1); 11661 m_host.AddScriptLPS(1);
10788 NotImplemented("llSetSoundQueueing");
10789 } 11662 }
10790 11663
10791 public void llCollisionSprite(string impact_sprite) 11664 public void llCollisionSprite(string impact_sprite)
@@ -10797,7 +11670,133 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10797 public void llGodLikeRezObject(string inventory, LSL_Vector pos) 11670 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
10798 { 11671 {
10799 m_host.AddScriptLPS(1); 11672 m_host.AddScriptLPS(1);
10800 NotImplemented("llGodLikeRezObject"); 11673
11674 if (!World.Permissions.IsGod(m_host.OwnerID))
11675 NotImplemented("llGodLikeRezObject");
11676
11677 AssetBase rezAsset = World.AssetService.Get(inventory);
11678 if (rezAsset == null)
11679 {
11680 llSay(0, "Asset not found");
11681 return;
11682 }
11683
11684 SceneObjectGroup group = null;
11685
11686 try
11687 {
11688 string xmlData = Utils.BytesToString(rezAsset.Data);
11689 group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
11690 }
11691 catch
11692 {
11693 llSay(0, "Asset not found");
11694 return;
11695 }
11696
11697 if (group == null)
11698 {
11699 llSay(0, "Asset not found");
11700 return;
11701 }
11702
11703 group.RootPart.AttachPoint = group.RootPart.Shape.State;
11704 group.RootPart.AttachOffset = group.AbsolutePosition;
11705
11706 group.ResetIDs();
11707
11708 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
11709 World.AddNewSceneObject(group, true, llpos, Quaternion.Identity, Vector3.Zero);
11710 group.CreateScriptInstances(0, true, World.DefaultScriptEngine, 3);
11711 group.ScheduleGroupForFullUpdate();
11712
11713 // objects rezzed with this method are die_at_edge by default.
11714 group.RootPart.SetDieAtEdge(true);
11715
11716 group.ResumeScripts();
11717
11718 m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
11719 "object_rez", new Object[] {
11720 new LSL_String(
11721 group.RootPart.UUID.ToString()) },
11722 new DetectParams[0]));
11723 }
11724
11725 public LSL_String llTransferLindenDollars(string destination, int amount)
11726 {
11727 UUID txn = UUID.Random();
11728
11729 Util.FireAndForget(delegate(object x)
11730 {
11731 int replycode = 0;
11732 string replydata = destination + "," + amount.ToString();
11733
11734 try
11735 {
11736 UUID invItemID=InventorySelf();
11737 if (invItemID == UUID.Zero)
11738 {
11739 replydata = "SERVICE_ERROR";
11740 return;
11741 }
11742
11743 m_host.AddScriptLPS(1);
11744
11745 m_host.TaskInventory.LockItemsForRead(true);
11746 TaskInventoryItem item = m_host.TaskInventory[invItemID];
11747 m_host.TaskInventory.LockItemsForRead(false);
11748
11749 if (item.PermsGranter == UUID.Zero)
11750 {
11751 replydata = "MISSING_PERMISSION_DEBIT";
11752 return;
11753 }
11754
11755 if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
11756 {
11757 replydata = "MISSING_PERMISSION_DEBIT";
11758 return;
11759 }
11760
11761 UUID toID = new UUID();
11762
11763 if (!UUID.TryParse(destination, out toID))
11764 {
11765 replydata = "INVALID_AGENT";
11766 return;
11767 }
11768
11769 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
11770
11771 if (money == null)
11772 {
11773 replydata = "TRANSFERS_DISABLED";
11774 return;
11775 }
11776
11777 bool result = money.ObjectGiveMoney(
11778 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
11779
11780 if (result)
11781 {
11782 replycode = 1;
11783 return;
11784 }
11785
11786 replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS";
11787 }
11788 finally
11789 {
11790 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
11791 "transaction_result", new Object[] {
11792 new LSL_String(txn.ToString()),
11793 new LSL_Integer(replycode),
11794 new LSL_String(replydata) },
11795 new DetectParams[0]));
11796 }
11797 });
11798
11799 return txn.ToString();
10801 } 11800 }
10802 11801
10803 #endregion 11802 #endregion
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index b1583eb..614872e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -137,6 +137,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
137 internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow; 137 internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow;
138 internal float m_ScriptDelayFactor = 1.0f; 138 internal float m_ScriptDelayFactor = 1.0f;
139 internal float m_ScriptDistanceFactor = 1.0f; 139 internal float m_ScriptDistanceFactor = 1.0f;
140 internal bool m_debuggerSafe = false;
140 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >(); 141 internal Dictionary<string, FunctionPerms > m_FunctionPerms = new Dictionary<string, FunctionPerms >();
141 142
142 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) 143 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
@@ -145,6 +146,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
145 m_host = host; 146 m_host = host;
146 m_localID = localID; 147 m_localID = localID;
147 m_itemID = itemID; 148 m_itemID = itemID;
149 m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
148 150
149 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) 151 if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false))
150 m_OSFunctionsEnabled = true; 152 m_OSFunctionsEnabled = true;
@@ -206,7 +208,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
206 208
207 internal void OSSLError(string msg) 209 internal void OSSLError(string msg)
208 { 210 {
209 throw new Exception("OSSL Runtime Error: " + msg); 211 if (m_debuggerSafe)
212 {
213 OSSLShoutError(msg);
214 }
215 else
216 {
217 throw new Exception("OSSL Runtime Error: " + msg);
218 }
210 } 219 }
211 220
212 private void InitLSL() 221 private void InitLSL()
@@ -917,18 +926,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
917 if (target != null) 926 if (target != null)
918 { 927 {
919 UUID animID=UUID.Zero; 928 UUID animID=UUID.Zero;
920 lock (m_host.TaskInventory) 929 m_host.TaskInventory.LockItemsForRead(true);
930 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
921 { 931 {
922 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 932 if (inv.Value.Name == animation)
923 { 933 {
924 if (inv.Value.Name == animation) 934 if (inv.Value.Type == (int)AssetType.Animation)
925 { 935 animID = inv.Value.AssetID;
926 if (inv.Value.Type == (int)AssetType.Animation) 936 continue;
927 animID = inv.Value.AssetID;
928 continue;
929 }
930 } 937 }
931 } 938 }
939 m_host.TaskInventory.LockItemsForRead(false);
932 if (animID == UUID.Zero) 940 if (animID == UUID.Zero)
933 target.Animator.AddAnimation(animation, m_host.UUID); 941 target.Animator.AddAnimation(animation, m_host.UUID);
934 else 942 else
@@ -955,18 +963,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
955 if (target != null) 963 if (target != null)
956 { 964 {
957 UUID animID = UUID.Zero; 965 UUID animID = UUID.Zero;
958 lock (m_host.TaskInventory) 966 m_host.TaskInventory.LockItemsForRead(true);
967 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
959 { 968 {
960 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory) 969 if (inv.Value.Name == animation)
961 { 970 {
962 if (inv.Value.Name == animation) 971 if (inv.Value.Type == (int)AssetType.Animation)
963 { 972 animID = inv.Value.AssetID;
964 if (inv.Value.Type == (int)AssetType.Animation) 973 continue;
965 animID = inv.Value.AssetID;
966 continue;
967 }
968 } 974 }
969 } 975 }
976 m_host.TaskInventory.LockItemsForRead(false);
970 977
971 if (animID == UUID.Zero) 978 if (animID == UUID.Zero)
972 target.Animator.RemoveAnimation(animation); 979 target.Animator.RemoveAnimation(animation);
@@ -1798,6 +1805,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1798 1805
1799 if (!UUID.TryParse(notecardNameOrUuid, out assetID)) 1806 if (!UUID.TryParse(notecardNameOrUuid, out assetID))
1800 { 1807 {
1808 m_host.TaskInventory.LockItemsForRead(true);
1801 foreach (TaskInventoryItem item in m_host.TaskInventory.Values) 1809 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
1802 { 1810 {
1803 if (item.Type == 7 && item.Name == notecardNameOrUuid) 1811 if (item.Type == 7 && item.Name == notecardNameOrUuid)
@@ -1805,6 +1813,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
1805 assetID = item.AssetID; 1813 assetID = item.AssetID;
1806 } 1814 }
1807 } 1815 }
1816 m_host.TaskInventory.LockItemsForRead(false);
1808 } 1817 }
1809 1818
1810 if (assetID == UUID.Zero) 1819 if (assetID == UUID.Zero)
@@ -2233,7 +2242,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2233 CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); 2242 CheckThreatLevel(ThreatLevel.High, "osNpcCreate");
2234 m_host.AddScriptLPS(1); 2243 m_host.AddScriptLPS(1);
2235 2244
2236 return NpcCreate(firstname, lastname, position, notecard, false, true); 2245 return NpcCreate(firstname, lastname, position, notecard, true, false);
2237 } 2246 }
2238 2247
2239 public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, int options) 2248 public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, int options)
@@ -2244,24 +2253,36 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2244 return NpcCreate( 2253 return NpcCreate(
2245 firstname, lastname, position, notecard, 2254 firstname, lastname, position, notecard,
2246 (options & ScriptBaseClass.OS_NPC_NOT_OWNED) == 0, 2255 (options & ScriptBaseClass.OS_NPC_NOT_OWNED) == 0,
2247 (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) == 0); 2256 false);
2257// (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) == 0);
2248 } 2258 }
2249 2259
2250 private LSL_Key NpcCreate( 2260 private LSL_Key NpcCreate(
2251 string firstname, string lastname, LSL_Vector position, string notecard, bool owned, bool senseAsAgent) 2261 string firstname, string lastname, LSL_Vector position, string notecard, bool owned, bool senseAsAgent)
2252 { 2262 {
2263 if (!owned)
2264 OSSLError("Unowned NPCs are unsupported");
2265
2266 string groupTitle = String.Empty;
2267
2268 if (firstname != String.Empty || lastname != String.Empty)
2269 {
2270 if (firstname != "Shown outfit:")
2271 groupTitle = "- NPC -";
2272 }
2273
2253 INPCModule module = World.RequestModuleInterface<INPCModule>(); 2274 INPCModule module = World.RequestModuleInterface<INPCModule>();
2254 if (module != null) 2275 if (module != null)
2255 { 2276 {
2256 AvatarAppearance appearance = null; 2277 AvatarAppearance appearance = null;
2257 2278
2258 UUID id; 2279// UUID id;
2259 if (UUID.TryParse(notecard, out id)) 2280// if (UUID.TryParse(notecard, out id))
2260 { 2281// {
2261 ScenePresence clonePresence = World.GetScenePresence(id); 2282// ScenePresence clonePresence = World.GetScenePresence(id);
2262 if (clonePresence != null) 2283// if (clonePresence != null)
2263 appearance = clonePresence.Appearance; 2284// appearance = clonePresence.Appearance;
2264 } 2285// }
2265 2286
2266 if (appearance == null) 2287 if (appearance == null)
2267 { 2288 {
@@ -2289,6 +2310,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2289 World, 2310 World,
2290 appearance); 2311 appearance);
2291 2312
2313 ScenePresence sp;
2314 if (World.TryGetScenePresence(x, out sp))
2315 {
2316 sp.Grouptitle = groupTitle;
2317 sp.SendAvatarDataToAllAgents();
2318 }
2292 return new LSL_Key(x.ToString()); 2319 return new LSL_Key(x.ToString());
2293 } 2320 }
2294 2321
@@ -2557,15 +2584,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2557 CheckThreatLevel(ThreatLevel.High, "osNpcRemove"); 2584 CheckThreatLevel(ThreatLevel.High, "osNpcRemove");
2558 m_host.AddScriptLPS(1); 2585 m_host.AddScriptLPS(1);
2559 2586
2560 INPCModule module = World.RequestModuleInterface<INPCModule>(); 2587 Util.FireAndForget(delegate(object x) {
2561 if (module != null) 2588 INPCModule module = World.RequestModuleInterface<INPCModule>();
2562 { 2589 if (module != null)
2563 UUID npcId = new UUID(npc.m_string); 2590 {
2591 UUID npcId = new UUID(npc.m_string);
2564 2592
2565 if (!module.CheckPermissions(npcId, m_host.OwnerID)) 2593 if (!module.CheckPermissions(npcId, m_host.OwnerID))
2566 return; 2594 return;
2567 2595
2568 module.DeleteNPC(npcId, World); 2596 module.DeleteNPC(npcId, World);
2597 });
2569 } 2598 }
2570 } 2599 }
2571 2600
@@ -2917,4 +2946,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2917 return date.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"); 2946 return date.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
2918 } 2947 }
2919 } 2948 }
2920} \ No newline at end of file 2949}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
index 3e0e452..2a0ce44 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs
@@ -209,7 +209,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
209 // Is the sensor type is AGENT and not SCRIPTED then include agents 209 // Is the sensor type is AGENT and not SCRIPTED then include agents
210 if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC)) != 0 && (ts.type & SCRIPTED) == 0) 210 if ((ts.type & (AGENT | AGENT_BY_USERNAME | NPC)) != 0 && (ts.type & SCRIPTED) == 0)
211 { 211 {
212 sensedEntities.AddRange(doAgentSensor(ts)); 212 sensedEntities.AddRange(doAgentSensor(ts));
213 } 213 }
214 214
215 // If SCRIPTED or PASSIVE or ACTIVE check objects 215 // If SCRIPTED or PASSIVE or ACTIVE check objects
@@ -306,13 +306,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
306 float dy; 306 float dy;
307 float dz; 307 float dz;
308 308
309 Quaternion q = SensePoint.RotationOffset; 309// Quaternion q = SensePoint.RotationOffset;
310 Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation!
310 if (SensePoint.ParentGroup.IsAttachment) 311 if (SensePoint.ParentGroup.IsAttachment)
311 { 312 {
312 // In attachments, the sensor cone always orients with the 313 // In attachments, the sensor cone always orients with the
313 // avatar rotation. This may include a nonzero elevation if 314 // avatar rotation. This may include a nonzero elevation if
314 // in mouselook. 315 // in mouselook.
315 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); 316 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
317 fromRegionPos = avatar.AbsolutePosition;
316 q = avatar.Rotation; 318 q = avatar.Rotation;
317 } 319 }
318 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); 320 LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
@@ -435,6 +437,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
435 // avatar rotation. This may include a nonzero elevation if 437 // avatar rotation. This may include a nonzero elevation if
436 // in mouselook. 438 // in mouselook.
437 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); 439 ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
440 if (avatar == null)
441 return sensedEntities;
442 fromRegionPos = avatar.AbsolutePosition;
438 q = avatar.Rotation; 443 q = avatar.Rotation;
439 } 444 }
440 445
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 6106a65..f2d4399 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
@@ -123,6 +123,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
123 LSL_Float llGetEnergy(); 123 LSL_Float llGetEnergy();
124 LSL_Vector llGetForce(); 124 LSL_Vector llGetForce();
125 LSL_Integer llGetFreeMemory(); 125 LSL_Integer llGetFreeMemory();
126 LSL_Integer llGetUsedMemory();
126 LSL_Integer llGetFreeURLs(); 127 LSL_Integer llGetFreeURLs();
127 LSL_Vector llGetGeometricCenter(); 128 LSL_Vector llGetGeometricCenter();
128 LSL_Float llGetGMTclock(); 129 LSL_Float llGetGMTclock();
@@ -201,6 +202,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
201 void llGiveInventory(string destination, string inventory); 202 void llGiveInventory(string destination, string inventory);
202 void llGiveInventoryList(string destination, string category, LSL_List inventory); 203 void llGiveInventoryList(string destination, string category, LSL_List inventory);
203 LSL_Integer llGiveMoney(string destination, int amount); 204 LSL_Integer llGiveMoney(string destination, int amount);
205 LSL_String llTransferLindenDollars(string destination, int amount);
204 void llGodLikeRezObject(string inventory, LSL_Vector pos); 206 void llGodLikeRezObject(string inventory, LSL_Vector pos);
205 LSL_Float llGround(LSL_Vector offset); 207 LSL_Float llGround(LSL_Vector offset);
206 LSL_Vector llGroundContour(LSL_Vector offset); 208 LSL_Vector llGroundContour(LSL_Vector offset);
@@ -408,7 +410,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
408 LSL_Vector llWind(LSL_Vector offset); 410 LSL_Vector llWind(LSL_Vector offset);
409 LSL_String llXorBase64Strings(string str1, string str2); 411 LSL_String llXorBase64Strings(string str1, string str2);
410 LSL_String llXorBase64StringsCorrect(string str1, string str2); 412 LSL_String llXorBase64StringsCorrect(string str1, string str2);
411 void print(string str); 413 LSL_Integer llGetLinkNumberOfSides(LSL_Integer link);
412 414
413 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 415 void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules);
414 LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); 416 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 dbc1dfc..ca24051 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -85,7 +85,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
85 // Avatar Info Commands 85 // Avatar Info Commands
86 string osGetAgentIP(string agent); 86 string osGetAgentIP(string agent);
87 LSL_List osGetAgents(); 87 LSL_List osGetAgents();
88 88
89 // Teleport commands 89 // Teleport commands
90 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 90 void osTeleportAgent(string agent, string regionName, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat);
91 void osTeleportAgent(string agent, int regionX, int regionY, LSL_Types.Vector3 position, LSL_Types.Vector3 lookat); 91 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 bb498b5..3d0e5cb 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -282,6 +282,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
282 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART 282 public const int CHANGED_REGION_START = 1024; //LL Changed the constant from CHANGED_REGION_RESTART
283 public const int CHANGED_MEDIA = 2048; 283 public const int CHANGED_MEDIA = 2048;
284 public const int CHANGED_ANIMATION = 16384; 284 public const int CHANGED_ANIMATION = 16384;
285 public const int CHANGED_POSITION = 32768;
285 public const int TYPE_INVALID = 0; 286 public const int TYPE_INVALID = 0;
286 public const int TYPE_INTEGER = 1; 287 public const int TYPE_INTEGER = 1;
287 public const int TYPE_FLOAT = 2; 288 public const int TYPE_FLOAT = 2;
@@ -378,6 +379,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
378 public const int PRIM_SCULPT_TYPE_TORUS = 2; 379 public const int PRIM_SCULPT_TYPE_TORUS = 2;
379 public const int PRIM_SCULPT_TYPE_PLANE = 3; 380 public const int PRIM_SCULPT_TYPE_PLANE = 3;
380 public const int PRIM_SCULPT_TYPE_CYLINDER = 4; 381 public const int PRIM_SCULPT_TYPE_CYLINDER = 4;
382 public const int PRIM_SCULPT_FLAG_INVERT = 64;
383 public const int PRIM_SCULPT_FLAG_MIRROR = 128;
381 384
382 public const int MASK_BASE = 0; 385 public const int MASK_BASE = 0;
383 public const int MASK_OWNER = 1; 386 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 83550a5..fad6c35 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;
@@ -164,6 +165,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
164 m_LSL_Functions.llBreakLink(linknum); 165 m_LSL_Functions.llBreakLink(linknum);
165 } 166 }
166 167
168 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
169 {
170 return m_LSL_Functions.llCastRay(start, end, options);
171 }
172
167 public LSL_Integer llCeil(double f) 173 public LSL_Integer llCeil(double f)
168 { 174 {
169 return m_LSL_Functions.llCeil(f); 175 return m_LSL_Functions.llCeil(f);
@@ -314,6 +320,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
314 m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel); 320 m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel);
315 } 321 }
316 322
323 [DebuggerNonUserCode]
317 public void llDie() 324 public void llDie()
318 { 325 {
319 m_LSL_Functions.llDie(); 326 m_LSL_Functions.llDie();
@@ -464,6 +471,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
464 return m_LSL_Functions.llGetFreeMemory(); 471 return m_LSL_Functions.llGetFreeMemory();
465 } 472 }
466 473
474 public LSL_Integer llGetUsedMemory()
475 {
476 return m_LSL_Functions.llGetUsedMemory();
477 }
478
467 public LSL_Integer llGetFreeURLs() 479 public LSL_Integer llGetFreeURLs()
468 { 480 {
469 return m_LSL_Functions.llGetFreeURLs(); 481 return m_LSL_Functions.llGetFreeURLs();
@@ -849,6 +861,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
849 return m_LSL_Functions.llGiveMoney(destination, amount); 861 return m_LSL_Functions.llGiveMoney(destination, amount);
850 } 862 }
851 863
864 public LSL_String llTransferLindenDollars(string destination, int amount)
865 {
866 return m_LSL_Functions.llTransferLindenDollars(destination, amount);
867 }
868
852 public void llGodLikeRezObject(string inventory, LSL_Vector pos) 869 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
853 { 870 {
854 m_LSL_Functions.llGodLikeRezObject(inventory, pos); 871 m_LSL_Functions.llGodLikeRezObject(inventory, pos);
@@ -1893,9 +1910,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
1893 return m_LSL_Functions.llClearPrimMedia(face); 1910 return m_LSL_Functions.llClearPrimMedia(face);
1894 } 1911 }
1895 1912
1896 public void print(string str) 1913 public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
1897 { 1914 {
1898 m_LSL_Functions.print(str); 1915 return m_LSL_Functions.llGetLinkNumberOfSides(link);
1899 } 1916 }
1900 } 1917 }
1901} 1918}
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 8cebb4a..7e7e278 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 9b93135..34f2cc7 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;
@@ -264,13 +265,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
264 265
265 if (part != null) 266 if (part != null)
266 { 267 {
267 lock (part.TaskInventory) 268 part.TaskInventory.LockItemsForRead(true);
269 if (part.TaskInventory.ContainsKey(m_ItemID))
268 { 270 {
269 if (part.TaskInventory.ContainsKey(m_ItemID)) 271 m_thisScriptTask = part.TaskInventory[m_ItemID];
270 {
271 m_thisScriptTask = part.TaskInventory[m_ItemID];
272 }
273 } 272 }
273 part.TaskInventory.LockItemsForRead(false);
274 } 274 }
275 275
276 ApiManager am = new ApiManager(); 276 ApiManager am = new ApiManager();
@@ -469,14 +469,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
469 { 469 {
470 int permsMask; 470 int permsMask;
471 UUID permsGranter; 471 UUID permsGranter;
472 lock (part.TaskInventory) 472 part.TaskInventory.LockItemsForRead(true);
473 if (!part.TaskInventory.ContainsKey(m_ItemID))
473 { 474 {
474 if (!part.TaskInventory.ContainsKey(m_ItemID)) 475 part.TaskInventory.LockItemsForRead(false);
475 return; 476 return;
476
477 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
478 permsMask = part.TaskInventory[m_ItemID].PermsMask;
479 } 477 }
478 permsGranter = part.TaskInventory[m_ItemID].PermsGranter;
479 permsMask = part.TaskInventory[m_ItemID].PermsMask;
480 part.TaskInventory.LockItemsForRead(false);
480 481
481 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) 482 if ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
482 { 483 {
@@ -585,6 +586,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
585 return true; 586 return true;
586 } 587 }
587 588
589 [DebuggerNonUserCode] //Prevents the debugger from farting in this function
588 public void SetState(string state) 590 public void SetState(string state)
589 { 591 {
590 if (state == State) 592 if (state == State)
@@ -596,7 +598,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
596 new DetectParams[0])); 598 new DetectParams[0]));
597 PostEvent(new EventParams("state_entry", new Object[0], 599 PostEvent(new EventParams("state_entry", new Object[0],
598 new DetectParams[0])); 600 new DetectParams[0]));
599 601
600 throw new EventAbortException(); 602 throw new EventAbortException();
601 } 603 }
602 604
@@ -679,41 +681,42 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
679 /// <returns></returns> 681 /// <returns></returns>
680 public object EventProcessor() 682 public object EventProcessor()
681 { 683 {
682 lock (m_Script) 684 EventParams data = null;
683 {
684// m_log.DebugFormat("[XEngine]: EventProcessor() invoked for {0}.{1}", PrimName, ScriptName);
685 685
686 if (Suspended) 686// m_log.DebugFormat("[XEngine]: EventProcessor() invoked for {0}.{1}", PrimName, ScriptName);
687 return 0;
688 687
689 EventParams data = null; 688 if (Suspended)
689 return 0;
690 690
691 lock (m_EventQueue) 691 lock (m_EventQueue)
692 {
693 data = (EventParams) m_EventQueue.Dequeue();
694 if (data == null) // Shouldn't happen
692 { 695 {
693 data = (EventParams) m_EventQueue.Dequeue(); 696 if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown))
694 if (data == null) // Shouldn't happen
695 { 697 {
696 if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown)) 698 m_CurrentResult = m_Engine.QueueEventHandler(this);
697 {
698 m_CurrentResult = m_Engine.QueueEventHandler(this);
699 }
700 else
701 {
702 m_CurrentResult = null;
703 }
704 return 0;
705 } 699 }
706 700 else
707 if (data.EventName == "timer")
708 m_TimerQueued = false;
709 if (data.EventName == "control")
710 { 701 {
711 if (m_ControlEventsInQueue > 0) 702 m_CurrentResult = null;
712 m_ControlEventsInQueue--;
713 } 703 }
714 if (data.EventName == "collision") 704 return 0;
715 m_CollisionInQueue = false; 705 }
706
707 if (data.EventName == "timer")
708 m_TimerQueued = false;
709 if (data.EventName == "control")
710 {
711 if (m_ControlEventsInQueue > 0)
712 m_ControlEventsInQueue--;
716 } 713 }
714 if (data.EventName == "collision")
715 m_CollisionInQueue = false;
716 }
717
718 lock(m_Script)
719 {
717 720
718// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this); 721// m_log.DebugFormat("[XEngine]: Processing event {0} for {1}", data.EventName, this);
719 722
@@ -870,6 +873,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
870 new Object[0], new DetectParams[0])); 873 new Object[0], new DetectParams[0]));
871 } 874 }
872 875
876 [DebuggerNonUserCode] //Stops the VS debugger from farting in this function
873 public void ApiResetScript() 877 public void ApiResetScript()
874 { 878 {
875 // bool running = Running; 879 // bool running = Running;
@@ -901,10 +905,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
901 905
902 public Dictionary<string, object> GetVars() 906 public Dictionary<string, object> GetVars()
903 { 907 {
904 if (m_Script != null) 908 return m_Script.GetVars();
905 return m_Script.GetVars();
906 else
907 return new Dictionary<string, object>();
908 } 909 }
909 910
910 public void SetVars(Dictionary<string, object> vars) 911 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 d848b2a..9e6752c 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 c68f03f..02d47bd 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.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.Globalization; 32using System.Globalization;
32using System.IO; 33using System.IO;
33using System.Reflection; 34using System.Reflection;
@@ -109,6 +110,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
109 private Dictionary<UUID, IScriptInstance> m_Scripts = 110 private Dictionary<UUID, IScriptInstance> m_Scripts =
110 new Dictionary<UUID, IScriptInstance>(); 111 new Dictionary<UUID, IScriptInstance>();
111 112
113 private OpenMetaverse.ReaderWriterLockSlim m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
114
112 // Maps the asset ID to the assembly 115 // Maps the asset ID to the assembly
113 116
114 private Dictionary<UUID, string> m_Assemblies = 117 private Dictionary<UUID, string> m_Assemblies =
@@ -131,6 +134,71 @@ namespace OpenSim.Region.ScriptEngine.XEngine
131 IWorkItemResult m_CurrentCompile = null; 134 IWorkItemResult m_CurrentCompile = null;
132 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>(); 135 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
133 136
137 private void lockScriptsForRead(bool locked)
138 {
139 if (locked)
140 {
141 if (m_scriptsLock.RecursiveReadCount > 0)
142 {
143 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.");
144 m_scriptsLock.ExitReadLock();
145 }
146 if (m_scriptsLock.RecursiveWriteCount > 0)
147 {
148 m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
149 m_scriptsLock.ExitWriteLock();
150 }
151
152 while (!m_scriptsLock.TryEnterReadLock(60000))
153 {
154 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.");
155 if (m_scriptsLock.IsWriteLockHeld)
156 {
157 m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
158 }
159 }
160 }
161 else
162 {
163 if (m_scriptsLock.RecursiveReadCount > 0)
164 {
165 m_scriptsLock.ExitReadLock();
166 }
167 }
168 }
169 private void lockScriptsForWrite(bool locked)
170 {
171 if (locked)
172 {
173 if (m_scriptsLock.RecursiveReadCount > 0)
174 {
175 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.");
176 m_scriptsLock.ExitReadLock();
177 }
178 if (m_scriptsLock.RecursiveWriteCount > 0)
179 {
180 m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
181 m_scriptsLock.ExitWriteLock();
182 }
183
184 while (!m_scriptsLock.TryEnterWriteLock(60000))
185 {
186 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.");
187 if (m_scriptsLock.IsWriteLockHeld)
188 {
189 m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
190 }
191 }
192 }
193 else
194 {
195 if (m_scriptsLock.RecursiveWriteCount > 0)
196 {
197 m_scriptsLock.ExitWriteLock();
198 }
199 }
200 }
201
134 public string ScriptEngineName 202 public string ScriptEngineName
135 { 203 {
136 get { return "XEngine"; } 204 get { return "XEngine"; }
@@ -501,44 +569,37 @@ namespace OpenSim.Region.ScriptEngine.XEngine
501 { 569 {
502 if (!m_Enabled) 570 if (!m_Enabled)
503 return; 571 return;
504 572 lockScriptsForRead(true);
505 lock (m_Scripts) 573 foreach (IScriptInstance instance in m_Scripts.Values)
506 { 574 {
507 m_log.InfoFormat( 575 // Force a final state save
508 "[XEngine]: Shutting down {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName); 576 //
509 577 if (m_Assemblies.ContainsKey(instance.AssetID))
510 foreach (IScriptInstance instance in m_Scripts.Values)
511 { 578 {
512 // Force a final state save 579 string assembly = m_Assemblies[instance.AssetID];
513 // 580 instance.SaveState(assembly);
514 if (m_Assemblies.ContainsKey(instance.AssetID)) 581 }
515 {
516 string assembly = m_Assemblies[instance.AssetID];
517 instance.SaveState(assembly);
518 }
519 582
520 // Clear the event queue and abort the instance thread 583 // Clear the event queue and abort the instance thread
521 // 584 //
522 instance.ClearQueue(); 585 instance.ClearQueue();
523 instance.Stop(0); 586 instance.Stop(0);
524 587
525 // Release events, timer, etc 588 // Release events, timer, etc
526 // 589 //
527 instance.DestroyScriptInstance(); 590 instance.DestroyScriptInstance();
528 591
529 // Unload scripts and app domains. 592 // Unload scripts and app domains
530 // Must be done explicitly because they have infinite 593 // Must be done explicitly because they have infinite
531 // lifetime. 594 // lifetime
532 // However, don't bother to do this if the simulator is shutting 595 //
533 // down since it takes a long time with many scripts. 596 if (!m_SimulatorShuttingDown)
534 if (!m_SimulatorShuttingDown) 597 {
598 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
599 if (m_DomainScripts[instance.AppDomain].Count == 0)
535 { 600 {
536 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); 601 m_DomainScripts.Remove(instance.AppDomain);
537 if (m_DomainScripts[instance.AppDomain].Count == 0) 602 UnloadAppDomain(instance.AppDomain);
538 {
539 m_DomainScripts.Remove(instance.AppDomain);
540 UnloadAppDomain(instance.AppDomain);
541 }
542 } 603 }
543 } 604 }
544 605
@@ -547,6 +608,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
547 m_Assemblies.Clear(); 608 m_Assemblies.Clear();
548 m_DomainScripts.Clear(); 609 m_DomainScripts.Clear();
549 } 610 }
611 lockScriptsForRead(false);
612 lockScriptsForWrite(true);
613 m_Scripts.Clear();
614 lockScriptsForWrite(false);
615 m_PrimObjects.Clear();
616 m_Assemblies.Clear();
617 m_DomainScripts.Clear();
618
550 lock (m_ScriptEngines) 619 lock (m_ScriptEngines)
551 { 620 {
552 m_ScriptEngines.Remove(this); 621 m_ScriptEngines.Remove(this);
@@ -611,22 +680,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
611 680
612 List<IScriptInstance> instances = new List<IScriptInstance>(); 681 List<IScriptInstance> instances = new List<IScriptInstance>();
613 682
614 lock (m_Scripts) 683 lockScriptsForRead(true);
615 { 684 foreach (IScriptInstance instance in m_Scripts.Values)
616 foreach (IScriptInstance instance in m_Scripts.Values)
617 instances.Add(instance); 685 instances.Add(instance);
618 } 686 lockScriptsForRead(false);
619 687
620 foreach (IScriptInstance i in instances) 688 foreach (IScriptInstance i in instances)
621 { 689 {
622 string assembly = String.Empty; 690 string assembly = String.Empty;
623 691
624 lock (m_Scripts) 692
625 {
626 if (!m_Assemblies.ContainsKey(i.AssetID)) 693 if (!m_Assemblies.ContainsKey(i.AssetID))
627 continue; 694 continue;
628 assembly = m_Assemblies[i.AssetID]; 695 assembly = m_Assemblies[i.AssetID];
629 } 696
630 697
631 i.SaveState(assembly); 698 i.SaveState(assembly);
632 } 699 }
@@ -970,92 +1037,95 @@ namespace OpenSim.Region.ScriptEngine.XEngine
970 } 1037 }
971 1038
972 ScriptInstance instance = null; 1039 ScriptInstance instance = null;
973 lock (m_Scripts) 1040 // Create the object record
1041 lockScriptsForRead(true);
1042 if ((!m_Scripts.ContainsKey(itemID)) ||
1043 (m_Scripts[itemID].AssetID != assetID))
974 { 1044 {
975 // Create the object record 1045 lockScriptsForRead(false);
976 1046
977 if ((!m_Scripts.ContainsKey(itemID)) || 1047 UUID appDomain = assetID;
978 (m_Scripts[itemID].AssetID != assetID))
979 {
980 UUID appDomain = assetID;
981 1048
982 if (part.ParentGroup.IsAttachment) 1049 if (part.ParentGroup.IsAttachment)
983 appDomain = part.ParentGroup.RootPart.UUID; 1050 appDomain = part.ParentGroup.RootPart.UUID;
984 1051
985 if (!m_AppDomains.ContainsKey(appDomain)) 1052 if (!m_AppDomains.ContainsKey(appDomain))
1053 {
1054 try
986 { 1055 {
987 try 1056 AppDomainSetup appSetup = new AppDomainSetup();
988 { 1057 appSetup.PrivateBinPath = Path.Combine(
989 AppDomainSetup appSetup = new AppDomainSetup(); 1058 m_ScriptEnginesPath,
990 appSetup.PrivateBinPath = Path.Combine( 1059 m_Scene.RegionInfo.RegionID.ToString());
991 m_ScriptEnginesPath, 1060
992 m_Scene.RegionInfo.RegionID.ToString()); 1061 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
993 1062 Evidence evidence = new Evidence(baseEvidence);
994 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence; 1063
995 Evidence evidence = new Evidence(baseEvidence); 1064 AppDomain sandbox;
996 1065 if (m_AppDomainLoading)
997 AppDomain sandbox; 1066 sandbox = AppDomain.CreateDomain(
998 if (m_AppDomainLoading) 1067 m_Scene.RegionInfo.RegionID.ToString(),
999 sandbox = AppDomain.CreateDomain( 1068 evidence, appSetup);
1000 m_Scene.RegionInfo.RegionID.ToString(), 1069 else
1001 evidence, appSetup); 1070 sandbox = AppDomain.CurrentDomain;
1002 else 1071
1003 sandbox = AppDomain.CurrentDomain; 1072 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
1004 1073 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
1005 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); 1074 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
1006 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); 1075 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
1007 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet"); 1076 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
1008 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet); 1077 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
1009 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement); 1078 //sandbox.SetAppDomainPolicy(sandboxPolicy);
1010 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup; 1079
1011 //sandbox.SetAppDomainPolicy(sandboxPolicy); 1080 m_AppDomains[appDomain] = sandbox;
1012 1081
1013 m_AppDomains[appDomain] = sandbox; 1082 m_AppDomains[appDomain].AssemblyResolve +=
1014 1083 new ResolveEventHandler(
1015 m_AppDomains[appDomain].AssemblyResolve += 1084 AssemblyResolver.OnAssemblyResolve);
1016 new ResolveEventHandler( 1085 m_DomainScripts[appDomain] = new List<UUID>();
1017 AssemblyResolver.OnAssemblyResolve); 1086 }
1018 m_DomainScripts[appDomain] = new List<UUID>(); 1087 catch (Exception e)
1019 } 1088 {
1020 catch (Exception e) 1089 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
1090 m_ScriptErrorMessage += "Exception creating app domain:\n";
1091 m_ScriptFailCount++;
1092 lock (m_AddingAssemblies)
1021 { 1093 {
1022 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString()); 1094 m_AddingAssemblies[assembly]--;
1023 m_ScriptErrorMessage += "Exception creating app domain:\n";
1024 m_ScriptFailCount++;
1025 lock (m_AddingAssemblies)
1026 {
1027 m_AddingAssemblies[assembly]--;
1028 }
1029 return false;
1030 } 1095 }
1096 return false;
1031 } 1097 }
1032 m_DomainScripts[appDomain].Add(itemID); 1098 }
1033 1099 m_DomainScripts[appDomain].Add(itemID);
1034 instance = new ScriptInstance(this, part, 1100
1035 itemID, assetID, assembly, 1101 instance = new ScriptInstance(this, part,
1036 m_AppDomains[appDomain], 1102 itemID, assetID, assembly,
1037 part.ParentGroup.RootPart.Name, 1103 m_AppDomains[appDomain],
1038 item.Name, startParam, postOnRez, 1104 part.ParentGroup.RootPart.Name,
1039 stateSource, m_MaxScriptQueue); 1105 item.Name, startParam, postOnRez,
1040 1106 stateSource, m_MaxScriptQueue);
1041 m_log.DebugFormat( 1107
1042 "[XEngine] Loaded script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}", 1108 m_log.DebugFormat(
1043 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID, 1109 "[XEngine] Loaded script {0}.{1}, script UUID {2}, prim UUID {3} @ {4}.{5}",
1110 part.ParentGroup.RootPart.Name, item.Name, assetID, part.UUID,
1044 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName); 1111 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1045 1112
1046 if (presence != null) 1113 if (presence != null)
1047 { 1114 {
1048 ShowScriptSaveResponse(item.OwnerID, 1115 ShowScriptSaveResponse(item.OwnerID,
1049 assetID, "Compile successful", true); 1116 assetID, "Compile successful", true);
1050 }
1051
1052 instance.AppDomain = appDomain;
1053 instance.LineMap = linemap;
1054
1055 m_Scripts[itemID] = instance;
1056 } 1117 }
1057 }
1058 1118
1119 instance.AppDomain = appDomain;
1120 instance.LineMap = linemap;
1121 lockScriptsForWrite(true);
1122 m_Scripts[itemID] = instance;
1123 lockScriptsForWrite(false);
1124 }
1125 else
1126 {
1127 lockScriptsForRead(false);
1128 }
1059 lock (m_PrimObjects) 1129 lock (m_PrimObjects)
1060 { 1130 {
1061 if (!m_PrimObjects.ContainsKey(localID)) 1131 if (!m_PrimObjects.ContainsKey(localID))
@@ -1074,9 +1144,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1074 m_AddingAssemblies[assembly]--; 1144 m_AddingAssemblies[assembly]--;
1075 } 1145 }
1076 1146
1077 if (instance != null) 1147 if (instance!=null)
1078 instance.Init(); 1148 instance.Init();
1079 1149
1080 return true; 1150 return true;
1081 } 1151 }
1082 1152
@@ -1089,20 +1159,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1089 m_CompileDict.Remove(itemID); 1159 m_CompileDict.Remove(itemID);
1090 } 1160 }
1091 1161
1092 IScriptInstance instance = null; 1162 lockScriptsForRead(true);
1093 1163 // Do we even have it?
1094 lock (m_Scripts) 1164 if (!m_Scripts.ContainsKey(itemID))
1095 { 1165 {
1096 // Do we even have it? 1166 // Do we even have it?
1097 if (!m_Scripts.ContainsKey(itemID)) 1167 if (!m_Scripts.ContainsKey(itemID))
1098 return; 1168 return;
1099 1169
1100 instance = m_Scripts[itemID]; 1170 lockScriptsForRead(false);
1171 lockScriptsForWrite(true);
1101 m_Scripts.Remove(itemID); 1172 m_Scripts.Remove(itemID);
1173 lockScriptsForWrite(false);
1174
1175 return;
1102 } 1176 }
1177
1103 1178
1179 IScriptInstance instance=m_Scripts[itemID];
1180 lockScriptsForRead(false);
1181 lockScriptsForWrite(true);
1182 m_Scripts.Remove(itemID);
1183 lockScriptsForWrite(false);
1104 instance.ClearQueue(); 1184 instance.ClearQueue();
1105 instance.Stop(0); 1185 instance.Stop(0);
1186
1106// bool objectRemoved = false; 1187// bool objectRemoved = false;
1107 1188
1108 lock (m_PrimObjects) 1189 lock (m_PrimObjects)
@@ -1138,10 +1219,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1138 ObjectRemoved handlerObjectRemoved = OnObjectRemoved; 1219 ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
1139 if (handlerObjectRemoved != null) 1220 if (handlerObjectRemoved != null)
1140 { 1221 {
1141 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); 1222 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
1142 handlerObjectRemoved(part.UUID); 1223 handlerObjectRemoved(part.UUID);
1143 } 1224 }
1144 1225
1226 CleanAssemblies();
1227
1145 ScriptRemoved handlerScriptRemoved = OnScriptRemoved; 1228 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
1146 if (handlerScriptRemoved != null) 1229 if (handlerScriptRemoved != null)
1147 handlerScriptRemoved(itemID); 1230 handlerScriptRemoved(itemID);
@@ -1283,7 +1366,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1283 return false; 1366 return false;
1284 1367
1285 uuids = m_PrimObjects[localID]; 1368 uuids = m_PrimObjects[localID];
1286 } 1369
1287 1370
1288 foreach (UUID itemID in uuids) 1371 foreach (UUID itemID in uuids)
1289 { 1372 {
@@ -1301,6 +1384,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1301 result = true; 1384 result = true;
1302 } 1385 }
1303 } 1386 }
1387 }
1304 1388
1305 return result; 1389 return result;
1306 } 1390 }
@@ -1402,12 +1486,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1402 private IScriptInstance GetInstance(UUID itemID) 1486 private IScriptInstance GetInstance(UUID itemID)
1403 { 1487 {
1404 IScriptInstance instance; 1488 IScriptInstance instance;
1405 lock (m_Scripts) 1489 lockScriptsForRead(true);
1490 if (!m_Scripts.ContainsKey(itemID))
1406 { 1491 {
1407 if (!m_Scripts.ContainsKey(itemID)) 1492 lockScriptsForRead(false);
1408 return null; 1493 return null;
1409 instance = m_Scripts[itemID];
1410 } 1494 }
1495 instance = m_Scripts[itemID];
1496 lockScriptsForRead(false);
1411 return instance; 1497 return instance;
1412 } 1498 }
1413 1499
@@ -1431,6 +1517,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1431 return false; 1517 return false;
1432 } 1518 }
1433 1519
1520 [DebuggerNonUserCode]
1434 public void ApiResetScript(UUID itemID) 1521 public void ApiResetScript(UUID itemID)
1435 { 1522 {
1436 IScriptInstance instance = GetInstance(itemID); 1523 IScriptInstance instance = GetInstance(itemID);
@@ -1482,6 +1569,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1482 return UUID.Zero; 1569 return UUID.Zero;
1483 } 1570 }
1484 1571
1572 [DebuggerNonUserCode]
1485 public void SetState(UUID itemID, string newState) 1573 public void SetState(UUID itemID, string newState)
1486 { 1574 {
1487 IScriptInstance instance = GetInstance(itemID); 1575 IScriptInstance instance = GetInstance(itemID);
@@ -1504,11 +1592,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1504 1592
1505 List<IScriptInstance> instances = new List<IScriptInstance>(); 1593 List<IScriptInstance> instances = new List<IScriptInstance>();
1506 1594
1507 lock (m_Scripts) 1595 lockScriptsForRead(true);
1508 { 1596 foreach (IScriptInstance instance in m_Scripts.Values)
1509 foreach (IScriptInstance instance in m_Scripts.Values)
1510 instances.Add(instance); 1597 instances.Add(instance);
1511 } 1598 lockScriptsForRead(false);
1512 1599
1513 foreach (IScriptInstance i in instances) 1600 foreach (IScriptInstance i in instances)
1514 { 1601 {
@@ -1893,5 +1980,17 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1893// else 1980// else
1894// m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID); 1981// m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
1895 } 1982 }
1983
1984 public bool HasScript(UUID itemID, out bool running)
1985 {
1986 running = true;
1987
1988 IScriptInstance instance = GetInstance(itemID);
1989 if (instance == null)
1990 return false;
1991
1992 running = instance.Running;
1993 return true;
1994 }
1896 } 1995 }
1897} \ No newline at end of file 1996}